csv_decision2 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -4,7 +4,7 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers.
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# All CSVDecision specific errors
|
9
9
|
class Error < StandardError; end
|
10
10
|
|
@@ -22,8 +22,8 @@ module CSVDecision
|
|
22
22
|
#
|
23
23
|
# @example Simple Example
|
24
24
|
# If you have cloned the gem's git repo, then you can run:
|
25
|
-
# table =
|
26
|
-
# #=>
|
25
|
+
# table = CSVDecision2.parse(Pathname('spec/data/valid/simple_example.csv'))
|
26
|
+
# #=> CSVDecision2::Table
|
27
27
|
# table.decide(topic: 'finance', region: 'Europe') #=> team_member: 'Donald'
|
28
28
|
#
|
29
29
|
# @param data [Pathname, File, Array<Array<String>>, String] input data given as
|
@@ -39,24 +39,24 @@ module CSVDecision
|
|
39
39
|
# @option options [Array<Matchers::Matcher>] :matchers May be used to control the inclusion and
|
40
40
|
# ordering of special matchers. (Advanced feature, use with care.)
|
41
41
|
#
|
42
|
-
# @return [
|
42
|
+
# @return [CSVDecision2::Table] Resulting decision table.
|
43
43
|
#
|
44
|
-
# @raise [
|
45
|
-
# @raise [
|
44
|
+
# @raise [CSVDecision2::CellValidationError] Table parsing cell validation error.
|
45
|
+
# @raise [CSVDecision2::FileError] Table parsing error for a named CSV file.
|
46
46
|
#
|
47
47
|
def self.parse(data, options = {})
|
48
48
|
Parse.table(data: data, options: Options.normalize(options))
|
49
49
|
end
|
50
50
|
|
51
|
-
# Methods to parse the decision table and return
|
51
|
+
# Methods to parse the decision table and return CSVDecision2::Table object.
|
52
52
|
# @api private
|
53
53
|
module Parse
|
54
54
|
# Parse the CSV file or input data and create a new decision table object.
|
55
55
|
#
|
56
|
-
# @param (see
|
57
|
-
# @return (see
|
56
|
+
# @param (see CSVDecision2.parse)
|
57
|
+
# @return (see CSVDecision2.parse)
|
58
58
|
def self.table(data:, options:)
|
59
|
-
table =
|
59
|
+
table = CSVDecision2::Table.new
|
60
60
|
|
61
61
|
# In most cases the decision table will be loaded from a CSV file.
|
62
62
|
table.file = data if Data.input_file?(data)
|
@@ -66,14 +66,14 @@ module CSVDecision
|
|
66
66
|
# The table object is now immutable.
|
67
67
|
table.columns.freeze
|
68
68
|
table.freeze
|
69
|
-
rescue
|
69
|
+
rescue CSVDecision2::Error => exp
|
70
70
|
raise_error(file: table.file, exception: exp)
|
71
71
|
end
|
72
72
|
|
73
73
|
def self.raise_error(file:, exception:)
|
74
74
|
raise exception unless file
|
75
75
|
|
76
|
-
raise
|
76
|
+
raise CSVDecision2::FileError,
|
77
77
|
"error processing CSV file #{file}\n#{exception.inspect}"
|
78
78
|
end
|
79
79
|
private_class_method :raise_error
|
@@ -87,7 +87,7 @@ module CSVDecision
|
|
87
87
|
table.options = Options.from_csv(rows: table.rows, options: options).freeze
|
88
88
|
|
89
89
|
# Parse table header and data rows with special cell matchers.
|
90
|
-
parse_with_matchers(table: table, matchers:
|
90
|
+
parse_with_matchers(table: table, matchers: CSVDecision2::Matchers.new(options))
|
91
91
|
|
92
92
|
# Build the data index if one is indicated
|
93
93
|
Index.build(table: table)
|
@@ -162,4 +162,4 @@ module CSVDecision
|
|
162
162
|
end
|
163
163
|
private_class_method :outs_functions
|
164
164
|
end
|
165
|
-
end
|
165
|
+
end
|
@@ -4,15 +4,15 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers.
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# Build an index for a decision table with one or more input columns
|
9
9
|
# designated as keys
|
10
10
|
# @api private
|
11
11
|
class Paths
|
12
12
|
# Build the index of paths
|
13
13
|
#
|
14
|
-
# @param table [
|
15
|
-
# @return [
|
14
|
+
# @param table [CSVDecision2::Table] Decision table being indexed.
|
15
|
+
# @return [CSVDecision2::Paths] The built index of paths.
|
16
16
|
def self.scan(table:)
|
17
17
|
# Do we even have paths?
|
18
18
|
columns = table.columns.paths.keys
|
@@ -40,7 +40,7 @@ module CSVDecision
|
|
40
40
|
# @return [Hash] The index hash mapping in input values to one or more data array row indexes.
|
41
41
|
attr_reader :paths
|
42
42
|
|
43
|
-
# @param table [
|
43
|
+
# @param table [CSVDecision2::Table] Decision table.
|
44
44
|
# @param columns [Array<Index>] Array of column indexes to be indexed.
|
45
45
|
def initialize(table:, columns:)
|
46
46
|
@paths = []
|
@@ -75,4 +75,4 @@ module CSVDecision
|
|
75
75
|
@columns.map { |col| Paths.symbol(row[col]) }.compact
|
76
76
|
end
|
77
77
|
end
|
78
|
-
end
|
78
|
+
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers <brett@phillips-vickers.com>
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# Accumulate the matching row(s) into a result hash.
|
9
9
|
# @api private
|
10
10
|
class Result
|
@@ -201,4 +201,4 @@ module CSVDecision
|
|
201
201
|
end
|
202
202
|
end
|
203
203
|
end
|
204
|
-
end
|
204
|
+
end
|
@@ -4,13 +4,13 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers <brett@phillips-vickers.com>
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# Scan the input hash for all the paths specified in the decision table
|
9
9
|
# @api private
|
10
10
|
class Scan
|
11
11
|
# Main method for making decisions with a table that has paths.
|
12
12
|
#
|
13
|
-
# @param table [
|
13
|
+
# @param table [CSVDecision2::Table] Decision table.
|
14
14
|
# @param input [Hash] Input hash (keys may or may not be symbolized)
|
15
15
|
# @param symbolize_keys [Boolean] Set to false if keys are symbolized and it's
|
16
16
|
# OK to mutate the input hash. Otherwise a copy of the input hash is symbolized.
|
@@ -114,4 +114,4 @@ module CSVDecision
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
117
|
-
end
|
117
|
+
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers <brett@phillips-vickers.com>
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# Data row object indicating which columns are constants versus procs.
|
9
9
|
# @api private
|
10
10
|
class ScanRow
|
@@ -139,4 +139,4 @@ module CSVDecision
|
|
139
139
|
proc
|
140
140
|
end
|
141
141
|
end
|
142
|
-
end
|
142
|
+
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers <brett@phillips-vickers.com>
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# Decision table that accepts an input hash and outputs a decision (hash).
|
9
9
|
class Table
|
10
10
|
# Make a decision based off an input hash.
|
@@ -27,17 +27,17 @@ module CSVDecision
|
|
27
27
|
decision( input: input, symbolize_keys: false)
|
28
28
|
end
|
29
29
|
|
30
|
-
# @return [
|
30
|
+
# @return [CSVDecision2::Columns] Dictionary of all input and output columns.
|
31
31
|
attr_accessor :columns
|
32
32
|
|
33
33
|
# @return [File, Pathname, nil] File path name if decision table was loaded from a
|
34
34
|
# CSV file.
|
35
35
|
attr_accessor :file
|
36
36
|
|
37
|
-
# @return [
|
37
|
+
# @return [CSVDecision2::Index] The index built on one or more input columns.
|
38
38
|
attr_accessor :index
|
39
39
|
|
40
|
-
# @return [
|
40
|
+
# @return [CSVDecision2::Path] The array of paths built on one or more input columns.
|
41
41
|
attr_accessor :paths
|
42
42
|
|
43
43
|
# @return [Hash] All options, explicitly set or defaulted, used to parse the table.
|
@@ -51,16 +51,16 @@ module CSVDecision
|
|
51
51
|
# @api private
|
52
52
|
attr_accessor :rows
|
53
53
|
|
54
|
-
# @return [Array<
|
54
|
+
# @return [Array<CSVDecision2::ScanRow>] Scanning objects used to implement input
|
55
55
|
# matching logic.
|
56
56
|
# @api private
|
57
57
|
attr_accessor :scan_rows
|
58
58
|
|
59
|
-
# @return [Array<
|
59
|
+
# @return [Array<CSVDecision2::ScanRow>] Used to implement outputting of final results.
|
60
60
|
# @api private
|
61
61
|
attr_accessor :outs_rows
|
62
62
|
|
63
|
-
# @return [Array<
|
63
|
+
# @return [Array<CSVDecision2::ScanRow>] Used to implement filtering of final results.
|
64
64
|
# @api private
|
65
65
|
attr_accessor :if_rows
|
66
66
|
|
@@ -98,4 +98,4 @@ module CSVDecision
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
101
|
-
end
|
101
|
+
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Created December 2017.
|
5
5
|
# @author Brett Vickers <brett@phillips-vickers.com>
|
6
6
|
# See LICENSE and README.md for details.
|
7
|
-
module
|
7
|
+
module CSVDecision2
|
8
8
|
# Parse and validate the column names in the header row.
|
9
9
|
# These methods are only required at table load time.
|
10
10
|
# @api private
|
@@ -82,4 +82,4 @@ module CSVDecision
|
|
82
82
|
end
|
83
83
|
private_class_method :validate_in_name
|
84
84
|
end
|
85
|
-
end
|
85
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/object'
|
4
|
+
require 'csv_decision2/parse'
|
5
|
+
|
6
|
+
# CSV Decision: CSV based Ruby decision tables.
|
7
|
+
# Created December 2017.
|
8
|
+
# @author Brett Vickers <brett@phillips-vickers.com>
|
9
|
+
# See LICENSE and README.md for details.
|
10
|
+
module CSVDecision2
|
11
|
+
# @return [String] gem project's root directory
|
12
|
+
def self.root
|
13
|
+
File.dirname __dir__
|
14
|
+
end
|
15
|
+
|
16
|
+
autoload :Columns, 'csv_decision2/columns'
|
17
|
+
autoload :Data, 'csv_decision2/data'
|
18
|
+
autoload :Decision, 'csv_decision2/decision'
|
19
|
+
autoload :Defaults, 'csv_decision2/defaults'
|
20
|
+
autoload :Dictionary, 'csv_decision2/dictionary'
|
21
|
+
autoload :Header, 'csv_decision2/header'
|
22
|
+
autoload :Index, 'csv_decision2/index'
|
23
|
+
autoload :Input, 'csv_decision2/input'
|
24
|
+
autoload :Load, 'csv_decision2/load'
|
25
|
+
autoload :Matchers, 'csv_decision2/matchers'
|
26
|
+
autoload :Options, 'csv_decision2/options'
|
27
|
+
autoload :Parse, 'csv_decision2/parse'
|
28
|
+
autoload :Paths, 'csv_decision2/paths'
|
29
|
+
autoload :Result, 'csv_decision2/result'
|
30
|
+
autoload :Scan, 'csv_decision2/scan'
|
31
|
+
autoload :ScanRow, 'csv_decision2/scan_row'
|
32
|
+
autoload :Table, 'csv_decision2/table'
|
33
|
+
autoload :Validate, 'csv_decision2/validate'
|
34
|
+
|
35
|
+
# Cell matchers
|
36
|
+
class Matchers
|
37
|
+
autoload :Constant, 'csv_decision2/matchers/constant'
|
38
|
+
autoload :Function, 'csv_decision2/matchers/function'
|
39
|
+
autoload :Guard, 'csv_decision2/matchers/guard'
|
40
|
+
autoload :Numeric, 'csv_decision2/matchers/numeric'
|
41
|
+
autoload :Pattern, 'csv_decision2/matchers/pattern'
|
42
|
+
autoload :Range, 'csv_decision2/matchers/range'
|
43
|
+
autoload :Symbol, 'csv_decision2/matchers/symbol'
|
44
|
+
end
|
45
|
+
end
|
@@ -1,17 +1,17 @@
|
|
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::Columns do
|
9
9
|
describe '#new' do
|
10
10
|
# it 'creates a columns object' do
|
11
|
-
# table =
|
12
|
-
# columns =
|
11
|
+
# table = CSVDecision2::Table.new
|
12
|
+
# columns = CSVDecision2::Columns.new(table)
|
13
13
|
#
|
14
|
-
# expect(columns).to be_a(
|
14
|
+
# expect(columns).to be_a(CSVDecision2::Columns)
|
15
15
|
# end
|
16
16
|
end
|
17
17
|
|
@@ -20,8 +20,8 @@ describe CSVDecision::Columns do
|
|
20
20
|
IN :input, OUT :output, IN/text : input, OUT/text:output
|
21
21
|
input0, output0, input1, output1
|
22
22
|
DATA
|
23
|
-
expect {
|
24
|
-
.to raise_error(
|
23
|
+
expect { CSVDecision2.parse(data) }
|
24
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
25
25
|
"output column name 'output' is duplicated")
|
26
26
|
end
|
27
27
|
|
@@ -30,9 +30,9 @@ describe CSVDecision::Columns do
|
|
30
30
|
IN :input, OUT :output, IN/text : input, OUT/text:output2
|
31
31
|
input0, output0, input1, output1
|
32
32
|
DATA
|
33
|
-
table =
|
33
|
+
table = CSVDecision2.parse(data)
|
34
34
|
|
35
|
-
expect(table.columns).to be_a(
|
35
|
+
expect(table.columns).to be_a(CSVDecision2::Columns)
|
36
36
|
expect(table.columns.ins[0].to_h).to eq(name: :input, eval: nil, type: :in, set_if: nil)
|
37
37
|
expect(table.columns.ins[2].to_h).to eq(name: :input, eval: false, type: :in, set_if: nil)
|
38
38
|
expect(table.columns.outs[1].to_h).to eq(name: :output, eval: nil, type: :out, set_if: nil)
|
@@ -44,12 +44,12 @@ describe CSVDecision::Columns do
|
|
44
44
|
it 'recognises all input and output column symbols' do
|
45
45
|
data = <<~DATA
|
46
46
|
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: len, guard:
|
47
|
-
input0, output0, input1, output1, :input2.length,
|
47
|
+
input0, output0, input1, output1, :input2.length,
|
48
48
|
input1, output1, input1, output2, :input3.length, :input4.present?
|
49
49
|
DATA
|
50
|
-
table =
|
50
|
+
table = CSVDecision2.parse(data)
|
51
51
|
|
52
|
-
expect(table.columns).to be_a(
|
52
|
+
expect(table.columns).to be_a(CSVDecision2::Columns)
|
53
53
|
expect(table.columns.ins[0].to_h).to eq(name: :input, eval: nil, type: :in, set_if: nil)
|
54
54
|
expect(table.columns.ins[2].to_h).to eq(name: :input, eval: false, type: :in, set_if: nil)
|
55
55
|
expect(table.columns.ins[5].to_h).to eq(name: nil, eval: true, type: :guard, set_if: nil)
|
@@ -66,14 +66,14 @@ describe CSVDecision::Columns do
|
|
66
66
|
|
67
67
|
it 'recognises the output symbol referenced by an output function' do
|
68
68
|
data = <<~DATA
|
69
|
-
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: input3, out: len
|
69
|
+
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: input3, out: len
|
70
70
|
input0, output0, input1, output1, , :input2.length
|
71
71
|
input1, output1, input1, output2, :input4.present?, :input3.length
|
72
72
|
DATA
|
73
73
|
|
74
|
-
table =
|
74
|
+
table = CSVDecision2.parse(data)
|
75
75
|
|
76
|
-
expect(table.columns).to be_a(
|
76
|
+
expect(table.columns).to be_a(CSVDecision2::Columns)
|
77
77
|
expect(table.columns.ins[0].to_h).to eq(name: :input, eval: nil, type: :in, set_if: nil)
|
78
78
|
expect(table.columns.ins[2].to_h).to eq(name: :input, eval: false, type: :in, set_if: nil)
|
79
79
|
expect(table.columns.outs[1].to_h).to eq(name: :output, eval: nil, type: :out, set_if: nil)
|
@@ -89,35 +89,35 @@ describe CSVDecision::Columns do
|
|
89
89
|
|
90
90
|
it 'raises an error for an output column referring to a later output column' do
|
91
91
|
data = <<~DATA
|
92
|
-
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: len, out: input3,
|
93
|
-
input0, output0, input1, output1, :input2.length,
|
92
|
+
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: len, out: input3,
|
93
|
+
input0, output0, input1, output1, :input2.length,
|
94
94
|
input1, output1, input1, output2, :input3.length :input4.upcase
|
95
95
|
DATA
|
96
96
|
|
97
|
-
expect {
|
97
|
+
expect { CSVDecision2.parse(data) }
|
98
98
|
.to raise_error(
|
99
|
-
|
99
|
+
CSVDecision2::CellValidationError,
|
100
100
|
"output column 'len' makes an out of order reference to output column 'input3'"
|
101
101
|
)
|
102
102
|
end
|
103
103
|
|
104
104
|
it 'raises an error for an output column referring to itself' do
|
105
105
|
data = <<~DATA
|
106
|
-
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: len, out: input3,
|
107
|
-
input0, output0, input1, output1, :len.length,
|
106
|
+
IN :input, OUT :output, IN/text :input, OUT/text:output2, out: len, out: input3,
|
107
|
+
input0, output0, input1, output1, :len.length,
|
108
108
|
input1, output1, input1, output2, :len.length :input4.upcase
|
109
109
|
DATA
|
110
110
|
|
111
|
-
expect {
|
112
|
-
.to raise_error(
|
111
|
+
expect { CSVDecision2.parse(data) }
|
112
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
113
113
|
"output column 'len' makes reference to itself")
|
114
114
|
end
|
115
115
|
|
116
116
|
it 'parses a decision table columns from a CSV file' do
|
117
117
|
file = Pathname(File.join(SPEC_DATA_VALID, 'valid.csv'))
|
118
|
-
result =
|
118
|
+
result = CSVDecision2.parse(file)
|
119
119
|
|
120
|
-
expect(result.columns).to be_a(
|
120
|
+
expect(result.columns).to be_a(CSVDecision2::Columns)
|
121
121
|
expect(result.columns.ins.count).to eq 1
|
122
122
|
expect(result.columns.outs.count).to eq 1
|
123
123
|
expect(result.columns.ins[0].to_h).to eql(name: :input, type: :in, eval: nil, set_if: nil)
|
@@ -130,8 +130,8 @@ describe CSVDecision::Columns do
|
|
130
130
|
['input', '']
|
131
131
|
]
|
132
132
|
|
133
|
-
expect {
|
134
|
-
.to raise_error(
|
133
|
+
expect { CSVDecision2.parse(data) }
|
134
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
135
135
|
"header column 'BAD :output' is not valid as " \
|
136
136
|
'the column name is not well formed')
|
137
137
|
end
|
@@ -142,8 +142,8 @@ describe CSVDecision::Columns do
|
|
142
142
|
['input', '']
|
143
143
|
]
|
144
144
|
|
145
|
-
expect {
|
146
|
-
.to raise_error(
|
145
|
+
expect { CSVDecision2.parse(data) }
|
146
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
147
147
|
"header column 'IN:' is not valid as the column name is missing")
|
148
148
|
end
|
149
149
|
|
@@ -153,8 +153,8 @@ describe CSVDecision::Columns do
|
|
153
153
|
['input', '']
|
154
154
|
]
|
155
155
|
|
156
|
-
expect {
|
157
|
-
.to raise_error(
|
156
|
+
expect { CSVDecision2.parse(data) }
|
157
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
158
158
|
"header column 'IN: a-b' is not valid as " \
|
159
159
|
"the column name 'a-b' contains invalid characters")
|
160
160
|
end
|
@@ -164,8 +164,8 @@ describe CSVDecision::Columns do
|
|
164
164
|
pathname = Pathname(file_name)
|
165
165
|
|
166
166
|
it "rejects CSV file #{pathname.basename}" do
|
167
|
-
expect {
|
168
|
-
.to raise_error(
|
167
|
+
expect { CSVDecision2.parse(pathname) }
|
168
|
+
.to raise_error(CSVDecision2::FileError, /\Aerror processing CSV file/)
|
169
169
|
end
|
170
170
|
end
|
171
171
|
end
|
@@ -176,7 +176,7 @@ describe CSVDecision::Columns do
|
|
176
176
|
US, :CUSIP.present?, :CUSIP, CUSUP
|
177
177
|
GB, :SEDOL.present?, :SEDOL, SEDOL
|
178
178
|
DATA
|
179
|
-
table =
|
179
|
+
table = CSVDecision2.parse(data)
|
180
180
|
|
181
181
|
expect(table.columns.ins[1].to_h)
|
182
182
|
.to eq(name: nil, eval: true, type: :guard, set_if: nil)
|
@@ -191,8 +191,8 @@ describe CSVDecision::Columns do
|
|
191
191
|
GB, :SEDOL.present?, :SEDOL, SEDOL
|
192
192
|
DATA
|
193
193
|
|
194
|
-
expect {
|
195
|
-
.to raise_error(
|
194
|
+
expect { CSVDecision2.parse(data) }
|
195
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
196
196
|
"output column name 'country' is also an input column")
|
197
197
|
end
|
198
198
|
|
@@ -202,8 +202,8 @@ describe CSVDecision::Columns do
|
|
202
202
|
==:node, top
|
203
203
|
, child
|
204
204
|
DATA
|
205
|
-
expect {
|
206
|
-
.to raise_error(
|
205
|
+
expect { CSVDecision2.parse(data) }
|
206
|
+
.to raise_error(CSVDecision2::CellValidationError,
|
207
207
|
"output column name 'node' is also an input column")
|
208
208
|
end
|
209
209
|
|
@@ -213,7 +213,7 @@ describe CSVDecision::Columns do
|
|
213
213
|
US, :CUSIP, CUSIP, :PAID.present?
|
214
214
|
GB, :SEDOL, SEDOL, :PAID.present?
|
215
215
|
DATA
|
216
|
-
table =
|
216
|
+
table = CSVDecision2.parse(data)
|
217
217
|
|
218
218
|
expect(table.columns.ifs[3].to_h).to eq(name: 3, eval: true, type: :if, set_if: nil)
|
219
219
|
expect(table.columns.input_keys).to eq %i[country CUSIP SEDOL]
|
@@ -226,7 +226,7 @@ describe CSVDecision::Columns do
|
|
226
226
|
US, :CUSIP.present?, != PRIVATE, :CUSIP, :PAID.length, :len == 9
|
227
227
|
!=US, :ISIN.present?, != PRIVATE, :ISIN, :PAID.length, :len == 12
|
228
228
|
DATA
|
229
|
-
table =
|
229
|
+
table = CSVDecision2.parse(data)
|
230
230
|
|
231
231
|
expect(table.columns.ins[0].to_h).to eq(name: :country, eval: nil, type: :set, set_if: :nil?)
|
232
232
|
expect(table.columns.ins[1].to_h).to eq(name: nil, eval: true, type: :guard, set_if: nil)
|
@@ -242,10 +242,10 @@ describe CSVDecision::Columns do
|
|
242
242
|
payload, , !nil?, :type_cd, :value.present?
|
243
243
|
payload, ref_data, , :type_id, :value.present?
|
244
244
|
DATA
|
245
|
-
table =
|
245
|
+
table = CSVDecision2.parse(data)
|
246
246
|
|
247
247
|
expect(table.columns.input_keys).to eq %i[type_cd type_id]
|
248
248
|
expect(table.columns.paths[0].to_h).to eq(name: nil, eval: false, type: :path, set_if: nil)
|
249
249
|
expect(table.columns.paths[1].to_h).to eq(name: nil, eval: false, type: :path, set_if: nil)
|
250
250
|
end
|
251
|
-
end
|
251
|
+
end
|
@@ -1,8 +1,8 @@
|
|
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::Constant do
|
6
6
|
describe '#matches?' do
|
7
7
|
context 'constant matches value' do
|
8
8
|
data = [
|
@@ -16,7 +16,7 @@ describe CSVDecision::Matchers::Constant do
|
|
16
16
|
data.each do |cell, value|
|
17
17
|
it "constant #{cell} matches #{value}" do
|
18
18
|
proc = described_class.matches?(cell)
|
19
|
-
expect(proc).to be_a(
|
19
|
+
expect(proc).to be_a(CSVDecision2::Matchers::Proc)
|
20
20
|
expect(proc.type).to eq :constant
|
21
21
|
expect(proc.function).to eq value
|
22
22
|
end
|
@@ -33,4 +33,4 @@ describe CSVDecision::Matchers::Constant do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require_relative '../../lib/
|
2
|
+
require_relative '../../lib/csv_decision2'
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe CSVDecision2::Data do
|
5
5
|
it 'parses an CSV string' do
|
6
|
-
result =
|
6
|
+
result = CSVDecision2::Data.to_array(data: '')
|
7
7
|
expect(result).to be_a Array
|
8
8
|
expect(result.empty?).to eq true
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'parses an array' do
|
12
|
-
result =
|
12
|
+
result = CSVDecision2::Data.to_array(data: [[]])
|
13
13
|
expect(result).to eq []
|
14
14
|
|
15
15
|
data = [
|
@@ -17,21 +17,21 @@ describe CSVDecision::Data do
|
|
17
17
|
['IN :input', ' OUT :output ', nil],
|
18
18
|
['input', '# comment', nil]
|
19
19
|
]
|
20
|
-
result =
|
20
|
+
result = CSVDecision2::Data.to_array(data: data)
|
21
21
|
expect(result).to eq [['IN :input', 'OUT :output', ''], ['input', '', '']]
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'parses a CSV file' do
|
25
|
-
file = Pathname(File.join(
|
26
|
-
result =
|
25
|
+
file = Pathname(File.join(CSVDecision2.root, 'spec/data/valid', 'valid.csv'))
|
26
|
+
result = CSVDecision2::Data.to_array(data: file)
|
27
27
|
expected = [
|
28
28
|
['', 'IN :input', '', 'OUT :output', ''],
|
29
29
|
['', 'input', '', '', '']
|
30
30
|
]
|
31
31
|
expect(result).to eq(expected)
|
32
32
|
|
33
|
-
file = Pathname(File.join(
|
34
|
-
result =
|
33
|
+
file = Pathname(File.join(CSVDecision2.root, 'spec/data/valid', 'options_in_file2.csv'))
|
34
|
+
result = CSVDecision2::Data.to_array(data: file)
|
35
35
|
expected = [
|
36
36
|
['accumulate'],
|
37
37
|
['regexp_implicit'],
|
@@ -42,9 +42,9 @@ describe CSVDecision::Data do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'raises an error for invalid input' do
|
45
|
-
expect {
|
45
|
+
expect { CSVDecision2::Data.to_array(data: {}) }
|
46
46
|
.to raise_error(ArgumentError,
|
47
47
|
'Hash input invalid; ' \
|
48
48
|
'input must be a file path name, CSV string or array of arrays')
|
49
49
|
end
|
50
|
-
end
|
50
|
+
end
|
@@ -1,8 +1,8 @@
|
|
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::Decision do
|
6
6
|
it 'decision for table with no functions and first_match: true' do
|
7
7
|
data = <<~DATA
|
8
8
|
IN :input, OUT :output, IN: input1
|
@@ -10,10 +10,10 @@ describe CSVDecision::Decision do
|
|
10
10
|
input0, output1,
|
11
11
|
DATA
|
12
12
|
|
13
|
-
table =
|
13
|
+
table = CSVDecision2.parse(data)
|
14
14
|
|
15
|
-
decision =
|
15
|
+
decision = CSVDecision2::Decision.new(table: table)
|
16
16
|
|
17
|
-
expect(decision).to be_a(
|
17
|
+
expect(decision).to be_a(CSVDecision2::Decision)
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|