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
|
@@ -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
|