csv_decision2 0.5.1

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 (134) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +3 -0
  3. data/.coveralls.yml +2 -0
  4. data/.gitignore +14 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +30 -0
  7. data/.travis.yml +6 -0
  8. data/CHANGELOG.md +85 -0
  9. data/Dockerfile +6 -0
  10. data/Gemfile +7 -0
  11. data/LICENSE +21 -0
  12. data/README.md +356 -0
  13. data/benchmarks/rufus_decision.rb +158 -0
  14. data/csv_decision2.gemspec +38 -0
  15. data/doc/CSVDecision/CellValidationError.html +143 -0
  16. data/doc/CSVDecision/Columns/Default.html +589 -0
  17. data/doc/CSVDecision/Columns/Dictionary.html +801 -0
  18. data/doc/CSVDecision/Columns/Entry.html +508 -0
  19. data/doc/CSVDecision/Columns.html +1259 -0
  20. data/doc/CSVDecision/Constant.html +254 -0
  21. data/doc/CSVDecision/Data.html +479 -0
  22. data/doc/CSVDecision/Decide.html +302 -0
  23. data/doc/CSVDecision/Decision.html +1011 -0
  24. data/doc/CSVDecision/Defaults.html +291 -0
  25. data/doc/CSVDecision/Dictionary/Entry.html +1147 -0
  26. data/doc/CSVDecision/Dictionary.html +426 -0
  27. data/doc/CSVDecision/Error.html +139 -0
  28. data/doc/CSVDecision/FileError.html +143 -0
  29. data/doc/CSVDecision/Function.html +240 -0
  30. data/doc/CSVDecision/Guard.html +245 -0
  31. data/doc/CSVDecision/Header.html +647 -0
  32. data/doc/CSVDecision/Index.html +741 -0
  33. data/doc/CSVDecision/Input.html +404 -0
  34. data/doc/CSVDecision/Load.html +296 -0
  35. data/doc/CSVDecision/Matchers/Constant.html +484 -0
  36. data/doc/CSVDecision/Matchers/Function.html +511 -0
  37. data/doc/CSVDecision/Matchers/Guard.html +503 -0
  38. data/doc/CSVDecision/Matchers/Matcher.html +507 -0
  39. data/doc/CSVDecision/Matchers/Numeric.html +415 -0
  40. data/doc/CSVDecision/Matchers/Pattern.html +491 -0
  41. data/doc/CSVDecision/Matchers/Proc.html +704 -0
  42. data/doc/CSVDecision/Matchers/Range.html +379 -0
  43. data/doc/CSVDecision/Matchers/Symbol.html +426 -0
  44. data/doc/CSVDecision/Matchers.html +1567 -0
  45. data/doc/CSVDecision/Numeric.html +259 -0
  46. data/doc/CSVDecision/Options.html +443 -0
  47. data/doc/CSVDecision/Parse.html +282 -0
  48. data/doc/CSVDecision/Paths.html +742 -0
  49. data/doc/CSVDecision/Result.html +1200 -0
  50. data/doc/CSVDecision/Scan/InputHashes.html +369 -0
  51. data/doc/CSVDecision/Scan.html +313 -0
  52. data/doc/CSVDecision/ScanRow.html +866 -0
  53. data/doc/CSVDecision/Symbol.html +256 -0
  54. data/doc/CSVDecision/Table.html +1470 -0
  55. data/doc/CSVDecision/TableValidationError.html +143 -0
  56. data/doc/CSVDecision/Validate.html +422 -0
  57. data/doc/CSVDecision.html +621 -0
  58. data/doc/_index.html +471 -0
  59. data/doc/class_list.html +51 -0
  60. data/doc/css/common.css +1 -0
  61. data/doc/css/full_list.css +58 -0
  62. data/doc/css/style.css +499 -0
  63. data/doc/file.README.html +421 -0
  64. data/doc/file_list.html +56 -0
  65. data/doc/frames.html +17 -0
  66. data/doc/index.html +421 -0
  67. data/doc/js/app.js +248 -0
  68. data/doc/js/full_list.js +216 -0
  69. data/doc/js/jquery.js +4 -0
  70. data/doc/method_list.html +1163 -0
  71. data/doc/top-level-namespace.html +110 -0
  72. data/docker-compose.yml +13 -0
  73. data/lib/csv_decision/columns.rb +192 -0
  74. data/lib/csv_decision/data.rb +92 -0
  75. data/lib/csv_decision/decision.rb +196 -0
  76. data/lib/csv_decision/defaults.rb +47 -0
  77. data/lib/csv_decision/dictionary.rb +180 -0
  78. data/lib/csv_decision/header.rb +83 -0
  79. data/lib/csv_decision/index.rb +107 -0
  80. data/lib/csv_decision/input.rb +121 -0
  81. data/lib/csv_decision/load.rb +36 -0
  82. data/lib/csv_decision/matchers/constant.rb +74 -0
  83. data/lib/csv_decision/matchers/function.rb +56 -0
  84. data/lib/csv_decision/matchers/guard.rb +142 -0
  85. data/lib/csv_decision/matchers/numeric.rb +44 -0
  86. data/lib/csv_decision/matchers/pattern.rb +94 -0
  87. data/lib/csv_decision/matchers/range.rb +95 -0
  88. data/lib/csv_decision/matchers/symbol.rb +149 -0
  89. data/lib/csv_decision/matchers.rb +220 -0
  90. data/lib/csv_decision/options.rb +124 -0
  91. data/lib/csv_decision/parse.rb +165 -0
  92. data/lib/csv_decision/paths.rb +78 -0
  93. data/lib/csv_decision/result.rb +204 -0
  94. data/lib/csv_decision/scan.rb +117 -0
  95. data/lib/csv_decision/scan_row.rb +142 -0
  96. data/lib/csv_decision/table.rb +101 -0
  97. data/lib/csv_decision/validate.rb +85 -0
  98. data/lib/csv_decision.rb +45 -0
  99. data/spec/csv_decision/columns_spec.rb +251 -0
  100. data/spec/csv_decision/constant_spec.rb +36 -0
  101. data/spec/csv_decision/data_spec.rb +50 -0
  102. data/spec/csv_decision/decision_spec.rb +19 -0
  103. data/spec/csv_decision/examples_spec.rb +242 -0
  104. data/spec/csv_decision/index_spec.rb +58 -0
  105. data/spec/csv_decision/input_spec.rb +55 -0
  106. data/spec/csv_decision/load_spec.rb +28 -0
  107. data/spec/csv_decision/matchers/function_spec.rb +82 -0
  108. data/spec/csv_decision/matchers/guard_spec.rb +170 -0
  109. data/spec/csv_decision/matchers/numeric_spec.rb +47 -0
  110. data/spec/csv_decision/matchers/pattern_spec.rb +183 -0
  111. data/spec/csv_decision/matchers/range_spec.rb +70 -0
  112. data/spec/csv_decision/matchers/symbol_spec.rb +67 -0
  113. data/spec/csv_decision/options_spec.rb +94 -0
  114. data/spec/csv_decision/parse_spec.rb +44 -0
  115. data/spec/csv_decision/table_spec.rb +683 -0
  116. data/spec/csv_decision_spec.rb +7 -0
  117. data/spec/data/invalid/empty.csv +0 -0
  118. data/spec/data/invalid/invalid_header1.csv +4 -0
  119. data/spec/data/invalid/invalid_header2.csv +4 -0
  120. data/spec/data/invalid/invalid_header3.csv +4 -0
  121. data/spec/data/invalid/invalid_header4.csv +4 -0
  122. data/spec/data/valid/benchmark_regexp.csv +10 -0
  123. data/spec/data/valid/index_example.csv +13 -0
  124. data/spec/data/valid/multi_column_index.csv +10 -0
  125. data/spec/data/valid/multi_column_index2.csv +12 -0
  126. data/spec/data/valid/options_in_file1.csv +5 -0
  127. data/spec/data/valid/options_in_file2.csv +5 -0
  128. data/spec/data/valid/options_in_file3.csv +13 -0
  129. data/spec/data/valid/regular_expressions.csv +11 -0
  130. data/spec/data/valid/simple_constants.csv +5 -0
  131. data/spec/data/valid/simple_example.csv +10 -0
  132. data/spec/data/valid/valid.csv +4 -0
  133. data/spec/spec_helper.rb +106 -0
  134. metadata +352 -0
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../lib/csv_decision'
4
+
5
+ describe CSVDecision::Matchers::Symbol do
6
+ subject { described_class.new }
7
+
8
+ describe '#new' do
9
+ it { is_expected.to be_a CSVDecision::Matchers::Symbol }
10
+ it { is_expected.to be_a CSVDecision::Matchers::Matcher }
11
+ it { is_expected.to respond_to(:matches?).with(1).argument }
12
+ end
13
+
14
+ describe '#matches?' do
15
+ matcher = described_class.new
16
+
17
+ context 'symbol expression matches value to hash data' do
18
+ examples = [
19
+ { cell: ':col', value: 0, hash: { col: 0 }, result: true },
20
+ { cell: ':col', value: '0', hash: { col: '0' }, result: true },
21
+ { cell: ':col', value: 0, hash: { col: '0' }, result: false },
22
+ { cell: ':col', value: '0', hash: { col: 0 }, result: false },
23
+ { cell: ':col', value: 1, hash: { col: 0 }, result: false },
24
+ { cell: ':key', value: 0, hash: { col: 0 }, result: false },
25
+ { cell: '!=:col', value: 0, hash: { col: 0 }, result: false },
26
+ { cell: '!=:col', value: '0', hash: { col: '0' }, result: false },
27
+ { cell: '!=:col', value: 0, hash: { col: '0' }, result: true },
28
+ { cell: '!=:col', value: '0', hash: { col: 0 }, result: true },
29
+ { cell: '!=:col', value: 1, hash: { col: 0 }, result: true },
30
+ { cell: '!=:key', value: 0, hash: { col: 0 }, result: true },
31
+ { cell: '>:col', value: 1, hash: { col: 0 }, result: true },
32
+ { cell: '>:col', value: 0, hash: { col: 1 }, result: false },
33
+ { cell: '<:col', value: 0, hash: { col: 1 }, result: true },
34
+ { cell: '<:col', value: 1, hash: { col: 0 }, result: false },
35
+ { cell: '= :col', value: 0, hash: { col: 0 }, result: true },
36
+ { cell: '==:col', value: 0, hash: { col: 0 }, result: true },
37
+ { cell: ':=:col', value: 0, hash: { col: 0 }, result: true },
38
+ { cell: '= :col', value: '0', hash: { col: 0 }, result: false },
39
+ { cell: '>=:col', value: 1, hash: { col: 0 }, result: true },
40
+ { cell: '>=:col', value: 1, hash: { col: 1 }, result: true },
41
+ { cell: '>=:col', value: 0, hash: { col: 1 }, result: false },
42
+ { cell: '<=:col', value: 0, hash: { col: 1 }, result: true },
43
+ { cell: '<=:col', value: 1, hash: { col: 0 }, result: false },
44
+ { cell: '<=:col', value: 1, hash: { col: 1 }, result: true },
45
+ { cell: '<=:col', value: '1', hash: { col: 1 }, result: nil },
46
+ { cell: '<=:col', value: '1', hash: { col: '1' }, result: true },
47
+ ]
48
+ examples.each do |ex|
49
+ it "cell #{ex[:cell]} matches value: #{ex[:value]} to hash: #{ex[:hash]}" do
50
+ proc = matcher.matches?(ex[:cell])
51
+ expect(proc).to be_a(CSVDecision::Matchers::Proc)
52
+ expect(proc.function.call(ex[:value], ex[:hash])).to eq ex[:result]
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'does not match a function' do
58
+ data = ['1', 'abc', 'abc.*def', '-1..1', '0...3', ':= false()', ':= lookup?()']
59
+
60
+ data.each do |cell|
61
+ it "cell #{cell} is not a function" do
62
+ expect(matcher.matches?(cell)).to eq false
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/csv_decision'
4
+
5
+ SPEC_DATA_VALID ||= File.join(CSVDecision.root, 'spec', 'data', 'valid')
6
+ SPEC_DATA_INVALID ||= File.join(CSVDecision.root, 'spec', 'data', 'invalid')
7
+
8
+ describe CSVDecision::Options do
9
+ it 'sets the default options' do
10
+ data = <<~DATA
11
+ IN :input, OUT :output
12
+ input0, output0
13
+ DATA
14
+
15
+ result = CSVDecision.parse(data)
16
+
17
+ expected = {
18
+ first_match: true,
19
+ regexp_implicit: false,
20
+ text_only: false,
21
+ matchers: CSVDecision::Options::DEFAULT_MATCHERS
22
+ }
23
+ expect(result.options).to eql expected
24
+ end
25
+
26
+ it 'overrides the default options' do
27
+ data = <<~DATA
28
+ IN :input, OUT :output
29
+ input0, output0
30
+ DATA
31
+
32
+ result = CSVDecision.parse(data,
33
+ first_match: false,
34
+ matchers: [CSVDecision::Matchers::Pattern])
35
+
36
+ expected = {
37
+ first_match: false,
38
+ regexp_implicit: false,
39
+ text_only: false,
40
+ matchers: [CSVDecision::Matchers::Pattern]
41
+ }
42
+ expect(result.options).to eql expected
43
+ end
44
+
45
+ it 'rejects an invalid option argument' do
46
+ data = <<~DATA
47
+ IN :input, OUT :output
48
+ input0, output0
49
+ DATA
50
+
51
+ expect { CSVDecision.parse(data, bad_option: false) }
52
+ .to raise_error(CSVDecision::CellValidationError,
53
+ "invalid option(s) supplied: [:bad_option]")
54
+ end
55
+
56
+ it 'parses options from a CSV file' do
57
+ file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file1.csv'))
58
+ result = CSVDecision.parse(file)
59
+
60
+ expected = {
61
+ first_match: false,
62
+ regexp_implicit: false,
63
+ text_only: false,
64
+ matchers: CSVDecision::Options::DEFAULT_MATCHERS
65
+ }
66
+ expect(result.options).to eql expected
67
+ end
68
+
69
+ it 'options from the CSV file override method options' do
70
+ file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file2.csv'))
71
+ result = CSVDecision.parse(file, first_match: true, regexp_implicit: nil)
72
+
73
+ expected = {
74
+ first_match: false,
75
+ regexp_implicit: true,
76
+ text_only: false,
77
+ matchers: CSVDecision::Options::DEFAULT_MATCHERS
78
+ }
79
+ expect(result.options).to eql expected
80
+ end
81
+
82
+ it 'parses index option from the CSV file' do
83
+ file = Pathname(File.join(SPEC_DATA_VALID, 'options_in_file3.csv'))
84
+ result = CSVDecision.parse(file)
85
+
86
+ expected = {
87
+ first_match: false,
88
+ regexp_implicit: true,
89
+ text_only: false,
90
+ matchers: CSVDecision::Options::DEFAULT_MATCHERS
91
+ }
92
+ expect(result.options).to eql expected
93
+ end
94
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/csv_decision'
4
+
5
+ describe CSVDecision::Parse do
6
+ it 'rejects an empty decision table' do
7
+ expect { CSVDecision.parse('') }
8
+ .to raise_error(CSVDecision::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(CSVDecision.root, 'spec/data/valid', 'valid.csv'))
14
+ result = CSVDecision.parse(file)
15
+
16
+ expected = [
17
+ ['input', '']
18
+ ]
19
+
20
+ expect(result).to be_a(CSVDecision::Table)
21
+ expect(result.rows).to eq expected
22
+ end
23
+
24
+ context 'it parses valid CSV files' do
25
+ Dir[File.join(CSVDecision.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 { CSVDecision.parse(pathname) }.not_to raise_error
30
+ expect(CSVDecision.parse(pathname)).to be_a CSVDecision::Table
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'it rejects invalid CSV files' do
36
+ Dir[File.join(CSVDecision.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 { CSVDecision.parse(pathname) }.to raise_error(CSVDecision::FileError)
41
+ end
42
+ end
43
+ end
44
+ end