ledger-rest 2.0.3 → 3.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.
Files changed (41) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +1 -1
  4. data/Guardfile +4 -22
  5. data/{LICENSE.txt → LICENSE} +1 -1
  6. data/README.md +62 -11
  7. data/config.ru +1 -1
  8. data/ledger-rest.gemspec +17 -17
  9. data/ledger-rest.yml.example +3 -0
  10. data/lib/ledger-rest/app.rb +21 -34
  11. data/lib/ledger-rest/core_ext.rb +4 -3
  12. data/lib/ledger-rest/git.rb +8 -7
  13. data/lib/ledger-rest/ledger.rb +29 -24
  14. data/lib/ledger-rest/ledger/balance.rb +48 -15
  15. data/lib/ledger-rest/ledger/budget.rb +35 -16
  16. data/lib/ledger-rest/ledger/entry.rb +1 -4
  17. data/lib/ledger-rest/ledger/parser.rb +41 -37
  18. data/lib/ledger-rest/ledger/register.rb +31 -24
  19. data/lib/ledger-rest/ledger/transaction.rb +33 -28
  20. data/lib/ledger-rest/transactions.py +47 -0
  21. data/lib/ledger-rest/version.rb +2 -1
  22. data/spec/files/append.ledger +13 -0
  23. data/spec/files/budget.ledger +4 -0
  24. data/spec/files/main.ledger +4 -0
  25. data/spec/files/opening_balance.ledger +4 -0
  26. data/spec/files/transactions.ledger +11 -0
  27. data/spec/ledger-rest.yml +3 -0
  28. data/spec/ledger-rest/api/accounts_spec.rb +19 -0
  29. data/spec/ledger-rest/api/balance_spec.rb +117 -0
  30. data/spec/ledger-rest/api/budget_spec.rb +110 -0
  31. data/spec/ledger-rest/api/payees_spec.rb +19 -0
  32. data/spec/ledger-rest/api/register_spec.rb +233 -0
  33. data/spec/ledger-rest/api/transactions_spec.rb +201 -0
  34. data/spec/ledger-rest/api/version_spec.rb +13 -0
  35. data/spec/ledger-rest/ledger/balance_spec.rb +124 -0
  36. data/spec/ledger-rest/ledger/parser_spec.rb +184 -117
  37. data/spec/ledger-rest/ledger/transaction_spec.rb +38 -31
  38. data/spec/spec_helper.rb +22 -0
  39. data/spec/support/deep_eq_matcher.rb +149 -0
  40. metadata +52 -31
  41. data/ledger-rest.org +0 -22
@@ -0,0 +1,201 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe '/transactions' do
5
+ describe 'GET' do
6
+ let(:valid_json) do
7
+ [
8
+ {
9
+ 'date' => '2013/01/01',
10
+ 'payee' => 'Opening Balance',
11
+ 'cleared' => true,
12
+ 'posts' =>
13
+ [
14
+ {
15
+ 'account' => 'Assets:Giro',
16
+ 'amount' => 2000.0,
17
+ 'commodity' => 'EUR'
18
+ }, {
19
+ 'account' => 'Assets:Reimbursements:Hans Maulwurf',
20
+ 'amount' => 19.0,
21
+ 'commodity' => 'EUR'
22
+ }, {
23
+ 'account' => 'Equity:Opening Balances',
24
+ 'amount' => -2019.0,
25
+ 'commodity' => 'EUR'
26
+ }
27
+ ],
28
+ 'pending' => false
29
+ }, {
30
+ 'date' => '2013/12/03',
31
+ 'payee' => 'NaveenaPath',
32
+ 'cleared' => false,
33
+ 'posts' =>
34
+ [
35
+ {
36
+ 'account' => 'Expenses:Restaurants',
37
+ 'amount' => 9.0,
38
+ 'commodity' => 'EUR'
39
+ }, {
40
+ 'account' => 'Assets:Cash',
41
+ 'amount' => -9.0,
42
+ 'commodity' => 'EUR'
43
+ }
44
+ ],
45
+ 'pending' => false
46
+ }, {
47
+ 'date' => '2013/12/05',
48
+ 'payee' => 'Shikgoo',
49
+ 'cleared' => false,
50
+ 'posts' =>
51
+ [
52
+ {
53
+ 'account' => 'Expenses:Restaurants',
54
+ 'amount' => 12.0,
55
+ 'commodity' => 'EUR'
56
+ }, {
57
+ 'account' => 'Liabilities:Max Mustermann',
58
+ 'amount' => -12.0,
59
+ 'commodity' => 'EUR'
60
+ }
61
+ ],
62
+ 'pending' => false
63
+ }, {
64
+ 'posts' =>
65
+ [
66
+ {
67
+ 'account' => 'Assets:Reimbursements:Hans Maulwurf',
68
+ 'amount' => 3.1,
69
+ 'commodity' => 'EUR'
70
+ }, {
71
+ 'account' => 'Assets:Cash',
72
+ 'amount' => -3.1,
73
+ 'commodity' => 'EUR'
74
+ }
75
+ ],
76
+ 'note' => 'Sonnenblumenkernbrot',
77
+ 'payee' => 'Bioladen Tegeler Straße',
78
+ 'date' => '2013/12/10',
79
+ 'cleared' => false,
80
+ 'pending' => false
81
+ }, {
82
+ 'effective_date' => '2013/12/02',
83
+ 'posts' =>
84
+ [
85
+ {
86
+ 'account' => 'Assets:Cash',
87
+ 'amount' => 50.0,
88
+ 'commodity' => 'EUR'
89
+ }, {
90
+ 'account' => 'Assets:Giro',
91
+ 'amount' => -50.0,
92
+ 'commodity' => 'EUR'
93
+ }
94
+ ],
95
+ 'payee' => 'Sparkasse',
96
+ 'date' => '2013/12/01',
97
+ 'cleared' => true,
98
+ 'pending' => false
99
+ }, {
100
+ 'date' => '2013/12/04',
101
+ 'payee' => 'Trattoria La Vialla',
102
+ 'cleared' => false,
103
+ 'posts' =>
104
+ [
105
+ {
106
+ 'account' => 'Expenses:Restaurants',
107
+ 'amount' => 32.2,
108
+ 'commodity' => 'EUR'
109
+ }, {
110
+ 'account' => 'Assets:Cash',
111
+ 'amount' => -32.2,
112
+ 'commodity' => 'EUR'
113
+ }
114
+ ],
115
+ 'pending' => false
116
+ }, {
117
+ 'date' => '2013/12/06',
118
+ 'payee' => 'Customer X',
119
+ 'cleared' => false,
120
+ 'posts' =>
121
+ [
122
+ {
123
+ 'account' => 'Assets:Giro',
124
+ 'amount' => 1200.0,
125
+ 'commodity' => 'EUR'
126
+ }, {
127
+ 'account' => 'Income:Invoice',
128
+ 'amount' => -1200.0,
129
+ 'commodity' => 'EUR'
130
+ }
131
+ ],
132
+ 'pending' => false
133
+ }
134
+ ]
135
+ end
136
+
137
+ it 'returns all transactions' do
138
+ get '/transactions'
139
+ JSON.parse(last_response.body).should deep_eq valid_json
140
+ end
141
+ end
142
+
143
+ describe 'POST' do
144
+ let(:transaction) do
145
+ {
146
+ date: '2013/12/12',
147
+ cleared: true,
148
+ payee: 'New Payee',
149
+ postings:
150
+ [
151
+ {
152
+ account: 'Expenses:Restaurants',
153
+ amount: 11.0,
154
+ commodity: 'EUR'
155
+ },
156
+ {
157
+ account: 'Assets:Cash',
158
+ amount: -11.0,
159
+ commodity: 'EUR'
160
+ }
161
+ ]
162
+ }
163
+ end
164
+
165
+ let(:correct_response) do
166
+ { transaction: transaction }
167
+ end
168
+
169
+ it 'adds a new transaction to the append file' do
170
+ restore_file('spec/files/append.ledger') do
171
+ post '/transactions', transaction.to_json
172
+
173
+ last_response.status.should == 201
174
+ JSON.parse(last_response.body, symbolize_names: true).should deep_eq correct_response
175
+ puts File.read('spec/files/append.ledger').should == <<RESULT
176
+ 2013/12/03 NaveenaPath
177
+ Expenses:Restaurants 9.00EUR
178
+ Assets:Cash
179
+
180
+ 2013/12/05 Shikgoo
181
+ Expenses:Restaurants 12.00EUR
182
+ Liabilities:Max Mustermann
183
+ ; meta_info: Some interesting meta information
184
+
185
+ 2013/12/10 Bioladen Tegeler Straße
186
+ ; Sonnenblumenkernbrot
187
+ Assets:Reimbursements:Hans Maulwurf 3.10EUR
188
+ Assets:Cash
189
+
190
+ 2013/12/12 * New Payee
191
+ Expenses:Restaurants 11.00EUR
192
+ Assets:Cash -11.00EUR
193
+ RESULT
194
+ end
195
+ end
196
+ end
197
+
198
+ describe 'PUT' do
199
+ it 'updates a transaction'
200
+ end
201
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe '/version' do
5
+ it 'returns the ledger-rest version' do
6
+ get '/version'
7
+
8
+ JSON.parse(last_response.body).should == {
9
+ 'version' => LedgerRest::VERSION,
10
+ 'ledger-version' => LedgerRest::Ledger.version
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe LedgerRest::Ledger::Balance do
4
+ describe '::expand_accounts' do
5
+ let(:accounts) do
6
+ [
7
+ {
8
+ fullname: 'Expenses',
9
+ name: 'Expenses',
10
+ depth: 1,
11
+ total: '453.10EUR'
12
+ },
13
+ {
14
+ fullname: 'Expenses:Groceries:Bread',
15
+ name: 'Groceries:Bread',
16
+ depth: 3,
17
+ total: '3.10EUR'
18
+ },
19
+ {
20
+ fullname: 'Assets:Cash',
21
+ name: 'Assets:Cash',
22
+ depth: 1,
23
+ total: '200.00EUR'
24
+ }
25
+ ]
26
+ end
27
+
28
+ let(:expanded) do
29
+ [
30
+ { fullname: 'Expenses', name: 'Expenses', depth: 1, total: '453.10EUR' },
31
+ { fullname: 'Expenses:Groceries', name: 'Groceries', depth: 2, total: '3.10EUR' },
32
+ { fullname: 'Expenses:Groceries:Bread', name: 'Bread', depth: 3, total: '3.10EUR' },
33
+ { fullname: 'Assets', name: 'Assets', depth: 1, total: '200.00EUR' },
34
+ { fullname: 'Assets:Cash', name: 'Cash', depth: 2, total: '200.00EUR' }
35
+ ]
36
+ end
37
+
38
+ it 'expands accounts correctly' do
39
+ LedgerRest::Ledger::Balance.expand_accounts(accounts).should deep_eq expanded
40
+ end
41
+ end
42
+
43
+ describe '::wrap_accounts' do
44
+ let(:accounts) do
45
+ [
46
+ {
47
+ fullname: 'Expenses',
48
+ name: 'Expenses',
49
+ depth: 1,
50
+ total: '453.10EUR'
51
+ },
52
+ {
53
+ fullname: 'Expenses:Groceries',
54
+ name: 'Groceries',
55
+ depth: 2,
56
+ total: '3.10EUR'
57
+ },
58
+ {
59
+ fullname: 'Expenses:Groceries:Bread',
60
+ name: 'Bread',
61
+ depth: 3,
62
+ total: '3.10EUR'
63
+ },
64
+ {
65
+ fullname: 'Expenses:Flat',
66
+ name: 'Flat',
67
+ depth: 2,
68
+ total: '450.00EUR'
69
+ },
70
+ {
71
+ fullname: 'Assets',
72
+ name: 'Assets',
73
+ depth: 1,
74
+ total: '200.00EUR'
75
+ }
76
+ ]
77
+ end
78
+
79
+ let(:wrapped) do
80
+ [
81
+ {
82
+ fullname: 'Expenses',
83
+ name: 'Expenses',
84
+ depth: 1,
85
+ total: '453.10EUR',
86
+ accounts:
87
+ [
88
+ {
89
+ fullname: 'Expenses:Groceries',
90
+ name: 'Groceries',
91
+ depth: 2,
92
+ total: '3.10EUR',
93
+ accounts:
94
+ [
95
+ {
96
+ fullname: 'Expenses:Groceries:Bread',
97
+ name: 'Bread',
98
+ depth: 3,
99
+ total: '3.10EUR'
100
+ }
101
+ ]
102
+ },
103
+ {
104
+ fullname: 'Expenses:Flat',
105
+ name: 'Flat',
106
+ depth: 2,
107
+ total: '450.00EUR'
108
+ }
109
+ ]
110
+ },
111
+ {
112
+ fullname: 'Assets',
113
+ name: 'Assets',
114
+ depth: 1,
115
+ total: '200.00EUR'
116
+ }
117
+ ]
118
+ end
119
+
120
+ it 'wraps accounts correctly' do
121
+ LedgerRest::Ledger::Balance.wrap_accounts(accounts).should deep_eq wrapped
122
+ end
123
+ end
124
+ end
@@ -6,79 +6,83 @@ describe LedgerRest::Ledger::Parser do
6
6
  @parser = LedgerRest::Ledger::Parser.new
7
7
  end
8
8
 
9
- context '#parse' do
10
- subject {
11
- LedgerRest::Ledger::Transaction.new(:date => "2012/03/01",
12
- :effective_date => "2012/03/23",
13
- :cleared => true,
14
- :pending => false,
15
- :code => "INV#23",
16
- :payee => "me, myself and I",
17
- :postings => [
18
- {
19
- :account => "Expenses:Imaginary",
20
- :amount => "€ 23",
21
- :per_unit_cost => "USD 2300",
22
- :actual_date => "2012/03/24",
23
- :effective_date => "2012/03/25"
24
- }, {
25
- :account => "Expenses:Magical",
26
- :amount => "€ 42",
27
- :posting_cost => "USD 23000000",
28
- :virtual => true
29
- }, {
30
- :account => "Assets:Mighty"
31
- }, {
32
- :comment => "This is a freeform comment"
33
- },
34
- ])
35
- }
9
+ describe '#parse' do
10
+ subject do
11
+ LedgerRest::Ledger::Transaction.new(date: '2012/03/01',
12
+ effective_date: '2012/03/23',
13
+ cleared: true,
14
+ pending: false,
15
+ code: 'INV#23',
16
+ payee: 'me, myself and I',
17
+ postings:
18
+ [
19
+ {
20
+ account: 'Expenses:Imaginary',
21
+ amount: 23.0,
22
+ commodity: 'EUR',
23
+ per_unit_cost: 2300.0,
24
+ per_unit_commodity: 'USD',
25
+ actual_date: '2012/03/24',
26
+ effective_date: '2012/03/25'
27
+ }, {
28
+ account: 'Expenses:Magical',
29
+ amount: 42.0,
30
+ commodity: 'EUR',
31
+ posting_cost: 23000000.0,
32
+ posting_cost_commodity: 'USD',
33
+ virtual: true
34
+ }, {
35
+ account: 'Assets:Mighty'
36
+ }, {
37
+ comment: 'This is a freeform comment'
38
+ },
39
+ ])
40
+ end
36
41
 
37
42
  it 'should parse a to_ledger converted transaction into the same original hash' do
38
43
  @parser.parse(subject.to_ledger).should == subject
39
44
  end
40
-
41
45
  end
42
46
 
43
- context '#parse_date' do
47
+ describe '#parse_date' do
44
48
  before :all do
45
49
  @ret = @parser.parse_date("2012/11/23 * Rest with\nAnd Stuff")
46
50
  end
47
51
 
48
- it 'should return the parsed date' do
52
+ it 'returns the parsed date' do
49
53
  @ret[0].should == '2012/11/23'
50
54
  end
51
55
 
52
- it 'should return the rest of the input' do
56
+ it 'returns the rest of the input' do
53
57
  @ret[1].should == " * Rest with\nAnd Stuff"
54
58
  end
55
59
  end
56
60
 
57
- context '#parse_effective_date' do
61
+ describe '#parse_effective_date' do
58
62
  before :all do
59
63
  @ret = @parser.parse_effective_date("=2012/11/24 * Rest with\nAnd Stuff")
60
64
  end
61
65
 
62
- it 'should return the parsed date' do
63
- @ret[0].should == "2012/11/24"
66
+ it 'returns the parsed date' do
67
+ @ret[0].should == '2012/11/24'
64
68
  end
65
69
 
66
- it 'should return the rest of the input' do
70
+ it 'returns the rest of the input' do
67
71
  @ret[1].should == " * Rest with\nAnd Stuff"
68
72
  end
69
73
  end
70
74
 
71
- context '#parse_state' do
75
+ describe '#parse_state' do
72
76
  context 'given cleared transaction input' do
73
77
  before :all do
74
78
  @ret = @parser.parse_cleared(" * Rest with\nAnd Stuff")
75
79
  end
76
80
 
77
- it 'should return true' do
81
+ it 'returns true' do
78
82
  @ret[0].should == true
79
83
  end
80
84
 
81
- it 'should return the rest of the input' do
85
+ it 'returns the rest of the input' do
82
86
  @ret[1].should == "Rest with\nAnd Stuff"
83
87
  end
84
88
  end
@@ -88,27 +92,27 @@ describe LedgerRest::Ledger::Parser do
88
92
  @ret = @parser.parse_cleared("Rest with\nAnd Stuff")
89
93
  end
90
94
 
91
- it 'should return false' do
95
+ it 'returns false' do
92
96
  @ret[0].should == false
93
97
  end
94
98
 
95
- it 'should return the rest of the input' do
99
+ it 'returns the rest of the input' do
96
100
  @ret[1].should == "Rest with\nAnd Stuff"
97
101
  end
98
102
  end
99
103
  end
100
104
 
101
- context '#parse_pending' do
105
+ describe '#parse_pending' do
102
106
  context 'given pending transaction input' do
103
107
  before :all do
104
108
  @ret = @parser.parse_pending(" ! Rest with\nAnd Stuff")
105
109
  end
106
110
 
107
- it 'should return true' do
111
+ it 'returns true' do
108
112
  @ret[0].should == true
109
113
  end
110
114
 
111
- it 'should return the rest of the input' do
115
+ it 'returns the rest of the input' do
112
116
  @ret[1].should == "Rest with\nAnd Stuff"
113
117
  end
114
118
  end
@@ -118,22 +122,22 @@ describe LedgerRest::Ledger::Parser do
118
122
  @ret = @parser.parse_pending("Rest with\nAnd Stuff")
119
123
  end
120
124
 
121
- it 'should return false' do
125
+ it 'returns false' do
122
126
  @ret[0].should == false
123
127
  end
124
128
 
125
- it 'should return the rest of the input' do
129
+ it 'returns the rest of the input' do
126
130
  @ret[1].should == "Rest with\nAnd Stuff"
127
131
  end
128
132
  end
129
133
  end
130
134
 
131
- context '#parse_code' do
135
+ describe '#parse_code' do
132
136
  context 'given a transaction with white-spaced code' do
133
137
  subject { @parser.parse_code(" (#123) Rest with\nAnd Stuff") }
134
138
 
135
139
  its(:first) { should == '#123' }
136
- its(:last) { should == "Rest with\nAnd Stuff"}
140
+ its(:last) { should == "Rest with\nAnd Stuff" }
137
141
  end
138
142
 
139
143
  context 'given a transaction with code' do
@@ -146,124 +150,124 @@ describe LedgerRest::Ledger::Parser do
146
150
  context 'given a transaction without code' do
147
151
  subject { @parser.parse_code("Rest with\nAnd Stuff") }
148
152
 
149
- its(:first) { should == nil }
153
+ its(:first) { should be_nil }
150
154
  its(:last) { should == "Rest with\nAnd Stuff" }
151
155
  end
152
156
  end
153
157
 
154
- context '#parse_payee' do
158
+ describe '#parse_payee' do
155
159
  context 'given an unstripped line' do
156
160
  subject { @parser.parse_payee(" Monsieur Le Payee\n Some:Account 123EUR\n Some:Other")}
157
161
 
158
- its(:first) { should == "Monsieur Le Payee" }
159
- its(:last) { should == " Some:Account 123EUR\n Some:Other"}
162
+ its(:first) { should == 'Monsieur Le Payee' }
163
+ its(:last) { should == " Some:Account 123EUR\n Some:Other" }
160
164
  end
161
165
 
162
166
  context 'given a stripped line' do
163
167
  context 'given an unstripped line' do
164
168
  subject { @parser.parse_payee("Monsieur Le Payee\n Some:Account 123EUR\n Some:Other")}
165
169
 
166
- its(:first) { should == "Monsieur Le Payee" }
167
- its(:last) { should == " Some:Account 123EUR\n Some:Other"}
170
+ its(:first) { should == 'Monsieur Le Payee' }
171
+ its(:last) { should == " Some:Account 123EUR\n Some:Other" }
168
172
  end
169
173
  end
170
174
  end
171
175
 
172
- context '#parse_comments' do
176
+ describe '#parse_comments' do
173
177
  context 'given no comments' do
174
- subject { @parser.parse_comments(" Assets:Some:Stuff 23EUR")}
178
+ subject { @parser.parse_comments(' Assets:Some:Stuff 23EUR')}
175
179
 
176
- it 'should return all comments' do
177
- subject[0].should == nil
180
+ it 'returns all comments' do
181
+ subject[0].should be_nil
178
182
  end
179
183
 
180
- it 'should return the rest of the input' do
181
- subject[1].should == " Assets:Some:Stuff 23EUR"
184
+ it 'returns the rest of the input' do
185
+ subject[1].should == ' Assets:Some:Stuff 23EUR'
182
186
  end
183
187
  end
184
188
 
185
189
  context 'given one line of transaction comments' do
186
190
  subject { @parser.parse_comments(" ; ABC\n Assets:Some:Stuff 23EUR")}
187
191
 
188
- it 'should return all comments' do
192
+ it 'returns all comments' do
189
193
  subject[0].should == "ABC\n"
190
194
  end
191
195
 
192
- it 'should return the rest of the input' do
193
- subject[1].should == " Assets:Some:Stuff 23EUR"
196
+ it 'returns the rest of the input' do
197
+ subject[1].should == ' Assets:Some:Stuff 23EUR'
194
198
  end
195
199
  end
196
200
 
197
201
  context 'given multiple lines of transaction comments' do
198
202
  subject { @parser.parse_comments(" ; ABC\n ;DEF\n Assets:Some:Stuff 23EUR")}
199
203
 
200
- it 'should return all comments' do
204
+ it 'returns all comments' do
201
205
  subject[0].should == "ABC\nDEF\n"
202
206
  end
203
207
 
204
- it 'should return the rest of the input' do
205
- subject[1].should == " Assets:Some:Stuff 23EUR"
208
+ it 'returns the rest of the input' do
209
+ subject[1].should == ' Assets:Some:Stuff 23EUR'
206
210
  end
207
211
  end
208
212
  end
209
213
 
210
- context '#parse_account' do
214
+ describe '#parse_account' do
211
215
  context 'given normal' do
212
216
  subject { @parser.parse_account(" Assets:Some:Nice 200EUR\n Assets:Account")}
213
217
 
214
- it 'should return the account' do
215
- subject[0].should == "Assets:Some:Nice"
218
+ it 'returns the account' do
219
+ subject[0].should == 'Assets:Some:Nice'
216
220
  end
217
221
 
218
- it 'should not be virtual' do
222
+ it 'is not virtual' do
219
223
  subject[1].should == false
220
224
  end
221
225
 
222
- it 'should not be balanced virtual' do
226
+ it 'is not balanced virtual' do
223
227
  subject[2].should == false
224
228
  end
225
229
 
226
- it 'should return the rest of the input' do
230
+ it 'returns the rest of the input' do
227
231
  subject[3].should == "200EUR\n Assets:Account"
228
232
  end
229
233
  end
230
234
 
231
235
  context 'given input without amount' do
232
- subject { @parser.parse_account(" Assets:Some:Nice")}
236
+ subject { @parser.parse_account(' Assets:Some:Nice') }
233
237
 
234
- it 'should return the account' do
235
- subject[0].should == "Assets:Some:Nice"
238
+ it 'returns the account' do
239
+ subject[0].should == 'Assets:Some:Nice'
236
240
  end
237
241
 
238
- it 'should not be virtual' do
242
+ it 'is not virtual' do
239
243
  subject[1].should == false
240
244
  end
241
245
 
242
- it 'should not be balanced virtual' do
246
+ it 'is not balanced virtual' do
243
247
  subject[2].should == false
244
248
  end
245
249
 
246
- it 'should return the rest of the input' do
247
- subject[3].should == ""
250
+ it 'returns the rest of the input' do
251
+ subject[3].should == ''
248
252
  end
249
253
  end
250
254
 
251
255
  context 'given virtual' do
252
256
  subject { @parser.parse_account(" (Assets:Some:Nice) 200EUR\n Assets:Account")}
253
257
 
254
- it 'should return the account' do
255
- subject[0].should == "Assets:Some:Nice"
258
+ it 'returns the account' do
259
+ subject[0].should == 'Assets:Some:Nice'
256
260
  end
257
261
 
258
- it 'should not be virtual' do
262
+ it 'is not virtual' do
259
263
  subject[1].should == true
260
264
  end
261
265
 
262
- it 'should not be balanced virtual' do
266
+ it 'is not balanced virtual' do
263
267
  subject[2].should == false
264
268
  end
265
269
 
266
- it 'should return the rest of the input' do
270
+ it 'returns the rest of the input' do
267
271
  subject[3].should == "200EUR\n Assets:Account"
268
272
  end
269
273
  end
@@ -271,92 +275,155 @@ describe LedgerRest::Ledger::Parser do
271
275
  context 'given balanced virtual' do
272
276
  subject { @parser.parse_account(" [Assets:Some:Nice] 200EUR\n Assets:Account")}
273
277
 
274
- it 'should return the account' do
275
- subject[0].should == "Assets:Some:Nice"
278
+ it 'returns the account' do
279
+ subject[0].should == 'Assets:Some:Nice'
276
280
  end
277
281
 
278
- it 'should not be virtual' do
282
+ it 'is not virtual' do
279
283
  subject[1].should == true
280
284
  end
281
285
 
282
- it 'should not be balanced virtual' do
286
+ it 'is not balanced virtual' do
283
287
  subject[2].should == true
284
288
  end
285
289
 
286
- it 'should return the rest of the input' do
290
+ it 'returns the rest of the input' do
287
291
  subject[3].should == "200EUR\n Assets:Account"
288
292
  end
289
293
  end
290
294
  end
291
295
 
292
- context '#parse_amount' do
296
+ describe '#parse_amount_parts' do
297
+ context 'given "23.00EUR"' do
298
+ subject { @parser.parse_amount_parts('23.00EUR') }
299
+
300
+ it 'returns the value' do
301
+ subject[0].should == 23.0
302
+ end
303
+
304
+ it 'returns the commodity' do
305
+ subject[1].should == 'EUR'
306
+ end
307
+ end
308
+
309
+ context 'given "23EUR"' do
310
+ subject { @parser.parse_amount_parts('23EUR') }
311
+
312
+ it 'returns the value' do
313
+ subject[0].should == 23.0
314
+ end
315
+
316
+ it 'returns the commodity' do
317
+ subject[1].should == 'EUR'
318
+ end
319
+ end
320
+
321
+ context 'given "USD23"' do
322
+ subject { @parser.parse_amount_parts('USD23') }
323
+
324
+ it 'returns the value' do
325
+ subject[0].should == 23.0
326
+ end
327
+
328
+ it 'returns the commodity' do
329
+ subject[1].should == 'USD'
330
+ end
331
+ end
332
+
333
+ context 'given "USD23.00"' do
334
+ subject { @parser.parse_amount_parts('USD23') }
335
+
336
+ it 'returns the value' do
337
+ subject[0].should == 23.0
338
+ end
339
+
340
+ it 'returns the commodity' do
341
+ subject[1].should == 'USD'
342
+ end
343
+ end
344
+
345
+ context 'given "€ 23.00"' do
346
+ subject { @parser.parse_amount_parts('€ 23.00') }
347
+
348
+ it 'returns the value' do
349
+ subject[0].should == 23.0
350
+ end
351
+
352
+ it 'returns the commodity' do
353
+ subject[1].should == '€'
354
+ end
355
+ end
356
+ end
357
+
358
+ describe '#parse_amount' do
293
359
  context 'given "23.00EUR"' do
294
- subject { @parser.parse_amount("23.00EUR") }
360
+ subject { @parser.parse_amount('23.00EUR') }
295
361
 
296
- it 'should return amount and commodity' do
297
- subject[0].should == "23.00EUR"
362
+ it 'returns amount and commodity' do
363
+ subject[0].should == '23.00EUR'
298
364
  end
299
365
 
300
- it 'should return no posting_cost' do
301
- subject[1].should == nil
366
+ it 'returns no posting_cost' do
367
+ subject[1].should be_nil
302
368
  end
303
369
 
304
- it 'should return no per_unit_cost' do
305
- subject[2].should == nil
370
+ it 'returns no per_unit_cost' do
371
+ subject[2].should be_nil
306
372
  end
307
373
  end
308
374
 
309
375
  context 'given "25 AAPL @ 10.00EUR"' do
310
- subject { @parser.parse_amount("25 AAPL @ 10.00EUR") }
376
+ subject { @parser.parse_amount('25 AAPL @ 10.00EUR') }
311
377
 
312
- it 'should return amount and commodity' do
313
- subject[0].should == "25 AAPL"
378
+ it 'returns amount and commodity' do
379
+ subject[0].should == '25 AAPL'
314
380
  end
315
381
 
316
- it 'should return correct posting_cost' do
317
- subject[1].should == "10.00EUR"
382
+ it 'returns correct posting_cost' do
383
+ subject[1].should == '10.00EUR'
318
384
  end
319
385
 
320
- it 'should return no per_unit_cost' do
321
- subject[2].should == nil
386
+ it 'returns no per_unit_cost' do
387
+ subject[2].should be_nil
322
388
  end
323
389
  end
324
390
 
325
391
  context 'given "30Liters @@ 1.64EUR"' do
326
- subject { @parser.parse_amount("30Liters @@ 1.64EUR") }
392
+ subject { @parser.parse_amount('30Liters @@ 1.64EUR') }
327
393
 
328
- it 'should return amount and commodity' do
329
- subject[0].should == "30Liters"
394
+ it 'returns amount and commodity' do
395
+ subject[0].should == '30Liters'
330
396
  end
331
397
 
332
- it 'should return no posting_cost' do
333
- subject[1].should == nil
398
+ it 'returns no posting_cost' do
399
+ subject[1].should be_nil
334
400
  end
335
401
 
336
- it 'should return correct per_unit_cost' do
337
- subject[2].should == "1.64EUR"
402
+ it 'returns correct per_unit_cost' do
403
+ subject[2].should == '1.64EUR'
338
404
  end
339
405
  end
340
406
  end
341
407
 
342
- context '#parse_posting' do
408
+ describe '#parse_posting' do
343
409
  context 'given posting with comment' do
344
410
  subject { @parser.parse_posting(" Assets:Test:Account 123EUR\n ; Some comment") }
345
411
 
346
- it 'should have parsed correctly' do
412
+ it 'has parsed correctly' do
347
413
  subject.should == {
348
- :account => "Assets:Test:Account",
349
- :amount => "123EUR"
414
+ account: 'Assets:Test:Account',
415
+ amount: 123.0,
416
+ commodity: 'EUR'
350
417
  }
351
418
  end
352
419
  end
353
420
 
354
421
  context 'given source posting' do
355
- subject { @parser.parse_posting(" Assets:Test:Account") }
422
+ subject { @parser.parse_posting(' Assets:Test:Account') }
356
423
 
357
- it 'should have parsed correctly' do
424
+ it 'has parsed correctly' do
358
425
  subject.should == {
359
- :account => "Assets:Test:Account"
426
+ account: 'Assets:Test:Account'
360
427
  }
361
428
  end
362
429
  end