csv_decision 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +1 -1
  4. data/benchmarks/rufus_decision.rb +3 -5
  5. data/csv_decision.gemspec +1 -3
  6. data/doc/CSVDecision/CellValidationError.html +1 -1
  7. data/doc/CSVDecision/Columns/Dictionary.html +112 -18
  8. data/doc/CSVDecision/Columns.html +112 -81
  9. data/doc/CSVDecision/Data.html +1 -1
  10. data/doc/CSVDecision/Decide.html +1 -1
  11. data/doc/CSVDecision/Decision.html +1 -1
  12. data/doc/CSVDecision/Dictionary/Entry.html +1 -1
  13. data/doc/CSVDecision/Dictionary.html +152 -7
  14. data/doc/CSVDecision/Error.html +1 -1
  15. data/doc/CSVDecision/FileError.html +1 -1
  16. data/doc/CSVDecision/Header.html +1 -1
  17. data/doc/CSVDecision/Input.html +5 -11
  18. data/doc/CSVDecision/Load.html +1 -1
  19. data/doc/CSVDecision/Matchers/Constant.html +1 -1
  20. data/doc/CSVDecision/Matchers/Function.html +1 -1
  21. data/doc/CSVDecision/Matchers/Guard.html +23 -23
  22. data/doc/CSVDecision/Matchers/Matcher.html +13 -13
  23. data/doc/CSVDecision/Matchers/Numeric.html +3 -3
  24. data/doc/CSVDecision/Matchers/Pattern.html +9 -11
  25. data/doc/CSVDecision/Matchers/Proc.html +571 -0
  26. data/doc/CSVDecision/Matchers/Range.html +1 -1
  27. data/doc/CSVDecision/Matchers/Symbol.html +1 -1
  28. data/doc/CSVDecision/Matchers.html +63 -83
  29. data/doc/CSVDecision/Options.html +1 -1
  30. data/doc/CSVDecision/Parse.html +115 -8
  31. data/doc/CSVDecision/Result.html +55 -37
  32. data/doc/CSVDecision/ScanRow.html +3 -3
  33. data/doc/CSVDecision/Table.html +5 -6
  34. data/doc/CSVDecision.html +5 -5
  35. data/doc/_index.html +12 -5
  36. data/doc/class_list.html +1 -1
  37. data/doc/file.README.html +2 -2
  38. data/doc/index.html +2 -2
  39. data/doc/method_list.html +110 -46
  40. data/doc/top-level-namespace.html +1 -1
  41. data/lib/csv_decision/columns.rb +14 -9
  42. data/lib/csv_decision/dictionary.rb +46 -21
  43. data/lib/csv_decision/input.rb +13 -6
  44. data/lib/csv_decision/matchers/constant.rb +1 -1
  45. data/lib/csv_decision/matchers/guard.rb +7 -10
  46. data/lib/csv_decision/matchers/numeric.rb +2 -2
  47. data/lib/csv_decision/matchers/pattern.rb +1 -2
  48. data/lib/csv_decision/matchers/range.rb +1 -1
  49. data/lib/csv_decision/matchers/symbol.rb +1 -1
  50. data/lib/csv_decision/matchers.rb +38 -4
  51. data/lib/csv_decision/parse.rb +100 -5
  52. data/lib/csv_decision/result.rb +23 -7
  53. data/lib/csv_decision/table.rb +2 -2
  54. data/spec/csv_decision/columns_spec.rb +89 -0
  55. data/spec/csv_decision/examples_spec.rb +23 -1
  56. data/spec/csv_decision/input_spec.rb +0 -2
  57. data/spec/csv_decision/table_spec.rb +1 -1
  58. metadata +3 -30
@@ -74,8 +74,7 @@ module CSVDecision
74
74
  # No need for a regular expression if we have simple string inequality
75
75
  pattern = comparator == '!=' ? value : Matchers.regexp(value)
76
76
 
77
- Proc.with(type: :proc,
78
- function: PATTERN_LAMBDAS[comparator].curry[pattern].freeze)
77
+ Proc.new(type: :proc, function: PATTERN_LAMBDAS[comparator].curry[pattern].freeze)
79
78
  end
80
79
 
81
80
  # @param options [Hash{Symbol=>Object}] Used to determine the value of regexp_implicit:.
@@ -81,7 +81,7 @@ module CSVDecision
81
81
  negate, range = range(match, coerce: coerce)
82
82
  method = coerce ? :numeric_range : :alnum_range
83
83
  function = Range.send(method, negate, range).freeze
84
- Proc.with(type: :proc, function: function)
84
+ Proc.new(type: :proc, function: function)
85
85
  end
86
86
  private_class_method :range_proc
87
87
 
@@ -60,7 +60,7 @@ module CSVDecision
60
60
  # E.g., > :col, we get comparator: >, args: col
61
61
  def self.comparison(comparator:, name:)
62
62
  function = COMPARE[comparator]
63
- Matchers::Proc.with(type: :symbol, function: function[name])
63
+ Matchers::Proc.new(type: :symbol, function: function[name], symbols: name)
64
64
  end
65
65
  private_class_method :comparison
66
66
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'values'
4
-
5
3
  # CSV Decision: CSV based Ruby decision tables.
6
4
  # Created December 2017.
7
5
  # @author Brett Vickers.
@@ -10,9 +8,45 @@ module CSVDecision
10
8
  # Match table data cells against a valid decision table expression or a simple constant.
11
9
  # @api private
12
10
  class Matchers
13
- # Value object for a data cell proc.
11
+ # Composite object for a data cell proc. Note that we do not need it to be comparable.
12
+ # Implemented as an immutable array of 2 or 3 entries for memory compactness and speed.
14
13
  # @api private
15
- Proc = Value.new(:type, :function)
14
+ class Proc < Array
15
+ # @param type [Symbol] Type of the function value - e.g., :constant or :guard.
16
+ # @param function [Object] Either a lambda function,
17
+ # or some kind of constant such as an Integer.
18
+ # @param symbols [nil, Symbol, Array<Symbol>] The symbol or list of symbols
19
+ # that the function uses to reference input hash keys (which are always symbolized).
20
+ def initialize(type:, function:, symbols: nil)
21
+ super()
22
+
23
+ self << type
24
+
25
+ # Function values should always be frozen
26
+ self << function.freeze
27
+
28
+ # Some function values, such as constants or 0-arity functions, do not reference symbols.
29
+ self << symbols if symbols
30
+
31
+ freeze
32
+ end
33
+
34
+ # @return [Symbol] Type of the function value - e.g., :constant or :guard.
35
+ def type
36
+ fetch(0)
37
+ end
38
+
39
+ # @return [Object] Either a lambda function, or some kind of constant such as an Integer.
40
+ def function
41
+ fetch(1)
42
+ end
43
+
44
+ # @return [nil, Symbol, Array<Symbol>] The symbol or list of symbols
45
+ # that the function uses to reference input hash keys (which are always symbolized).
46
+ def symbols
47
+ fetch(2, nil)
48
+ end
49
+ end
16
50
 
17
51
  # Negation sign prefixed to ranges and functions.
18
52
  NEGATE = '!'
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ice_nine'
4
- require 'ice_nine/core_ext/object'
5
-
6
3
  # CSV Decision: CSV based Ruby decision tables.
7
4
  # Created December 2017.
8
5
  # @author Brett Vickers.
@@ -63,7 +60,7 @@ module CSVDecision
63
60
  parse_table(table: table, input: data, options: options)
64
61
 
65
62
  # The table object is now immutable.
66
- table.columns.deep_freeze
63
+ table.columns.freeze
67
64
  table.freeze
68
65
  rescue CSVDecision::Error => exp
69
66
  raise_error(file: table.file, exception: exp)
@@ -108,12 +105,110 @@ module CSVDecision
108
105
  private_class_method :parse_data
109
106
 
110
107
  def self.parse_row(table:, matchers:, row:, index:)
108
+ # Parse the input cells for this row
109
+ row = parse_row_ins(table: table, matchers: matchers, row: row, index: index)
110
+
111
+ # Parse the output cells for this row
112
+ parse_row_outs(table: table, matchers: matchers, row: row, index: index)
113
+ end
114
+ private_class_method :parse_row
115
+
116
+ def self.parse_row_ins(table:, matchers:, row:, index:)
117
+ # Parse the input cells for this row
111
118
  row, table.scan_rows[index] = matchers.parse_ins(columns: table.columns.ins, row: row)
119
+
120
+ # Add any symbol references made by input cell procs to the column dictionary
121
+ ins_column_dictionary(columns: table.columns.dictionary, row: row)
122
+
123
+ row
124
+ end
125
+ private_class_method :parse_row_ins
126
+
127
+ def self.parse_row_outs(table:, matchers:, row:, index:)
128
+ # Parse the output cells for this row
112
129
  row, table.outs_rows[index] = matchers.parse_outs(columns: table.columns.outs, row: row)
113
130
 
131
+ outs_column_dictionary(columns: table.columns, row: row)
132
+
114
133
  row
115
134
  end
116
- private_class_method :parse_row
135
+ private_class_method :parse_row_outs
136
+
137
+ def self.outs_column_dictionary(columns:, row:)
138
+ row.each_with_index do |cell, index|
139
+ outs_check_cell(columns: columns, cell: cell, index: index)
140
+ end
141
+ end
142
+ private_class_method :outs_column_dictionary
143
+
144
+ def self.outs_check_cell(columns:, cell:, index:)
145
+ return unless cell.is_a?(Matchers::Proc)
146
+ return if cell.symbols.nil?
147
+
148
+ check_outs_symbols(columns: columns, cell: cell, index: index)
149
+ end
150
+ private_class_method :outs_check_cell
151
+
152
+ def self.check_outs_symbols(columns:, cell:, index:)
153
+ Array(cell.symbols).each do |symbol|
154
+ check_outs_symbol(columns: columns, symbol: symbol, index: index)
155
+ end
156
+ end
157
+ private_class_method :check_outs_symbols
158
+
159
+ def self.check_outs_symbol(columns:, symbol:, index:)
160
+ in_out = columns.dictionary[symbol]
161
+
162
+ # If its an input column symbol then we're good.
163
+ return if ins_symbol?(columns: columns, symbol: symbol, in_out: in_out)
164
+
165
+ # Check if this output symbol reference is on or after this cell's column
166
+ invalid_out_ref?(columns, index, in_out)
167
+ end
168
+ private_class_method :check_outs_symbol
169
+
170
+ # If the symbol exists either as an input or does not exist then we're good.
171
+ def self.ins_symbol?(columns:, symbol:, in_out:)
172
+ return true if in_out == :in
173
+
174
+ # It must an input symbol, as all the output symbols have been parsed.
175
+ return columns.dictionary[symbol] = :in if in_out.nil?
176
+
177
+ false
178
+ end
179
+ private_class_method :ins_symbol?
180
+
181
+ def self.invalid_out_ref?(columns, index, in_out)
182
+ return false if in_out < index
183
+
184
+ that_column = if in_out == index
185
+ 'reference to itself'
186
+ else
187
+ "an out of order reference to output column '#{columns.outs[in_out].name}'"
188
+ end
189
+ raise CellValidationError,
190
+ "output column '#{columns.outs[index].name}' makes #{that_column}"
191
+ end
192
+
193
+ def self.ins_column_dictionary(columns:, row:)
194
+ row.each { |cell| ins_cell_dictionary(columns: columns, cell: cell) }
195
+ end
196
+ private_class_method :ins_column_dictionary
197
+
198
+ def self.ins_cell_dictionary(columns:, cell:)
199
+ return unless cell.is_a?(Matchers::Proc)
200
+ return if cell.symbols.nil?
201
+
202
+ add_ins_symbols(columns: columns, cell: cell)
203
+ end
204
+ private_class_method :ins_cell_dictionary
205
+
206
+ def self.add_ins_symbols(columns:, cell:)
207
+ Array(cell.symbols).each do |symbol|
208
+ Dictionary.add_name(columns: columns, name: symbol)
209
+ end
210
+ end
211
+ private_class_method :add_ins_symbols
117
212
 
118
213
  def self.outs_functions(table:, index:)
119
214
  return if table.outs_rows[index].procs.empty?
@@ -20,10 +20,18 @@ module CSVDecision
20
20
  @outs = table.columns.outs
21
21
  @if_columns = table.columns.ifs
22
22
 
23
- # Partial result always includes the input hash for calculating output functions.
24
- @partial_result = input[:hash].dup if table.outs_functions
25
-
23
+ # Partial result always copies in the input hash for calculating output functions.
24
+ # Note that these input key values will not be mutated, as output columns can never
25
+ # have the same symbol as an input hash key.
26
+ # However, the rest of this hash is mutated as output column evaluation results
27
+ # are accumulated.
28
+ @partial_result = input[:hash]&.slice(*table.columns.input_keys) if table.outs_functions
29
+
30
+ # Attributes hash contains the output decision key value pairs
26
31
  @attributes = {}
32
+
33
+ # Set to true if the result has more than one row.
34
+ # Only possible for the first_match: false option.
27
35
  @multi_result = false
28
36
  end
29
37
 
@@ -35,7 +43,7 @@ module CSVDecision
35
43
  @outs.each_pair { |col, column| @attributes[column.name] = row[col] }
36
44
  end
37
45
 
38
- # Accumulate the outs into arrays.
46
+ # Accumulate the outs into arrays of values.
39
47
  # @param row [Array]
40
48
  # @return [void]
41
49
  def accumulate_outs(row)
@@ -45,6 +53,7 @@ module CSVDecision
45
53
  # Derive the final result.
46
54
  # @return [{Symbol=>Object}]
47
55
  def final
56
+ # If there are no if: columns, then nothing needs to be filtered out of this result hash.
48
57
  return @attributes if @if_columns.empty?
49
58
 
50
59
  @multi_result ? multi_row_result : single_row_result
@@ -76,12 +85,13 @@ module CSVDecision
76
85
 
77
86
  private
78
87
 
79
- # Case where we have a single row result
88
+ # Case where we have a single row result, which either gets returned
89
+ # or filtered by the if: column conditions.
80
90
  def single_row_result
81
91
  @if_columns.each_key do |col|
82
92
  return nil unless @attributes[col]
83
93
 
84
- # Remove the if: column from the final result
94
+ # Remove the if: column from the final result hash.
85
95
  @attributes.delete(col)
86
96
  end
87
97
 
@@ -121,9 +131,11 @@ module CSVDecision
121
131
  case count
122
132
  when 0
123
133
  {}
124
- # Single row array values do not require arrays.
134
+
135
+ # Single row array values do not require arrays.
125
136
  when 1
126
137
  @attributes.transform_values!(&:first)
138
+
127
139
  else
128
140
  @attributes
129
141
  end
@@ -168,6 +180,10 @@ module CSVDecision
168
180
  when nil
169
181
  @attributes[column_name] = cell
170
182
 
183
+ when Matchers::Proc
184
+ @attributes[column_name] = [current, cell]
185
+ @multi_result = true
186
+
171
187
  when Array
172
188
  @attributes[column_name] << cell
173
189
 
@@ -16,11 +16,11 @@ module CSVDecision
16
16
  Decide.decide(table: self, input: input, symbolize_keys: true)
17
17
  end
18
18
 
19
- # Unsafe version of decide - will mutate the hash if +set: column+ type
20
- # is used (planned feature).
19
+ # Unsafe version of decide - assumes the input hash is symbolized.
21
20
  #
22
21
  # @param input (see #decide)
23
22
  # @note Input hash must have its keys symbolized.
23
+ # Input hash will be mutated by any functions that have side effects.
24
24
  # @return (see #decide)
25
25
  def decide!(input)
26
26
  Decide.decide(table: self, input: input, symbolize_keys: false)
@@ -37,6 +37,80 @@ describe CSVDecision::Columns do
37
37
  expect(table.columns.ins[2].to_h).to eq(name: :input, eval: false, type: :in)
38
38
  expect(table.columns.outs[1].to_h).to eq(name: :output, eval: nil, type: :out)
39
39
  expect(table.columns.outs[3].to_h).to eq(name: :output2, eval: false, type: :out)
40
+
41
+ expect(table.columns.dictionary).to eq(input: :in, output: 1, output2: 3)
42
+ end
43
+
44
+ it 'recognises all input and output column symbols' do
45
+ data = <<~DATA
46
+ IN :input, OUT :output, IN/text :input, OUT/text:output2, out: len, guard:
47
+ input0, output0, input1, output1, :input2.length,
48
+ input1, output1, input1, output2, :input3.length, :input4.present?
49
+ DATA
50
+ table = CSVDecision.parse(data)
51
+
52
+ expect(table.columns).to be_a(CSVDecision::Columns)
53
+ expect(table.columns.ins[0].to_h).to eq(name: :input, eval: nil, type: :in)
54
+ expect(table.columns.ins[2].to_h).to eq(name: :input, eval: false, type: :in)
55
+ expect(table.columns.ins[5].to_h).to eq(name: nil, eval: true, type: :guard)
56
+
57
+ expect(table.columns.outs[1].to_h).to eq(name: :output, eval: nil, type: :out)
58
+ expect(table.columns.outs[3].to_h).to eq(name: :output2, eval: false, type: :out)
59
+ expect(table.columns.outs[4].to_h).to eq(name: :len, eval: true, type: :out)
60
+
61
+ expect(table.columns.dictionary)
62
+ .to eq(input: :in, output: 1, output2: 3, len: 4, input2: :in, input3: :in, input4: :in)
63
+
64
+ expect(table.columns.input_keys).to eq %i[input input2 input4 input3]
65
+ end
66
+
67
+ it 'recognises the output symbol referenced by an output function' do
68
+ data = <<~DATA
69
+ IN :input, OUT :output, IN/text :input, OUT/text:output2, out: input3, out: len
70
+ input0, output0, input1, output1, , :input2.length
71
+ input1, output1, input1, output2, :input4.present?, :input3.length
72
+ DATA
73
+
74
+ table = CSVDecision.parse(data)
75
+
76
+ expect(table.columns).to be_a(CSVDecision::Columns)
77
+ expect(table.columns.ins[0].to_h).to eq(name: :input, eval: nil, type: :in)
78
+ expect(table.columns.ins[2].to_h).to eq(name: :input, eval: false, type: :in)
79
+ expect(table.columns.outs[1].to_h).to eq(name: :output, eval: nil, type: :out)
80
+ expect(table.columns.outs[3].to_h).to eq(name: :output2, eval: false, type: :out)
81
+ expect(table.columns.outs[4].to_h).to eq(name: :input3, eval: true, type: :out)
82
+ expect(table.columns.outs[5].to_h).to eq(name: :len, eval: true, type: :out)
83
+
84
+ expect(table.columns.dictionary)
85
+ .to eq(input: :in, output: 1, output2: 3, len: 5, input2: :in, input3: 4, input4: :in)
86
+
87
+ expect(table.columns.input_keys).to eq %i[input input2 input4]
88
+ end
89
+
90
+ it 'raises an error for an output column referring to a later output column' do
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,
94
+ input1, output1, input1, output2, :input3.length :input4.upcase
95
+ DATA
96
+
97
+ expect { CSVDecision.parse(data) }
98
+ .to raise_error(
99
+ CSVDecision::CellValidationError,
100
+ "output column 'len' makes an out of order reference to output column 'input3'"
101
+ )
102
+ end
103
+
104
+ it 'raises an error for an output column referring to itself' do
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,
108
+ input1, output1, input1, output2, :len.length :input4.upcase
109
+ DATA
110
+
111
+ expect { CSVDecision.parse(data) }
112
+ .to raise_error(CSVDecision::CellValidationError,
113
+ "output column 'len' makes reference to itself")
40
114
  end
41
115
 
42
116
  it 'parses a decision table columns from a CSV file' do
@@ -106,6 +180,8 @@ describe CSVDecision::Columns do
106
180
 
107
181
  expect(table.columns.ins[1].to_h)
108
182
  .to eq(name: nil, eval: true, type: :guard)
183
+
184
+ expect(table.columns.input_keys).to eq %i[country CUSIP SEDOL]
109
185
  end
110
186
 
111
187
  it 'rejects output column being same as input column' do
@@ -114,11 +190,23 @@ describe CSVDecision::Columns do
114
190
  US, :CUSIP.present?, :CUSIP, CUSUP
115
191
  GB, :SEDOL.present?, :SEDOL, SEDOL
116
192
  DATA
193
+
117
194
  expect { CSVDecision.parse(data) }
118
195
  .to raise_error(CSVDecision::CellValidationError,
119
196
  "output column name 'country' is also an input column")
120
197
  end
121
198
 
199
+ it 'rejects output column being same as an input symbol not in the header' do
200
+ data = <<~DATA
201
+ in :parent, out :node
202
+ ==:node, top
203
+ , child
204
+ DATA
205
+ expect { CSVDecision.parse(data) }
206
+ .to raise_error(CSVDecision::CellValidationError,
207
+ "output column name 'node' is also an input column")
208
+ end
209
+
122
210
  it 'recognises the if: column' do
123
211
  data = <<~DATA
124
212
  in :country, out :PAID, out :PAID_type, if:
@@ -128,5 +216,6 @@ describe CSVDecision::Columns do
128
216
  table = CSVDecision.parse(data)
129
217
 
130
218
  expect(table.columns.ifs[3].to_h).to eq(name: 3, eval: true, type: :if)
219
+ expect(table.columns.input_keys).to eq %i[country CUSIP SEDOL]
131
220
  end
132
221
  end
@@ -95,6 +95,27 @@ context 'simple examples' do
95
95
  end
96
96
  end
97
97
 
98
+ context 'simple example - column symbols not in header' do
99
+ data = <<~DATA
100
+ in :parent, out :top?
101
+ ==:node, yes
102
+ , no
103
+ DATA
104
+
105
+ it 'makes correct decisions' do
106
+ table = CSVDecision.parse(data)
107
+
108
+ result = table.decide(node: 0, parent: 0)
109
+ expect(result).to eq(top?: 'yes')
110
+
111
+ result = table.decide(node: 1, parent: 0)
112
+ expect(result).to eq(top?: 'no')
113
+
114
+ result = table.decide(node: '0', parent: 0)
115
+ expect(result).to eq(top?: 'no')
116
+ end
117
+ end
118
+
98
119
  it 'makes correct decision for table with symbol ordered compares' do
99
120
  data = <<~DATA
100
121
  in :traded, in :settled, out :status
@@ -103,9 +124,10 @@ context 'simple examples' do
103
124
  , <:traded, invalid trade
104
125
  , , invalid data
105
126
  DATA
106
-
107
127
  table = CSVDecision.parse(data)
108
128
 
129
+ expect(table.columns.input_keys).to eq %i[traded settled]
130
+
109
131
  expect(table.decide(traded: '20171227', settled: '20171227')).to eq(status: 'same day')
110
132
  expect(table.decide(traded: 20171227, settled: 20171227 )).to eq(status: 'same day')
111
133
  expect(table.decide(traded: '20171227', settled: '20171228')).to eq(status: 'pending')
@@ -30,7 +30,6 @@ describe CSVDecision::Input do
30
30
  expect(result).to eql expected
31
31
  expect(result[:hash]).not_to equal expected[:hash]
32
32
  expect(result[:hash].frozen?).to eq true
33
- expect(result[:defaults].frozen?).to eq true
34
33
  end
35
34
 
36
35
  it 'processes input hash with symbolize_keys: false' do
@@ -49,6 +48,5 @@ describe CSVDecision::Input do
49
48
  expect(result).to eql expected
50
49
  expect(result[:hash]).to equal expected[:hash]
51
50
  expect(result[:hash].frozen?).to eq false
52
- expect(result[:defaults].frozen?).to eq true
53
51
  end
54
52
  end
@@ -439,7 +439,7 @@ describe CSVDecision::Table do
439
439
  it "#{method} correctly #{test[:example]}" do
440
440
  table = CSVDecision.parse(test[:data], test[:options])
441
441
 
442
- expect(table.send(method, country: 'US', CUSIP: '123456789'))
442
+ expect(table.send(method, country: 'US', CUSIP: '123456789', Ticker: 'USTY'))
443
443
  .to eq(ID: '123456789', ID_type: 'CUSIP', len: 9)
444
444
 
445
445
  expect(table.send(method, country: 'US', CUSIP: '123456789', ISIN: '123456789012'))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csv_decision
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Vickers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-06 00:00:00.000000000 Z
11
+ date: 2018-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,34 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.1'
27
- - !ruby/object:Gem::Dependency
28
- name: ice_nine
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.11'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.11'
41
- - !ruby/object:Gem::Dependency
42
- name: values
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.8'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.8'
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: benchmark-ips
57
29
  requirement: !ruby/object:Gem::Requirement
@@ -223,6 +195,7 @@ files:
223
195
  - doc/CSVDecision/Matchers/Matcher.html
224
196
  - doc/CSVDecision/Matchers/Numeric.html
225
197
  - doc/CSVDecision/Matchers/Pattern.html
198
+ - doc/CSVDecision/Matchers/Proc.html
226
199
  - doc/CSVDecision/Matchers/Range.html
227
200
  - doc/CSVDecision/Matchers/Symbol.html
228
201
  - doc/CSVDecision/Numeric.html