csv_decision2 0.5.1 → 0.5.2
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 +4 -4
- data/Dockerfile +1 -1
- data/README.md +16 -16
- data/benchmarks/rufus_decision.rb +5 -7
- data/csv_decision2.gemspec +2 -2
- data/doc/CSVDecision/CellValidationError.html +117 -110
- data/doc/CSVDecision/Columns/Default.html +537 -508
- data/doc/CSVDecision/Columns/Dictionary.html +729 -686
- data/doc/CSVDecision/Columns/Entry.html +457 -433
- data/doc/CSVDecision/Columns.html +1134 -1051
- data/doc/CSVDecision/Constant.html +205 -191
- data/doc/CSVDecision/Data.html +423 -398
- data/doc/CSVDecision/Decide.html +236 -225
- data/doc/CSVDecision/Decision.html +872 -825
- data/doc/CSVDecision/Defaults.html +243 -230
- data/doc/CSVDecision/Dictionary/Entry.html +1026 -964
- data/doc/CSVDecision/Dictionary.html +377 -355
- data/doc/CSVDecision/Error.html +116 -105
- data/doc/CSVDecision/FileError.html +117 -110
- data/doc/CSVDecision/Function.html +181 -168
- data/doc/CSVDecision/Guard.html +200 -185
- data/doc/CSVDecision/Header.html +557 -523
- data/doc/CSVDecision/Index.html +652 -617
- data/doc/CSVDecision/Input.html +329 -312
- data/doc/CSVDecision/Load.html +232 -220
- data/doc/CSVDecision/Matchers/Constant.html +432 -399
- data/doc/CSVDecision/Matchers/Function.html +451 -415
- data/doc/CSVDecision/Matchers/Guard.html +459 -424
- data/doc/CSVDecision/Matchers/Matcher.html +470 -426
- data/doc/CSVDecision/Matchers/Numeric.html +375 -346
- data/doc/CSVDecision/Matchers/Pattern.html +429 -396
- data/doc/CSVDecision/Matchers/Proc.html +617 -575
- data/doc/CSVDecision/Matchers/Range.html +331 -302
- data/doc/CSVDecision/Matchers/Symbol.html +386 -353
- data/doc/CSVDecision/Matchers.html +1509 -1393
- data/doc/CSVDecision/Numeric.html +201 -188
- data/doc/CSVDecision/Options.html +376 -357
- data/doc/CSVDecision/Parse.html +217 -204
- data/doc/CSVDecision/Paths.html +664 -629
- data/doc/CSVDecision/Result.html +1076 -1005
- data/doc/CSVDecision/Scan/InputHashes.html +305 -288
- data/doc/CSVDecision/Scan.html +262 -249
- data/doc/CSVDecision/ScanRow.html +749 -705
- data/doc/CSVDecision/Symbol.html +204 -191
- data/doc/CSVDecision/Table.html +1391 -1305
- data/doc/CSVDecision/TableValidationError.html +117 -110
- data/doc/CSVDecision/Validate.html +353 -337
- data/doc/CSVDecision.html +623 -552
- data/doc/_index.html +488 -448
- data/doc/class_list.html +250 -45
- data/doc/file.README.html +304 -278
- data/doc/index.html +304 -278
- data/doc/method_list.html +1159 -1017
- data/doc/top-level-namespace.html +79 -75
- data/lib/{csv_decision → csv_decision2}/columns.rb +7 -7
- data/lib/{csv_decision → csv_decision2}/data.rb +1 -1
- data/lib/{csv_decision → csv_decision2}/decision.rb +5 -5
- data/lib/{csv_decision → csv_decision2}/defaults.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/dictionary.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/header.rb +5 -5
- data/lib/{csv_decision → csv_decision2}/index.rb +5 -5
- data/lib/{csv_decision → csv_decision2}/input.rb +3 -3
- data/lib/{csv_decision → csv_decision2}/load.rb +6 -6
- data/lib/{csv_decision → csv_decision2}/matchers/constant.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers/function.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers/guard.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers/numeric.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers/pattern.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers/range.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers/symbol.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/matchers.rb +5 -5
- data/lib/{csv_decision → csv_decision2}/options.rb +3 -3
- data/lib/{csv_decision → csv_decision2}/parse.rb +14 -14
- data/lib/{csv_decision → csv_decision2}/paths.rb +5 -5
- data/lib/{csv_decision → csv_decision2}/result.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/scan.rb +3 -3
- data/lib/{csv_decision → csv_decision2}/scan_row.rb +2 -2
- data/lib/{csv_decision → csv_decision2}/table.rb +8 -8
- data/lib/{csv_decision → csv_decision2}/validate.rb +2 -2
- data/lib/csv_decision2.rb +45 -0
- data/spec/{csv_decision → csv_decision2}/columns_spec.rb +44 -44
- data/spec/{csv_decision → csv_decision2}/constant_spec.rb +4 -4
- data/spec/{csv_decision → csv_decision2}/data_spec.rb +11 -11
- data/spec/{csv_decision → csv_decision2}/decision_spec.rb +6 -6
- data/spec/{csv_decision → csv_decision2}/examples_spec.rb +14 -14
- data/spec/{csv_decision → csv_decision2}/index_spec.rb +8 -8
- data/spec/{csv_decision → csv_decision2}/input_spec.rb +9 -9
- data/spec/{csv_decision → csv_decision2}/load_spec.rb +8 -8
- data/spec/{csv_decision → csv_decision2}/matchers/function_spec.rb +7 -7
- data/spec/{csv_decision → csv_decision2}/matchers/guard_spec.rb +14 -14
- data/spec/{csv_decision → csv_decision2}/matchers/numeric_spec.rb +5 -5
- data/spec/{csv_decision → csv_decision2}/matchers/pattern_spec.rb +6 -6
- data/spec/{csv_decision → csv_decision2}/matchers/range_spec.rb +5 -5
- data/spec/{csv_decision → csv_decision2}/matchers/symbol_spec.rb +6 -6
- data/spec/{csv_decision → csv_decision2}/options_spec.rb +18 -18
- data/spec/csv_decision2/parse_spec.rb +44 -0
- data/spec/{csv_decision → csv_decision2}/table_spec.rb +17 -17
- data/spec/csv_decision2_spec.rb +7 -0
- metadata +64 -64
- data/lib/csv_decision.rb +0 -45
- data/spec/csv_decision/parse_spec.rb +0 -44
- data/spec/csv_decision_spec.rb +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../lib/
|
|
3
|
+
require_relative '../../lib/csv_decision2'
|
|
4
4
|
|
|
5
5
|
context 'simple examples' do
|
|
6
6
|
context 'simple example - strings-only' do
|
|
@@ -18,7 +18,7 @@ context 'simple examples' do
|
|
|
18
18
|
DATA
|
|
19
19
|
|
|
20
20
|
it 'makes correct decisions for CSV string' do
|
|
21
|
-
table =
|
|
21
|
+
table = CSVDecision2.parse(data)
|
|
22
22
|
|
|
23
23
|
result = table.decide(topic: 'finance', region: 'Europe')
|
|
24
24
|
expect(result).to eq(team_member: 'Donald')
|
|
@@ -31,7 +31,7 @@ context 'simple examples' do
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
it 'makes correct decisions for CSV file' do
|
|
34
|
-
table =
|
|
34
|
+
table = CSVDecision2.parse(Pathname('spec/data/valid/simple_example.csv'))
|
|
35
35
|
|
|
36
36
|
result = table.decide(topic: 'finance', region: 'Europe')
|
|
37
37
|
expect(result).to eq(team_member: 'Donald')
|
|
@@ -55,7 +55,7 @@ context 'simple examples' do
|
|
|
55
55
|
DATA
|
|
56
56
|
|
|
57
57
|
it 'makes correct decisions for CSV string' do
|
|
58
|
-
table =
|
|
58
|
+
table = CSVDecision2.parse(data)
|
|
59
59
|
|
|
60
60
|
result = table.decide(constant: nil)
|
|
61
61
|
expect(result).to eq(value: nil)
|
|
@@ -82,7 +82,7 @@ context 'simple examples' do
|
|
|
82
82
|
DATA
|
|
83
83
|
|
|
84
84
|
it 'makes correct decisions' do
|
|
85
|
-
table =
|
|
85
|
+
table = CSVDecision2.parse(data)
|
|
86
86
|
|
|
87
87
|
result = table.decide(node: 0, parent: 0)
|
|
88
88
|
expect(result).to eq(top?: 'yes')
|
|
@@ -103,7 +103,7 @@ context 'simple examples' do
|
|
|
103
103
|
DATA
|
|
104
104
|
|
|
105
105
|
it 'makes correct decisions' do
|
|
106
|
-
table =
|
|
106
|
+
table = CSVDecision2.parse(data)
|
|
107
107
|
|
|
108
108
|
result = table.decide(node: 0, parent: 0)
|
|
109
109
|
expect(result).to eq(top?: 'yes')
|
|
@@ -124,7 +124,7 @@ context 'simple examples' do
|
|
|
124
124
|
, <:traded, invalid trade
|
|
125
125
|
, , invalid data
|
|
126
126
|
DATA
|
|
127
|
-
table =
|
|
127
|
+
table = CSVDecision2.parse(data)
|
|
128
128
|
|
|
129
129
|
expect(table.columns.input_keys).to eq %i[traded settled]
|
|
130
130
|
|
|
@@ -136,7 +136,7 @@ context 'simple examples' do
|
|
|
136
136
|
expect(table.decide(traded: 20171228, settled: 20171227 )).to eq(status: 'invalid trade')
|
|
137
137
|
expect(table.decide(traded: '20171227', settled: 20171228 )).to eq(status: 'invalid data')
|
|
138
138
|
end
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
it 'makes a correct decision using a guard column' do
|
|
141
141
|
data = <<~DATA
|
|
142
142
|
in :country, guard:, out :ID, out :ID_type, out :len
|
|
@@ -148,7 +148,7 @@ context 'simple examples' do
|
|
|
148
148
|
, , := nil, := nil, := nil
|
|
149
149
|
DATA
|
|
150
150
|
|
|
151
|
-
table =
|
|
151
|
+
table = CSVDecision2.parse(data)
|
|
152
152
|
|
|
153
153
|
expect(table.decide(country: 'US', CUSIP: '123456789'))
|
|
154
154
|
.to eq(ID: '123456789', ID_type: 'CUSIP', len: 9)
|
|
@@ -167,7 +167,7 @@ context 'simple examples' do
|
|
|
167
167
|
, :CUSIP.present?, :CUSIP, DUMMY, :ID.length,
|
|
168
168
|
DATA
|
|
169
169
|
|
|
170
|
-
table =
|
|
170
|
+
table = CSVDecision2.parse(data)
|
|
171
171
|
|
|
172
172
|
expect(table.decide(country: 'US', CUSIP: '12345678'))
|
|
173
173
|
.to eq(ID: '12345678', ID_type: 'CUSIP8', len: 8)
|
|
@@ -191,7 +191,7 @@ context 'simple examples' do
|
|
|
191
191
|
!=US, :ISIN.present?, PRIVATE, :ISIN, :PAID.length,
|
|
192
192
|
DATA
|
|
193
193
|
|
|
194
|
-
table =
|
|
194
|
+
table = CSVDecision2.parse(data)
|
|
195
195
|
expect(table.decide(CUSIP: '1234567890', class: 'Private')).to eq(PAID: '1234567890', len: 10)
|
|
196
196
|
expect(table.decide(CUSIP: '123456789', class: 'Public')).to eq(PAID: '123456789', len: 9)
|
|
197
197
|
expect(table.decide(ISIN: '123456789', country: 'GB', class: 'public')).to eq({})
|
|
@@ -208,7 +208,7 @@ context 'simple examples' do
|
|
|
208
208
|
!=US, , !.blank?, PRIVATE, :ISIN, :PAID.length,
|
|
209
209
|
DATA
|
|
210
210
|
|
|
211
|
-
table =
|
|
211
|
+
table = CSVDecision2.parse(data)
|
|
212
212
|
expect(table.decide(CUSIP: '1234567890', class: 'Private')).to eq(PAID: '1234567890', len: 10)
|
|
213
213
|
expect(table.decide(CUSIP: '123456789', class: 'Public')).to eq(PAID: '123456789', len: 9)
|
|
214
214
|
expect(table.decide(ISIN: '123456789', country: 'GB', class: 'public')).to eq({})
|
|
@@ -223,7 +223,7 @@ context 'simple examples' do
|
|
|
223
223
|
payload, , :amount
|
|
224
224
|
payload, ref_data, :account_id
|
|
225
225
|
DATA
|
|
226
|
-
table =
|
|
226
|
+
table = CSVDecision2.parse(data, first_match: false)
|
|
227
227
|
|
|
228
228
|
input = {
|
|
229
229
|
header: {
|
|
@@ -239,4 +239,4 @@ context 'simple examples' do
|
|
|
239
239
|
expect(table.decide(input)).to eq(value: %w[Client Trading 100.00 5010])
|
|
240
240
|
expect(table.decide!(input)).to eq(value: %w[Client Trading 100.00 5010])
|
|
241
241
|
end
|
|
242
|
-
end
|
|
242
|
+
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../lib/
|
|
3
|
+
require_relative '../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
SPEC_DATA_VALID ||= File.join(
|
|
6
|
-
SPEC_DATA_INVALID ||= File.join(
|
|
5
|
+
SPEC_DATA_VALID ||= File.join(CSVDecision2.root, 'spec', 'data', 'valid')
|
|
6
|
+
SPEC_DATA_INVALID ||= File.join(CSVDecision2.root, 'spec', 'data', 'invalid')
|
|
7
7
|
|
|
8
|
-
describe
|
|
8
|
+
describe CSVDecision2::Index do
|
|
9
9
|
it 'indexes a single column CSV' do
|
|
10
10
|
file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file3.csv'))
|
|
11
|
-
result =
|
|
11
|
+
result = CSVDecision2.parse(file)
|
|
12
12
|
|
|
13
13
|
expected = {
|
|
14
14
|
'none' => 0,
|
|
@@ -28,7 +28,7 @@ describe CSVDecision::Index do
|
|
|
28
28
|
|
|
29
29
|
it 'indexes two columns with contiguous values' do
|
|
30
30
|
file = Pathname(File.join(SPEC_DATA_VALID, 'multi_column_index.csv'))
|
|
31
|
-
result =
|
|
31
|
+
result = CSVDecision2.parse(file)
|
|
32
32
|
|
|
33
33
|
expected = {
|
|
34
34
|
%w[integer none] => [[0, 1]],
|
|
@@ -43,7 +43,7 @@ describe CSVDecision::Index do
|
|
|
43
43
|
|
|
44
44
|
it 'indexes two columns with non-contiguous values' do
|
|
45
45
|
file = Pathname(File.join(SPEC_DATA_VALID, 'multi_column_index2.csv'))
|
|
46
|
-
result =
|
|
46
|
+
result = CSVDecision2.parse(file)
|
|
47
47
|
|
|
48
48
|
expected = {
|
|
49
49
|
%w[integer none] => [0, 8],
|
|
@@ -55,4 +55,4 @@ describe CSVDecision::Index do
|
|
|
55
55
|
expect(result.index.columns).to eq [1, 2]
|
|
56
56
|
expect(result.index.hash).to eql expected
|
|
57
57
|
end
|
|
58
|
-
end
|
|
58
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../lib/
|
|
3
|
+
require_relative '../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Input do
|
|
6
6
|
it 'rejects a non-hash or empty hash value' do
|
|
7
|
-
expect {
|
|
7
|
+
expect { CSVDecision2::Input.parse(table: nil, input: [], symbolize_keys: true ) }
|
|
8
8
|
.to raise_error(ArgumentError, 'input must be a non-empty hash')
|
|
9
|
-
expect {
|
|
9
|
+
expect { CSVDecision2::Input.parse(table: nil, input: {}, symbolize_keys: true ) }
|
|
10
10
|
.to raise_error(ArgumentError, 'input must be a non-empty hash')
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -17,7 +17,7 @@ describe CSVDecision::Input do
|
|
|
17
17
|
input0, output1,
|
|
18
18
|
DATA
|
|
19
19
|
|
|
20
|
-
table =
|
|
20
|
+
table = CSVDecision2.parse(data)
|
|
21
21
|
|
|
22
22
|
input = { 'input' => 'input0', input1: 'input1' }
|
|
23
23
|
expected = {
|
|
@@ -26,7 +26,7 @@ describe CSVDecision::Input do
|
|
|
26
26
|
key: 'input0'
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
result =
|
|
29
|
+
result = CSVDecision2::Input.parse(table: table, input: input, symbolize_keys: true)
|
|
30
30
|
|
|
31
31
|
expect(result).to eql expected
|
|
32
32
|
expect(result[:hash]).not_to equal expected[:hash]
|
|
@@ -39,7 +39,7 @@ describe CSVDecision::Input do
|
|
|
39
39
|
input0, output1,
|
|
40
40
|
DATA
|
|
41
41
|
|
|
42
|
-
table =
|
|
42
|
+
table = CSVDecision2.parse(data)
|
|
43
43
|
input = { input: 'input0', input1: 'input1' }
|
|
44
44
|
expected = {
|
|
45
45
|
hash: input,
|
|
@@ -47,9 +47,9 @@ describe CSVDecision::Input do
|
|
|
47
47
|
key: 'input0'
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
result =
|
|
50
|
+
result = CSVDecision2::Input.parse(table: table, input: input, symbolize_keys: false)
|
|
51
51
|
|
|
52
52
|
expect(result).to eql expected
|
|
53
53
|
expect(result[:hash]).to equal expected[:hash]
|
|
54
54
|
end
|
|
55
|
-
end
|
|
55
|
+
end
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../lib/
|
|
3
|
+
require_relative '../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
6
|
-
path = Pathname(File.join(
|
|
5
|
+
describe CSVDecision2::Load do
|
|
6
|
+
path = Pathname(File.join(CSVDecision2.root, 'spec/data/valid'))
|
|
7
7
|
|
|
8
8
|
it "loads all valid CSV files in the directory" do
|
|
9
|
-
tables =
|
|
9
|
+
tables = CSVDecision2.load(path, first_match: false, regexp_implicit: true)
|
|
10
10
|
expect(tables).to be_a Hash
|
|
11
11
|
expect(tables.count).to eq Dir[path.join('*.csv')].count
|
|
12
12
|
|
|
13
13
|
tables.each_pair do |name, table|
|
|
14
14
|
expect(name).to be_a(Symbol)
|
|
15
|
-
expect(table).to be_a(
|
|
15
|
+
expect(table).to be_a(CSVDecision2::Table)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
it 'rejects an invalid path name' do
|
|
20
|
-
expect {
|
|
20
|
+
expect { CSVDecision2.load('path') }
|
|
21
21
|
.to raise_error(ArgumentError, 'path argument must be a Pathname')
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'rejects an invalid folder name' do
|
|
25
|
-
expect {
|
|
25
|
+
expect { CSVDecision2.load(Pathname('path')) }
|
|
26
26
|
.to raise_error(ArgumentError, 'path argument not a valid folder')
|
|
27
27
|
end
|
|
28
|
-
end
|
|
28
|
+
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../lib/
|
|
3
|
+
require_relative '../../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Matchers::Function do
|
|
6
6
|
subject { described_class.new }
|
|
7
7
|
|
|
8
8
|
describe '#new' do
|
|
9
|
-
it { is_expected.to be_a
|
|
10
|
-
it { is_expected.to be_a
|
|
9
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Function }
|
|
10
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Matcher }
|
|
11
11
|
it { is_expected.to respond_to(:matches?).with(1).argument }
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ describe CSVDecision::Matchers::Function do
|
|
|
21
21
|
}
|
|
22
22
|
cells.each_pair do |cell, expected|
|
|
23
23
|
it "recognises #{cell} as a function" do
|
|
24
|
-
match =
|
|
24
|
+
match = CSVDecision2::Matchers::Function::FUNCTION_RE.match(cell)
|
|
25
25
|
expect(match['operator']).to eq expected[:operator]
|
|
26
26
|
expect(match['name']).to eq expected[:name]
|
|
27
27
|
end
|
|
@@ -63,7 +63,7 @@ describe CSVDecision::Matchers::Function do
|
|
|
63
63
|
# examples.each do |ex|
|
|
64
64
|
# it "cell #{ex[:cell]} matches value: #{ex[:value]} to hash: #{ex[:hash]}" do
|
|
65
65
|
# proc = matcher.matches?(ex[:cell])
|
|
66
|
-
# expect(proc).to be_a(
|
|
66
|
+
# expect(proc).to be_a(CSVDecision2::Proc)
|
|
67
67
|
# expect(proc.function.call(ex[:value], ex[:hash])).to eq ex[:result]
|
|
68
68
|
# end
|
|
69
69
|
# end
|
|
@@ -79,4 +79,4 @@ describe CSVDecision::Matchers::Function do
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
|
-
end
|
|
82
|
+
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../lib/
|
|
3
|
+
require_relative '../../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Matchers::Guard do
|
|
6
6
|
subject { described_class.new }
|
|
7
7
|
|
|
8
8
|
describe '#new' do
|
|
9
|
-
it { is_expected.to be_a
|
|
10
|
-
it { is_expected.to be_a
|
|
9
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Guard }
|
|
10
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Matcher }
|
|
11
11
|
it { is_expected.to respond_to(:matches?).with(1).argument }
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -116,7 +116,7 @@ describe CSVDecision::Matchers::Guard do
|
|
|
116
116
|
examples.each do |ex|
|
|
117
117
|
it "cell #{ex[:cell]} matches to hash: #{ex[:hash]}" do
|
|
118
118
|
proc = matcher.matches?(ex[:cell])
|
|
119
|
-
expect(proc).to be_a(
|
|
119
|
+
expect(proc).to be_a(CSVDecision2::Matchers::Proc)
|
|
120
120
|
expect(proc.type).to eq :guard
|
|
121
121
|
expect(proc.function.call(ex[:hash])).to eq ex[:result]
|
|
122
122
|
end
|
|
@@ -145,8 +145,8 @@ describe CSVDecision::Matchers::Guard do
|
|
|
145
145
|
DATA
|
|
146
146
|
|
|
147
147
|
specify do
|
|
148
|
-
expect {
|
|
149
|
-
.to raise_error(
|
|
148
|
+
expect { CSVDecision2.parse(data) }
|
|
149
|
+
.to raise_error(CSVDecision2::CellValidationError, 'guard: column cannot contain constants')
|
|
150
150
|
end
|
|
151
151
|
end
|
|
152
152
|
|
|
@@ -154,17 +154,17 @@ describe CSVDecision::Matchers::Guard do
|
|
|
154
154
|
data = <<~DATA
|
|
155
155
|
IN :country, guard : country, out :PAID, out :PAID_type, if:
|
|
156
156
|
US, :CUSIP.present?, :CUSIP, CUSIP, TRUE
|
|
157
|
-
GB, :SEDOL.present?, :SEDOL, SEDOL,
|
|
158
|
-
, :ISIN.present?, :ISIN, ISIN,
|
|
159
|
-
, :SEDOL.present?, :SEDOL, SEDOL,
|
|
160
|
-
, :CUSIP.present?, :CUSIP, CUSIP,
|
|
157
|
+
GB, :SEDOL.present?, :SEDOL, SEDOL,
|
|
158
|
+
, :ISIN.present?, :ISIN, ISIN,
|
|
159
|
+
, :SEDOL.present?, :SEDOL, SEDOL,
|
|
160
|
+
, :CUSIP.present?, :CUSIP, CUSIP,
|
|
161
161
|
, := nil, := nil, MISSING, := nil
|
|
162
162
|
DATA
|
|
163
163
|
|
|
164
164
|
specify do
|
|
165
|
-
expect {
|
|
166
|
-
.to raise_error(
|
|
165
|
+
expect { CSVDecision2.parse(data) }
|
|
166
|
+
.to raise_error(CSVDecision2::CellValidationError, 'if: column cannot contain constants')
|
|
167
167
|
end
|
|
168
168
|
end
|
|
169
169
|
end
|
|
170
|
-
end
|
|
170
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../lib/
|
|
3
|
+
require_relative '../../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Matchers::Numeric do
|
|
6
6
|
subject { described_class.new }
|
|
7
7
|
|
|
8
8
|
describe '#new' do
|
|
9
|
-
it { is_expected.to be_a
|
|
9
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Numeric }
|
|
10
10
|
it { is_expected.to respond_to(:matches?).with(1).argument }
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -27,7 +27,7 @@ describe CSVDecision::Matchers::Numeric do
|
|
|
27
27
|
data.each do |cell, value|
|
|
28
28
|
it "comparision #{cell} matches #{value}" do
|
|
29
29
|
proc = matcher.matches?(cell)
|
|
30
|
-
expect(proc).to be_a(
|
|
30
|
+
expect(proc).to be_a(CSVDecision2::Matchers::Proc)
|
|
31
31
|
expect(proc.type).to eq :proc
|
|
32
32
|
expect(proc.function[value]).to eq true
|
|
33
33
|
end
|
|
@@ -44,4 +44,4 @@ describe CSVDecision::Matchers::Numeric do
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
|
-
end
|
|
47
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../lib/
|
|
3
|
+
require_relative '../../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Matchers::Pattern do
|
|
6
6
|
subject { described_class.new }
|
|
7
7
|
|
|
8
8
|
describe '#new' do
|
|
9
|
-
it { is_expected.to be_a
|
|
9
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Pattern }
|
|
10
10
|
it { is_expected.to respond_to(:matches?).with(1).argument }
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -27,7 +27,7 @@ describe CSVDecision::Matchers::Pattern do
|
|
|
27
27
|
expressions.each do |cell|
|
|
28
28
|
it "recognises regexp #{cell}" do
|
|
29
29
|
proc = matcher.matches?(cell)
|
|
30
|
-
expect(proc).to be_a
|
|
30
|
+
expect(proc).to be_a CSVDecision2::Matchers::Proc
|
|
31
31
|
expect(proc.type).to eq :proc
|
|
32
32
|
expect(proc.function).to be_a ::Proc
|
|
33
33
|
expect(proc.function.arity).to eq -1
|
|
@@ -50,7 +50,7 @@ describe CSVDecision::Matchers::Pattern do
|
|
|
50
50
|
expressions.each do |cell|
|
|
51
51
|
it "recognises regexp #{cell}" do
|
|
52
52
|
proc = matcher.matches?(cell)
|
|
53
|
-
expect(proc).to be_a
|
|
53
|
+
expect(proc).to be_a CSVDecision2::Matchers::Proc
|
|
54
54
|
expect(proc.type).to eq :proc
|
|
55
55
|
expect(proc.function).to be_a ::Proc
|
|
56
56
|
expect(proc.function.arity).to eq -1
|
|
@@ -180,4 +180,4 @@ describe CSVDecision::Matchers::Pattern do
|
|
|
180
180
|
end
|
|
181
181
|
end
|
|
182
182
|
end
|
|
183
|
-
end
|
|
183
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../lib/
|
|
3
|
+
require_relative '../../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Matchers::Range do
|
|
6
6
|
subject { described_class.new }
|
|
7
7
|
|
|
8
8
|
describe '#new' do
|
|
9
|
-
it { is_expected.to be_a
|
|
9
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Range }
|
|
10
10
|
it { is_expected.to respond_to(:matches?).with(1).argument }
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -29,7 +29,7 @@ describe CSVDecision::Matchers::Range do
|
|
|
29
29
|
data.each do |cell, value|
|
|
30
30
|
it "range #{cell} matches #{value}" do
|
|
31
31
|
proc = matcher.matches?(cell)
|
|
32
|
-
expect(proc).to be_a(
|
|
32
|
+
expect(proc).to be_a(CSVDecision2::Matchers::Proc)
|
|
33
33
|
expect(proc.type).to eq :proc
|
|
34
34
|
expect(proc.function[value]).to eq true
|
|
35
35
|
end
|
|
@@ -50,7 +50,7 @@ describe CSVDecision::Matchers::Range do
|
|
|
50
50
|
data.each do |cell, value|
|
|
51
51
|
it "range #{cell} does not match #{value}" do
|
|
52
52
|
proc = matcher.matches?(cell)
|
|
53
|
-
expect(proc).to be_a(
|
|
53
|
+
expect(proc).to be_a(CSVDecision2::Matchers::Proc)
|
|
54
54
|
expect(proc.type).to eq :proc
|
|
55
55
|
expect(proc.function[value]).to eq false
|
|
56
56
|
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../lib/
|
|
3
|
+
require_relative '../../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
describe
|
|
5
|
+
describe CSVDecision2::Matchers::Symbol do
|
|
6
6
|
subject { described_class.new }
|
|
7
7
|
|
|
8
8
|
describe '#new' do
|
|
9
|
-
it { is_expected.to be_a
|
|
10
|
-
it { is_expected.to be_a
|
|
9
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Symbol }
|
|
10
|
+
it { is_expected.to be_a CSVDecision2::Matchers::Matcher }
|
|
11
11
|
it { is_expected.to respond_to(:matches?).with(1).argument }
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -48,7 +48,7 @@ describe CSVDecision::Matchers::Symbol do
|
|
|
48
48
|
examples.each do |ex|
|
|
49
49
|
it "cell #{ex[:cell]} matches value: #{ex[:value]} to hash: #{ex[:hash]}" do
|
|
50
50
|
proc = matcher.matches?(ex[:cell])
|
|
51
|
-
expect(proc).to be_a(
|
|
51
|
+
expect(proc).to be_a(CSVDecision2::Matchers::Proc)
|
|
52
52
|
expect(proc.function.call(ex[:value], ex[:hash])).to eq ex[:result]
|
|
53
53
|
end
|
|
54
54
|
end
|
|
@@ -64,4 +64,4 @@ describe CSVDecision::Matchers::Symbol do
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
|
-
end
|
|
67
|
+
end
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../lib/
|
|
3
|
+
require_relative '../../lib/csv_decision2'
|
|
4
4
|
|
|
5
|
-
SPEC_DATA_VALID ||= File.join(
|
|
6
|
-
SPEC_DATA_INVALID ||= File.join(
|
|
5
|
+
SPEC_DATA_VALID ||= File.join(CSVDecision2.root, 'spec', 'data', 'valid')
|
|
6
|
+
SPEC_DATA_INVALID ||= File.join(CSVDecision2.root, 'spec', 'data', 'invalid')
|
|
7
7
|
|
|
8
|
-
describe
|
|
8
|
+
describe CSVDecision2::Options do
|
|
9
9
|
it 'sets the default options' do
|
|
10
10
|
data = <<~DATA
|
|
11
11
|
IN :input, OUT :output
|
|
12
12
|
input0, output0
|
|
13
13
|
DATA
|
|
14
14
|
|
|
15
|
-
result =
|
|
15
|
+
result = CSVDecision2.parse(data)
|
|
16
16
|
|
|
17
17
|
expected = {
|
|
18
18
|
first_match: true,
|
|
19
19
|
regexp_implicit: false,
|
|
20
20
|
text_only: false,
|
|
21
|
-
matchers:
|
|
21
|
+
matchers: CSVDecision2::Options::DEFAULT_MATCHERS
|
|
22
22
|
}
|
|
23
23
|
expect(result.options).to eql expected
|
|
24
24
|
end
|
|
@@ -29,15 +29,15 @@ describe CSVDecision::Options do
|
|
|
29
29
|
input0, output0
|
|
30
30
|
DATA
|
|
31
31
|
|
|
32
|
-
result =
|
|
32
|
+
result = CSVDecision2.parse(data,
|
|
33
33
|
first_match: false,
|
|
34
|
-
matchers: [
|
|
34
|
+
matchers: [CSVDecision2::Matchers::Pattern])
|
|
35
35
|
|
|
36
36
|
expected = {
|
|
37
37
|
first_match: false,
|
|
38
38
|
regexp_implicit: false,
|
|
39
39
|
text_only: false,
|
|
40
|
-
matchers: [
|
|
40
|
+
matchers: [CSVDecision2::Matchers::Pattern]
|
|
41
41
|
}
|
|
42
42
|
expect(result.options).to eql expected
|
|
43
43
|
end
|
|
@@ -48,47 +48,47 @@ describe CSVDecision::Options do
|
|
|
48
48
|
input0, output0
|
|
49
49
|
DATA
|
|
50
50
|
|
|
51
|
-
expect {
|
|
52
|
-
.to raise_error(
|
|
51
|
+
expect { CSVDecision2.parse(data, bad_option: false) }
|
|
52
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
|
53
53
|
"invalid option(s) supplied: [:bad_option]")
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
it 'parses options from a CSV file' do
|
|
57
57
|
file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file1.csv'))
|
|
58
|
-
result =
|
|
58
|
+
result = CSVDecision2.parse(file)
|
|
59
59
|
|
|
60
60
|
expected = {
|
|
61
61
|
first_match: false,
|
|
62
62
|
regexp_implicit: false,
|
|
63
63
|
text_only: false,
|
|
64
|
-
matchers:
|
|
64
|
+
matchers: CSVDecision2::Options::DEFAULT_MATCHERS
|
|
65
65
|
}
|
|
66
66
|
expect(result.options).to eql expected
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
it 'options from the CSV file override method options' do
|
|
70
70
|
file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file2.csv'))
|
|
71
|
-
result =
|
|
71
|
+
result = CSVDecision2.parse(file, first_match: true, regexp_implicit: nil)
|
|
72
72
|
|
|
73
73
|
expected = {
|
|
74
74
|
first_match: false,
|
|
75
75
|
regexp_implicit: true,
|
|
76
76
|
text_only: false,
|
|
77
|
-
matchers:
|
|
77
|
+
matchers: CSVDecision2::Options::DEFAULT_MATCHERS
|
|
78
78
|
}
|
|
79
79
|
expect(result.options).to eql expected
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
it 'parses index option from the CSV file' do
|
|
83
83
|
file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file3.csv'))
|
|
84
|
-
result =
|
|
84
|
+
result = CSVDecision2.parse(file)
|
|
85
85
|
|
|
86
86
|
expected = {
|
|
87
87
|
first_match: false,
|
|
88
88
|
regexp_implicit: true,
|
|
89
89
|
text_only: false,
|
|
90
|
-
matchers:
|
|
90
|
+
matchers: CSVDecision2::Options::DEFAULT_MATCHERS
|
|
91
91
|
}
|
|
92
92
|
expect(result.options).to eql expected
|
|
93
93
|
end
|
|
94
|
-
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../lib/csv_decision2'
|
|
4
|
+
|
|
5
|
+
describe CSVDecision2::Parse do
|
|
6
|
+
it 'rejects an empty decision table' do
|
|
7
|
+
expect { CSVDecision2.parse('') }
|
|
8
|
+
.to raise_error(CSVDecision2::TableValidationError,
|
|
9
|
+
'table has no header row')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'parses a decision table from a CSV file' do
|
|
13
|
+
file = Pathname(File.join(CSVDecision2.root, 'spec/data/valid', 'valid.csv'))
|
|
14
|
+
result = CSVDecision2.parse(file)
|
|
15
|
+
|
|
16
|
+
expected = [
|
|
17
|
+
['input', '']
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
expect(result).to be_a(CSVDecision2::Table)
|
|
21
|
+
expect(result.rows).to eq expected
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'it parses valid CSV files' do
|
|
25
|
+
Dir[File.join(CSVDecision2.root, 'spec/data/valid/*.csv')].each do |file_name|
|
|
26
|
+
pathname = Pathname(file_name)
|
|
27
|
+
|
|
28
|
+
it "loads CSV file: #{pathname.basename}" do
|
|
29
|
+
expect { CSVDecision2.parse(pathname) }.not_to raise_error
|
|
30
|
+
expect(CSVDecision2.parse(pathname)).to be_a CSVDecision2::Table
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'it rejects invalid CSV files' do
|
|
36
|
+
Dir[File.join(CSVDecision2.root, 'spec/data/invalid/*.csv')].each do |file_name|
|
|
37
|
+
pathname = Pathname(file_name)
|
|
38
|
+
|
|
39
|
+
it "rejects CSV file: #{pathname.basename}" do
|
|
40
|
+
expect { CSVDecision2.parse(pathname) }.to raise_error(CSVDecision2::FileError)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|