sie 2.1.0 → 2.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 +8 -8
- data/README.md +10 -3
- data/lib/sie/document.rb +2 -1
- data/lib/sie/parser.rb +13 -1
- data/lib/sie/parser/build_entry.rb +57 -0
- data/lib/sie/parser/line_parser.rb +5 -25
- data/lib/sie/parser/tokenizer/token.rb +4 -0
- data/lib/sie/version.rb +2 -1
- data/spec/fixtures/sie_file_with_unknown_entries.se +32 -0
- data/spec/integration/parser_spec.rb +34 -2
- data/spec/unit/parser/line_parser_spec.rb +20 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OTRlMWFiNTRkMmRjZDllMmY2MWYzYjFiMWYxZWI1MTNjNDNhODZkYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzliZThiOGNhNjZmODMyNzVkNTJhZWY0NzYzOTRjMGIyMjFkYTM1Zg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ODJiZjc3ZDI5YWFiN2YxZTg0NTEwMTNjYjVjZDI4NjhlYWJhOGM4YzUyZjNi
|
10
|
+
Y2QxMDA2YmI4MjFiMDU3OWFhMjE5NmNjZTM2ZTRjYTdlMzFiOTA5OTcyNmQ4
|
11
|
+
ODdmNDAwYjZmNDRmZmM2NjY4ZDFhYzI0NTEwZDcyYTFkYmVkNzM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MzBlMzIzZTAyMGVkYTE1YWYyM2E4MDQ1NjM0MjMyMmU1Yjg3NGQ5MzBiMjFj
|
14
|
+
ZGJlMDY1MjhhZGJiZTQ4NTRmNzg0OTFkMGNmMjA5MTlmMjdmOGU0N2M1NzMz
|
15
|
+
NjI5ZjFjYzBhMTg5YzFlMTVmMjg1MGM0ZWY5YjQzZDIxODNkN2Q=
|
data/README.md
CHANGED
@@ -124,6 +124,12 @@ File.open("path/to/file.se") do |f|
|
|
124
124
|
end
|
125
125
|
```
|
126
126
|
|
127
|
+
By default the parser will raise an error if it encounters unknown entry types. Use the `lenient` option to avoid this:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
parser = Sie::Parser.new(lenient: true)
|
131
|
+
```
|
132
|
+
|
127
133
|
For more info, see the specs.
|
128
134
|
|
129
135
|
## Developing
|
@@ -144,9 +150,10 @@ Getting the latest code and gems:
|
|
144
150
|
|
145
151
|
1. Fork it
|
146
152
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
147
|
-
3.
|
148
|
-
4.
|
149
|
-
5.
|
153
|
+
3. Try to be consistent with the local code style. `[ foo ]` not `[foo]`, double quotes not single quotes, small and well named methods, etc.
|
154
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
155
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
156
|
+
6. Create new Pull Request
|
150
157
|
|
151
158
|
## Credits and license
|
152
159
|
|
data/lib/sie/document.rb
CHANGED
@@ -5,10 +5,11 @@ require "active_support/core_ext/module/delegation"
|
|
5
5
|
|
6
6
|
module Sie
|
7
7
|
class Document
|
8
|
-
pattr_initialize :data_source
|
9
8
|
# Because fortnox imposes these limits
|
10
9
|
DESCRIPTION_LENGTH_MAX = 30
|
11
10
|
|
11
|
+
pattr_initialize :data_source
|
12
|
+
|
12
13
|
def render
|
13
14
|
add_header
|
14
15
|
add_financial_years
|
data/lib/sie/parser.rb
CHANGED
@@ -9,6 +9,12 @@ module Sie
|
|
9
9
|
END_OF_ARRAY = "}"
|
10
10
|
ENTRY = /^#/
|
11
11
|
|
12
|
+
attr_private :options
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
@options = options
|
16
|
+
end
|
17
|
+
|
12
18
|
def parse(io)
|
13
19
|
stack = []
|
14
20
|
sie_file = SieFile.new
|
@@ -34,7 +40,13 @@ module Sie
|
|
34
40
|
private
|
35
41
|
|
36
42
|
def parse_line(line)
|
37
|
-
LineParser.new(line).parse
|
43
|
+
LineParser.new(line, lenient: lenient).parse
|
44
|
+
rescue BuildEntry::InvalidEntryError => ex
|
45
|
+
raise ex, "#{ex.message}. Pass 'lenient: true' to Parser.new to avoid this exception."
|
46
|
+
end
|
47
|
+
|
48
|
+
def lenient
|
49
|
+
options.fetch(:lenient, false)
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Sie
|
2
|
+
class Parser
|
3
|
+
class BuildEntry
|
4
|
+
method_object :line, :first_token, :tokens, :lenient
|
5
|
+
|
6
|
+
InvalidEntryError = Class.new(StandardError)
|
7
|
+
|
8
|
+
def call
|
9
|
+
if first_token.known_entry_type?
|
10
|
+
build_complete_entry
|
11
|
+
elsif lenient
|
12
|
+
build_empty_entry
|
13
|
+
else
|
14
|
+
raise_invalid_entry_error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_complete_entry
|
21
|
+
entry = build_empty_entry
|
22
|
+
entry_type = first_token.entry_type
|
23
|
+
|
24
|
+
entry_type.each_with_index do |entry_type, i|
|
25
|
+
break if i >= tokens.size
|
26
|
+
|
27
|
+
if entry_type.is_a?(Hash)
|
28
|
+
skip_array(tokens, i)
|
29
|
+
next
|
30
|
+
else
|
31
|
+
label = entry_type
|
32
|
+
entry.attributes[label] = tokens[i].value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
entry
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_empty_entry
|
40
|
+
Entry.new(first_token.label)
|
41
|
+
end
|
42
|
+
|
43
|
+
def raise_invalid_entry_error
|
44
|
+
raise InvalidEntryError, "Unknown entry type: #{first_token.label}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def skip_array(tokens, i)
|
48
|
+
if tokens[i].is_a?(Tokenizer::BeginArrayToken) &&
|
49
|
+
!tokens[i+1].is_a?(Tokenizer::EndArrayToken)
|
50
|
+
raise "We currently don't support metadata within entries as we haven't had a need for it yet (the data between {} in #{line})."
|
51
|
+
end
|
52
|
+
|
53
|
+
tokens.reject! { |token| token.is_a?(Tokenizer::EndArrayToken) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,32 +1,17 @@
|
|
1
1
|
require "sie/parser/tokenizer"
|
2
2
|
require "sie/parser/entry"
|
3
3
|
require "sie/parser/sie_file"
|
4
|
+
require "sie/parser/build_entry"
|
4
5
|
|
5
6
|
module Sie
|
6
7
|
class Parser
|
7
8
|
class LineParser
|
8
|
-
pattr_initialize :line
|
9
|
+
pattr_initialize :line, [ :lenient ]
|
9
10
|
|
10
11
|
def parse
|
11
12
|
tokens = tokenize(line)
|
12
13
|
first_token = tokens.shift
|
13
|
-
|
14
|
-
entry = Entry.new(first_token.label)
|
15
|
-
entry_type = first_token.entry_type
|
16
|
-
|
17
|
-
entry_type.each_with_index do |entry_type, i|
|
18
|
-
break if i >= tokens.size
|
19
|
-
|
20
|
-
if entry_type.is_a?(Hash)
|
21
|
-
skip_array(tokens, i)
|
22
|
-
next
|
23
|
-
else
|
24
|
-
label = entry_type
|
25
|
-
entry.attributes[label] = tokens[i].value
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
entry
|
14
|
+
build_entry(first_token, tokens)
|
30
15
|
end
|
31
16
|
|
32
17
|
private
|
@@ -35,13 +20,8 @@ module Sie
|
|
35
20
|
Tokenizer.new(line).tokenize
|
36
21
|
end
|
37
22
|
|
38
|
-
def
|
39
|
-
|
40
|
-
!tokens[i+1].is_a?(Tokenizer::EndArrayToken)
|
41
|
-
raise "We currently don't support metadata within entries as we haven't had a need for it yet (the data between {} in #{line})."
|
42
|
-
end
|
43
|
-
|
44
|
-
tokens.reject! { |token| token.is_a?(Tokenizer::EndArrayToken) }
|
23
|
+
def build_entry(first_token, tokens)
|
24
|
+
BuildEntry.call(line, first_token, tokens, lenient)
|
45
25
|
end
|
46
26
|
end
|
47
27
|
end
|
data/lib/sie/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
#FLAGGA 0
|
2
|
+
#PROGRAM "fooconomic" "1.0"
|
3
|
+
#FORMAT PC8
|
4
|
+
#GEN 20130101
|
5
|
+
#SIETYP 4
|
6
|
+
#ORGNR 555555-5555
|
7
|
+
#FNAMN "Foocorp"
|
8
|
+
#ADRESS "Foocorp" "" "12345 City" "555-12345"
|
9
|
+
#KONTO 1510 "Accounts receivable"
|
10
|
+
#KTYP 1510 T
|
11
|
+
#SRU 1510 204
|
12
|
+
#KONTO 1930 "Bank account"
|
13
|
+
#KTYP 1930 T
|
14
|
+
#SRU 1930 200
|
15
|
+
#KONTO 2440 Supplier
|
16
|
+
#KTYP 2440 S
|
17
|
+
#SRU 2440 300
|
18
|
+
#KONTO 2610 "Utgaende moms, oreducerad "
|
19
|
+
#KTYP 2610 S
|
20
|
+
#SRU 2610 7369
|
21
|
+
#MOMSKOD 2610 10
|
22
|
+
#VER A 1 20130101 "Invoice" 20120105
|
23
|
+
{
|
24
|
+
#TRANS 1510 {} -200 20130101 "Coffee machine"
|
25
|
+
#TRANS 4100 {} 180 20130101 "Coffee machine"
|
26
|
+
#TRANS 2611 {} -20 20130101 "VAT"
|
27
|
+
}
|
28
|
+
#VER A 2 20130102 "Payment" 20120105
|
29
|
+
{
|
30
|
+
#TRANS 1510 {} -200 20130101 "Payment: Coffee machine"
|
31
|
+
#TRANS 1970 {} 200 20130101 "Payment: Coffee machine"
|
32
|
+
}
|
@@ -18,7 +18,39 @@ describe Sie::Parser do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
context "with unknown entries" do
|
22
|
+
let(:file_with_unknown_entries) { "fixtures/sie_file_with_unknown_entries.se" }
|
23
|
+
|
24
|
+
context "using a lenient parser" do
|
25
|
+
let(:parser) { Sie::Parser.new(lenient: true) }
|
26
|
+
|
27
|
+
it "handles unknown entries without raising error" do
|
28
|
+
open_file(file_with_unknown_entries) do |f|
|
29
|
+
expect { parser.parse(f) }.not_to raise_error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "continues to parse the complete file after unknown entries" do
|
34
|
+
open_file(file_with_unknown_entries) do |f|
|
35
|
+
sie_file = parser.parse(f)
|
36
|
+
|
37
|
+
expect(sie_file.entries_with_label("ver").size).to eq(2)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with strict parser" do
|
43
|
+
let(:parser) { Sie::Parser.new }
|
44
|
+
|
45
|
+
it "raises error when encountering unknown entries" do
|
46
|
+
open_file(file_with_unknown_entries) do |f|
|
47
|
+
expect { parser.parse(f) }.to raise_error(/Unknown entry type: momskod.+Pass 'lenient: true'/)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def open_file(fixture_file, &block)
|
54
|
+
File.open(File.join(File.dirname(__FILE__), "../#{fixture_file}"), &block)
|
23
55
|
end
|
24
56
|
end
|
@@ -14,6 +14,26 @@ describe Sie::Parser::LineParser, "parse" do
|
|
14
14
|
})
|
15
15
|
end
|
16
16
|
|
17
|
+
context "with unknown entry" do
|
18
|
+
let(:line) { "#MOMSKOD 2611 10"}
|
19
|
+
|
20
|
+
context "using a lenient parser" do
|
21
|
+
let(:parser) { Sie::Parser::LineParser.new(line, lenient: true) }
|
22
|
+
|
23
|
+
it "raises no error when encountering unknown entries" do
|
24
|
+
expect { parser.parse }.not_to raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "using a strict parser" do
|
29
|
+
let(:parser) { Sie::Parser::LineParser.new(line) }
|
30
|
+
|
31
|
+
it "raises error when encountering unknown entries" do
|
32
|
+
expect { parser.parse }.to raise_error(/Unknown entry type/)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
17
37
|
it "fails if you have non empty metadata arrays until there is a need to support that" do
|
18
38
|
parser = Sie::Parser::LineParser.new('#TRANS 2400 { 1 "2" } -200 20130101 "Foocorp expense"')
|
19
39
|
expect(-> { parser.parse }).to raise_error(/don't support metadata/)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Barsoom AB
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attr_extras
|
@@ -99,6 +99,7 @@ files:
|
|
99
99
|
- lib/sie/document/renderer.rb
|
100
100
|
- lib/sie/document/voucher_series.rb
|
101
101
|
- lib/sie/parser.rb
|
102
|
+
- lib/sie/parser/build_entry.rb
|
102
103
|
- lib/sie/parser/entry.rb
|
103
104
|
- lib/sie/parser/entry_types.rb
|
104
105
|
- lib/sie/parser/line_parser.rb
|
@@ -113,6 +114,7 @@ files:
|
|
113
114
|
- script/turbux_rspec
|
114
115
|
- sie.gemspec
|
115
116
|
- spec/fixtures/sie_file.se
|
117
|
+
- spec/fixtures/sie_file_with_unknown_entries.se
|
116
118
|
- spec/integration/parser_spec.rb
|
117
119
|
- spec/spec_helper.rb
|
118
120
|
- spec/unit/document/renderer_spec.rb
|
@@ -147,6 +149,7 @@ specification_version: 4
|
|
147
149
|
summary: Parses and generates SIE files (http://sie.se/)
|
148
150
|
test_files:
|
149
151
|
- spec/fixtures/sie_file.se
|
152
|
+
- spec/fixtures/sie_file_with_unknown_entries.se
|
150
153
|
- spec/integration/parser_spec.rb
|
151
154
|
- spec/spec_helper.rb
|
152
155
|
- spec/unit/document/renderer_spec.rb
|