ofx_br 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +13 -0
  3. data/.gitignore +4 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +9 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +50 -0
  8. data/README.rdoc +51 -0
  9. data/Rakefile +7 -0
  10. data/lib/ofx_br/account.rb +11 -0
  11. data/lib/ofx_br/balance.rb +7 -0
  12. data/lib/ofx_br/errors.rb +3 -0
  13. data/lib/ofx_br/foundation.rb +9 -0
  14. data/lib/ofx_br/parser/ofx102.rb +201 -0
  15. data/lib/ofx_br/parser/ofx103.rb +7 -0
  16. data/lib/ofx_br/parser/ofx211.rb +40 -0
  17. data/lib/ofx_br/parser.rb +72 -0
  18. data/lib/ofx_br/sign_on.rb +8 -0
  19. data/lib/ofx_br/statement.rb +5 -0
  20. data/lib/ofx_br/status.rb +12 -0
  21. data/lib/ofx_br/transaction.rb +16 -0
  22. data/lib/ofx_br/version.rb +8 -0
  23. data/lib/ofx_br.rb +33 -0
  24. data/ofx_br.gemspec +32 -0
  25. data/spec/fixtures/avatar.gif +0 -0
  26. data/spec/fixtures/bb.ofx +700 -0
  27. data/spec/fixtures/bradesco.ofx +96 -0
  28. data/spec/fixtures/creditcard.ofx +79 -0
  29. data/spec/fixtures/dtsof_balance_issue.ofx +54 -0
  30. data/spec/fixtures/error.ofx +24 -0
  31. data/spec/fixtures/invalid_version.ofx +308 -0
  32. data/spec/fixtures/nd-amex-sample.ofx +12 -0
  33. data/spec/fixtures/sample.ofx +315 -0
  34. data/spec/fixtures/santander.ofx +91 -0
  35. data/spec/fixtures/utf8.ofx +308 -0
  36. data/spec/fixtures/v103.ofx +80 -0
  37. data/spec/fixtures/v211.ofx +85 -0
  38. data/spec/ofx_br/account_spec.rb +131 -0
  39. data/spec/ofx_br/ofx102_spec.rb +67 -0
  40. data/spec/ofx_br/ofx103_spec.rb +50 -0
  41. data/spec/ofx_br/ofx211_spec.rb +84 -0
  42. data/spec/ofx_br/ofx_parser_spec.rb +123 -0
  43. data/spec/ofx_br/ofx_spec.rb +21 -0
  44. data/spec/ofx_br/sign_on_spec.rb +27 -0
  45. data/spec/ofx_br/statement_spec.rb +131 -0
  46. data/spec/ofx_br/status_spec.rb +47 -0
  47. data/spec/ofx_br/transaction_spec.rb +201 -0
  48. data/spec/spec_helper.rb +9 -0
  49. metadata +174 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7762b34050e1cb1c3cd7191d88bdbff23902c771a4e76e50ec960ead46464bb7
4
+ data.tar.gz: 4fb5f842f6592c125a07007dc7e33aefb7ec6b72a37c0c9d270f374d3f16e424
5
+ SHA512:
6
+ metadata.gz: ec56cc287b9b1c4accc141a97ffbb7f10c649cb4a29ee4b5234ef77aee52d413ee65177b26d20d33a5c468610bf2a4734aff9cedcaee881efc12bbfb3dab800e
7
+ data.tar.gz: ebc5b4d3243f90de88678b0cd696e47fd9c01e160ad529946936b1276ca55f9d892e60b0b11122ab3a7e972dabe9c8234fba0c0b5641509defcc9aecf7d3ba73
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "08:00"
8
+ open-pull-requests-limit: 10
9
+ ignore:
10
+ - dependency-name: nokogiri
11
+ versions:
12
+ - 1.11.1
13
+ - 1.11.2
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ *.gem
3
+ pkg
4
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.7
4
+ - 2.6
5
+ - 2.5
6
+ - 2.4
7
+ - 2.3
8
+ - 2.2
9
+ - 2.1
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ofx (0.3.2)
5
+ nokogiri
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ byebug (11.1.1)
11
+ coderay (1.1.2)
12
+ diff-lcs (1.4.4)
13
+ method_source (1.0.0)
14
+ mini_portile2 (2.5.3)
15
+ nokogiri (1.11.7)
16
+ mini_portile2 (~> 2.5.0)
17
+ racc (~> 1.4)
18
+ pry (0.13.0)
19
+ coderay (~> 1.1)
20
+ method_source (~> 1.0)
21
+ pry-byebug (3.9.0)
22
+ byebug (~> 11.0)
23
+ pry (~> 0.13.0)
24
+ racc (1.5.2)
25
+ rake (13.0.3)
26
+ rspec (3.10.0)
27
+ rspec-core (~> 3.10.0)
28
+ rspec-expectations (~> 3.10.0)
29
+ rspec-mocks (~> 3.10.0)
30
+ rspec-core (3.10.1)
31
+ rspec-support (~> 3.10.0)
32
+ rspec-expectations (3.10.1)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.10.0)
35
+ rspec-mocks (3.10.2)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.10.0)
38
+ rspec-support (3.10.2)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ ofx!
45
+ pry-byebug
46
+ rake
47
+ rspec (~> 3.10)
48
+
49
+ BUNDLED WITH
50
+ 1.16.4
data/README.rdoc ADDED
@@ -0,0 +1,51 @@
1
+ = OFX
2
+
3
+ {<img src="https://badge.fury.io/rb/ofx.png" alt="Gem Version" />}[http://badge.fury.io/rb/ofx]
4
+ {<img src="https://travis-ci.org/annacruz/ofx.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/annacruz/ofx]
5
+
6
+ A simple OFX (Open Financial Exchange) parser built on top of Nokogiri. Currently supports both OFX 1.0.2 and 2.1.1.
7
+
8
+ Works on both ruby 1.9 and 2.0.
9
+
10
+ == Usage
11
+
12
+ require "ofx"
13
+
14
+ OFX("file.ofx") do
15
+ p account
16
+ p account.balance
17
+ p account.transactions
18
+ end
19
+
20
+ Invalid files will raise an OFX::UnsupportedFileError.
21
+
22
+ == Creator
23
+
24
+ * Nando Vieira - http://simplesideias.com.br
25
+
26
+ == Maintainer
27
+
28
+ * Anna Cruz - http://anna-cruz.com
29
+
30
+ == License
31
+
32
+ (The MIT License)
33
+
34
+ Permission is hereby granted, free of charge, to any person obtaining
35
+ a copy of this software and associated documentation files (the
36
+ 'Software'), to deal in the Software without restriction, including
37
+ without limitation the rights to use, copy, modify, merge, publish,
38
+ distribute, sublicense, and/or sell copies of the Software, and to
39
+ permit persons to whom the Software is furnished to do so, subject to
40
+ the following conditions:
41
+
42
+ The above copyright notice and this permission notice shall be
43
+ included in all copies or substantial portions of the Software.
44
+
45
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
46
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
49
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
50
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
51
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task :default => :spec
@@ -0,0 +1,11 @@
1
+ module OFX
2
+ class Account < Foundation
3
+ attr_accessor :balance
4
+ attr_accessor :bank_id
5
+ attr_accessor :currency
6
+ attr_accessor :id
7
+ attr_accessor :transactions
8
+ attr_accessor :type
9
+ attr_accessor :available_balance
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module OFX
2
+ class Balance < Foundation
3
+ attr_accessor :amount
4
+ attr_accessor :amount_in_pennies
5
+ attr_accessor :posted_at
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module OFX
2
+ class UnsupportedFileError < StandardError; end
3
+ end
@@ -0,0 +1,9 @@
1
+ module OFX
2
+ class Foundation
3
+ def initialize(attrs)
4
+ attrs.each do |key, value|
5
+ send("#{key}=", value)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,201 @@
1
+ module OFX
2
+ module Parser
3
+ class OFX102
4
+ VERSION = '1.0.2'
5
+
6
+ ACCOUNT_TYPES = {
7
+ 'CHECKING' => :checking,
8
+ 'SAVINGS' => :savings,
9
+ 'CREDITLINE' => :creditline,
10
+ 'MONEYMRKT' => :moneymrkt
11
+ }
12
+
13
+ TRANSACTION_TYPES = %w[
14
+ ATM CASH CHECK CREDIT DEBIT DEP DIRECTDEBIT DIRECTDEP DIV
15
+ FEE INT OTHER PAYMENT POS REPEATPMT SRVCHG XFER
16
+ ].each_with_object({}) { |tran_type, hash| hash[tran_type] = tran_type.downcase.to_sym; }
17
+
18
+ SEVERITY = {
19
+ 'INFO' => :info,
20
+ 'WARN' => :warn,
21
+ 'ERROR' => :error
22
+ }
23
+
24
+ attr_reader :headers, :body, :html, :date_start, :date_end
25
+
26
+ def initialize(options = {})
27
+ @headers = options[:headers]
28
+ @body = options[:body]
29
+ @html = Nokogiri::HTML.parse(body)
30
+
31
+ @date_start ||= build_date(@html.search('banktranlist > dtstart').inner_text)
32
+ @date_end ||= build_date(@html.search('banktranlist > dtend').inner_text)
33
+ end
34
+
35
+ def statements
36
+ @statements ||= html.search('stmttrnrs, ccstmttrnrs').collect { |node| build_statement(node) }
37
+ end
38
+
39
+ def accounts
40
+ @accounts ||= html.search('stmttrnrs, ccstmttrnrs').collect { |node| build_account(node) }
41
+ end
42
+
43
+ # DEPRECATED: kept for legacy support
44
+ def account
45
+ @account ||= build_account(html.search('stmttrnrs, ccstmttrnrs').first)
46
+ end
47
+
48
+ def sign_on
49
+ @sign_on ||= build_sign_on
50
+ end
51
+
52
+ def self.parse_headers(header_text)
53
+ # Change single CR's to LF's to avoid issues with some banks
54
+ header_text.gsub!(/\r(?!\n)/, "\n")
55
+
56
+ # Parse headers. When value is NONE, convert it to nil.
57
+ headers = header_text.to_enum(:each_line).each_with_object({}) do |line, memo|
58
+ _, key, value = *line.match(/^(.*?):(.*?)\s*(\r?\n)*$/)
59
+
60
+ unless key.nil?
61
+ memo[key] = value == 'NONE' ? nil : value
62
+ end
63
+ end
64
+
65
+ return headers unless headers.empty?
66
+ end
67
+
68
+ private
69
+
70
+ def build_statement(node)
71
+ stmrs_node = node.search('stmtrs, ccstmtrs')
72
+ account = build_account(node)
73
+ OFX::Statement.new(
74
+ currency: stmrs_node.search('curdef').inner_text,
75
+ account: account,
76
+ transactions: account.transactions,
77
+ balance: account.balance,
78
+ available_balance: account.available_balance
79
+ )
80
+ end
81
+
82
+ def build_account(node)
83
+ OFX::Account.new({
84
+ bank_id: node.search('bankacctfrom > bankid').inner_text,
85
+ id: node.search('bankacctfrom > acctid, ccacctfrom > acctid').inner_text,
86
+ type: ACCOUNT_TYPES[node.search('bankacctfrom > accttype').inner_text.to_s.upcase],
87
+ transactions: build_transactions(node),
88
+ balance: build_balance(node),
89
+ available_balance: build_available_balance(node),
90
+ currency: node.search('stmtrs > curdef, ccstmtrs > curdef').inner_text
91
+ })
92
+ end
93
+
94
+ def build_status(node)
95
+ OFX::Status.new({
96
+ code: node.search('code').inner_text.to_i,
97
+ severity: SEVERITY[node.search('severity').inner_text],
98
+ message: node.search('message').inner_text
99
+ })
100
+ end
101
+
102
+ def build_sign_on
103
+ OFX::SignOn.new({
104
+ language: html.search('signonmsgsrsv1 > sonrs > language').inner_text,
105
+ fi_id: html.search('signonmsgsrsv1 > sonrs > fi > fid').inner_text,
106
+ fi_name: html.search('signonmsgsrsv1 > sonrs > fi > org').inner_text,
107
+ status: build_status(html.search('signonmsgsrsv1 > sonrs > status'))
108
+ })
109
+ end
110
+
111
+ def build_transactions(node)
112
+ node.search('banktranlist > stmttrn').collect do |element|
113
+ build_transaction(element)
114
+ end
115
+ end
116
+
117
+ def build_transaction(element)
118
+ occurred_at = begin
119
+ build_date(element.search('dtuser').inner_text)
120
+ rescue StandardError
121
+ nil
122
+ end
123
+
124
+ OFX::Transaction.new({
125
+ amount: build_amount(element),
126
+ amount_in_pennies: (build_amount(element) * 100).to_i,
127
+ fit_id: element.search('fitid').inner_text,
128
+ memo: element.search('memo').inner_text,
129
+ name: element.search('name').inner_text,
130
+ payee: element.search('payee').inner_text,
131
+ check_number: element.search('checknum').inner_text,
132
+ ref_number: element.search('refnum').inner_text,
133
+ posted_at: build_date(element.search('dtposted').inner_text),
134
+ occurred_at: occurred_at,
135
+ type: build_type(element),
136
+ sic: element.search('sic').inner_text
137
+ })
138
+ end
139
+
140
+ def build_type(element)
141
+ TRANSACTION_TYPES[element.search('trntype').inner_text.to_s.upcase]
142
+ end
143
+
144
+ def build_amount(element)
145
+ to_decimal(element.search('trnamt').inner_text)
146
+ end
147
+
148
+ # Input format is `YYYYMMDDHHMMSS.XXX[gmt offset[:tz name]]`
149
+ def build_date(date)
150
+ tz_pattern = /(?:\[([+-]?\d{1,4}):\S{3}\])?\z/
151
+
152
+ # Timezone offset handling
153
+ date.sub!(tz_pattern, '')
154
+ offset = Regexp.last_match(1)
155
+
156
+ if offset
157
+ # Offset padding
158
+ _, hours, mins = *offset.match(/\A([+-]?\d{1,2})(\d{0,2})?\z/)
159
+ offset = format('%+03d%02d', hours.to_i, mins.to_i)
160
+ else
161
+ offset = '+0000'
162
+ end
163
+
164
+ date << " #{offset}"
165
+
166
+ Time.parse(date)
167
+ end
168
+
169
+ def build_balance(node)
170
+ amount = to_decimal(node.search('ledgerbal > balamt').inner_text)
171
+ posted_at = begin
172
+ build_date(node.search('ledgerbal > dtasof').inner_text)
173
+ rescue StandardError
174
+ nil
175
+ end
176
+
177
+ OFX::Balance.new({
178
+ amount: amount,
179
+ amount_in_pennies: (amount * 100).to_i,
180
+ posted_at: posted_at
181
+ })
182
+ end
183
+
184
+ def build_available_balance(node)
185
+ if node.search('availbal').size > 0
186
+ amount = to_decimal(node.search('availbal > balamt').inner_text)
187
+
188
+ OFX::Balance.new({
189
+ amount: amount,
190
+ amount_in_pennies: (amount * 100).to_i,
191
+ posted_at: build_date(node.search('availbal > dtasof').inner_text)
192
+ })
193
+ end
194
+ end
195
+
196
+ def to_decimal(amount)
197
+ BigDecimal(amount.to_s.gsub(',', '.'))
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,7 @@
1
+ module OFX
2
+ module Parser
3
+ class OFX103 < OFX102
4
+ VERSION = "1.0.3"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ module OFX
2
+ module Parser
3
+ class OFX211 < OFX102
4
+ VERSION = "2.1.1"
5
+
6
+ def self.parse_headers(header_text)
7
+ doc = Nokogiri::XML(header_text)
8
+
9
+ # Nokogiri can't search for processing instructions, so we
10
+ # need to do this manually.
11
+ doc.children.each do |e|
12
+ if e.type == Nokogiri::XML::Node::PI_NODE && e.name == "OFX"
13
+ # Getting the attributes from the element doesn't seem to
14
+ # work either.
15
+ return extract_headers(e.text)
16
+ end
17
+ end
18
+
19
+ nil
20
+ end
21
+
22
+ private
23
+ def self.extract_headers(text)
24
+ headers = {}
25
+ text.split(/\s+/).each do |attr_text|
26
+ match = /(.+)="(.+)"/.match(attr_text)
27
+ next unless match
28
+ k, v = match[1], match[2]
29
+ headers[k] = v
30
+ end
31
+ headers
32
+ end
33
+
34
+ def self.strip_quotes(s)
35
+ return unless s
36
+ s.sub(/^"(.*)"$/, '\1')
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,72 @@
1
+ module OFX
2
+ module Parser
3
+ class Base
4
+ attr_reader :headers
5
+ attr_reader :body
6
+ attr_reader :content
7
+ attr_reader :parser
8
+
9
+ def initialize(resource)
10
+ resource = open_resource(resource)
11
+ resource.rewind
12
+ begin
13
+ @content = convert_to_utf8(resource.read)
14
+ @headers, @body = prepare(content)
15
+ rescue
16
+ raise OFX::UnsupportedFileError
17
+ end
18
+
19
+ case headers["VERSION"]
20
+ when /102/ then
21
+ @parser = OFX102.new(:headers => headers, :body => body)
22
+ when /103/ then
23
+ @parser = OFX103.new(:headers => headers, :body => body)
24
+ when /200|202|211|220/ then
25
+ @parser = OFX211.new(:headers => headers, :body => body)
26
+ else
27
+ raise OFX::UnsupportedFileError
28
+ end
29
+ end
30
+
31
+ def open_resource(resource)
32
+ if resource.respond_to?(:read)
33
+ resource
34
+ else
35
+ open(resource)
36
+ end
37
+ rescue
38
+ StringIO.new(resource)
39
+ end
40
+
41
+ private
42
+ def prepare(content)
43
+ # split headers & body
44
+ header_text, body = content.dup.split(/<OFX>/, 2)
45
+
46
+ raise OFX::UnsupportedFileError unless body
47
+
48
+ # Header format is different between versions. Give each
49
+ # parser a chance to parse the headers.
50
+ headers = nil
51
+
52
+ OFX::Parser.constants.grep(/OFX/).each do |name|
53
+ headers = OFX::Parser.const_get(name).parse_headers(header_text)
54
+ break if headers
55
+ end
56
+
57
+ # Replace body tags to parse it with Nokogiri
58
+ body.gsub!(/>\s+</m, "><")
59
+ body.gsub!(/\s+</m, "<")
60
+ body.gsub!(/>\s+/m, ">")
61
+ body.gsub!(/<(\w+?)>([^<]+)/m, '<\1>\2</\1>')
62
+
63
+ [headers, body]
64
+ end
65
+
66
+ def convert_to_utf8(string)
67
+ return string if Kconv.isutf8(string)
68
+ string.encode("UTF-8", "ISO-8859-1")
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,8 @@
1
+ module OFX
2
+ class SignOn < Foundation
3
+ attr_accessor :language
4
+ attr_accessor :fi_id
5
+ attr_accessor :fi_name
6
+ attr_accessor :status
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module OFX
2
+ class Statement < Foundation
3
+ attr_accessor :account, :available_balance, :balance, :currency, :transactions
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module OFX
2
+ # Error Reporting Aggregate
3
+ class Status < Foundation
4
+ attr_accessor :code # Error code
5
+ attr_accessor :severity # Severity of the error
6
+ attr_accessor :message # Textual explanation
7
+
8
+ def success?
9
+ code == 0
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module OFX
2
+ class Transaction < Foundation
3
+ attr_accessor :amount
4
+ attr_accessor :amount_in_pennies
5
+ attr_accessor :check_number
6
+ attr_accessor :fit_id
7
+ attr_accessor :memo
8
+ attr_accessor :name
9
+ attr_accessor :payee
10
+ attr_accessor :posted_at
11
+ attr_accessor :occurred_at
12
+ attr_accessor :ref_number
13
+ attr_accessor :type
14
+ attr_accessor :sic
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ module OFX
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 3
5
+ PATCH = 3
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
data/lib/ofx_br.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'bigdecimal'
4
+
5
+ require 'kconv'
6
+
7
+ require 'ofx_br/errors'
8
+ require 'ofx_br/parser'
9
+ require 'ofx_br/parser/ofx102'
10
+ require 'ofx_br/parser/ofx103'
11
+ require 'ofx_br/parser/ofx211'
12
+ require 'ofx_br/foundation'
13
+ require 'ofx_br/balance'
14
+ require 'ofx_br/account'
15
+ require 'ofx_br/sign_on'
16
+ require 'ofx_br/status'
17
+ require 'ofx_br/statement'
18
+ require 'ofx_br/transaction'
19
+ require 'ofx_br/version'
20
+
21
+ def OFX(resource, &block)
22
+ parser = OFX::Parser::Base.new(resource).parser
23
+
24
+ if block_given?
25
+ if block.arity == 1
26
+ yield parser
27
+ else
28
+ parser.instance_eval(&block)
29
+ end
30
+ end
31
+
32
+ parser
33
+ end
data/ofx_br.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ $:.push File.expand_path('lib', __dir__)
2
+ require 'ofx_br/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'ofx_br'
6
+ s.version = OFX::Version::STRING
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Nando Vieira', 'Anna Cruz']
9
+ s.email = ['fnando.vieira@gmail.com', 'anna.cruz@gmail.com']
10
+ s.homepage = 'http://rubygems.org/gems/ofx'
11
+ s.summary = 'A simple OFX (Open Financial Exchange) parser built on top of Nokogiri. Currently supports OFX 102, 200 and 211.'
12
+ s.description = <<~TXT
13
+ A simple OFX (Open Financial Exchange) parser built on top of Nokogiri.
14
+ Currently supports OFX 102, 200 and 211.
15
+ #{' '}
16
+ Usage:
17
+ #{' '}
18
+ OFX("sample.ofx") do |ofx|
19
+ p ofx
20
+ end
21
+ TXT
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+
28
+ s.add_dependency 'nokogiri'
29
+ s.add_development_dependency 'pry-byebug'
30
+ s.add_development_dependency 'rake'
31
+ s.add_development_dependency 'rspec', '~> 3.10'
32
+ end
Binary file