Class: OFX::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/ofx_kit/parser.rb

Overview

The object returned by OFX.new. Provides access to the parsed statements, accounts, transactions, and balances from an OFX file or IO object. Prefer the top-level OFX.new entry point over instantiating this class directly.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(resource, &block) ⇒ Parser

Parses the given OFX resource and builds the statement graph. resource is a file path (String) or IO object containing OFX data. If a block is given with arity 1, it receives the parser instance; otherwise it is evaluated in the parser’s context.



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/ofx_kit/parser.rb', line 14

def initialize(resource, &block)
  @filename   = extract_filename(resource)
  content     = read_resource(resource)
  tokenizer   = build_tokenizer(content).new(content)
  @document   = Base::Document.new(headers: tokenizer.headers, body: tokenizer.body)
  @statements = Base::Builder.new(@document).statements

  return unless block_given?

  block.arity == 1 ? block.call(self) : instance_eval(&block)
end

Instance Attribute Details

#filenameObject (readonly)

Original file path, if a path string was provided (String or nil).



39
40
41
# File 'lib/ofx_kit/parser.rb', line 39

def filename
  @filename
end

#statementsObject (readonly)

All statements in the file (Array of BankStatement or CreditCardStatement).

Example: Iterate statements in a multi-account file

ofx = OFX.new("multi.ofx")
ofx.statements.each do |stmt|
  puts "#{stmt..}: #{stmt.transactions.length} transactions"
end


35
36
37
# File 'lib/ofx_kit/parser.rb', line 35

def statements
  @statements
end

Instance Method Details

#accountObject

Returns the account for files containing a single statement (BankAccount, CreditCardAccount, or nil). Raises Errors::MultipleStatementsError if the file contains more than one statement.

Example

ofx = OFX.new("statement.ofx")
ofx..    #=> "123456789"
ofx..currency      #=> "USD"
ofx..bank_id       #=> "021000021"   # BankAccount only


58
59
60
61
62
63
64
# File 'lib/ofx_kit/parser.rb', line 58

def 
  if statements.length > 1
    raise Errors::MultipleStatementsError, 'File contains multiple statements. Use `accounts` to get all accounts.'
  end

  statements.first&.
end

#accountsObject

Returns all accounts across all statements (Array of BankAccount or CreditCardAccount).

Example: Multi-statement file

ofx = OFX.new("multi.ofx")
ofx.accounts.map(&:account_id)  #=> ["123456", "789012"]


74
75
76
# File 'lib/ofx_kit/parser.rb', line 74

def accounts
  statements.map(&:account)
end

#balanceObject

Returns the balance for files containing a single statement (Balance or nil). Raises Errors::MultipleStatementsError if the file contains more than one statement.

Example

ofx = OFX.new("statement.ofx")
ofx.balance.amount.format  #=> "$2,500.00"
ofx.balance.amount_cents   #=> 250000
ofx.balance.posted_at      #=> 2024-01-31 00:00:00 +0000


109
110
111
112
113
114
115
# File 'lib/ofx_kit/parser.rb', line 109

def balance
  if statements.length > 1
    raise Errors::MultipleStatementsError, 'File contains multiple statements. Use `balances` to get all balances.'
  end

  statements.first&.balance
end

#balancesObject

Returns balances for each statement (Array of Balance or nil).



119
120
121
122
123
124
125
126
127
# File 'lib/ofx_kit/parser.rb', line 119

def balances
  if statements.length > 1 && OFX.config.multi_statement_warnings?
    warn "[OFX] `balances` is aggregating across #{statements.length} statements. " \
         'For per-account balance use `statements[i].balance`. ' \
         'To disable this warning: OFX.config.multi_statement_warnings = false'
  end

  statements.map(&:balance)
end

#headersObject

Returns the parsed OFX header fields (Hash).



43
44
45
# File 'lib/ofx_kit/parser.rb', line 43

def headers
  @document.headers
end

#summaryObject

Returns a structured summary of all statements, including transaction counts, credit/debit totals (in cents), and closing balance.

Returns a Hash with keys:

  • :headers — compact OFX header fields

  • :statements — hash keyed by account_id, each with: :currency, :transactions (net_cents:), :credits (total_cents:), :debits (total_cents:), :balance_cents



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/ofx_kit/parser.rb', line 139

def summary
  {
    headers: headers.compact,
    statements: statements.each_with_object({}) do |stmt, h|
      acct = stmt.
      txns = stmt.transactions
      h[acct.] = {
        currency: acct.currency,
        transactions: { count: txns.length, net_cents: txns.net.fractional },
        credits: { count: txns.credits.length, total_cents: txns.total_credits.fractional },
        debits: { count: txns.debits.length, total_cents: txns.total_debits.fractional },
        balance_cents: stmt.balance&.amount&.fractional
      }
    end
  }
end

#transactionsObject

Returns all transactions aggregated across all statements as a TransactionCollection. Emits a warning when the file contains multiple statements.

Example

ofx = OFX.new("statement.ofx")
ofx.transactions.length               #=> 42
ofx.transactions.credits.length       #=> 10
ofx.transactions.total_debits.format  #=> "-$1,234.56"
ofx.transactions.net.format           #=> "$500.00"


89
90
91
92
93
94
95
96
97
# File 'lib/ofx_kit/parser.rb', line 89

def transactions
  if statements.length > 1 && OFX.config.multi_statement_warnings?
    warn "[OFX] `transactions` is aggregating across #{statements.length} statements. " \
         'For per-account transactions use `statements[i].transactions`. ' \
         'To disable this warning: OFX.config.multi_statement_warnings = false'
  end

  TransactionCollection.new(statements.flat_map { |s| s.transactions.to_a })
end