ofxparser 1.0.0
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.
- data/History.txt +4 -0
- data/Manifest.txt +14 -0
- data/README.txt +107 -0
- data/Rakefile +23 -0
- data/lib/class-extension.rb +154 -0
- data/lib/mcc.rb +674 -0
- data/lib/ofx.rb +189 -0
- data/lib/ofxparser.rb +236 -0
- data/test/test_ofxparser.rb +8 -0
- metadata +91 -0
data/lib/ofx.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
module OfxParser
|
2
|
+
module MonetarySupport
|
3
|
+
# @@monies = []
|
4
|
+
# @@monies ||= []
|
5
|
+
|
6
|
+
# class_extension do
|
7
|
+
# def monetary_vars(*methods) #:nodoc:
|
8
|
+
# @@monies += methods
|
9
|
+
# end
|
10
|
+
# end
|
11
|
+
|
12
|
+
# Returns pennies for a given string amount, i.e:
|
13
|
+
# '-123.45' => -12345
|
14
|
+
# '123' => 12300
|
15
|
+
def pennies_for(amount)
|
16
|
+
return nil if amount == ""
|
17
|
+
int, fraction = amount.scan(/\d+/)
|
18
|
+
i = (fraction.to_s.strip =~ /[1-9]/) ? "#{int}#{fraction[0,2]}".to_i : int.to_i * 100
|
19
|
+
amount =~ /^\s*-\s*\d+/ ? -i : i
|
20
|
+
end
|
21
|
+
|
22
|
+
def original_method(meth) #:nodoc:
|
23
|
+
meth.to_s.sub('_in_pennies','').to_sym rescue nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def monetary_method_call?(meth) #:nodoc:
|
27
|
+
orig = original_method(meth)
|
28
|
+
@@monies.include?(orig) && meth.to_s == "#{orig}_in_pennies"
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(meth, *args) #:nodoc:
|
32
|
+
if (monetary_method_call?(meth))
|
33
|
+
pennies_for(send(original_method(meth)))
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def respond_to?(meth) #:nodoc:
|
40
|
+
monetary_method_call?(meth) ? true : super
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
# This class is returned when a parse is successful.
|
46
|
+
# == General Notes
|
47
|
+
# * currency symbols are an iso4217 3-letter code
|
48
|
+
# * language is defined by iso639 3-letter code
|
49
|
+
class Ofx
|
50
|
+
attr_accessor :header, :sign_on, :signup_account_info,
|
51
|
+
:bank_account, :credit_card, :investment
|
52
|
+
|
53
|
+
def accounts
|
54
|
+
accounts = []
|
55
|
+
[:bank_account, :credit_card, :investment].each do |method|
|
56
|
+
val = send(method)
|
57
|
+
accounts << val if val
|
58
|
+
end
|
59
|
+
accounts
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class SignOn
|
64
|
+
attr_accessor :status, :date, :language, :institute
|
65
|
+
end
|
66
|
+
|
67
|
+
class AccountInfo
|
68
|
+
attr_accessor :desc, :number
|
69
|
+
end
|
70
|
+
|
71
|
+
class Account
|
72
|
+
attr_accessor :number, :statement, :transaction_uid
|
73
|
+
end
|
74
|
+
|
75
|
+
class BankAccount < Account
|
76
|
+
TYPE = [:CHECKING, :SAVINGS, :MONEYMRKT, :CREDITLINE]
|
77
|
+
attr_accessor :routing_number, :type, :balance, :balance_date
|
78
|
+
|
79
|
+
include MonetarySupport
|
80
|
+
#monetary_vars :balance
|
81
|
+
|
82
|
+
undef type
|
83
|
+
def type
|
84
|
+
@type.to_s.upcase.to_sym
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class CreditAccount < Account
|
89
|
+
attr_accessor :remaining_credit, :remaining_credit_date, :balance, :balance_date
|
90
|
+
|
91
|
+
include MonetarySupport
|
92
|
+
# monetary_vars :remaining_credit, :balance
|
93
|
+
end
|
94
|
+
|
95
|
+
class InvestmentAccount < Account
|
96
|
+
attr_accessor :broker_id, :positions, :margin_balance, :short_balance, :cash_balance
|
97
|
+
|
98
|
+
# include MonetarySupport
|
99
|
+
# monetary_vars :margin_balance, :short_balance, :cash_balance
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
class Statement
|
104
|
+
attr_accessor :currency, :transactions, :start_date, :end_date, :stock_positions, :opt_positions
|
105
|
+
end
|
106
|
+
|
107
|
+
class Transaction
|
108
|
+
attr_accessor :type, :date, :amount, :fit_id, :check_number, :sic, :memo, :payee
|
109
|
+
|
110
|
+
include MonetarySupport
|
111
|
+
# monetary_vars :amount
|
112
|
+
|
113
|
+
TYPE = {
|
114
|
+
:CREDIT => "Generic credit",
|
115
|
+
:DEBIT => "Generic debit",
|
116
|
+
:INT => "Interest earned or paid ",
|
117
|
+
:DIV => "Dividend",
|
118
|
+
:FEE => "FI fee",
|
119
|
+
:SRVCHG => "Service charge",
|
120
|
+
:DEP => "Deposit",
|
121
|
+
:ATM => "ATM debit or credit",
|
122
|
+
:POS => "Point of sale debit or credit ",
|
123
|
+
:XFER => "Transfer",
|
124
|
+
:CHECK => "Check",
|
125
|
+
:PAYMENT => "Electronic payment",
|
126
|
+
:CASH => "Cash withdrawal",
|
127
|
+
:DIRECTDEP => "Direct deposit",
|
128
|
+
:DIRECTDEBIT => "Merchant initiated debit",
|
129
|
+
:REPEATPMT => "Repeating payment/standing order",
|
130
|
+
:OTHER => "Other"
|
131
|
+
}
|
132
|
+
|
133
|
+
def type_desc
|
134
|
+
TYPE[type]
|
135
|
+
end
|
136
|
+
|
137
|
+
undef type
|
138
|
+
def type
|
139
|
+
@type.to_s.strip.upcase.to_sym
|
140
|
+
end
|
141
|
+
|
142
|
+
undef sic
|
143
|
+
def sic
|
144
|
+
@sic == "" ? nil : @sic
|
145
|
+
end
|
146
|
+
|
147
|
+
def sic_desc
|
148
|
+
Mcc::CODES[sic]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Stock_Position
|
153
|
+
attr_accessor :uniqueid, :uniqueid_type, :heldinacct, :type, :units, :unitprice, :pricedate, :memo
|
154
|
+
end
|
155
|
+
|
156
|
+
class Opt_Position
|
157
|
+
attr_accessor :uniqueid, :uniqueid_type, :heldinacct, :type, :units, :unitprice, :pricedate, :memo, :mktval
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Status of a sign on
|
162
|
+
class Status
|
163
|
+
attr_accessor :code, :severity, :message
|
164
|
+
|
165
|
+
CODES = {
|
166
|
+
'0' => 'Success',
|
167
|
+
'2000' => 'General error',
|
168
|
+
'15000' => 'Must change USERPASS',
|
169
|
+
'15500' => 'Signon invalid',
|
170
|
+
'15501' => 'Customer account already in use',
|
171
|
+
'15502' => 'USERPASS Lockout'
|
172
|
+
}
|
173
|
+
|
174
|
+
def code_desc
|
175
|
+
CODES[code]
|
176
|
+
end
|
177
|
+
|
178
|
+
undef code
|
179
|
+
def code
|
180
|
+
@code.to_s.strip
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
class Institute
|
186
|
+
attr_accessor :name, :id
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
data/lib/ofxparser.rb
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
require 'time'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
%w(class-extension ofx mcc).each do |fn|
|
6
|
+
require File.dirname(__FILE__) + "/#{fn}"
|
7
|
+
end
|
8
|
+
|
9
|
+
module OfxParser
|
10
|
+
VERSION = '1.0.0'
|
11
|
+
|
12
|
+
class OfxParser
|
13
|
+
|
14
|
+
# Creates and returns an Ofx instance when given a well-formed OFX document,
|
15
|
+
# complete with the mandatory key:pair header.
|
16
|
+
def self.parse(ofx)
|
17
|
+
ofx = ofx.respond_to?(:read) ? ofx.read.to_s : ofx.to_s
|
18
|
+
|
19
|
+
return Ofx.new if ofx == ""
|
20
|
+
|
21
|
+
header, body = pre_process(ofx)
|
22
|
+
|
23
|
+
ofx_out = parse_body(body)
|
24
|
+
ofx_out.header = header
|
25
|
+
ofx_out
|
26
|
+
end
|
27
|
+
|
28
|
+
# Designed to make the main OFX body parsable. This means adding closing tags
|
29
|
+
# to the SGML to make it parsable by hpricot.
|
30
|
+
#
|
31
|
+
# Returns an array of 2 elements:
|
32
|
+
# * header as a hash,
|
33
|
+
# * body as an evily pre-processed string ready for parsing by hpricot.
|
34
|
+
def self.pre_process(ofx)
|
35
|
+
header, body = ofx.split(/\n{2,}|:?<OFX>/, 2)
|
36
|
+
|
37
|
+
header = Hash[*header.gsub(/^\r?\n+/,'').split(/\r\n/).collect do |e|
|
38
|
+
e.split(/:/,2)
|
39
|
+
end.flatten]
|
40
|
+
|
41
|
+
body.gsub!(/>\s+</m, '><')
|
42
|
+
body.gsub!(/\s+</m, '<')
|
43
|
+
body.gsub!(/>\s+/m, '>')
|
44
|
+
body.gsub!(/<(\w+?)>([^<]+)/m, '<\1>\2</\1>')
|
45
|
+
|
46
|
+
[header, body]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Takes an OFX datetime string of the format:
|
50
|
+
# * YYYYMMDDHHMMSS.XXX[gmt offset:tz name]
|
51
|
+
# * YYYYMMDD
|
52
|
+
# * YYYYMMDDHHMMSS
|
53
|
+
# * YYYYMMDDHHMMSS.XXX
|
54
|
+
#
|
55
|
+
# Returns a DateTime object. Milliseconds (XXX) are ignored.
|
56
|
+
def self.parse_datetime(date)
|
57
|
+
if /\A\s*
|
58
|
+
(\d{4})(\d{2})(\d{2}) ?# YYYYMMDD 1,2,3
|
59
|
+
(?:(\d{2})(\d{2})(\d{2}))? ?# HHMMSS - optional 4,5,6
|
60
|
+
(?:\.(\d{3}))? ?# .XXX - optional 7
|
61
|
+
(?:\[(-?\d+)\:\w{3}\])? ?# [-n:TZ] - optional 8,9
|
62
|
+
\s*\z/ix =~ date
|
63
|
+
year = $1.to_i
|
64
|
+
mon = $2.to_i
|
65
|
+
day = $3.to_i
|
66
|
+
hour = $4.to_i
|
67
|
+
min = $5.to_i
|
68
|
+
sec = $6.to_i
|
69
|
+
# DateTime does not support usecs.
|
70
|
+
# usec = 0
|
71
|
+
# usec = $7.to_f * 1000000 if $7
|
72
|
+
off = Rational($8.to_i, 24) # offset as a fraction of day. :|
|
73
|
+
DateTime.civil(year, mon, day, hour, min, sec, off)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def self.parse_body(body)
|
79
|
+
doc = Hpricot.XML(body)
|
80
|
+
|
81
|
+
ofx = Ofx.new
|
82
|
+
|
83
|
+
ofx.sign_on = build_signon((doc/"SIGNONMSGSRSV1/SONRS"))
|
84
|
+
ofx.signup_account_info = build_info((doc/"SIGNUPMSGSRSV1/ACCTINFOTRNRS"))
|
85
|
+
ofx.bank_account = build_bank((doc/"BANKMSGSRSV1/STMTTRNRS")) unless (doc/"BANKMSGSRSV1").empty?
|
86
|
+
ofx.credit_card = build_credit((doc/"CREDITCARDMSGSRSV1/CCSTMTTRNRS")) unless (doc/"CREDITCARDMSGSRSV1").empty?
|
87
|
+
ofx.investment=build_investment((doc/"INVSTMTMSGSRSV1/INVSTMTTRNRS"))
|
88
|
+
|
89
|
+
|
90
|
+
#build_investment((doc/"SIGNONMSGSRQV1"))
|
91
|
+
|
92
|
+
ofx
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.build_signon(doc)
|
96
|
+
sign_on = SignOn.new
|
97
|
+
sign_on.status = build_status((doc/"STATUS"))
|
98
|
+
sign_on.date = parse_datetime((doc/"DTSERVER").inner_text)
|
99
|
+
sign_on.language = (doc/"LANGUAGE").inner_text
|
100
|
+
|
101
|
+
sign_on.institute = Institute.new
|
102
|
+
sign_on.institute.name = ((doc/"FI")/"ORG").inner_text
|
103
|
+
sign_on.institute.id = ((doc/"FI")/"FID").inner_text
|
104
|
+
sign_on
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.build_info(doc)
|
108
|
+
account_infos = []
|
109
|
+
|
110
|
+
(doc/"ACCTINFO").each do |info_doc|
|
111
|
+
acc_info = AccountInfo.new
|
112
|
+
acc_info.desc = (info_doc/"DESC").inner_text
|
113
|
+
acc_info.number = (info_doc/"ACCTID").inner_text
|
114
|
+
account_infos << acc_info
|
115
|
+
end
|
116
|
+
|
117
|
+
account_infos
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.build_bank(doc)
|
121
|
+
acct = BankAccount.new
|
122
|
+
|
123
|
+
acct.transaction_uid = (doc/"TRNUID").inner_text.strip
|
124
|
+
acct.number = (doc/"STMTRS/BANKACCTFROM/ACCTID").inner_text
|
125
|
+
acct.routing_number = (doc/"STMTRS/BANKACCTFROM/BANKID").inner_text
|
126
|
+
acct.type = (doc/"STMTRS/BANKACCTFROM/ACCTTYPE").inner_text.strip
|
127
|
+
acct.balance = (doc/"STMTRS/LEDGERBAL/BALAMT").inner_text
|
128
|
+
acct.balance_date = parse_datetime((doc/"STMTRS/LEDGERBAL/DTASOF").inner_text)
|
129
|
+
|
130
|
+
statement = Statement.new
|
131
|
+
statement.currency = (doc/"STMTRS/CURDEF").inner_text
|
132
|
+
statement.start_date = parse_datetime((doc/"STMTRS/BANKTRANLIST/DTSTART").inner_text)
|
133
|
+
statement.end_date = parse_datetime((doc/"STMTRS/BANKTRANLIST/DTEND").inner_text)
|
134
|
+
acct.statement = statement
|
135
|
+
|
136
|
+
statement.transactions = (doc/"STMTRS/BANKTRANLIST/STMTTRN").collect do |t|
|
137
|
+
build_transaction(t)
|
138
|
+
end
|
139
|
+
|
140
|
+
acct
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.build_credit(doc)
|
144
|
+
acct = CreditAccount.new
|
145
|
+
|
146
|
+
acct.number = (doc/"CCSTMTRS/CCACCTFROM/ACCTID").inner_text
|
147
|
+
acct.transaction_uid = (doc/"TRNUID").inner_text.strip
|
148
|
+
acct.balance = (doc/"CCSTMTRS/LEDGERBAL/BALAMT").inner_text
|
149
|
+
acct.balance_date = parse_datetime((doc/"CCSTMTRS/LEDGERBAL/DTASOF").inner_text)
|
150
|
+
acct.remaining_credit = (doc/"CCSTMTRS/AVAILBAL/BALAMT").inner_text
|
151
|
+
acct.remaining_credit_date = parse_datetime((doc/"CCSTMTRS/AVAILBAL/DTASOF").inner_text)
|
152
|
+
|
153
|
+
statement = Statement.new
|
154
|
+
statement.currency = (doc/"CCSTMTRS/CURDEF").inner_text
|
155
|
+
statement.start_date = parse_datetime((doc/"CCSTMTRS/BANKTRANLIST/DTSTART").inner_text)
|
156
|
+
statement.end_date = parse_datetime((doc/"CCSTMTRS/BANKTRANLIST/DTEND").inner_text)
|
157
|
+
acct.statement = statement
|
158
|
+
|
159
|
+
statement.transactions = (doc/"CCSTMTRS/BANKTRANLIST/STMTTRN").collect do |t|
|
160
|
+
build_transaction(t)
|
161
|
+
end
|
162
|
+
|
163
|
+
acct
|
164
|
+
end
|
165
|
+
|
166
|
+
# for credit and bank transactions.
|
167
|
+
def self.build_transaction(t)
|
168
|
+
transaction = Transaction.new
|
169
|
+
transaction.type = (t/"TRNTYPE").inner_text
|
170
|
+
transaction.date = parse_datetime((t/"DTPOSTED").inner_text)
|
171
|
+
transaction.amount = (t/"TRNAMT").inner_text
|
172
|
+
transaction.fit_id = (t/"FITID").inner_text
|
173
|
+
transaction.payee = (t/"PAYEE").inner_text + (t/"NAME").inner_text
|
174
|
+
transaction.memo = (t/"MEMO").inner_text
|
175
|
+
transaction.sic = (t/"SIC").inner_text
|
176
|
+
transaction.check_number = (t/"CHECKNUM").inner_text if transaction.type == :CHECK
|
177
|
+
transaction
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
def self.build_investment(doc)
|
182
|
+
acct = InvestmentAccount.new
|
183
|
+
acct.broker_id=(doc/"INVSTMTRS/INVACCTFROM/BROKERID").inner_text
|
184
|
+
acct.cash_balance=(doc/"INVSTMTRS/INVBAL/AVAILCASH").inner_text
|
185
|
+
|
186
|
+
statement = Statement.new
|
187
|
+
acct.statement=statement
|
188
|
+
|
189
|
+
statement.stock_positions = (doc/"INVSTMTRS/INVPOSLIST/POSSTOCK").collect do |p|
|
190
|
+
build_stock_position(p)
|
191
|
+
end
|
192
|
+
|
193
|
+
statement.opt_positions = (doc/"INVSTMTRS/INVPOSLIST/POSOPT").collect do |p|
|
194
|
+
build_opt_position(p)
|
195
|
+
end
|
196
|
+
|
197
|
+
acct
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.build_stock_position(p)
|
201
|
+
stock_position = Stock_Position.new
|
202
|
+
stock_position.uniqueid = (p/"INVPOS/SECID/UNIQUEID").inner_text
|
203
|
+
stock_position.uniqueid_type = (p/"INVPOS/SECID/UNIQUEIDTYPE").inner_text
|
204
|
+
stock_position.heldinacct = (p/"INVPOS/HELDINACCT").inner_text
|
205
|
+
stock_position.type = (p/"INVPOS/POSTYPE").inner_text
|
206
|
+
stock_position.units = (p/"INVPOS/UNITS").inner_text
|
207
|
+
stock_position.unitprice = (p/"INVPOS/UNITPRICE").inner_text
|
208
|
+
stock_position.pricedate = parse_datetime((p/"INVPOS/DTPRICEASOF").inner_text)
|
209
|
+
stock_position.memo = (p/"INVPOS/MEMO").inner_text
|
210
|
+
stock_position
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.build_opt_position(p)
|
214
|
+
opt_position = Opt_Position.new
|
215
|
+
opt_position.uniqueid = (p/"INVPOS/SECID/UNIQUEID").inner_text
|
216
|
+
opt_position.uniqueid_type = (p/"INVPOS/SECID/UNIQUEIDTYPE").inner_text
|
217
|
+
opt_position.heldinacct = (p/"INVPOS/HELDINACCT").inner_text
|
218
|
+
opt_position.type = (p/"INVPOS/POSTYPE").inner_text
|
219
|
+
opt_position.units = (p/"INVPOS/UNITS").inner_text
|
220
|
+
opt_position.unitprice = (p/"INVPOS/UNITPRICE").inner_text
|
221
|
+
opt_position.mktval = (p/"INVPOS/MKTVAL").inner_text
|
222
|
+
opt_position.pricedate = parse_datetime((p/"INVPOS/DTPRICEASOF").inner_text)
|
223
|
+
opt_position.memo = (p/"INVPOS/MEMO").inner_text
|
224
|
+
opt_position
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.build_status(doc)
|
228
|
+
status = Status.new
|
229
|
+
status.code = (doc/"CODE").inner_text
|
230
|
+
status.severity = (doc/"SEVERITY").inner_text
|
231
|
+
status.message = (doc/"MESSAGE").inner_text
|
232
|
+
status
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ofxparser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pavit Masson (forked from Andrew A. Smith)
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-05-27 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hpricot
|
17
|
+
requirement: &9298020 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0.6'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *9298020
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: hoe
|
28
|
+
requirement: &9297684 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.5.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *9297684
|
37
|
+
description: ! '== DESCRIPTION: My fork of aasmith''s ofx-parser v1.0.2 and attempt
|
38
|
+
at building the investment acct methods. OfxParser is a ruby library to parse a
|
39
|
+
realistic subset of the lengthy OFX 1.x specification. == FEATURES/PROBLEMS: *
|
40
|
+
Reads OFX responses - i.e. those downloaded from financial institutions and puts
|
41
|
+
it into a usable object graph. * Supports the 3 main message sets: banking, credit
|
42
|
+
card and investment accounts, as well as the required ''sign on'' set. * Knows about
|
43
|
+
SIC codes - if your institution provides them. See http://www.eeoc.gov/stats/jobpat/siccodes.html
|
44
|
+
* Monetary amounts can be retrieved either as a raw string, or in pennies. * Supports
|
45
|
+
OFX timestamps.'
|
46
|
+
email: pavitm@gmail.com
|
47
|
+
executables: []
|
48
|
+
extensions: []
|
49
|
+
extra_rdoc_files:
|
50
|
+
- History.txt
|
51
|
+
- Manifest.txt
|
52
|
+
- README.txt
|
53
|
+
files:
|
54
|
+
- History.txt
|
55
|
+
- Manifest.txt
|
56
|
+
- README.txt
|
57
|
+
- Rakefile
|
58
|
+
- lib/class-extension.rb
|
59
|
+
- lib/mcc.rb
|
60
|
+
- lib/ofxparser.rb
|
61
|
+
- lib/ofx.rb
|
62
|
+
- test/test_ofxparser.rb
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://ofxparser.rubyforge.org/
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --main
|
69
|
+
- README.txt
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project: ofxparser
|
86
|
+
rubygems_version: 1.5.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 2
|
89
|
+
summary: ofx-parser is a ruby library for parsing OFX 1.x data.
|
90
|
+
test_files:
|
91
|
+
- test/test_ofxparser.rb
|