Class: LedgerRest::Ledger::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/ledger-rest/ledger/parser.rb

Overview

A very simple parser for single legder format transactions. There has to be a better way … This does not implement the whole ledger format. Tragically … someone told me it´s the essence of evil to do parser duplication. We need to use the ledger parser. Maybe we can use the ledger code base and integrate it into a ruby gem … I don´t know.

This works for ‘ledger entry` with my transactions …

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



20
21
22
# File 'lib/ledger-rest/ledger/parser.rb', line 20

def initialize
  @transaction = Transaction.new
end

Class Method Details

.parse(str) ⇒ Object



14
15
16
17
# File 'lib/ledger-rest/ledger/parser.rb', line 14

def parse(str)
  parser = Parser.new
  parser.parse(str)
end

Instance Method Details

#parse(str) ⇒ Object

Begins to parse a whole



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ledger-rest/ledger/parser.rb', line 25

def parse(str)
  @str = str
  @transaction[:postings] = []

  @transaction[:date], str = parse_date(str)

  effective_date, str = parse_effective_date(str)
  @transaction[:effective_date] = effective_date if effective_date

  @transaction[:cleared], str = parse_cleared(str)
  @transaction[:pending], str = parse_pending(str)

  code, str = parse_code(str)
  @transaction[:code] = code if code

  @transaction[:payee], str = parse_payee(str)

  comments, str = parse_comments(str)
  @transaction[:comments] = comments if comments

  str.split("\n").each do |line|
    posting = parse_posting(line)
    @transaction[:postings] << posting
  end

  @transaction
rescue Exception => e
  puts e
  puts "In: \n#{@str}"
end

#parse_account(str) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/ledger-rest/ledger/parser.rb', line 135

def (str)
  return [] if str.nil? || str.empty?
  if match = str.match(/\A +([\w:]+)(\n|$|  )(.*)/m)
    [match[1], false, false , match[3]]
  elsif match = str.match(/\A +\(([\w:]+)\)(\n|$|  )(.*)/m)
    [match[1], true, false , match[3]]
  elsif match = str.match(/\A +\[([\w:]+)\](\n|$|  )(.*)/m)
    [match[1], true, true , match[3]]
  else
    [nil, false, false, str]
  end
end

#parse_amount(str) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/ledger-rest/ledger/parser.rb', line 148

def parse_amount(str)
  if match = str.match(/\A(.*?)@@([^;]*?)(;(.*)|\n(.*)|$(.*))/m)
    amount = match[1].strip
    [amount.empty? ? nil : amount, nil, match[2].strip, match[3]]
  elsif match = str.match(/\A(.*?)@([^;]*)(;(.*)|\n(.*)|$(.*))/m)
    amount = match[1].strip
    [amount.empty? ? nil : amount, match[2].strip, nil, match[3]]
  elsif match = str.match(/\A([^;]*?)(;(.*)|\n(.*)|$(.*))/m)
    amount = match[1].strip
    [amount.empty? ? nil : amount, nil, nil, match[2]]
  end
end

#parse_amount_parts(str) ⇒ Object



161
162
163
164
165
166
167
# File 'lib/ledger-rest/ledger/parser.rb', line 161

def parse_amount_parts(str)
  if match = str.match(/^(.*?)(-?\d+(\.\d+)?)(.*?)$/)
    [match[2].to_f, match[1].strip + match[4].strip]
  else
    [str, nil]
  end
end

#parse_cleared(str) ⇒ Object



80
81
82
83
84
85
86
# File 'lib/ledger-rest/ledger/parser.rb', line 80

def parse_cleared(str)
  if match = str.match(/\A \* (.*)/m)
    [true, match[1]]
  else
    [false, str]
  end
end

#parse_code(str) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/ledger-rest/ledger/parser.rb', line 88

def parse_code(str)
  if match = str.match(/\A *?\(([^\(\)]+)\) (.*)/m)
    [match[1], match[2]]
  else
    [nil, str]
  end
end

#parse_comments(str) ⇒ Object



104
105
106
107
108
109
110
111
# File 'lib/ledger-rest/ledger/parser.rb', line 104

def parse_comments(str)
  comments = ''
  while str && match = str.match(/\A +;(.*?)(\n|$)(.*)/m)
    comments << match[1].strip << "\n"
    str = match[3]
  end
  [comments.empty? ? nil : comments, str]
end

#parse_date(str) ⇒ Object



56
57
58
59
60
61
62
# File 'lib/ledger-rest/ledger/parser.rb', line 56

def parse_date(str)
  if match = str.match(%r{\A(\d{4}/\d{1,2}/\d{1,2})(.*)}m)
    [match[1], match[2]]
  else
    fail 'Date was expected.'
  end
end

#parse_effective_date(str) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/ledger-rest/ledger/parser.rb', line 64

def parse_effective_date(str)
  if match = str.match(%r{\A=(\d{4}/\d{1,2}/\d{1,2})(.*)}m)
    [match[1], match[2]]
  else
    [nil, str]
  end
end

#parse_payee(str) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/ledger-rest/ledger/parser.rb', line 96

def parse_payee(str)
  if match = str.match(/\A *?([^ ][^\n]+)\n(.*)/m)
    [match[1], match[2]]
  else
    fail 'No payee given.'
  end
end

#parse_pending(str) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/ledger-rest/ledger/parser.rb', line 72

def parse_pending(str)
  if match = str.match(/\A ! (.*)/m)
    [true, match[1]]
  else
    [false, str]
  end
end

#parse_posting(str) ⇒ Object

parses a ledger posting line



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/ledger-rest/ledger/parser.rb', line 114

def parse_posting(str)
  posting = {}

  , virtual, balanced, str = (str)
  posting[:account] =  if 
  posting[:virtual] = virtual if virtual
  posting[:balanced] = balanced if balanced

  amount, posting_cost, per_unit_cost, str = parse_amount(str)
  posting[:amount], posting[:commodity] = parse_amount_parts(amount) if amount
  posting[:posting_cost], posting[:posting_cost_commodity] = parse_amount_parts(posting_cost) if posting_cost
  posting[:per_unit_cost], posting[:per_unit_commodity] = parse_amount_parts(per_unit_cost) if per_unit_cost

  comment, actual_date, effective_date = parse_posting_comment(str)
  posting[:comment] = comment if comment
  posting[:actual_date] = actual_date if actual_date
  posting[:effective_date] = effective_date if effective_date

  posting
end

#parse_posting_comment(str) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ledger-rest/ledger/parser.rb', line 169

def parse_posting_comment(str)
  comment, actual_date, effective_date = nil, nil, nil

  if match = str.match(/\A *?; \[(.*)\]/)
    actual_date, effective_date = match[1].split('=')
  elsif match = str.match(/\A *?; (.*)/)
    comment = match[1]
  end

  [comment, actual_date, effective_date]
end