qif 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 05d7562d52dc8df636d290de9e2cce5f412a6013
4
+ data.tar.gz: f47615d7c5077148c7c508bab6f14839730e49ad
5
+ SHA512:
6
+ metadata.gz: 4514f7c2a458fb6989ca943a5f8050f905f81e449ced6adfd79daab2ab97bbb033cb2125f42f8e576bdec73a1a0fa08657e23b77bf91f2d9c5759f8717664973
7
+ data.tar.gz: 87fe80e1d2b395d875121fdea2a3679e53269fa4b632cafcaca467c02bc89ddb43630c5fe113c34d0a694976386ccbc8ed2d89898f6006d99f167f03a4bee146
@@ -1,3 +1,5 @@
1
+ {<img src="https://travis-ci.org/jemmyw/Qif.png?branch=master" alt="Build Status" />}[https://travis-ci.org/jemmyw/Qif]
2
+
1
3
  = Library for reading Quicken Interchange Format (QIF) files
2
4
 
3
5
  * http://github.com/jemmyw/Qif
@@ -49,7 +51,7 @@
49
51
 
50
52
  === LICENSE:
51
53
 
52
- Copyright (c) 2010 Jeremy Wells
54
+ Copyright (c) 2011 Jeremy Wells
53
55
 
54
56
  Permission is hereby granted, free of charge, to any person
55
57
  obtaining a copy of this software and associated documentation
data/Rakefile CHANGED
@@ -1,12 +1,5 @@
1
- require 'echoe'
2
1
  require 'rspec/core/rake_task'
3
2
 
4
- Echoe.new('qif') do |gem|
5
- gem.author = "Jeremy Wells"
6
- gem.summary = "A library for reading and writing quicken QIF files."
7
- gem.email = "jemmyw@gmail.com"
8
- end
9
-
10
3
  desc "Run specs"
11
4
  RSpec::Core::RakeTask.new :spec
12
5
 
@@ -3,59 +3,46 @@ require 'time'
3
3
  module Qif
4
4
  class DateFormat
5
5
  attr_reader :format
6
-
6
+
7
+ SUPPORTED_DATEFORMAT = {
8
+ "dd/mm/yyyy" => "%d/%m/%Y",
9
+ "d/mm/yyyy" => "%d/%m/%Y",
10
+ "dd/m/yyyy" => "%d/%m/%Y",
11
+ "d/m/yyyy" => "%d/%m/%Y",
12
+
13
+ "dd/mm/yy" => "%d/%m/%y",
14
+ "d/mm/yy" => "%d/%m/%y",
15
+ "dd/m/yy" => "%d/%m/%y",
16
+ "d/m/yy" => "%d/%m/%y",
17
+
18
+ "mm/dd/yyyy" => "%m/%d/%Y",
19
+ "m/dd/yyyy" => "%m/%d/%Y",
20
+ "mm/d/yyyy" => "%m/%d/%Y",
21
+ "m/d/yyyy" => "%m/%d/%Y",
22
+
23
+ "mm/dd/yy" => "%m/%d/%y",
24
+ "m/dd/yy" => "%m/%d/%y",
25
+ "mm/d/yy" => "%m/%d/%y",
26
+ "m/d/yy" => "%m/%d/%y",
27
+ }
28
+
7
29
  def initialize(format = 'dd/mm/yyyy')
8
30
  @format = format
9
31
  end
10
-
32
+
11
33
  def parse(date)
12
- regex = convert_format_to_regex
13
- order = date_order
14
-
15
- if match = regex.match(date)
16
- year = match[order.index('y')+1].to_i
17
-
18
- if year < 100
19
- start_year = Time.now.year - 50
20
- start_cent = (start_year/100).to_i*100
21
- if year > start_year-start_cent
22
- year += start_cent
23
- else
24
- year += ((Time.now.year/100).to_i*100)
25
- end
26
- end
27
-
28
- Time.mktime(year, *%w(m d).map{|t| match[order.index(t) + 1].to_i })
29
- end
34
+ Date.strptime(date, convert_format_to_strftime)
30
35
  end
31
-
36
+
32
37
  def format(date)
33
38
  date.strftime(convert_format_to_strftime)
34
39
  end
35
-
40
+
36
41
  private
37
-
38
- def date_order
39
- %w(d m y).sort{|a,b| @format.index(a) <=> @format.index(b) }
40
- end
41
-
42
+
42
43
  def convert_format_to_strftime
43
- format = @format.dup
44
- format.gsub!('dd', '%d')
45
- format.gsub!('mm', '%m')
46
- format.gsub!('yyyy', '%Y')
47
- format.gsub!('yy', '%y')
48
- format
49
- end
50
-
51
- def convert_format_to_regex
52
- format = @format.dup
53
- format.gsub!('dd', '([0-3][0-9])')
54
- format.gsub!('mm', '([0-1][0-9])')
55
- format.gsub!('yyyy', '([1-2][0-9]{3})')
56
- format.gsub!('yy', '([0-9]{2})')
57
-
58
- /#{format}/mi
44
+ SUPPORTED_DATEFORMAT[@format]
59
45
  end
46
+
60
47
  end
61
48
  end
@@ -15,6 +15,8 @@ module Qif
15
15
  # end
16
16
  class Reader
17
17
  include Enumerable
18
+
19
+ attr_reader :index
18
20
 
19
21
  SUPPORTED_ACCOUNTS = {
20
22
  "!Type:Bank" => "Bank account transactions",
@@ -31,7 +33,7 @@ module Qif
31
33
  # either an IO object or a String containing the Qif file data.
32
34
  #
33
35
  # The optional format argument specifies the date format in the file.
34
- # Giving a format will force it, otherwise the format will guissed
36
+ # Giving a format will force it, otherwise the format will guessed
35
37
  # reading the transactions in the file, this defaults to 'dd/mm/yyyy'
36
38
  # if guessing method fails.
37
39
  def initialize(data, format = nil)
@@ -78,17 +80,29 @@ module Qif
78
80
  begin
79
81
  line = @data.gets
80
82
  break if line.nil?
81
- date = line.strip.scan(/^D(\d{1,2}).(\d{1,2}).(\d{2,4})/).flatten
82
- if date.count == 3
83
- guessed_format = date[0].to_i.between?(1, 12) ? (date[1].to_i.between?(1, 12) ? nil : 'mm/dd') : 'dd/mm'
84
- guessed_format += '/' + 'y'*date[2].length if guessed_format
85
- end
83
+
84
+ date = line[1..-1]
85
+ guessed_format = Qif::DateFormat::SUPPORTED_DATEFORMAT.find { |format_string, format|
86
+ test_date_with_format?(date, format_string, format)
87
+ }
86
88
  end until guessed_format
89
+
87
90
  @data.rewind
88
- guessed_format
91
+
92
+ guessed_format ? guessed_format.first : @fallback_format
89
93
  end
90
94
 
91
95
  private
96
+
97
+ def test_date_with_format?(date, format_string, format)
98
+ parsed_date = Date.strptime(date, format)
99
+ if parsed_date > Date.strptime('01/01/1900', '%d/%m/%Y')
100
+ @fallback_format ||= format_string
101
+ parsed_date.day > 12
102
+ end
103
+ rescue
104
+ false
105
+ end
92
106
 
93
107
  def read_all_transactions
94
108
  while next_transaction; end
@@ -0,0 +1,19 @@
1
+ !Type:Bank
2
+ D1/ 1/10
3
+ T-10.00
4
+ LDebit
5
+ PDescription
6
+ MReference
7
+ ^
8
+ D6/ 1/10
9
+ T-20.00
10
+ LDebit
11
+ PDescription
12
+ MReference
13
+ ^
14
+ D12/29/10
15
+ T30.00
16
+ LCredit
17
+ PDescription
18
+ MReference
19
+ ^
@@ -4,16 +4,16 @@ describe Qif::DateFormat do
4
4
  it 'should work with 2 digit years in mm/dd/yy format' do
5
5
  reader = Qif::DateFormat.new('mm/dd/yy')
6
6
  time = reader.parse('09/28/10')
7
- time.should == Time.mktime(2010, 9, 28)
7
+ time.should == Date.strptime('09/28/10', '%m/%d/%y')
8
8
  time = reader.parse('09/28/94')
9
- time.should == Time.mktime(1994, 9, 28)
9
+ time.should == Date.strptime('09/28/94', '%m/%d/%y')
10
10
  end
11
11
 
12
12
  it 'should work with 2 digit years in dd/mm/yy format' do
13
13
  reader = Qif::DateFormat.new('dd/mm/yy')
14
14
  time = reader.parse('28/09/10')
15
- time.should == Time.mktime(2010, 9, 28)
15
+ time.should == Date.strptime('28/09/10', '%d/%m/%y')
16
16
  time = reader.parse('28/09/94')
17
- time.should == Time.mktime(1994, 9, 28)
17
+ time.should == Date.strptime('28/09/94', '%d/%m/%y')
18
18
  end
19
19
  end
@@ -6,21 +6,21 @@ shared_examples_for "3 record files" do
6
6
  end
7
7
 
8
8
  it 'should have a debit of $10 on the 1st of January 2010' do
9
- transaction = instance.transactions.detect{|t| t.date == Time.mktime(2010, 1, 1)}
9
+ transaction = instance.transactions.detect{|t| t.date == Date.new(2010, 1, 1)}
10
10
  transaction.should_not be_nil
11
11
  transaction.category.should == 'Debit'
12
12
  transaction.amount.should == -10.0
13
13
  end
14
14
 
15
15
  it 'should have a debit of $20 on the 1st of June 1020' do
16
- transaction = instance.transactions.detect{|t| t.date == Time.mktime(2010, 6, 1)}
16
+ transaction = instance.transactions.detect{|t| t.date == Date.new(2010, 6, 1)}
17
17
  transaction.should_not be_nil
18
18
  transaction.category.should == 'Debit'
19
19
  transaction.amount.should == -20.0
20
20
  end
21
21
 
22
22
  it 'should have a credit of $30 on the 29th of December 2010' do
23
- transaction = instance.transactions.detect{|t| t.date == Time.mktime(2010, 12, 29)}
23
+ transaction = instance.transactions.detect{|t| t.date == Date.new(2010, 12, 29)}
24
24
  transaction.should_not be_nil
25
25
  transaction.category.should == 'Credit'
26
26
  transaction.amount.should == 30.0
@@ -46,6 +46,12 @@ describe Qif::Reader do
46
46
  end
47
47
  end
48
48
 
49
+ context "when format has spaces" do
50
+ it_behaves_like "3 record files" do
51
+ let(:instance) { Qif::Reader.new(open('spec/fixtures/3_records_spaced.qif').read) }
52
+ end
53
+ end
54
+
49
55
  context "it should still work when the record header is followed by an invalid transaction terminator" do
50
56
  it_behaves_like "3 record files" do
51
57
  let(:instance) { Qif::Reader.new(open('spec/fixtures/3_records_invalid_header.qif'), 'dd/mm/yy') }
@@ -58,29 +64,30 @@ describe Qif::Reader do
58
64
  it 'should reject the wrong file and raise an UnrecognizedData exception' do
59
65
  expect{ Qif::Reader.new(open('spec/fixtures/not_a_QIF_file.txt')) }.to raise_error(Qif::Reader::UnrecognizedData)
60
66
  end
61
- it 'should guess the date format dd/mm/yyyy' do
62
- @instance = Qif::Reader.new(open('spec/fixtures/3_records_ddmmyyyy.qif'))
63
- @instance.guess_date_format.should == 'dd/mm/yyyy'
64
- end
65
67
 
66
- it 'should guess the date format mm/dd/yy' do
67
- @instance = Qif::Reader.new(open('spec/fixtures/3_records_mmddyy.qif'))
68
- @instance.guess_date_format.should == 'mm/dd/yy'
69
- end
68
+ describe '#guess_date_format' do
69
+ it 'should guess the date format dd/mm/yyyy' do
70
+ @instance = Qif::Reader.new(open('spec/fixtures/3_records_ddmmyyyy.qif'))
71
+ @instance.guess_date_format.should == 'dd/mm/yyyy'
72
+ end
73
+
74
+ it 'should guess the date format mm/dd/yy' do
75
+ @instance = Qif::Reader.new(open('spec/fixtures/3_records_mmddyy.qif'))
76
+ @instance.guess_date_format.should == 'mm/dd/yy'
77
+ end
70
78
 
71
- it 'shouldn\t guess the date format because transactions are ambiguious, fall back on default dd/mm/yyyy and fail' do
72
- @instance = Qif::Reader.new(open('spec/fixtures/quicken_non_investement_account.qif'))
73
- @instance.guess_date_format.should == nil
74
- @instance.size.should == 0
79
+ it 'should fall back to best guess if the date are ambiguious' do
80
+ @instance = Qif::Reader.new(open('spec/fixtures/quicken_non_investement_account.qif'))
81
+ @instance.guess_date_format.should == 'dd/mm/yy'
82
+ end
83
+
84
+ it 'should guess the date format d/m/yy' do
85
+ @instance = Qif::Reader.new(open('spec/fixtures/3_records_dmyy.qif'))
86
+ @instance.guess_date_format.should == 'dd/mm/yy'
87
+ end
75
88
  end
76
-
77
- # TODO Date parser should be more flexible and efficient, probably using Date.strptime(str, format)
78
- # it 'should initialize if leading zeros are missing too' do
79
- # @instance = Qif::Reader.new(open('spec/fixtures/3_records_dmyy.qif'))
80
- # @instance.size.should == 3
81
- # end
82
89
 
83
- it 'should should parse amounts with comma separator too' do
90
+ it 'should parse amounts with comma separator too' do
84
91
  @instance = Qif::Reader.new(open('spec/fixtures/3_records_separator.qif'))
85
92
  @instance.size.should == 3
86
93
  @instance.collect(&:amount).should == [-1010.0, -30020.0, 30.0]
@@ -11,7 +11,7 @@ describe Qif::Writer do
11
11
  describe '::open' do
12
12
  before do
13
13
  @path = '/tmp/test'
14
- File.stub!(:open).and_yield @io
14
+ File.stub(:open).and_yield @io
15
15
  end
16
16
 
17
17
  it 'should yield a Qif::Writer' do
metadata CHANGED
@@ -1,27 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qif
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
5
- prerelease:
4
+ version: 1.1.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jeremy Wells
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2011-03-07 00:00:00.000000000Z
11
+ date: 2013-12-14 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
- requirement: &70212876609680 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: 2.5.0
22
20
  type: :development
23
21
  prerelease: false
24
- version_requirements: *70212876609680
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.5.0
25
27
  description: A library for reading and writing quicken QIF files.
26
28
  email: jemmyw@gmail.com
27
29
  executables: []
@@ -52,6 +54,7 @@ files:
52
54
  - spec/fixtures/3_records_mmddyy.qif
53
55
  - spec/fixtures/3_records_mmddyyyy.qif
54
56
  - spec/fixtures/3_records_separator.qif
57
+ - spec/fixtures/3_records_spaced.qif
55
58
  - spec/fixtures/not_a_QIF_file.txt
56
59
  - spec/fixtures/quicken_investment_account.qif
57
60
  - spec/fixtures/quicken_non_investement_account.qif
@@ -63,6 +66,7 @@ files:
63
66
  - spec/spec_helper.rb
64
67
  homepage: http://qif.github.com/qif
65
68
  licenses: []
69
+ metadata: {}
66
70
  post_install_message:
67
71
  rdoc_options:
68
72
  - --line-numbers
@@ -74,21 +78,20 @@ rdoc_options:
74
78
  require_paths:
75
79
  - lib
76
80
  required_ruby_version: !ruby/object:Gem::Requirement
77
- none: false
78
81
  requirements:
79
- - - ! '>='
82
+ - - '>='
80
83
  - !ruby/object:Gem::Version
81
84
  version: '0'
82
85
  required_rubygems_version: !ruby/object:Gem::Requirement
83
- none: false
84
86
  requirements:
85
- - - ! '>='
87
+ - - '>='
86
88
  - !ruby/object:Gem::Version
87
89
  version: '1.2'
88
90
  requirements: []
89
91
  rubyforge_project: qif
90
- rubygems_version: 1.8.6
92
+ rubygems_version: 2.1.11
91
93
  signing_key:
92
- specification_version: 3
94
+ specification_version: 4
93
95
  summary: A library for reading and writing quicken QIF files.
94
96
  test_files: []
97
+ has_rdoc: