sie 4.1.0 → 4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -3
- data/lib/sie/document/renderer.rb +2 -2
- data/lib/sie/parser/build_entry.rb +4 -3
- data/lib/sie/parser/entry_types.rb +35 -35
- data/lib/sie/parser/tokenizer/token.rb +1 -1
- data/lib/sie/version.rb +1 -1
- metadata +8 -40
- data/.gitignore +0 -18
- data/.rspec +0 -2
- data/.travis.yml +0 -5
- data/Gemfile +0 -4
- data/Gemfile.pre_2.2.2 +0 -8
- data/Rakefile +0 -15
- data/script/bootstrap +0 -3
- data/script/refresh +0 -25
- data/script/test +0 -1
- data/script/turbux_rspec +0 -6
- data/sie.gemspec +0 -27
- data/spec/fixtures/sie_file.se +0 -28
- data/spec/fixtures/sie_file_with_unknown_entries.se +0 -32
- data/spec/integration/parser_spec.rb +0 -56
- data/spec/spec_helper.rb +0 -5
- data/spec/unit/build_entry_spec.rb +0 -17
- data/spec/unit/document/renderer_spec.rb +0 -13
- data/spec/unit/document/voucher_series_spec.rb +0 -41
- data/spec/unit/document_spec.rb +0 -317
- data/spec/unit/parser/line_parser_spec.rb +0 -37
- data/spec/unit/parser/tokenizer_spec.rb +0 -98
- data/spec/unit/parser_spec.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26526531e52a08b42e851ecb48e7139284c0d123497e0690b96e034568d80260
|
4
|
+
data.tar.gz: 66f9a81079464969de19e6fdd5a5b35c2eda75376ec6495b7afe31d3bf3e9b45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a00336cae71fa202912e83f523fd3229600f6712f12531425e841cb328c2a45fd3f2203e009266b467ca9e544fcb3abbfceef8b5dc6254f324f88213957f217
|
7
|
+
data.tar.gz: 3fa86473dd8b9ade5ba84fd227fca41be16bb7c6e4cfc15ae27cb9cb1a4d2a1d3a765b7bd6134b3d6765a2446b74e6a209d3e355756d62d2c2de165a21a54749
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# Sie
|
2
2
|
|
3
|
-
[![Build
|
4
|
-
[![Code Climate](https://codeclimate.com/github/barsoom/sie.
|
3
|
+
[![Build status](https://github.com/barsoom/sie/actions/workflows/ci.yml/badge.svg)](https://github.com/barsoom/sie/actions/workflows/ci.yml)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/barsoom/sie.svg)](https://codeclimate.com/github/barsoom/sie)
|
5
5
|
|
6
|
+
SIE parser and generator supporting the [format "SIE typ 1-4 – Klassisk SIE"](https://sie.se/format/).
|
6
7
|
|
7
8
|
## Installation
|
8
9
|
|
@@ -161,7 +162,7 @@ Getting the latest code and gems:
|
|
161
162
|
|
162
163
|
## Resources
|
163
164
|
|
164
|
-
[SIE format specification rev 4B (
|
165
|
+
[SIE format specification rev 4B (Swedish)](https://sie.se/wp-content/uploads/2020/05/SIE_filformat_ver_4B_080930.pdf)
|
165
166
|
|
166
167
|
## See also
|
167
168
|
|
@@ -9,7 +9,7 @@ class Sie::Document::Renderer
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def add_line(label, *values)
|
12
|
-
append ["##{
|
12
|
+
append [ "##{label}", *format_values(values) ].join(" ")
|
13
13
|
end
|
14
14
|
|
15
15
|
def add_array
|
@@ -36,7 +36,7 @@ class Sie::Document::Renderer
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def encoded(text)
|
39
|
-
text.encode(ENCODING, :
|
39
|
+
text.encode(ENCODING, invalid: :replace, undef: :replace, replace: "?")
|
40
40
|
end
|
41
41
|
|
42
42
|
def format_value(value)
|
@@ -27,9 +27,9 @@ module Sie
|
|
27
27
|
entry.attributes[label] = attr_tokens.first
|
28
28
|
else
|
29
29
|
type = attr.fetch(:type)
|
30
|
-
values = attr_tokens
|
31
|
-
each_slice(type.size)
|
32
|
-
map { |slice| Hash[type.zip(slice)] }
|
30
|
+
values = attr_tokens
|
31
|
+
.each_slice(type.size)
|
32
|
+
.map { |slice| Hash[type.zip(slice)] }
|
33
33
|
|
34
34
|
entry.attributes[label] = values
|
35
35
|
end
|
@@ -53,6 +53,7 @@ module Sie
|
|
53
53
|
hash_tokens = []
|
54
54
|
while token = tokens.shift
|
55
55
|
break if token.is_a?(Tokenizer::EndArrayToken)
|
56
|
+
|
56
57
|
hash_tokens << token.value
|
57
58
|
end
|
58
59
|
|
@@ -1,41 +1,41 @@
|
|
1
1
|
module Sie
|
2
2
|
class Parser
|
3
3
|
ENTRY_TYPES = {
|
4
|
-
"adress" => [
|
5
|
-
"bkod" => [
|
6
|
-
"dim" => [
|
7
|
-
"enhet" => [
|
8
|
-
"flagga" => [
|
9
|
-
"fnamn" => [
|
10
|
-
"fnr" => [
|
11
|
-
"format" => [
|
12
|
-
"ftyp" => [
|
13
|
-
"gen" => [
|
14
|
-
"ib" => [
|
15
|
-
"konto" => [
|
16
|
-
"kptyp" => [
|
17
|
-
"ktyp" => [
|
18
|
-
"objekt" => [
|
19
|
-
"oib" => [
|
20
|
-
"omfattn" => [
|
21
|
-
"orgnr" => [
|
22
|
-
"oub" => [
|
23
|
-
"pbudget" => [
|
24
|
-
"program" => [
|
25
|
-
"prosa" => [
|
26
|
-
"psaldo" => [
|
27
|
-
"rar" => [
|
28
|
-
"res" => [
|
29
|
-
"sietyp" => [
|
30
|
-
"sru" => [
|
31
|
-
"taxar" => [
|
32
|
-
"trans" => [
|
33
|
-
"rtrans" => [
|
34
|
-
"btrans" => [
|
35
|
-
"ub" => [
|
36
|
-
"underdim" => [
|
37
|
-
"valuta" => [
|
38
|
-
"ver" => [
|
4
|
+
"adress" => [ "kontakt", "utdelningsadr", "postadr", "tel" ],
|
5
|
+
"bkod" => [ "SNI-kod" ],
|
6
|
+
"dim" => [ "dimensionsnr", "namn" ],
|
7
|
+
"enhet" => [ "kontonr", "enhet" ],
|
8
|
+
"flagga" => [ "x" ],
|
9
|
+
"fnamn" => [ "foretagsnamn" ],
|
10
|
+
"fnr" => [ "foretagsid" ],
|
11
|
+
"format" => [ "PC8" ],
|
12
|
+
"ftyp" => [ "foretagstyp" ],
|
13
|
+
"gen" => [ "datum", "sign" ],
|
14
|
+
"ib" => [ "arsnr", "konto", "saldo", "kvantitet" ],
|
15
|
+
"konto" => [ "kontonr", "kontonamn" ],
|
16
|
+
"kptyp" => [ "typ" ],
|
17
|
+
"ktyp" => [ "kontonr", "kontotyp" ],
|
18
|
+
"objekt" => [ "dimensionsnr", "objektnr", "objektnamn" ],
|
19
|
+
"oib" => [ "arsnr", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
20
|
+
"omfattn" => [ "datum" ],
|
21
|
+
"orgnr" => [ "orgnr", "forvnr", "verknr" ],
|
22
|
+
"oub" => [ "arsnr", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
23
|
+
"pbudget" => [ "arsnr", "period", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
24
|
+
"program" => [ "programnamn", "version" ],
|
25
|
+
"prosa" => [ "text" ],
|
26
|
+
"psaldo" => [ "arsnr", "period", "konto", { name: "objekt", type: [ "dimensionsnr", "objektnr" ] }, "saldo", "kvantitet" ],
|
27
|
+
"rar" => [ "arsnr", "start", "slut" ],
|
28
|
+
"res" => [ "ars", "konto", "saldo", "kvantitet" ],
|
29
|
+
"sietyp" => [ "typnr" ],
|
30
|
+
"sru" => [ "konto", "SRU-kod" ],
|
31
|
+
"taxar" => [ "ar" ],
|
32
|
+
"trans" => [ "kontonr", { name: "objektlista", type: [ "dimensionsnr", "objektnr" ], many: true }, "belopp", "transdat", "transtext", "kvantitet", "sign" ],
|
33
|
+
"rtrans" => [ "kontonr", { name: "objektlista", type: [ "dimensionsnr", "objektnr" ], many: true }, "belopp", "transdat", "transtext", "kvantitet", "sign" ],
|
34
|
+
"btrans" => [ "kontonr", { name: "objektlista", type: [ "dimensionsnr", "objektnr" ], many: true }, "belopp", "transdat", "transtext", "kvantitet", "sign" ],
|
35
|
+
"ub" => [ "arsnr", "konto", "saldo", "kvantitet" ],
|
36
|
+
"underdim" => [ "dimensionsnr", "namn", "superdimension" ],
|
37
|
+
"valuta" => [ "valutakod" ],
|
38
|
+
"ver" => [ "serie", "vernr", "verdatum", "vertext", "regdatum", "sign" ],
|
39
39
|
}
|
40
40
|
end
|
41
41
|
end
|
data/lib/sie/version.rb
CHANGED
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: 4.1.
|
4
|
+
version: 4.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Barsoom AB
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attr_extras
|
@@ -42,14 +42,14 @@ dependencies:
|
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
@@ -87,13 +87,7 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
-
- ".gitignore"
|
91
|
-
- ".rspec"
|
92
|
-
- ".travis.yml"
|
93
|
-
- Gemfile
|
94
|
-
- Gemfile.pre_2.2.2
|
95
90
|
- README.md
|
96
|
-
- Rakefile
|
97
91
|
- lib/sie.rb
|
98
92
|
- lib/sie/document.rb
|
99
93
|
- lib/sie/document/renderer.rb
|
@@ -107,26 +101,11 @@ files:
|
|
107
101
|
- lib/sie/parser/tokenizer.rb
|
108
102
|
- lib/sie/parser/tokenizer/token.rb
|
109
103
|
- lib/sie/version.rb
|
110
|
-
- script/bootstrap
|
111
|
-
- script/refresh
|
112
|
-
- script/test
|
113
|
-
- script/turbux_rspec
|
114
|
-
- sie.gemspec
|
115
|
-
- spec/fixtures/sie_file.se
|
116
|
-
- spec/fixtures/sie_file_with_unknown_entries.se
|
117
|
-
- spec/integration/parser_spec.rb
|
118
|
-
- spec/spec_helper.rb
|
119
|
-
- spec/unit/build_entry_spec.rb
|
120
|
-
- spec/unit/document/renderer_spec.rb
|
121
|
-
- spec/unit/document/voucher_series_spec.rb
|
122
|
-
- spec/unit/document_spec.rb
|
123
|
-
- spec/unit/parser/line_parser_spec.rb
|
124
|
-
- spec/unit/parser/tokenizer_spec.rb
|
125
|
-
- spec/unit/parser_spec.rb
|
126
104
|
homepage: ''
|
127
105
|
licenses:
|
128
106
|
- MIT
|
129
|
-
metadata:
|
107
|
+
metadata:
|
108
|
+
rubygems_mfa_required: 'true'
|
130
109
|
post_install_message:
|
131
110
|
rdoc_options: []
|
132
111
|
require_paths:
|
@@ -142,19 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
121
|
- !ruby/object:Gem::Version
|
143
122
|
version: '0'
|
144
123
|
requirements: []
|
145
|
-
rubygems_version: 3.
|
124
|
+
rubygems_version: 3.2.31
|
146
125
|
signing_key:
|
147
126
|
specification_version: 4
|
148
127
|
summary: Parses and generates SIE files (http://sie.se/)
|
149
|
-
test_files:
|
150
|
-
- spec/fixtures/sie_file.se
|
151
|
-
- spec/fixtures/sie_file_with_unknown_entries.se
|
152
|
-
- spec/integration/parser_spec.rb
|
153
|
-
- spec/spec_helper.rb
|
154
|
-
- spec/unit/build_entry_spec.rb
|
155
|
-
- spec/unit/document/renderer_spec.rb
|
156
|
-
- spec/unit/document/voucher_series_spec.rb
|
157
|
-
- spec/unit/document_spec.rb
|
158
|
-
- spec/unit/parser/line_parser_spec.rb
|
159
|
-
- spec/unit/parser/tokenizer_spec.rb
|
160
|
-
- spec/unit/parser_spec.rb
|
128
|
+
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/Gemfile
DELETED
data/Gemfile.pre_2.2.2
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in sie.gemspec
|
4
|
-
gemspec
|
5
|
-
|
6
|
-
# Ruby <2.2.2 can't use Active Support 5.
|
7
|
-
# https://apotonick.wordpress.com/2012/08/14/different-gemfiles-for-ruby-1-8-and-1-9-on-travis-ci/
|
8
|
-
gem "activesupport", "< 5"
|
data/Rakefile
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
|
3
|
-
namespace :spec do
|
4
|
-
task :unit do
|
5
|
-
puts "Running unit tests:"
|
6
|
-
system("rspec spec/unit/**_spec.rb") || exit(1)
|
7
|
-
end
|
8
|
-
|
9
|
-
task :integration do
|
10
|
-
puts "Running integrated tests:"
|
11
|
-
system("rspec spec/integration/**_spec.rb") || exit(1)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
task :default => [ :"spec:unit", :"spec:integration" ]
|
data/script/bootstrap
DELETED
data/script/refresh
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
|
3
|
-
printf "\e[00;34mGetting the latest version\e[00m... "
|
4
|
-
|
5
|
-
(git status|grep 'nothing to commit' 1> /dev/null)
|
6
|
-
|
7
|
-
if [ ! $? -eq 0 ]
|
8
|
-
then
|
9
|
-
set -e
|
10
|
-
git stash 1> /dev/null
|
11
|
-
git pull --rebase 1> /dev/null
|
12
|
-
git stash pop 1> /dev/null
|
13
|
-
else
|
14
|
-
set -e
|
15
|
-
git pull --rebase 1> /dev/null
|
16
|
-
fi
|
17
|
-
|
18
|
-
echo "done"
|
19
|
-
|
20
|
-
printf "\e[00;34mBundling\e[00m... "
|
21
|
-
bundle 1> /dev/null
|
22
|
-
echo "done"
|
23
|
-
echo
|
24
|
-
|
25
|
-
rake
|
data/script/test
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
script/turbux_rspec
|
data/script/turbux_rspec
DELETED
data/sie.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'sie/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "sie"
|
8
|
-
spec.version = Sie::VERSION
|
9
|
-
spec.authors = ["Barsoom AB"]
|
10
|
-
spec.email = ["all@barsoom.se"]
|
11
|
-
spec.description = %q{SIE parser and generator}
|
12
|
-
spec.summary = %q{Parses and generates SIE files (http://sie.se/)}
|
13
|
-
spec.homepage = ""
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_dependency "attr_extras"
|
22
|
-
spec.add_dependency "activesupport"
|
23
|
-
|
24
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
-
spec.add_development_dependency "rake"
|
26
|
-
spec.add_development_dependency "rspec"
|
27
|
-
end
|
data/spec/fixtures/sie_file.se
DELETED
@@ -1,28 +0,0 @@
|
|
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
|
-
#VER A 1 20130101 "Invoice" 20120105
|
19
|
-
{
|
20
|
-
#TRANS 1510 {} -200 20130101 "Coffee machine"
|
21
|
-
#TRANS 4100 {} 180 20130101 "Coffee machine"
|
22
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
23
|
-
}
|
24
|
-
#VER A 2 20130102 "Payment" 20120105
|
25
|
-
{
|
26
|
-
#TRANS 1510 {} -200 20130101 "Payment: Coffee machine"
|
27
|
-
#TRANS 1970 {} 200 20130101 "Payment: Coffee machine"
|
28
|
-
}
|
@@ -1,32 +0,0 @@
|
|
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
|
-
}
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Sie::Parser do
|
6
|
-
it "parses a file" do
|
7
|
-
parser = Sie::Parser.new
|
8
|
-
|
9
|
-
open_file("fixtures/sie_file.se") do |f|
|
10
|
-
sie_file = parser.parse(f)
|
11
|
-
|
12
|
-
expect(sie_file.entries_with_label("fnamn").first.attributes["foretagsnamn"]).to eq("Foocorp")
|
13
|
-
|
14
|
-
account = sie_file.entries_with_label("konto").first
|
15
|
-
expect(account.attributes["kontonr"]).to eq("1510")
|
16
|
-
expect(account.attributes["kontonamn"]).to eq("Accounts receivable")
|
17
|
-
expect(sie_file.entries_with_label("ver").size).to eq(2)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
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)
|
55
|
-
end
|
56
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser/build_entry"
|
3
|
-
require "sie/parser/tokenizer"
|
4
|
-
|
5
|
-
describe Sie::Parser::BuildEntry, ".call" do
|
6
|
-
context "with an unexpected token at start of array" do
|
7
|
-
it "raises InvalidEntryError" do
|
8
|
-
line = '#TRANS 2400 [] -200 20130101 "Foocorp expense"'
|
9
|
-
tokens = Sie::Parser::Tokenizer.new(line).tokenize
|
10
|
-
first_token = tokens.shift
|
11
|
-
|
12
|
-
expect {
|
13
|
-
Sie::Parser::BuildEntry.call(line, first_token, tokens, false)
|
14
|
-
}.to raise_error(Sie::Parser::BuildEntry::InvalidEntryError)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Sie::Document::Renderer, "#add_line" do
|
6
|
-
it "replaces input of the wrong encoding with '?'" do
|
7
|
-
renderer = Sie::Document::Renderer.new
|
8
|
-
renderer.add_line "Hello ☃", 1
|
9
|
-
output = renderer.render
|
10
|
-
|
11
|
-
expect(output).to eq "#Hello ? 1\n"
|
12
|
-
end
|
13
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Sie::Document::VoucherSeries, ".for" do
|
4
|
-
subject(:series) { Sie::Document::VoucherSeries.for(creditor, type) }
|
5
|
-
|
6
|
-
let(:type) { :invoice }
|
7
|
-
|
8
|
-
context "when on the creditor side" do
|
9
|
-
let(:creditor) { true }
|
10
|
-
|
11
|
-
context "with an invoice" do
|
12
|
-
let(:type) { :invoice }
|
13
|
-
it { should == "LF" }
|
14
|
-
end
|
15
|
-
|
16
|
-
context "with a payment" do
|
17
|
-
let(:type) { :payment }
|
18
|
-
it { should == "KB" }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context "when on the debtor side" do
|
23
|
-
let(:creditor) { false }
|
24
|
-
|
25
|
-
context "with an invoice" do
|
26
|
-
let(:type) { :invoice }
|
27
|
-
it { should == "KF" }
|
28
|
-
end
|
29
|
-
|
30
|
-
context "with a payment" do
|
31
|
-
let(:type) { :payment }
|
32
|
-
it { should == "KI" }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context "when neither a payment or invoice" do
|
37
|
-
let(:creditor) { false }
|
38
|
-
let(:type) { :manual_bookable }
|
39
|
-
it { should == "LV" }
|
40
|
-
end
|
41
|
-
end
|
data/spec/unit/document_spec.rb
DELETED
@@ -1,317 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "spec_helper"
|
3
|
-
require "sie"
|
4
|
-
require "active_support/core_ext/date/calculations"
|
5
|
-
|
6
|
-
describe Sie::Document, "#render" do
|
7
|
-
let(:financial_years) {
|
8
|
-
[
|
9
|
-
Date.new(2011, 1, 1)..Date.new(2011, 12, 31),
|
10
|
-
Date.new(2012, 1, 1)..Date.new(2012, 12, 31),
|
11
|
-
Date.new(2013, 1, 1)..Date.new(2013, 12, 31),
|
12
|
-
]
|
13
|
-
}
|
14
|
-
let(:generated_on) { Date.yesterday }
|
15
|
-
let(:accounts) {
|
16
|
-
[
|
17
|
-
number: 1500, description: "Customer ledger",
|
18
|
-
]
|
19
|
-
}
|
20
|
-
let(:vouchers) {
|
21
|
-
[
|
22
|
-
{
|
23
|
-
creditor: false, type: :invoice, number: 1, booked_on: Date.new(2011, 9, 3), description: "Invoice 1",
|
24
|
-
voucher_lines: [
|
25
|
-
{
|
26
|
-
account_number: 1500, amount: 512.0, booked_on: Date.new(2011, 9, 3), description: "Item 1",
|
27
|
-
dimensions: { 6 => 1 }
|
28
|
-
},
|
29
|
-
{
|
30
|
-
account_number: 3100, amount: -512.0, booked_on: Date.new(2011, 9, 3), description: "Item 1",
|
31
|
-
dimensions: { 6 => 1 }
|
32
|
-
},
|
33
|
-
]
|
34
|
-
},
|
35
|
-
{
|
36
|
-
creditor: true, type: :payment, number: 2, booked_on: Date.new(2012, 8, 31), description: "Payout 1",
|
37
|
-
voucher_lines: [
|
38
|
-
{
|
39
|
-
account_number: 2400, amount: 256.0, booked_on: Date.new(2012, 8, 31), description: "Payout line 1"
|
40
|
-
},
|
41
|
-
{
|
42
|
-
account_number: 1970, amount: -256.0, booked_on: Date.new(2012, 8, 31), description: "Payout line 2"
|
43
|
-
},
|
44
|
-
]
|
45
|
-
}
|
46
|
-
]
|
47
|
-
}
|
48
|
-
let(:dimensions) {
|
49
|
-
[
|
50
|
-
{
|
51
|
-
number: 6, description: "Project",
|
52
|
-
objects: [
|
53
|
-
{ number: 1, description: "Education" }
|
54
|
-
]
|
55
|
-
}
|
56
|
-
]
|
57
|
-
}
|
58
|
-
|
59
|
-
class TestDataSource
|
60
|
-
attr_accessor :program, :program_version, :generated_on, :company_name,
|
61
|
-
:accounts, :balance_account_numbers, :closing_account_numbers,
|
62
|
-
:vouchers, :financial_years, :dimensions
|
63
|
-
|
64
|
-
# vouchers is not part of the expected interface so making it private.
|
65
|
-
#
|
66
|
-
# Sie::Document uses #each_voucher so that you can build documents for huge sets of vouchers
|
67
|
-
# by loading them in batches.
|
68
|
-
private :vouchers
|
69
|
-
|
70
|
-
def initialize(hash)
|
71
|
-
hash.each do |k, v|
|
72
|
-
public_send("#{k}=", v)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def each_voucher(&block)
|
77
|
-
vouchers.each(&block)
|
78
|
-
end
|
79
|
-
|
80
|
-
def balance_before(account_number, date)
|
81
|
-
if account_number == 9999
|
82
|
-
# So we can test empty balances.
|
83
|
-
nil
|
84
|
-
else
|
85
|
-
# Faking a fetch based on date and number.
|
86
|
-
account_number.to_i + (date.mday * 100).to_f
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
let(:data_source) {
|
92
|
-
TestDataSource.new(
|
93
|
-
accounts: accounts,
|
94
|
-
vouchers: vouchers,
|
95
|
-
program: "Foonomic",
|
96
|
-
program_version: "3.11",
|
97
|
-
generated_on: generated_on,
|
98
|
-
company_name: "Foocorp",
|
99
|
-
financial_years: financial_years,
|
100
|
-
balance_account_numbers: [ 1500, 2400, 9999 ],
|
101
|
-
closing_account_numbers: [ 3100, 9999 ],
|
102
|
-
dimensions: dimensions
|
103
|
-
)
|
104
|
-
}
|
105
|
-
|
106
|
-
let(:doc) {
|
107
|
-
Sie::Document.new(data_source)
|
108
|
-
}
|
109
|
-
|
110
|
-
let(:sie_file) { Sie::Parser.new.parse(doc.render) }
|
111
|
-
|
112
|
-
it "adds a header" do
|
113
|
-
expect(entry_attribute("flagga", "x")).to eq("0")
|
114
|
-
expect(entry_attribute("program", "programnamn")).to eq("Foonomic")
|
115
|
-
expect(entry_attribute("program", "version")).to eq("3.11")
|
116
|
-
expect(entry_attribute("format", "PC8")).to eq("PC8")
|
117
|
-
expect(entry_attribute("gen", "datum")).to eq(generated_on.strftime("%Y%m%d"))
|
118
|
-
expect(entry_attribute("sietyp", "typnr")).to eq("4")
|
119
|
-
expect(entry_attribute("fnamn", "foretagsnamn")).to eq("Foocorp")
|
120
|
-
end
|
121
|
-
|
122
|
-
it "has accounting years" do
|
123
|
-
expect(indexed_entry_attribute("rar", 0, "arsnr")).to eq("0")
|
124
|
-
expect(indexed_entry_attribute("rar", 0, "start")).to eq("20130101")
|
125
|
-
expect(indexed_entry_attribute("rar", 0, "slut")).to eq("20131231")
|
126
|
-
expect(indexed_entry_attribute("rar", 1, "arsnr")).to eq("-1")
|
127
|
-
expect(indexed_entry_attribute("rar", 1, "start")).to eq("20120101")
|
128
|
-
expect(indexed_entry_attribute("rar", 1, "slut")).to eq("20121231")
|
129
|
-
expect(indexed_entry_attribute("rar", 2, "arsnr")).to eq("-2")
|
130
|
-
expect(indexed_entry_attribute("rar", 2, "start")).to eq("20110101")
|
131
|
-
expect(indexed_entry_attribute("rar", 2, "slut")).to eq("20111231")
|
132
|
-
end
|
133
|
-
|
134
|
-
it "has accounts" do
|
135
|
-
expect(indexed_entry_attributes("konto", 0)).to eq("kontonr" => "1500", "kontonamn" => "Customer ledger")
|
136
|
-
end
|
137
|
-
|
138
|
-
it "has dimensions" do
|
139
|
-
expect(indexed_entry_attributes("dim", 0)).to eq("dimensionsnr" => "6", "namn" => "Project")
|
140
|
-
end
|
141
|
-
|
142
|
-
it "has objects" do
|
143
|
-
expect(indexed_entry_attributes("objekt", 0)).to eq("dimensionsnr" => "6", "objektnr" => "1", "objektnamn" => "Education")
|
144
|
-
end
|
145
|
-
|
146
|
-
it "has balances brought forward (ingående balans)" do
|
147
|
-
expect(indexed_entry_attributes("ib", 0)).not_to eq("arsnr" => "0", "konto" => "9999", "saldo" => "")
|
148
|
-
expect(indexed_entry_attributes("ib", 0)).to eq("arsnr" => "0", "konto" => "1500", "saldo" => "1600.0")
|
149
|
-
expect(indexed_entry_attributes("ib", 1)).to eq("arsnr" => "0", "konto" => "2400", "saldo" => "2500.0")
|
150
|
-
expect(indexed_entry_attributes("ib", 2)).to eq("arsnr" => "-1", "konto" => "1500", "saldo" => "1600.0")
|
151
|
-
expect(indexed_entry_attributes("ib", 3)).to eq("arsnr" => "-1", "konto" => "2400", "saldo" => "2500.0")
|
152
|
-
expect(indexed_entry_attributes("ib", 4)).to eq("arsnr" => "-2", "konto" => "1500", "saldo" => "1600.0")
|
153
|
-
expect(indexed_entry_attributes("ib", 5)).to eq("arsnr" => "-2", "konto" => "2400", "saldo" => "2500.0")
|
154
|
-
end
|
155
|
-
|
156
|
-
it "has balances carried forward (utgående balans)" do
|
157
|
-
expect(indexed_entry_attributes("ub", 0)).not_to eq("arsnr" => "0", "konto" => "9999", "saldo" => "")
|
158
|
-
expect(indexed_entry_attributes("ub", 0)).to eq("arsnr" => "0", "konto" => "1500", "saldo" => "4600.0")
|
159
|
-
expect(indexed_entry_attributes("ub", 1)).to eq("arsnr" => "0", "konto" => "2400", "saldo" => "5500.0")
|
160
|
-
expect(indexed_entry_attributes("ub", 2)).to eq("arsnr" => "-1", "konto" => "1500", "saldo" => "4600.0")
|
161
|
-
expect(indexed_entry_attributes("ub", 3)).to eq("arsnr" => "-1", "konto" => "2400", "saldo" => "5500.0")
|
162
|
-
expect(indexed_entry_attributes("ub", 4)).to eq("arsnr" => "-2", "konto" => "1500", "saldo" => "4600.0")
|
163
|
-
expect(indexed_entry_attributes("ub", 5)).to eq("arsnr" => "-2", "konto" => "2400", "saldo" => "5500.0")
|
164
|
-
end
|
165
|
-
|
166
|
-
it "has closing account balances (saldo för resultatkonto)" do
|
167
|
-
expect(indexed_entry_attributes("res", 0)).not_to eq("ars" => "0", "konto" => "9999", "saldo" => "")
|
168
|
-
expect(indexed_entry_attributes("res", 0)).to eq("ars" => "0", "konto" => "3100", "saldo" => "6200.0")
|
169
|
-
expect(indexed_entry_attributes("res", 1)).to eq("ars" => "-1", "konto" => "3100", "saldo" => "6200.0")
|
170
|
-
expect(indexed_entry_attributes("res", 2)).to eq("ars" => "-2", "konto" => "3100", "saldo" => "6200.0")
|
171
|
-
end
|
172
|
-
|
173
|
-
it "has vouchers" do
|
174
|
-
expect(indexed_entry("ver", 0).attributes).to eq(
|
175
|
-
"serie" => "KF", "vernr" => "1",
|
176
|
-
"verdatum" => "20110903", "vertext" => "Invoice 1"
|
177
|
-
)
|
178
|
-
expect(indexed_voucher_entries(0)[0].attributes).to eq(
|
179
|
-
"kontonr" => "1500", "belopp" => "512.0",
|
180
|
-
"transdat" => "20110903", "transtext" => "Item 1",
|
181
|
-
"objektlista" => [{"dimensionsnr" => "6", "objektnr" => "1"}]
|
182
|
-
)
|
183
|
-
expect(indexed_voucher_entries(0)[1].attributes).to eq(
|
184
|
-
"kontonr" => "3100", "belopp" => "-512.0",
|
185
|
-
"transdat" => "20110903", "transtext" => "Item 1",
|
186
|
-
"objektlista" => [{"dimensionsnr" => "6", "objektnr" => "1"}]
|
187
|
-
)
|
188
|
-
|
189
|
-
expect(indexed_entry("ver", 1).attributes).to eq(
|
190
|
-
"serie" => "KB", "vernr" => "2",
|
191
|
-
"verdatum" => "20120831", "vertext" => "Payout 1"
|
192
|
-
)
|
193
|
-
expect(indexed_voucher_entries(1)[0].attributes).to eq(
|
194
|
-
"kontonr" => "2400", "belopp" => "256.0",
|
195
|
-
"transdat" => "20120831", "transtext" => "Payout line 1",
|
196
|
-
"objektlista" => []
|
197
|
-
)
|
198
|
-
expect(indexed_voucher_entries(1)[1].attributes).to eq(
|
199
|
-
"kontonr" => "1970", "belopp" => "-256.0",
|
200
|
-
"transdat" => "20120831", "transtext" => "Payout line 2",
|
201
|
-
"objektlista" => []
|
202
|
-
)
|
203
|
-
end
|
204
|
-
|
205
|
-
it "excludes balance rows if given the option 'exclude_balance_rows'" do
|
206
|
-
document_without_balance_rows = Sie::Document.new(data_source, exclude_balance_rows: true)
|
207
|
-
sie_file = Sie::Parser.new.parse(document_without_balance_rows.render)
|
208
|
-
expect(sie_file.entries_with_label("ib")).to be_empty
|
209
|
-
expect(sie_file.entries_with_label("ub")).to be_empty
|
210
|
-
expect(sie_file.entries_with_label("res")).to be_empty
|
211
|
-
|
212
|
-
document_with_balance_rows = Sie::Document.new(data_source, exclude_balance_rows: false)
|
213
|
-
sie_file = Sie::Parser.new.parse(document_with_balance_rows.render)
|
214
|
-
expect(sie_file.entries_with_label("ib")).not_to be_empty
|
215
|
-
expect(sie_file.entries_with_label("ub")).not_to be_empty
|
216
|
-
expect(sie_file.entries_with_label("res")).not_to be_empty
|
217
|
-
|
218
|
-
document_will_default_with_balance_rows = Sie::Document.new(data_source)
|
219
|
-
sie_file = Sie::Parser.new.parse(document_will_default_with_balance_rows.render)
|
220
|
-
expect(sie_file.entries_with_label("ib")).not_to be_empty
|
221
|
-
expect(sie_file.entries_with_label("ub")).not_to be_empty
|
222
|
-
expect(sie_file.entries_with_label("res")).not_to be_empty
|
223
|
-
end
|
224
|
-
|
225
|
-
context "with really long descriptions" do
|
226
|
-
let(:accounts) {
|
227
|
-
[
|
228
|
-
number: 1500, description: "k" * 101 # Make sure that the description exceeds the limit (100 chars).
|
229
|
-
]
|
230
|
-
}
|
231
|
-
let(:vouchers) {
|
232
|
-
[
|
233
|
-
build_voucher(
|
234
|
-
description: "d" * 101,
|
235
|
-
voucher_lines: [
|
236
|
-
build_voucher_line(description: "v" * 101),
|
237
|
-
build_voucher_line(description: "Payout line 2"),
|
238
|
-
]
|
239
|
-
)
|
240
|
-
]
|
241
|
-
}
|
242
|
-
|
243
|
-
it "truncates the descriptions" do
|
244
|
-
expect(indexed_entry_attributes("konto", 0)).to eq("kontonr" => "1500", "kontonamn" => "k" * 100)
|
245
|
-
expect(indexed_entry("ver", 0).attributes["vertext"]).to eq("d" * 100)
|
246
|
-
expect(indexed_voucher_entries(0)[0].attributes["transtext"]).to eq("v" * 100)
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
context "with a zeroed single voucher line" do
|
251
|
-
let(:vouchers) {
|
252
|
-
[
|
253
|
-
build_voucher(voucher_lines: [ build_voucher_line(amount: 0) ])
|
254
|
-
]
|
255
|
-
}
|
256
|
-
|
257
|
-
it "ensures there are at least two lines" do
|
258
|
-
expect(indexed_voucher_entries(0).size).to eq(2)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
context "with a series defined" do
|
263
|
-
let(:vouchers) {
|
264
|
-
[
|
265
|
-
build_voucher(series: "X"),
|
266
|
-
]
|
267
|
-
}
|
268
|
-
|
269
|
-
it "reads the series from the voucher" do
|
270
|
-
expect(indexed_entry("ver", 0).attributes["serie"]).to eq("X")
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
private
|
275
|
-
|
276
|
-
def build_voucher(attributes)
|
277
|
-
defaults = {
|
278
|
-
creditor: true,
|
279
|
-
type: :payment,
|
280
|
-
number: 1,
|
281
|
-
booked_on: Date.today,
|
282
|
-
description: "A voucher",
|
283
|
-
voucher_lines: [
|
284
|
-
build_voucher_line,
|
285
|
-
build_voucher_line,
|
286
|
-
],
|
287
|
-
}
|
288
|
-
defaults.merge(attributes)
|
289
|
-
end
|
290
|
-
|
291
|
-
def build_voucher_line(attributes = {})
|
292
|
-
defaults = { account_number: 1234, amount: 1, booked_on: Date.today, description: "A voucher line" }
|
293
|
-
defaults.merge(attributes)
|
294
|
-
end
|
295
|
-
|
296
|
-
def entry_attribute(label, attribute)
|
297
|
-
indexed_entry_attribute(label, 0, attribute)
|
298
|
-
end
|
299
|
-
|
300
|
-
def indexed_entry_attribute(label, index, attribute)
|
301
|
-
indexed_entry_attributes(label, index).fetch(attribute) do
|
302
|
-
raise "Unknown attribute #{ attribute } in #{ entry.attributes.keys.inspect }"
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
def indexed_entry_attributes(label, index)
|
307
|
-
indexed_entry(label, index).attributes
|
308
|
-
end
|
309
|
-
|
310
|
-
def indexed_voucher_entries(index)
|
311
|
-
indexed_entry("ver", index).entries
|
312
|
-
end
|
313
|
-
|
314
|
-
def indexed_entry(label, index)
|
315
|
-
sie_file.entries_with_label(label)[index] or raise "No entry with label #{ label.inspect } found!"
|
316
|
-
end
|
317
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser/line_parser"
|
3
|
-
|
4
|
-
describe Sie::Parser::LineParser, "parse" do
|
5
|
-
it "parses lines from a sie file" do
|
6
|
-
parser = Sie::Parser::LineParser.new('#TRANS 2400 {"3" "5"} -200 20130101 "Foocorp expense"')
|
7
|
-
entry = parser.parse
|
8
|
-
expect(entry.label).to eq("trans")
|
9
|
-
expect(entry.attributes).to eq({
|
10
|
-
"kontonr" => "2400",
|
11
|
-
"belopp" => "-200",
|
12
|
-
"transdat" => "20130101",
|
13
|
-
"transtext" => "Foocorp expense",
|
14
|
-
"objektlista" => [{"dimensionsnr" => "3", "objektnr" => "5"}],
|
15
|
-
})
|
16
|
-
end
|
17
|
-
|
18
|
-
context "with unknown entry" do
|
19
|
-
let(:line) { "#MOMSKOD 2611 10"}
|
20
|
-
|
21
|
-
context "using a lenient parser" do
|
22
|
-
let(:parser) { Sie::Parser::LineParser.new(line, lenient: true) }
|
23
|
-
|
24
|
-
it "raises no error when encountering unknown entries" do
|
25
|
-
expect { parser.parse }.not_to raise_error
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "using a strict parser" do
|
30
|
-
let(:parser) { Sie::Parser::LineParser.new(line) }
|
31
|
-
|
32
|
-
it "raises error when encountering unknown entries" do
|
33
|
-
expect { parser.parse }.to raise_error(/Unknown entry type/)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser/tokenizer"
|
3
|
-
|
4
|
-
describe Sie::Parser::Tokenizer do
|
5
|
-
it "tokenizes the given line" do
|
6
|
-
tokenizer = Sie::Parser::Tokenizer.new('#TRANS 2400 {} -200 20130101 "Foocorp expense"')
|
7
|
-
tokens = tokenizer.tokenize
|
8
|
-
|
9
|
-
expect(token_table_for(tokens)).to eq([
|
10
|
-
[ "EntryToken", "TRANS" ],
|
11
|
-
[ "StringToken", "2400" ],
|
12
|
-
[ "BeginArrayToken", "" ],
|
13
|
-
[ "EndArrayToken", "" ],
|
14
|
-
[ "StringToken", "-200" ],
|
15
|
-
[ "StringToken", "20130101" ],
|
16
|
-
[ "StringToken", "Foocorp expense" ]
|
17
|
-
])
|
18
|
-
end
|
19
|
-
|
20
|
-
it "can parse metadata arrays" do
|
21
|
-
tokenizer = Sie::Parser::Tokenizer.new('#TRANS 2400 { 1 "2" } -200 20130101 "Foocorp expense"')
|
22
|
-
tokens = tokenizer.tokenize
|
23
|
-
|
24
|
-
expect(token_table_for(tokens)).to eq([
|
25
|
-
[ "EntryToken", "TRANS" ],
|
26
|
-
[ "StringToken", "2400" ],
|
27
|
-
[ "BeginArrayToken", "" ],
|
28
|
-
[ "StringToken", "1" ],
|
29
|
-
[ "StringToken", "2" ],
|
30
|
-
[ "EndArrayToken", "" ],
|
31
|
-
[ "StringToken", "-200" ],
|
32
|
-
[ "StringToken", "20130101" ],
|
33
|
-
[ "StringToken", "Foocorp expense" ]
|
34
|
-
])
|
35
|
-
end
|
36
|
-
|
37
|
-
it "handles escaped quotes in quoted strings" do
|
38
|
-
tokenizer = Sie::Parser::Tokenizer.new('"String with \\" quote"')
|
39
|
-
tokens = tokenizer.tokenize
|
40
|
-
|
41
|
-
expect(token_table_for(tokens)).to eq([
|
42
|
-
[ "StringToken", 'String with " quote']
|
43
|
-
])
|
44
|
-
end
|
45
|
-
|
46
|
-
it "handles escaped quotes in non-quoted strings" do
|
47
|
-
tokenizer = Sie::Parser::Tokenizer.new('String_with_\\"_quote')
|
48
|
-
tokens = tokenizer.tokenize
|
49
|
-
|
50
|
-
expect(token_table_for(tokens)).to eq([
|
51
|
-
[ "StringToken", 'String_with_"_quote']
|
52
|
-
])
|
53
|
-
end
|
54
|
-
|
55
|
-
it "handles escaped backslash in strings" do
|
56
|
-
tokenizer = Sie::Parser::Tokenizer.new('"String with \\\\ backslash"')
|
57
|
-
tokens = tokenizer.tokenize
|
58
|
-
|
59
|
-
expect(token_table_for(tokens)).to eq([
|
60
|
-
[ "StringToken", 'String with \\ backslash']
|
61
|
-
])
|
62
|
-
end
|
63
|
-
|
64
|
-
it "has reasonable behavior for consecutive escape characters" do
|
65
|
-
tokenizer = Sie::Parser::Tokenizer.new('"\\\\\\"\\\\"')
|
66
|
-
tokens = tokenizer.tokenize
|
67
|
-
|
68
|
-
expect(token_table_for(tokens)).to eq([
|
69
|
-
[ "StringToken", '\\"\\']
|
70
|
-
])
|
71
|
-
end
|
72
|
-
|
73
|
-
it "handles tab character as field separator" do
|
74
|
-
tokenizer = Sie::Parser::Tokenizer.new("#TRANS\t2400")
|
75
|
-
tokens = tokenizer.tokenize
|
76
|
-
|
77
|
-
expect(token_table_for(tokens)).to eq([
|
78
|
-
[ "EntryToken", "TRANS"],
|
79
|
-
[ "StringToken", "2400"]
|
80
|
-
])
|
81
|
-
end
|
82
|
-
|
83
|
-
it "rejects control characters" do
|
84
|
-
codes_not_allowed = (0..8).to_a + (10..31).to_a + [127]
|
85
|
-
codes_not_allowed.each do |x|
|
86
|
-
tokenizer = Sie::Parser::Tokenizer.new([x].pack("C"))
|
87
|
-
expect{tokenizer.tokenize}.to raise_error /Unhandled character/
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
def token_table_for(tokens)
|
94
|
-
tokens.map { |token|
|
95
|
-
[ token.class.name.split("::").last, token.value ]
|
96
|
-
}
|
97
|
-
end
|
98
|
-
end
|
data/spec/unit/parser_spec.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "sie/parser"
|
3
|
-
|
4
|
-
describe Sie::Parser, "parse" do
|
5
|
-
it "parses sie data that includes arrays" do
|
6
|
-
data = <<-DATA
|
7
|
-
#VER "LF" 2222 20130101 "Foocorp expense"
|
8
|
-
{
|
9
|
-
#TRANS 2400 {} -200 20130101 "Foocorp expense"
|
10
|
-
#TRANS 4100 {} 180 20130101 "Widgets from foocorp"
|
11
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
12
|
-
}
|
13
|
-
DATA
|
14
|
-
|
15
|
-
parser = Sie::Parser.new
|
16
|
-
sie_file = parser.parse(data)
|
17
|
-
|
18
|
-
voucher_entry = sie_file.entries.first
|
19
|
-
expect(sie_file.entries.size).to eq(1)
|
20
|
-
expect(voucher_entry.attributes["verdatum"]).to eq("20130101")
|
21
|
-
expect(voucher_entry.entries.size).to eq(3)
|
22
|
-
expect(voucher_entry.entries.first.attributes["kontonr"]).to eq("2400")
|
23
|
-
end
|
24
|
-
|
25
|
-
it "handles leading whitespace" do
|
26
|
-
data = <<-DATA
|
27
|
-
#VER "LF" 2222 20130101 "Foocorp expense"
|
28
|
-
{
|
29
|
-
#TRANS 2400 {} -200 20130101 "Foocorp expense"
|
30
|
-
#TRANS 4100 {} 180 20130101 "Widgets from foocorp"
|
31
|
-
#TRANS 2611 {} -20 20130101 "VAT"
|
32
|
-
}
|
33
|
-
DATA
|
34
|
-
|
35
|
-
parser = Sie::Parser.new
|
36
|
-
sie_file = parser.parse(data)
|
37
|
-
|
38
|
-
voucher_entry = sie_file.entries.first
|
39
|
-
expect(sie_file.entries.size).to eq(1)
|
40
|
-
expect(voucher_entry.entries.size).to eq(3)
|
41
|
-
end
|
42
|
-
end
|