qif 1.1.2 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05d7562d52dc8df636d290de9e2cce5f412a6013
4
- data.tar.gz: f47615d7c5077148c7c508bab6f14839730e49ad
3
+ metadata.gz: 08266f25e1ffcdf187a4ebb8b1962c966174cccf
4
+ data.tar.gz: f6e324f5d4ad6dd5779998a106999d7a622c124f
5
5
  SHA512:
6
- metadata.gz: 4514f7c2a458fb6989ca943a5f8050f905f81e449ced6adfd79daab2ab97bbb033cb2125f42f8e576bdec73a1a0fa08657e23b77bf91f2d9c5759f8717664973
7
- data.tar.gz: 87fe80e1d2b395d875121fdea2a3679e53269fa4b632cafcaca467c02bc89ddb43630c5fe113c34d0a694976386ccbc8ed2d89898f6006d99f167f03a4bee146
6
+ metadata.gz: 2ee86e8d5aa5128e25fe50d65ded8ea804290d8b40f7013a4d83825acbf9c4ab3ace060dc2dd4c251b0033e0cecb160bca7cf32ed1bd6ce81c2e04663663592b
7
+ data.tar.gz: 856b067eaa0618b390c903cb236eeff28790afe131abc5bf570643ef86ddda93f494e09250046cd9a55529fffcff8e25518ebd12a5ea62de8525ffc6b480f8b7
@@ -6,23 +6,23 @@
6
6
 
7
7
  === INSTALL:
8
8
 
9
- * sudo gem install qif
9
+ * gem install qif
10
10
 
11
11
  === DOCUMENTATION:
12
12
 
13
- * http://rdoc.info/github/jemmyw/Qif/master/frames
13
+ * http://www.rubydoc.info/github/jemmyw/Qif
14
14
 
15
15
  === EXAMPLE:
16
16
 
17
17
  require 'qif'
18
18
  qif = Qif::Reader.new(open('/path/to/file.qif'))
19
19
  qif.each do |transaction|
20
- puts [transaction.name, transaction.description, transaction.amount].join(", ")
20
+ puts [transaction.payee, transaction.amount].join(", ")
21
21
  end
22
22
 
23
23
  === CSV conversion example
24
24
 
25
- # Ruby 1.9.2
25
+ # Ruby 2.1.0
26
26
  require 'csv'
27
27
  require 'qif'
28
28
 
@@ -33,10 +33,10 @@
33
33
  # [3] debit amount,
34
34
  # [4] credit amount
35
35
  # Ignore other fields
36
- basefile = 'file'
37
- bank_input = CSV.read("#{file}.csv")
36
+ basefile = 'filename'
37
+ bank_input = CSV.read("#{basefile}.csv")
38
38
 
39
- Qif::Writer.open("#{file}.qif", type = 'Bank', format = 'dd/mm/yyyy') do |qif|
39
+ Qif::Writer.open("#{basefile}.qif", type = 'Bank', format = 'dd/mm/yyyy') do |qif|
40
40
  bank_input.each do |row|
41
41
  # Fix the values depending on what state your CSV data is in
42
42
  row.each { |value| value.to_s.gsub!(/^\s+|\s+$/,'') }
@@ -51,7 +51,7 @@
51
51
 
52
52
  === LICENSE:
53
53
 
54
- Copyright (c) 2011 Jeremy Wells
54
+ Copyright (c) 2014 Jeremy Wells
55
55
 
56
56
  Permission is hereby granted, free of charge, to any person
57
57
  obtaining a copy of this software and associated documentation
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
1
  require 'rspec/core/rake_task'
2
+ require 'rdoc/task'
2
3
 
3
4
  desc "Run specs"
4
5
  RSpec::Core::RakeTask.new :spec
5
6
 
7
+ RDoc::Task.new do |rdoc|
8
+ rdoc.main = "README.rdoc"
9
+ rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb")
10
+ end
11
+
6
12
  task :default => :spec
data/lib/qif.rb CHANGED
@@ -1,5 +1,11 @@
1
1
  $: << File.dirname(__FILE__)
2
2
 
3
+ #
4
+ # See Qif::Reader for reading qif files and Qif::Writer for writing them.
5
+ #
6
+ module Qif
7
+ end
8
+
3
9
  require 'qif/reader'
4
10
  require 'qif/writer'
5
- require 'qif/transaction'
11
+ require 'qif/transaction'
@@ -0,0 +1,6 @@
1
+ module AmountParser
2
+ def self.parse(amount)
3
+ warn "= amounts are unsupported" if amount =~ /^=/
4
+ amount.gsub(/,/, '').gsub(/^=/, '').to_f
5
+ end
6
+ end
@@ -1,6 +1,7 @@
1
1
  require 'stringio'
2
2
  require 'qif/date_format'
3
3
  require 'qif/transaction'
4
+ require 'qif/transaction/builder'
4
5
 
5
6
  module Qif
6
7
  # The Qif::Reader class reads a qif file and provides access to
@@ -152,9 +153,8 @@ module Qif
152
153
  end
153
154
 
154
155
  def read_transaction
155
- if record = read_record
156
- transaction = Transaction.read(record)
157
- cache_transaction(transaction) if transaction
156
+ if transaction = read_record
157
+ cache_transaction(transaction)
158
158
  end
159
159
  end
160
160
 
@@ -163,17 +163,27 @@ module Qif
163
163
  end
164
164
 
165
165
  def read_record
166
- record = {}
166
+ builder = Qif::Transaction::Builder.new(->(dt){@format.parse(dt)})
167
167
  begin
168
- line = @data.readline
169
- key = line[0,1]
170
- record[key] = record.key?(key) ? record[key] + "\n" + line[1..-1].strip : line[1..-1].strip
171
-
172
- record[key].sub!(',','') if %w(T U $).include? key
173
- record[key] = @format.parse(record[key]) if %w(D).include? key
174
-
175
- end until line =~ /^\^/
176
- record
168
+ line = @data.readline.strip
169
+ key = line.slice!(0, 1)
170
+ builder =
171
+ case key
172
+ when 'D' then builder.set_date(line)
173
+ when 'T' then builder.set_amount(line)
174
+ when 'A' then builder.set_address(line)
175
+ when 'C' then builder.set_status(line)
176
+ when 'N' then builder.set_number(line)
177
+ when 'P' then builder.set_payee(line)
178
+ when 'M' then builder.set_memo(line)
179
+ when 'L' then builder.set_category(line)
180
+ when 'S' then builder.add_split(line)
181
+ when 'E' then builder.set_split_memo(line)
182
+ when '$' then builder.set_split_amount(line)
183
+ else builder
184
+ end
185
+ end until key == "^"
186
+ builder.build
177
187
  rescue EOFError => e
178
188
  @data.close
179
189
  nil
@@ -12,9 +12,6 @@ module Qif
12
12
  :memo => {"M" => "Memo" },
13
13
  :adress => {"A" => "Address (up to five lines; the sixth line is an optional message)" },
14
14
  :category => {"L" => "Category (Category/Subcategory/Transfer/Class)" },
15
- :split_category => {"S" => "Category in split (Category/Transfer/Class)" },
16
- :split_memo => {"E" => "Memo in split" },
17
- :split_amount => {"$" => "Dollar amount of split" },
18
15
  :end => {"^" => "End of entry" }
19
16
  }
20
17
  DEPRECATION_FIELDS = {
@@ -24,18 +21,20 @@ module Qif
24
21
  }
25
22
  SUPPORTED_FIELDS.keys.each{|s| attr_accessor s}
26
23
 
27
- def self.read(record) #::nodoc
28
- return nil unless record['D'].respond_to?(:strftime)
29
- SUPPORTED_FIELDS.each{|k,v| record[k] = record.delete(v.keys.first)}
30
- record.reject{|k,v| v.nil?}.each{|k,v| record[k] = record[k].to_f if k.to_s.include? "amount"}
31
- Transaction.new record
32
- end
24
+ attr_reader :splits
25
+ alias :address :adress
26
+ alias :address= :adress=
33
27
 
34
28
  def initialize(attributes = {})
29
+ @splits = []
35
30
  deprecate_attributes!(attributes)
36
31
  SUPPORTED_FIELDS.keys.each{|s| instance_variable_set("@#{s.to_s}", attributes[s])}
37
32
  end
38
33
 
34
+ def add_split(split)
35
+ @splits << split
36
+ end
37
+
39
38
  # Returns a representation of the transaction as it
40
39
  # would appear in a qif file.
41
40
  def to_s(format = 'dd/mm/yyyy')
@@ -52,7 +51,7 @@ module Qif
52
51
  else
53
52
  "#{field}#{current}"
54
53
  end
55
- end.flatten.compact.join("\n")
54
+ end.concat(@splits.collect{|s| s.to_s}).flatten.compact.join("\n")
56
55
  end
57
56
 
58
57
  private
@@ -0,0 +1,61 @@
1
+ require_relative "split/builder"
2
+ require_relative "builderable"
3
+ require_relative "../amount_parser"
4
+
5
+ #
6
+ # Factory class for building transactions.
7
+ #
8
+ # @usage
9
+ # txn = Qif::Transaction::Builder.new
10
+ # .set_date('10/06/1983')
11
+ # .set_amount('-10.0')
12
+ # .set_memo('debit $10')
13
+ # .add_split('jules')
14
+ # .set_split_memo('half to jules')
15
+ # .add_split_amount('-5.0')
16
+ # .build
17
+ #
18
+ class Qif::Transaction::Builder
19
+ include Builderable
20
+
21
+ def initialize(date_parser = ->(date) { Time.parse(date) })
22
+ @date_parser = date_parser
23
+ @splits = []
24
+ end
25
+
26
+ set_builder_method :date, :parse_date
27
+ set_builder_method :amount, ->(amt) { AmountParser.parse(amt) }
28
+ set_builder_method :status
29
+ set_builder_method :number
30
+ set_builder_method :payee
31
+ set_builder_method :memo
32
+ set_builder_method :category
33
+
34
+ def set_address(address)
35
+ @address = [@address, address].compact.join("\n")
36
+ self
37
+ end
38
+ alias :set_adress :set_address
39
+
40
+ def add_split(split)
41
+ Qif::Transaction::Split::Builder.new(self).set_split_category(split).tap do |builder|
42
+ @splits << builder
43
+ end
44
+ end
45
+
46
+ def build
47
+ _build(Qif::Transaction.new).tap do |txn|
48
+ txn.address = @address
49
+
50
+ @splits.each do |split_builder|
51
+ txn.add_split(split_builder.build_split)
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def parse_date(date)
59
+ @date_parser.call(date)
60
+ end
61
+ end
@@ -0,0 +1,39 @@
1
+ module Builderable
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ end
5
+
6
+ module ClassMethods
7
+ def builder_options(options)
8
+ @options = options
9
+ end
10
+
11
+ def set_builder_method(attribute, massager = nil)
12
+ options = @options || {}
13
+ method_name = ["set", options[:prefix], attribute].compact.join("_")
14
+
15
+ define_method(method_name) do |new_value|
16
+ @_builder_values ||= {}
17
+
18
+ unless massager.nil?
19
+ if massager.kind_of?(Symbol)
20
+ new_value = self.send(massager, new_value)
21
+ else
22
+ new_value = massager.call(new_value)
23
+ end
24
+ end
25
+
26
+ @_builder_values[attribute] = new_value
27
+ self
28
+ end
29
+ end
30
+ end
31
+
32
+ def _build(object)
33
+ (@_builder_values||{}).each do |attribute, value|
34
+ object.public_send("#{attribute}=", value)
35
+ end
36
+
37
+ object
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ class Qif::Transaction::Split
2
+ SUPPORTED_FIELDS = {
3
+ :category => {"S" => "Category in split (Category/Transfer/Class)" },
4
+ :memo => {"E" => "Memo in split" },
5
+ :amount => {"$" => "Dollar amount of split" },
6
+ }
7
+
8
+ attr_accessor :memo, :amount, :category
9
+
10
+ # Returns a representation of the split as it
11
+ # would appear in a qif file.
12
+ def to_s()
13
+ SUPPORTED_FIELDS.collect do |k,v|
14
+ next unless current = instance_variable_get("@#{k}")
15
+ field = v.keys.first
16
+ case current.class.to_s
17
+ when "Float"
18
+ "#{field}#{'%.2f'%current}"
19
+ when "String"
20
+ current.split("\n").collect {|x| "#{field}#{x}" }
21
+ else
22
+ "#{field}#{current}"
23
+ end
24
+ end.flatten.compact.join("\n")
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../builderable'
2
+ require_relative '../split'
3
+
4
+ #
5
+ # Factory class for buliding splits. Do not construct this directly, rather use
6
+ # Qif::Transaction::Builder#add_split
7
+ #
8
+ class Qif::Transaction::Split::Builder
9
+ include Builderable
10
+
11
+ def initialize(transaction_builder)
12
+ @transaction_builder = transaction_builder
13
+ yield self if block_given?
14
+ end
15
+
16
+ def add_split(split_memo)
17
+ @transaction_builder.add_split(split_memo)
18
+ end
19
+
20
+ builder_options prefix: 'split'
21
+ set_builder_method :memo
22
+ set_builder_method :amount, ->(amt) { AmountParser.parse(amt) }
23
+ set_builder_method :category
24
+
25
+ def build_split
26
+ _build(Qif::Transaction::Split.new)
27
+ end
28
+
29
+ def method_missing(name, *args, &block)
30
+ @transaction_builder.send(name, *args, &block)
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ !Type:Bank
2
+ D6/1/94
3
+ T-1,000.00
4
+ CX
5
+ N1005
6
+ PBank Of Mortgage
7
+ MMemo
8
+ L[linda]
9
+ S[steve]
10
+ ECash
11
+ $-253.64
12
+ SMort Int
13
+ $=746.36
14
+ ^
15
+ D6/2/94
16
+ Scategory 1
17
+ $23
18
+ T75.00
19
+ PDeposit
20
+ ^
@@ -107,4 +107,42 @@ describe Qif::Reader do
107
107
  @instance = Qif::Reader.new(open('spec/fixtures/3_records_ddmmyyyy.qif'), 'mm/dd/yyyy')
108
108
  @instance.size.should == 2
109
109
  end
110
+
111
+ context 'when reading splits' do
112
+ let(:reader) { Qif::Reader.new(open('spec/fixtures/splits.qif'), 'd/m/yyyy') }
113
+
114
+ context 'the first transaction' do
115
+ let (:transaction) { reader.transactions[0] }
116
+
117
+ it 'should have the correct number of splits' do
118
+ expect(transaction.splits.size).to eq(2)
119
+ end
120
+
121
+ context 'the first split' do
122
+ let (:split) { transaction.splits.first }
123
+
124
+ it { expect(split.category).to eq("[steve]") }
125
+ it { expect(split.memo).to eq("Cash") }
126
+ it { expect(split.amount).to eq(-253.64)}
127
+ end
128
+
129
+ context 'the second split' do
130
+ let (:split) { transaction.splits[1] }
131
+
132
+ it { expect(split.category).to eq("Mort Int") }
133
+ it { expect(split.amount).to eq(746.36) }
134
+ end
135
+
136
+ end
137
+
138
+ context "when the transaction has splits first" do
139
+ let(:transaction) { reader.transactions[1] }
140
+
141
+ it 'should correctly add the amount to the transaction' do
142
+ expect(transaction.amount).to eq(75)
143
+ end
144
+
145
+ it { expect(transaction.splits.first.amount).to eq(23) }
146
+ end
147
+ end
110
148
  end
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+ require 'qif/transaction/builder'
3
+ require 'qif/transaction/split/builder'
4
+
5
+ describe Qif::Transaction::Builder do
6
+ let(:builder) { Qif::Transaction::Builder.new }
7
+ def split_builder
8
+ double(Qif::Transaction::Split::Builder).tap do |b|
9
+ allow(b).to receive(:set_split_category).and_return(b)
10
+ end
11
+ end
12
+ def do_build
13
+ builder.build
14
+ end
15
+
16
+ context '#build' do
17
+ it 'should return a transaction object' do
18
+ expect(builder.build).to be_kind_of(Qif::Transaction)
19
+ end
20
+
21
+ context 'with splits' do
22
+ it 'should call build_split on each of the splits' do
23
+ sb1 = split_builder
24
+ sb2 = split_builder
25
+ allow(Qif::Transaction::Split::Builder).to receive(:new).and_return(sb1, sb2)
26
+ expect(sb1).to receive(:build_split).ordered
27
+ expect(sb2).to receive(:build_split).ordered
28
+ builder.add_split("a")
29
+ builder.add_split("b")
30
+ builder.build
31
+ end
32
+
33
+ it 'should add the splits to the transaction' do
34
+ builder.add_split("a")
35
+ builder.add_split("b")
36
+ expect(builder.build.splits.count).to eq(2)
37
+ end
38
+ end
39
+ end
40
+
41
+ context '#set_date' do
42
+ it_should_behave_like 'builder method', :date, '1994-06-01', :set_date, Time.mktime(1994, 6, 1)
43
+ it 'should use a given date parser' do
44
+ b = Qif::Transaction::Builder.new(->(date) { date })
45
+ b.set_date('1994')
46
+ expect(b.build.date).to eq('1994')
47
+ end
48
+ end
49
+
50
+ context '#set_amount' do
51
+ it_should_behave_like 'builder method', :amount, '-1000.00', :set_amount, -1000.0
52
+ it 'should parse commas out of the amount' do
53
+ builder.set_amount('1,000,000')
54
+ expect(builder.build.amount).to eq(1_000_000)
55
+ end
56
+ end
57
+
58
+ context '#set_status' do
59
+ it_should_behave_like 'builder method', :status, 'X', :set_status, 'X'
60
+ end
61
+
62
+ context '#set_number' do
63
+ it_should_behave_like 'builder method', :number, '1005', :set_number, '1005'
64
+ end
65
+
66
+ context '#set_payee' do
67
+ it_should_behave_like 'builder method', :payee, 'Bank of Mortgage', :set_payee, 'Bank of Mortgage'
68
+ end
69
+
70
+ context '#set_memo' do
71
+ it_should_behave_like 'builder method', :memo, 'Some stuff that happened', :set_memo, 'Some stuff that happened'
72
+ end
73
+
74
+ context '#set_category' do
75
+ it_should_behave_like 'builder method', :category, 'Fishing', :set_category, 'Fishing'
76
+ end
77
+
78
+ context '#set_address' do
79
+ address = <<-EOA
80
+ P.O. Box 1234
81
+ Somewhereton
82
+ 12345
83
+ EOA
84
+
85
+ it_should_behave_like 'builder method', :adress, address, :set_adress, address
86
+
87
+ context 'when called consecutively' do
88
+ it "should append to the address" do
89
+ builder
90
+ .set_address("Line 1")
91
+ .set_address("Line 2")
92
+ expect(do_build.address).to eq("Line 1\nLine 2")
93
+ end
94
+ end
95
+ end
96
+
97
+ context "#add_split" do
98
+ it 'should create a new split builder' do
99
+ expect(Qif::Transaction::Split::Builder).to receive(:new).with(builder).and_return(split_builder)
100
+ builder.add_split("aaa")
101
+ end
102
+
103
+ it 'should set the category on the split builder' do
104
+ sb = split_builder
105
+ allow(Qif::Transaction::Split::Builder).to receive(:new).and_return(sb)
106
+ expect(sb).to receive(:set_split_category).with('aaaa')
107
+ builder.add_split('aaaa')
108
+ end
109
+
110
+ it "should return a split builder" do
111
+ expect(builder.add_split('aaaa')).to be_kind_of(Qif::Transaction::Split::Builder)
112
+ end
113
+
114
+ context "when called multiple times" do
115
+ it "should return multiple different builders" do
116
+ sb1 = builder.add_split("aaaa")
117
+ expect(builder.add_split("bbbb")).to_not eq(sb1)
118
+ end
119
+ end
120
+ end
121
+
122
+ end
@@ -1,76 +1,59 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Qif::Transaction do
4
- describe '::read' do
5
- it 'should return a new transaction with all attributes set' do
6
- t = Qif::Transaction.read(
7
- 'D' => Time.parse('1994-06-01'),
8
- 'T' => '-1000.00'.to_f,
9
- 'C' => 'X',
10
- 'N' => '1005',
11
- 'P' => 'Bank Of Mortgage',
12
- 'M' => 'aMemo',
13
- 'L' => 'aCategory',
14
- # TODO Support correctly splits with an array of hash
15
- # 'S' => '[linda]
16
- #Mort Int',
17
- # 'E' => 'Cash',
18
- # '$' => '-253.64
19
- #=746.36',
20
- 'A' => 'P.O. Box 27027
21
- Tucson, AZ
22
- 85726',
23
- '^' => nil
24
- )
25
-
26
- t.should be_a(Qif::Transaction)
27
- t.date.should == Time.mktime(1994,6,1)
28
- t.amount.should == -1000.00
29
- t.status.should == 'X'
30
- t.number.should == '1005'
31
- t.payee.should == 'Bank Of Mortgage'
32
- t.memo.should == 'aMemo'
33
- t.category.should == 'aCategory'
34
- t.adress.should == 'P.O. Box 27027
35
- Tucson, AZ
36
- 85726'
37
- end
38
-
39
- it 'should return nil if the date does not respond to strftime' do
40
- Qif::Transaction.read('D' => 'hello').should be_nil
41
- end
42
- end
43
-
44
4
  describe '#to_s' do
45
- before do
46
- @instance = Qif::Transaction.new(
47
- :date => Time.mktime(2010, 1, 2),
48
- :amount => -10.0,
49
- :category => 'Debit',
50
- :memo => 'Supermarket',
51
- :payee => 'abcde'
52
- )
5
+ let(:builder) do
6
+ Qif::Transaction::Builder.new
7
+ .set_date(Time.mktime(2010, 1, 2).to_s)
8
+ .set_amount('-10.0')
9
+ .set_category('Debit')
10
+ .set_memo('Supermarket')
11
+ .set_payee('abcde')
53
12
  end
54
-
13
+
14
+ let(:txn) do
15
+ builder.build
16
+ end
17
+
18
+ subject { txn.to_s }
19
+
55
20
  it 'should format the date in the format specified as D' do
56
- @instance.to_s('dd/mm/yyyy').should include('D02/01/2010')
57
- @instance.to_s('mm/dd/yyyy').should include('D01/02/2010')
21
+ expect(txn.to_s('dd/mm/yyyy')).to include('D02/01/2010')
22
+ expect(txn.to_s('mm/dd/yyyy')).to include('D01/02/2010')
58
23
  end
59
24
 
60
25
  it 'should put the amount in T' do
61
- @instance.to_s.should include('T-10.00')
26
+ expect(subject).to include('T-10.00')
62
27
  end
63
28
 
64
29
  it 'should put the category in L' do
65
- @instance.to_s.should include('LDebit')
30
+ expect(subject).to include('LDebit')
66
31
  end
67
32
 
68
33
  it 'should put the description in M' do
69
- @instance.to_s.should include('MSupermarket')
34
+ expect(subject).to include('MSupermarket')
70
35
  end
71
36
 
72
37
  it 'should put the reference in P' do
73
- @instance.to_s.should include('Pabcde')
38
+ expect(subject).to include('Pabcde')
39
+ end
40
+
41
+ it 'adds splits to the output' do
42
+ builder.add_split('split_1')
43
+ .set_split_memo('test split 1')
44
+ .set_split_amount('-5.0')
45
+ .add_split('split_2')
46
+ .set_split_memo('test split 2')
47
+ .set_split_amount('-5.0')
48
+
49
+ expect(subject).to include(<<SPLIT.strip)
50
+ Ssplit_1
51
+ Etest split 1
52
+ $-5.00
53
+ Ssplit_2
54
+ Etest split 2
55
+ $-5.0
56
+ SPLIT
74
57
  end
75
58
  end
76
59
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'qif/transaction/split/builder'
3
+
4
+ describe Qif::Transaction::Split::Builder do
5
+ let(:parent) { double(Qif::Transaction::Builder) }
6
+ let(:builder) { Qif::Transaction::Split::Builder.new(parent) }
7
+ def do_build
8
+ builder.build_split
9
+ end
10
+
11
+ context '#add_split' do
12
+ it 'should call add_split on the parent' do
13
+ expect(parent).to receive(:add_split).with("12345")
14
+ described_class.new(parent).add_split("12345")
15
+ end
16
+
17
+ it 'should return the new split builder' do
18
+ new_builder = double("split-builder")
19
+ allow(parent).to receive(:add_split).and_return(new_builder)
20
+ expect(described_class.new(parent).add_split(anything)).to eq(new_builder)
21
+ end
22
+ end
23
+
24
+ context '#set_memo' do
25
+ it_should_behave_like "builder method", :memo, 'Split', :set_split_memo
26
+ end
27
+
28
+ context '#set_amount' do
29
+ it_should_behave_like "builder method", :amount, '-10,000', :set_split_amount, -10000
30
+ end
31
+
32
+ context '#set_category' do
33
+ it_should_behave_like 'builder method', :category, '[Cash]', :set_split_category
34
+ end
35
+
36
+ context "when receiving an unknown message" do
37
+ it "should pass the message to the parent" do
38
+ expect(parent).to receive(:set_date).with('2012-12-31')
39
+ builder.set_date('2012-12-31')
40
+ end
41
+
42
+ it 'should return the result of the message' do
43
+ allow(parent).to receive(:set_date).and_return(parent)
44
+ expect(builder.set_date(anything)).to eq(parent)
45
+ end
46
+ end
47
+ end
@@ -2,98 +2,94 @@ require 'spec_helper'
2
2
  require 'stringio'
3
3
 
4
4
  describe Qif::Writer do
5
- before do
6
- @buffer = ''
7
- @io = StringIO.new(@buffer)
8
- @instance = Qif::Writer.new(@io)
9
- end
5
+ let(:buffer) { "" }
6
+ let(:io) { StringIO.new(buffer) }
7
+ let(:instance) { Qif::Writer.new(io) }
8
+ let(:path) { "/tmp/test" }
10
9
 
11
10
  describe '::open' do
12
11
  before do
13
- @path = '/tmp/test'
14
- File.stub(:open).and_yield @io
12
+ File.stub(:open).and_yield io
15
13
  end
16
14
 
17
15
  it 'should yield a Qif::Writer' do
18
16
  ran = false
19
- Qif::Writer.open(@path) do |writer|
17
+ Qif::Writer.open(path) do |writer|
20
18
  ran = true
21
19
  writer.should be_a(Qif::Writer)
22
20
  end
23
- ran.should be_true
21
+ ran.should eq true
24
22
  end
25
23
 
26
24
  it 'should write the transactions' do
27
25
  date = Time.now
28
26
 
29
- Qif::Writer.open(@path) do |writer|
27
+ Qif::Writer.open(path) do |writer|
30
28
  writer << Qif::Transaction.new(:date => date, :amount => 10.0, :category => 'Credit')
31
29
  end
32
30
 
33
- @buffer.should include('D%s' % date.strftime('%d/%m/%Y'))
34
- @buffer.should include('T10.0')
35
- @buffer.should include('LCredit')
31
+ buffer.should include('D%s' % date.strftime('%d/%m/%Y'))
32
+ buffer.should include('T10.0')
33
+ buffer.should include('LCredit')
36
34
  end
37
35
 
38
36
  it 'should perform a File.open on the given path' do
39
- File.should_receive(:open).with(@path, 'w')
40
- Qif::Writer.open(@path) do |writer|
37
+ File.should_receive(:open).with(path, 'w')
38
+ Qif::Writer.open(path) do |writer|
41
39
  end
42
40
  end
43
41
  end
42
+
44
43
  describe '::new' do
45
44
  it 'should yield a Qif::Writer' do
46
45
  ran = false
47
- Qif::Writer.new(@io) do |writer|
46
+ Qif::Writer.new(io) do |writer|
48
47
  ran = true
49
48
  writer.should be_a(Qif::Writer)
50
49
  end
51
- ran.should be_true
50
+ expect(ran).to eq true
52
51
  end
53
52
 
54
53
  it 'should write the transactions' do
55
54
  date = Time.now
56
55
 
57
- Qif::Writer.new(@io) do |writer|
56
+ Qif::Writer.new(io) do |writer|
58
57
  writer << Qif::Transaction.new(:date => date, :amount => 10.0, :category => 'Credit')
59
58
  end
60
59
 
61
- @buffer.should include('D%s' % date.strftime('%d/%m/%Y'))
62
- @buffer.should include('T10.0')
63
- @buffer.should include('LCredit')
60
+ buffer.should include('D%s' % date.strftime('%d/%m/%Y'))
61
+ buffer.should include('T10.0')
62
+ buffer.should include('LCredit')
64
63
  end
65
64
 
66
65
  it 'should perform a File.open on the given path' do
67
- File.should_receive(:open).with(@path, 'w')
68
- Qif::Writer.open(@path) do |writer|
66
+ File.should_receive(:open).with(path, 'w')
67
+ Qif::Writer.open(path) do |writer|
69
68
  end
70
69
  end
71
70
  end
72
71
 
73
-
74
-
75
-
76
-
77
72
  describe '#write' do
73
+ let(:date) { Time.now }
74
+
78
75
  it 'should write the header' do
79
- @instance.write
80
- @buffer.should include("!Type:Bank\n")
76
+ instance.write
77
+ buffer.should include("!Type:Bank\n")
81
78
  end
82
79
 
83
80
  it 'should write any pending transactions' do
84
- date = Time.now
85
- @instance << Qif::Transaction.new(:date => date, :amount => 10.0, :category => 'Credit')
81
+ instance << Qif::Transaction.new(:date => date, :amount => 10.0, :category => 'Credit')
86
82
 
87
- @buffer.should_not include('D%s' % date.strftime('%d/%m/%Y'))
88
- @instance.write
89
- @buffer.should include('D%s' % date.strftime('%d/%m/%Y'))
83
+ buffer.should_not include('D%s' % date.strftime('%d/%m/%Y'))
84
+ instance.write
85
+ buffer.should include('D%s' % date.strftime('%d/%m/%Y'))
90
86
  end
91
87
  end
92
88
 
93
89
  describe '#close' do
94
90
  it 'should close the io stream' do
95
- @io.should_receive(:close)
96
- @instance.close
91
+ io.should_receive(:close)
92
+ instance.close
97
93
  end
98
94
  end
99
95
  end
@@ -1 +1,3 @@
1
- require File.dirname(__FILE__) + '/../lib/qif'
1
+ require File.dirname(__FILE__) + '/../lib/qif'
2
+
3
+ require_relative "support/shared/builder_method"
@@ -0,0 +1,14 @@
1
+ shared_context 'builder method' do |attribute, input, method = nil, expected = nil|
2
+ expected = input if expected.nil?
3
+ method = "set_#{attribute}" if method.nil?
4
+
5
+ it 'and set the #{attribute} on the transaction' do
6
+ builder.send(method, input)
7
+ expect(do_build.send(attribute)).to eq(expected)
8
+ end
9
+
10
+ it 'and return the builder' do
11
+ expect(builder.send(method, input)).to be_kind_of described_class
12
+ end
13
+ end
14
+
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qif
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Wells
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-14 00:00:00.000000000 Z
11
+ date: 2016-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.5.0
19
+ version: 3.0.0
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 2.5.0
26
+ version: 3.0.0
27
27
  description: A library for reading and writing quicken QIF files.
28
28
  email: jemmyw@gmail.com
29
29
  executables: []
@@ -38,15 +38,20 @@ extra_rdoc_files:
38
38
  - lib/qif/transaction.rb
39
39
  - lib/qif/writer.rb
40
40
  files:
41
- - README.rdoc
42
- - LICENSE
43
41
  - CHANGELOG
42
+ - LICENSE
43
+ - README.rdoc
44
44
  - Rakefile
45
+ - lib/qif.rb
46
+ - lib/qif/amount_parser.rb
45
47
  - lib/qif/date_format.rb
46
48
  - lib/qif/reader.rb
47
49
  - lib/qif/transaction.rb
50
+ - lib/qif/transaction/builder.rb
51
+ - lib/qif/transaction/builderable.rb
52
+ - lib/qif/transaction/split.rb
53
+ - lib/qif/transaction/split/builder.rb
48
54
  - lib/qif/writer.rb
49
- - lib/qif.rb
50
55
  - spec/fixtures/3_records_ddmmyy.qif
51
56
  - spec/fixtures/3_records_ddmmyyyy.qif
52
57
  - spec/fixtures/3_records_dmyy.qif
@@ -58,38 +63,42 @@ files:
58
63
  - spec/fixtures/not_a_QIF_file.txt
59
64
  - spec/fixtures/quicken_investment_account.qif
60
65
  - spec/fixtures/quicken_non_investement_account.qif
66
+ - spec/fixtures/splits.qif
61
67
  - spec/lib/date_format_spec.rb
62
68
  - spec/lib/reader_spec.rb
69
+ - spec/lib/transaction_builder_spec.rb
63
70
  - spec/lib/transaction_spec.rb
71
+ - spec/lib/transaction_split_builder_spec.rb
64
72
  - spec/lib/writer_spec.rb
65
73
  - spec/spec.opts
66
74
  - spec/spec_helper.rb
75
+ - spec/support/shared/builder_method.rb
67
76
  homepage: http://qif.github.com/qif
68
77
  licenses: []
69
78
  metadata: {}
70
79
  post_install_message:
71
80
  rdoc_options:
72
- - --line-numbers
73
- - --inline-source
74
- - --title
81
+ - "--line-numbers"
82
+ - "--inline-source"
83
+ - "--title"
75
84
  - Qif
76
- - --main
85
+ - "--main"
77
86
  - README.rdoc
78
87
  require_paths:
79
88
  - lib
80
89
  required_ruby_version: !ruby/object:Gem::Requirement
81
90
  requirements:
82
- - - '>='
91
+ - - ">="
83
92
  - !ruby/object:Gem::Version
84
93
  version: '0'
85
94
  required_rubygems_version: !ruby/object:Gem::Requirement
86
95
  requirements:
87
- - - '>='
96
+ - - ">="
88
97
  - !ruby/object:Gem::Version
89
98
  version: '1.2'
90
99
  requirements: []
91
100
  rubyforge_project: qif
92
- rubygems_version: 2.1.11
101
+ rubygems_version: 2.4.5.1
93
102
  signing_key:
94
103
  specification_version: 4
95
104
  summary: A library for reading and writing quicken QIF files.