ledger-rest 2.0.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,23 +1,29 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module LedgerRest
2
3
  class Ledger
3
4
  class Balance
4
-
5
5
  FORMAT = [
6
6
  '{',
7
- ' "total": %(quoted(display_total)),',
8
- ' "name": %(quoted(partial_account)),',
9
- ' "depth": %(depth), "fullname": %(quoted(account))',
7
+ '"total":%(quoted(display_total)),',
8
+ '"name":%(quoted(partial_account)),',
9
+ '"depth":%(depth), "fullname": %(quoted(account))',
10
10
  '},%/',
11
- '{ "total": %(quoted(display_total)) }'
12
- ].join('\\n')
11
+ '{"total":%(quoted(display_total))}'
12
+ ].join
13
13
 
14
14
  class << self
15
+ def get(query = nil, params = {})
16
+ data = JSON.parse(json(query, params), symbolize_names: true)
17
+
18
+ data[:accounts] = expand_accounts(data[:accounts])
19
+ unless query =~ /--flat/
20
+ data[:accounts] = wrap_accounts(data[:accounts])
21
+ end
15
22
 
16
- def get query = nil, params = {}
17
- JSON.parse(json(query, params), :symbolize_names => true)
23
+ data
18
24
  end
19
25
 
20
- def json query = nil, params = {}
26
+ def json(query = nil, params = {})
21
27
  params = { '--format' => FORMAT }.merge(params)
22
28
  result = Ledger.exec("bal #{query}", params)
23
29
 
@@ -25,19 +31,46 @@ module LedgerRest
25
31
  if result.end_with?(',')
26
32
  result = result[0..-2]
27
33
  else
28
- match_total = result.match(/,\n.*?{ +"total": +("[0-9\.A-Za-z ]+") +}\z/)
34
+ match_total = result.match(/,{"total":("[0-9\.A-Za-z ]+")}\z/)
29
35
  if match_total
30
36
  total = match_total[1]
31
- result = result[0,match_total.offset(0)[0]]
37
+ result = result[0, match_total.offset(0)[0]]
32
38
  end
33
39
  end
34
40
 
35
- json_str = "{"
36
- json_str << " \"accounts\": [ #{result} ]"
37
- json_str << ", \"total\": #{total}" if total
38
- json_str << " }"
41
+ json_str = '{'
42
+ json_str << "\"accounts\":[#{result}]"
43
+ json_str << ",\"total\":#{total}" if total
44
+ json_str << '}'
45
+ end
46
+
47
+ def expand_accounts(accounts)
48
+ accounts.inject([]) do |acc, elem|
49
+ fullname = elem[:fullname].gsub(/:?#{elem[:name]}/, '')
50
+ acc + elem[:name].split(':').map do |name|
51
+ fullname << "#{':' unless fullname.empty?}#{name}"
52
+ parent = elem.dup
53
+ parent[:fullname], parent[:name], parent[:depth] =
54
+ fullname.dup, name.dup, fullname.count(':')+1
55
+ parent
56
+ end
57
+ end
39
58
  end
40
59
 
60
+ def wrap_accounts(accounts)
61
+ stack = []
62
+ accounts.inject([]) do |acc, elem|
63
+ stack.pop while stack.last && stack.last[:depth] >= elem[:depth]
64
+ if stack.empty?
65
+ stack << elem
66
+ acc << elem
67
+ else
68
+ (stack.last[:accounts] ||= []) << elem
69
+ stack << elem
70
+ end
71
+ acc
72
+ end
73
+ end
41
74
  end
42
75
  end
43
76
  end
@@ -1,33 +1,52 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module LedgerRest
2
3
  class Ledger
3
4
  class Budget
4
5
  FORMAT = [
5
- '{',
6
- ' "name": %(quoted(account)),',
7
- ' "amount": %(quoted(get_at(T, 0))),',
8
- ' "budget": %(quoted(-get_at(T, 1)))',
9
- ' },%/',
10
- ' ],',
11
- ' "total_amount": %(quoted(get_at(T, 0))),',
12
- ' "total_budget": %(quoted(-get_at(T, 1)))'
13
- ].join('\\n')
6
+ '%(scrub(get_at(display_total, 0)))\n',
7
+ '%(-scrub(get_at(display_total, 1)))\n',
8
+ '%(scrub(get_at(display_total, 1) + get_at(display_total, 0)))\n',
9
+ '%(get_at(display_total, 1) ? (100% * scrub(get_at(display_total, 0))) / -scrub(get_at(display_total, 1)) : 0)\n',
10
+ '%(account)\n',
11
+ '---\n',
12
+ '%/---\n',
13
+ '%$1\n',
14
+ '%$2\n',
15
+ '%$3\n',
16
+ '%$4\n',
17
+ '%/'
18
+ ].join
14
19
 
15
20
  class << self
16
-
17
21
  def get(query = nil, params = {})
18
- JSON.parse(json(query, params), :symbolize_names => true)
22
+ JSON.parse(json(query, params), symbolize_names: true)
19
23
  end
20
24
 
21
25
  def json(query = nil, params = {})
22
26
  params = { '--format' => FORMAT }.merge(params)
23
27
  result = Ledger.exec("budget #{query}", params)
24
- result.gsub!(/\},\n *?\]/, "}\n ]")
25
-
26
- "{\n \"budget\": {\n \"accounts\": [\n #{result}\n }\n}"
28
+ budget = {}
29
+ accounts, total = result.split("---\n---\n")
30
+ budget['accounts'] = accounts.split("---\n").map do |str|
31
+ val = str.split("\n")
32
+ {
33
+ 'total' => val[0].empty? ? '0' : val[0],
34
+ 'budget' => val[1].empty? ? '0' : val[1],
35
+ 'difference' => val[2].empty? ? '0' : val[2],
36
+ 'percentage' => val[3].empty? ? '0' : val[3],
37
+ 'account' => val[4].empty? ? '0' : val[4]
38
+ }
39
+ end
40
+ if total
41
+ val = total.split("\n")
42
+ budget['total'] = val[0].empty? ? '0' : val[0]
43
+ budget['budget'] = val[1].empty? ? '0' : val[1]
44
+ budget['difference'] = val[2].empty? ? '0' : val[2]
45
+ budget['percentage'] = val[3].empty? ? '0' : val[3]
46
+ end
47
+ budget.to_json
27
48
  end
28
-
29
49
  end
30
-
31
50
  end
32
51
  end
33
52
  end
@@ -1,13 +1,11 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module LedgerRest
2
3
  class Ledger
3
-
4
4
  # Ledger offers a simple command to create a new entry based on
5
5
  # previous entries in your ledger files. This class abstracts
6
6
  # mentioned functionality for easy integration into ledger-rest.
7
7
  class Entry
8
-
9
8
  class << self
10
-
11
9
  # Return a new transaction object based on previous transactions.
12
10
  def get(desc, options = {})
13
11
  result = Ledger.exec("entry #{desc}", options)
@@ -20,7 +18,6 @@ module LedgerRest
20
18
  transaction.append_to(Ledger.append_file)
21
19
  transaction
22
20
  end
23
-
24
21
  end
25
22
  end
26
23
  end
@@ -1,7 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  module LedgerRest
3
3
  class Ledger
4
-
5
4
  # A very simple parser for single legder format transactions.
6
5
  # There has to be a better way ... This does not implement the
7
6
  # whole ledger format. Tragically ... someone told me it´s the
@@ -11,14 +10,11 @@ module LedgerRest
11
10
  #
12
11
  # This works for `ledger entry` with my transactions ...
13
12
  class Parser
14
-
15
13
  class << self
16
-
17
14
  def parse(str)
18
15
  parser = Parser.new
19
16
  parser.parse(str)
20
17
  end
21
-
22
18
  end
23
19
 
24
20
  def initialize
@@ -30,20 +26,20 @@ module LedgerRest
30
26
  @str = str
31
27
  @transaction[:postings] = []
32
28
 
33
- @transaction[:date],str = parse_date(str)
29
+ @transaction[:date], str = parse_date(str)
34
30
 
35
31
  effective_date, str = parse_effective_date(str)
36
32
  @transaction[:effective_date] = effective_date if effective_date
37
33
 
38
- @transaction[:cleared],str = parse_cleared(str)
39
- @transaction[:pending],str = parse_pending(str)
34
+ @transaction[:cleared], str = parse_cleared(str)
35
+ @transaction[:pending], str = parse_pending(str)
40
36
 
41
37
  code, str = parse_code(str)
42
38
  @transaction[:code] = code if code
43
39
 
44
- @transaction[:payee],str = parse_payee(str)
40
+ @transaction[:payee], str = parse_payee(str)
45
41
 
46
- comments,str = parse_comments(str)
42
+ comments, str = parse_comments(str)
47
43
  @transaction[:comments] = comments if comments
48
44
 
49
45
  str.split("\n").each do |line|
@@ -58,60 +54,60 @@ module LedgerRest
58
54
  end
59
55
 
60
56
  def parse_date(str)
61
- if match = str.match(/\A(\d{4}\/\d{1,2}\/\d{1,2})(.*)/m)
62
- [ match[1], match[2] ]
57
+ if match = str.match(%r{\A(\d{4}/\d{1,2}/\d{1,2})(.*)}m)
58
+ [match[1], match[2]]
63
59
  else
64
- raise "Date was expected."
60
+ fail 'Date was expected.'
65
61
  end
66
62
  end
67
63
 
68
64
  def parse_effective_date(str)
69
- if match = str.match(/\A=(\d{4}\/\d{1,2}\/\d{1,2})(.*)/m)
70
- [ match[1], match[2] ]
65
+ if match = str.match(%r{\A=(\d{4}/\d{1,2}/\d{1,2})(.*)}m)
66
+ [match[1], match[2]]
71
67
  else
72
- [ nil, str ]
68
+ [nil, str]
73
69
  end
74
70
  end
75
71
 
76
72
  def parse_pending(str)
77
73
  if match = str.match(/\A ! (.*)/m)
78
- [ true, match[1] ]
74
+ [true, match[1]]
79
75
  else
80
- [ false, str]
76
+ [false, str]
81
77
  end
82
78
  end
83
79
 
84
80
  def parse_cleared(str)
85
81
  if match = str.match(/\A \* (.*)/m)
86
- [ true, match[1] ]
82
+ [true, match[1]]
87
83
  else
88
- [ false, str]
84
+ [false, str]
89
85
  end
90
86
  end
91
87
 
92
88
  def parse_code(str)
93
89
  if match = str.match(/\A *?\(([^\(\)]+)\) (.*)/m)
94
- [ match[1], match[2] ]
90
+ [match[1], match[2]]
95
91
  else
96
- [ nil, str ]
92
+ [nil, str]
97
93
  end
98
94
  end
99
95
 
100
96
  def parse_payee(str)
101
97
  if match = str.match(/\A *?([^ ][^\n]+)\n(.*)/m)
102
- [ match[1], match[2] ]
98
+ [match[1], match[2]]
103
99
  else
104
- raise "No payee given."
100
+ fail 'No payee given.'
105
101
  end
106
102
  end
107
103
 
108
104
  def parse_comments(str)
109
- comments = ""
105
+ comments = ''
110
106
  while str && match = str.match(/\A +;(.*?)(\n|$)(.*)/m)
111
107
  comments << match[1].strip << "\n"
112
108
  str = match[3]
113
109
  end
114
- [ comments.empty? ? nil : comments, str ]
110
+ [comments.empty? ? nil : comments, str]
115
111
  end
116
112
 
117
113
  # parses a ledger posting line
@@ -124,9 +120,9 @@ module LedgerRest
124
120
  posting[:balanced] = balanced if balanced
125
121
 
126
122
  amount, posting_cost, per_unit_cost, str = parse_amount(str)
127
- posting[:amount] = amount if amount
128
- posting[:posting_cost] = posting_cost if posting_cost
129
- posting[:per_unit_cost] = per_unit_cost if per_unit_cost
123
+ posting[:amount], posting[:commodity] = parse_amount_parts(amount) if amount
124
+ posting[:posting_cost], posting[:posting_cost_commodity] = parse_amount_parts(posting_cost) if posting_cost
125
+ posting[:per_unit_cost], posting[:per_unit_commodity] = parse_amount_parts(per_unit_cost) if per_unit_cost
130
126
 
131
127
  comment, actual_date, effective_date = parse_posting_comment(str)
132
128
  posting[:comment] = comment if comment
@@ -137,28 +133,36 @@ module LedgerRest
137
133
  end
138
134
 
139
135
  def parse_account(str)
140
- return [] if str.nil? or str.empty?
136
+ return [] if str.nil? || str.empty?
141
137
  if match = str.match(/\A +([\w:]+)(\n|$| )(.*)/m)
142
- [ match[1], false, false , match[3] ]
138
+ [match[1], false, false , match[3]]
143
139
  elsif match = str.match(/\A +\(([\w:]+)\)(\n|$| )(.*)/m)
144
- [ match[1], true, false , match[3] ]
140
+ [match[1], true, false , match[3]]
145
141
  elsif match = str.match(/\A +\[([\w:]+)\](\n|$| )(.*)/m)
146
- [ match[1], true, true , match[3] ]
142
+ [match[1], true, true , match[3]]
147
143
  else
148
- [ nil, false, false, str ]
144
+ [nil, false, false, str]
149
145
  end
150
146
  end
151
147
 
152
148
  def parse_amount(str)
153
149
  if match = str.match(/\A(.*?)@@([^;]*?)(;(.*)|\n(.*)|$(.*))/m)
154
150
  amount = match[1].strip
155
- [ amount.empty? ? nil : amount, nil, match[2].strip, match[3] ]
151
+ [amount.empty? ? nil : amount, nil, match[2].strip, match[3]]
156
152
  elsif match = str.match(/\A(.*?)@([^;]*)(;(.*)|\n(.*)|$(.*))/m)
157
153
  amount = match[1].strip
158
- [ amount.empty? ? nil : amount, match[2].strip, nil, match[3] ]
154
+ [amount.empty? ? nil : amount, match[2].strip, nil, match[3]]
159
155
  elsif match = str.match(/\A([^;]*?)(;(.*)|\n(.*)|$(.*))/m)
160
156
  amount = match[1].strip
161
- [ amount.empty? ? nil : amount, nil, nil, match[2] ]
157
+ [amount.empty? ? nil : amount, nil, nil, match[2]]
158
+ end
159
+ end
160
+
161
+ def parse_amount_parts(str)
162
+ if match = str.match(/^(.*?)(\d+(\.\d+)?)(.*?)$/)
163
+ [match[2].to_f, match[1].strip + match[4].strip]
164
+ else
165
+ [str, nil]
162
166
  end
163
167
  end
164
168
 
@@ -171,7 +175,7 @@ module LedgerRest
171
175
  comment = match[1]
172
176
  end
173
177
 
174
- [ comment, actual_date, effective_date ]
178
+ [comment, actual_date, effective_date]
175
179
  end
176
180
  end
177
181
  end
@@ -1,38 +1,45 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module LedgerRest
2
3
  class Ledger
3
4
  class Register
4
-
5
- FORMAT = [
6
- "{",
7
- ' "date": %(quoted(date)),',
8
- ' "effective_date": %(effective_date ? quoted(effective_date) : "null"),',
9
- ' "code": %(code ? quoted(code) : "null"),',
10
- ' "cleared": %(cleared ? "true" : "false"),',
11
- ' "pending": %(pending ? "true" : "false"),',
12
- ' "payee": %(quoted(payee)),',
13
- ' "postings":',
14
- ' [',
15
- ' { "account": %(quoted(display_account)), "amount": %(quoted(amount)) },%/',
16
- ' { "account": %(quoted(display_account)), "amount": %(quoted(amount)) },%/',
17
- ' ]',
18
- '},'
19
- ].join('\\n')
20
-
21
5
  class << self
6
+ def format(query)
7
+ format = '{'
8
+ if query =~ /-D|--daily|-W|--weekly|-M|--monthly|--quarterly|-Y|--yearly/
9
+ format << '"beginning": %(quoted(format_date(date))),'
10
+ format << '"end": %(quoted(payee)),'
11
+ elsif query =~ /--by-payee/
12
+ format << '"payee": %(quoted(payee)),'
13
+ else
14
+ format << '"date": %(quoted(format_date(date))),'
15
+ format << '"effective_date": %(effective_date ? quoted(format_date(effective_date)) : "null"),'
16
+ format << '"code": %(code ? quoted(code) : "null"),'
17
+ format << '"cleared": %(cleared ? "true" : "false"),'
18
+ format << '"pending": %(pending ? "true" : "false"),'
19
+ format << '"payee": %(quoted(payee)),'
20
+ end
21
+ format << '"postings": ['
22
+ format << '{ "account": %(quoted(display_account)), "amount": %(quoted(quantity(scrub(display_amount)))), "total": %(quoted(quantity(scrub(display_amount)))), "commodity": %(quoted(commodity)) },%/'
23
+ format << '{ "account": %(quoted(display_account)), "amount": %(quoted(quantity(scrub(display_amount)))), "total": %(quoted(quantity(scrub(display_amount)))), "commodity": %(quoted(commodity)) },%/'
24
+ format << ']},'
25
+ format
26
+ end
22
27
 
23
28
  def get(query = nil, params = {})
24
- JSON.parse(json(query, params), :symbolize_names => true)
29
+ JSON.parse(json(query, params), symbolize_names: true)
25
30
  end
26
31
 
27
32
  def json(query = nil, params = {})
28
- params = { '--format' => FORMAT }.merge(params)
33
+ params = {
34
+ '--format' => format(query),
35
+ '--date-format' => '%Y/%m/%d'
36
+ }.merge(params)
29
37
  result = Ledger.exec("reg #{query}", params)
30
- result << "\n]\n}"
31
- result.gsub! /\},\n *?\]/m, "}\n \]"
32
-
33
- "{\"transactions\":[#{result}]}"
38
+ result << "]}"
39
+ result.gsub! '"end": "- ', '"end": "'
40
+ result.gsub! /\},\n? *?\]/m, "}]"
41
+ "[#{result}]"
34
42
  end
35
-
36
43
  end
37
44
  end
38
45
  end
@@ -2,14 +2,11 @@
2
2
  module LedgerRest
3
3
  class Ledger
4
4
  class Transaction < Hash
5
-
6
5
  class << self
7
-
8
6
  # Parse a ledger transaction string into a `Transaction` object.
9
7
  def parse(str)
10
8
  LedgerRest::Ledger::Parser.parse(str)
11
9
  end
12
-
13
10
  end
14
11
 
15
12
  def initialize(params = {})
@@ -18,31 +15,39 @@ module LedgerRest
18
15
 
19
16
  # Return true if the `Transaction#to_ledger` is a valid ledger string.
20
17
  def valid?
21
- result = IO.popen("#{settings.ledger_bin} -f - stats 2>&1", "r+") do |f|
22
- f.write self.to_ledger
18
+ result = IO.popen("#{Ledger.bin} -f - stats 2>&1", 'r+') do |f|
19
+ f.write to_ledger
23
20
  f.close_write
24
21
  f.readlines
25
22
  end
26
23
 
27
- $?.success? and not result.empty?
24
+ $?.success? && !result.empty?
25
+ end
26
+
27
+ def check
28
+ IO.popen("#{Ledger.bin} -f - stats 2>&1", 'r+') do |f|
29
+ f.write to_ledger
30
+ f.close_write
31
+ f.readlines
32
+ end
28
33
  end
29
34
 
30
35
  def to_ledger
31
- if self[:date].nil? or
32
- self[:payee].nil? or
33
- self[:postings].nil?
36
+ if self[:date].nil? || self[:payee].nil? || self[:postings].nil?
34
37
  return nil
35
38
  end
36
39
 
37
- result = ""
40
+ result = ''
38
41
 
39
42
  result << self[:date]
40
- result << "=#{self[:effective_date]}" if self[:effective_date]
43
+ if self[:effective_date]
44
+ result << "=#{self[:effective_date]}"
45
+ end
41
46
 
42
47
  if self[:cleared]
43
- result << " *"
48
+ result << ' *'
44
49
  elsif self[:pending]
45
- result << " !"
50
+ result << ' !'
46
51
  end
47
52
 
48
53
  result << " (#{self[:code]})" if self[:code]
@@ -51,7 +56,7 @@ module LedgerRest
51
56
 
52
57
  self[:postings].each do |posting|
53
58
  if posting[:comment]
54
- result << " ; #{posting[:comment]}\n"
59
+ result << " ; #{posting[:comment]}\n"
55
60
  next
56
61
  end
57
62
 
@@ -59,12 +64,12 @@ module LedgerRest
59
64
 
60
65
  if posting[:virtual]
61
66
  if posting[:balance]
62
- result << " [#{posting[:account]}]"
67
+ result << " [#{posting[:account]}]"
63
68
  else
64
- result << " (#{posting[:account]})"
69
+ result << " (#{posting[:account]})"
65
70
  end
66
71
  else
67
- result << " #{posting[:account]}"
72
+ result << " #{posting[:account]}"
68
73
  end
69
74
 
70
75
  if posting[:amount].nil?
@@ -72,26 +77,26 @@ module LedgerRest
72
77
  next
73
78
  end
74
79
 
75
- result << " #{posting[:amount]}"
80
+ result << " #{'%.2f' % posting[:amount]}#{posting[:commodity]}"
76
81
 
77
- if(posting[:per_unit_cost])
78
- result << " @@ #{posting[:per_unit_cost]}"
79
- elsif(posting[:posting_cost])
80
- result << " @ #{posting[:posting_cost]}"
82
+ if posting[:per_unit_cost]
83
+ result << " @@ #{'%.2f' % posting[:per_unit_cost]}#{posting[:per_unit_commodity]}"
84
+ elsif posting[:posting_cost]
85
+ result << " @ #{'%.2f' % posting[:posting_cost]}#{posting[:posting_cost_commodity]}"
81
86
  end
82
87
 
83
- if posting[:actual_date] or posting[:effective_date]
84
- result << " ; ["
88
+ if posting[:actual_date] || posting[:effective_date]
89
+ result << ' ; ['
85
90
  result << posting[:actual_date] if posting[:actual_date]
86
- result << "=#{posting[:effective_date]}" if posting[:effective_date]
87
- result << "]"
91
+ if posting[:effective_date]
92
+ result << "=#{posting[:effective_date]}"
93
+ end
94
+ result << ']'
88
95
  end
89
96
 
90
97
  result << "\n"
91
98
  end
92
99
 
93
- result << "\n"
94
-
95
100
  result
96
101
  end
97
102
  end