csv_decision 0.0.8 → 0.0.9
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +4 -0
- data/README.md +62 -28
- data/csv_decision.gemspec +1 -1
- data/doc/CSVDecision/CellValidationError.html +2 -2
- data/doc/CSVDecision/Columns/Dictionary.html +114 -20
- data/doc/CSVDecision/Columns/Entry.html +2 -2
- data/doc/CSVDecision/Columns.html +109 -27
- data/doc/CSVDecision/Data.html +2 -2
- data/doc/CSVDecision/Decide.html +2 -2
- data/doc/CSVDecision/Decision.html +21 -21
- data/doc/CSVDecision/Dictionary/Entry.html +508 -0
- data/doc/CSVDecision/Dictionary.html +265 -0
- data/doc/CSVDecision/Error.html +2 -2
- data/doc/CSVDecision/FileError.html +3 -3
- data/doc/CSVDecision/Header.html +37 -136
- data/doc/CSVDecision/Input.html +2 -2
- data/doc/CSVDecision/Load.html +2 -2
- data/doc/CSVDecision/Matchers/Constant.html +2 -2
- data/doc/CSVDecision/Matchers/Function.html +2 -2
- data/doc/CSVDecision/Matchers/Guard.html +92 -25
- data/doc/CSVDecision/Matchers/Matcher.html +14 -18
- data/doc/CSVDecision/Matchers/Numeric.html +2 -2
- data/doc/CSVDecision/Matchers/Pattern.html +2 -2
- data/doc/CSVDecision/Matchers/Range.html +2 -2
- data/doc/CSVDecision/Matchers/Symbol.html +2 -2
- data/doc/CSVDecision/Matchers.html +5 -5
- data/doc/CSVDecision/Options.html +2 -2
- data/doc/CSVDecision/Parse.html +6 -4
- data/doc/CSVDecision/Result.html +944 -0
- data/doc/CSVDecision/ScanRow.html +70 -80
- data/doc/CSVDecision/Table.html +134 -54
- data/doc/CSVDecision.html +5 -5
- data/doc/_index.html +18 -4
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +132 -62
- data/doc/index.html +132 -62
- data/doc/method_list.html +156 -60
- data/doc/top-level-namespace.html +2 -2
- data/lib/csv_decision/columns.rb +1 -8
- data/lib/csv_decision/decision.rb +45 -96
- data/lib/csv_decision/dictionary.rb +149 -0
- data/lib/csv_decision/header.rb +6 -133
- data/lib/csv_decision/matchers.rb +1 -2
- data/lib/csv_decision/parse.rb +18 -7
- data/lib/csv_decision/result.rb +180 -0
- data/lib/csv_decision/scan_row.rb +13 -7
- data/lib/csv_decision/table.rb +6 -5
- data/lib/csv_decision.rb +3 -1
- data/spec/csv_decision/columns_spec.rb +25 -4
- data/spec/csv_decision/examples_spec.rb +25 -0
- data/spec/csv_decision/matchers/guard_spec.rb +26 -9
- data/spec/csv_decision/table_spec.rb +48 -2
- metadata +7 -2
data/doc/_index.html
CHANGED
@@ -135,6 +135,13 @@
|
|
135
135
|
|
136
136
|
</li>
|
137
137
|
|
138
|
+
<li>
|
139
|
+
<span class='object_link'><a href="CSVDecision/Dictionary.html" title="CSVDecision::Dictionary (module)">Dictionary</a></span>
|
140
|
+
|
141
|
+
<small>(CSVDecision)</small>
|
142
|
+
|
143
|
+
</li>
|
144
|
+
|
138
145
|
<li>
|
139
146
|
<span class='object_link'><a href="CSVDecision/Columns/Dictionary.html" title="CSVDecision::Columns::Dictionary (class)">Dictionary</a></span>
|
140
147
|
|
@@ -151,9 +158,9 @@
|
|
151
158
|
<ul>
|
152
159
|
|
153
160
|
<li>
|
154
|
-
<span class='object_link'><a href="CSVDecision/
|
161
|
+
<span class='object_link'><a href="CSVDecision/Dictionary/Entry.html" title="CSVDecision::Dictionary::Entry (class)">Entry</a></span>
|
155
162
|
|
156
|
-
<small>(CSVDecision::
|
163
|
+
<small>(CSVDecision::Dictionary)</small>
|
157
164
|
|
158
165
|
</li>
|
159
166
|
|
@@ -338,6 +345,13 @@
|
|
338
345
|
|
339
346
|
</li>
|
340
347
|
|
348
|
+
<li>
|
349
|
+
<span class='object_link'><a href="CSVDecision/Result.html" title="CSVDecision::Result (class)">Result</a></span>
|
350
|
+
|
351
|
+
<small>(CSVDecision)</small>
|
352
|
+
|
353
|
+
</li>
|
354
|
+
|
341
355
|
</ul>
|
342
356
|
</ul>
|
343
357
|
|
@@ -387,9 +401,9 @@
|
|
387
401
|
</div>
|
388
402
|
|
389
403
|
<div id="footer">
|
390
|
-
Generated on
|
404
|
+
Generated on Fri Jan 5 21:43:58 2018 by
|
391
405
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
392
|
-
0.9.12 (ruby-2.
|
406
|
+
0.9.12 (ruby-2.4.0).
|
393
407
|
</div>
|
394
408
|
|
395
409
|
</div>
|
data/doc/class_list.html
CHANGED
@@ -43,7 +43,7 @@
|
|
43
43
|
|
44
44
|
<ul id="full_list" class="class">
|
45
45
|
<li id="object_" class="odd"><div class="item" style="padding-left:30px"><span class='object_link'><a href="top-level-namespace.html" title="Top Level Namespace (root)">Top Level Namespace</a></span></div></li>
|
46
|
-
<li id='object_CSVDecision' class='even'><div class='item' style='padding-left:30px'><a class='toggle'></a> <span class='object_link'><a href="CSVDecision.html" title="CSVDecision (module)">CSVDecision</a></span><small class='search_info'>Top Level Namespace</small></div><ul><li id='object_CSVDecision::CellValidationError' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/CellValidationError.html" title="CSVDecision::CellValidationError (class)">CellValidationError</a></span> < Error<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Columns' class='collapsed even'><div class='item' style='padding-left:45px'><a class='toggle'></a> <span class='object_link'><a href="CSVDecision/Columns.html" title="CSVDecision::Columns (class)">Columns</a></span> < Object<small class='search_info'>CSVDecision</small></div><ul><li id='object_CSVDecision::Columns::Dictionary' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Columns/Dictionary.html" title="CSVDecision::Columns::Dictionary (class)">Dictionary</a></span> < Object<small class='search_info'>CSVDecision::Columns</small></div></li><li id='object_CSVDecision::
|
46
|
+
<li id='object_CSVDecision' class='even'><div class='item' style='padding-left:30px'><a class='toggle'></a> <span class='object_link'><a href="CSVDecision.html" title="CSVDecision (module)">CSVDecision</a></span><small class='search_info'>Top Level Namespace</small></div><ul><li id='object_CSVDecision::CellValidationError' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/CellValidationError.html" title="CSVDecision::CellValidationError (class)">CellValidationError</a></span> < Error<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Columns' class='collapsed even'><div class='item' style='padding-left:45px'><a class='toggle'></a> <span class='object_link'><a href="CSVDecision/Columns.html" title="CSVDecision::Columns (class)">Columns</a></span> < Object<small class='search_info'>CSVDecision</small></div><ul><li id='object_CSVDecision::Columns::Dictionary' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Columns/Dictionary.html" title="CSVDecision::Columns::Dictionary (class)">Dictionary</a></span> < Object<small class='search_info'>CSVDecision::Columns</small></div></li></ul></li><li id='object_CSVDecision::Data' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Data.html" title="CSVDecision::Data (module)">Data</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Decide' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Decide.html" title="CSVDecision::Decide (module)">Decide</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Decision' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Decision.html" title="CSVDecision::Decision (class)">Decision</a></span> < Object<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Dictionary' class='collapsed even'><div class='item' style='padding-left:45px'><a class='toggle'></a> <span class='object_link'><a href="CSVDecision/Dictionary.html" title="CSVDecision::Dictionary (module)">Dictionary</a></span><small class='search_info'>CSVDecision</small></div><ul><li id='object_CSVDecision::Dictionary::Entry' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Dictionary/Entry.html" title="CSVDecision::Dictionary::Entry (class)">Entry</a></span> < Struct<small class='search_info'>CSVDecision::Dictionary</small></div></li></ul></li><li id='object_CSVDecision::Error' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Error.html" title="CSVDecision::Error (class)">Error</a></span> < StandardError<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::FileError' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/FileError.html" title="CSVDecision::FileError (class)">FileError</a></span> < Error<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Header' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Header.html" title="CSVDecision::Header (module)">Header</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Input' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Input.html" title="CSVDecision::Input (module)">Input</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Load' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Load.html" title="CSVDecision::Load (module)">Load</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Matchers' class='collapsed even'><div class='item' style='padding-left:45px'><a class='toggle'></a> <span class='object_link'><a href="CSVDecision/Matchers.html" title="CSVDecision::Matchers (class)">Matchers</a></span> < Object<small class='search_info'>CSVDecision</small></div><ul><li id='object_CSVDecision::Matchers::Constant' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Constant.html" title="CSVDecision::Matchers::Constant (class)">Constant</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Function' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Function.html" title="CSVDecision::Matchers::Function (class)">Function</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Guard' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Guard.html" title="CSVDecision::Matchers::Guard (class)">Guard</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Matcher' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Matcher.html" title="CSVDecision::Matchers::Matcher (class)">Matcher</a></span> < Object<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Numeric' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Numeric.html" title="CSVDecision::Matchers::Numeric (class)">Numeric</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Pattern' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Pattern.html" title="CSVDecision::Matchers::Pattern (class)">Pattern</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Range' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Range.html" title="CSVDecision::Matchers::Range (class)">Range</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li><li id='object_CSVDecision::Matchers::Symbol' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="CSVDecision/Matchers/Symbol.html" title="CSVDecision::Matchers::Symbol (class)">Symbol</a></span> < Matcher<small class='search_info'>CSVDecision::Matchers</small></div></li></ul></li><li id='object_CSVDecision::Options' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Options.html" title="CSVDecision::Options (module)">Options</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Parse' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Parse.html" title="CSVDecision::Parse (module)">Parse</a></span><small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Result' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Result.html" title="CSVDecision::Result (class)">Result</a></span> < Object<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::ScanRow' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/ScanRow.html" title="CSVDecision::ScanRow (class)">ScanRow</a></span> < Object<small class='search_info'>CSVDecision</small></div></li><li id='object_CSVDecision::Table' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="CSVDecision/Table.html" title="CSVDecision::Table (class)">Table</a></span> < Object<small class='search_info'>CSVDecision</small></div></li></ul></li>
|
47
47
|
|
48
48
|
</ul>
|
49
49
|
</div>
|
data/doc/file.README.html
CHANGED
@@ -75,17 +75,17 @@ src="http://img.shields.io/badge/license-MIT-yellowgreen.svg"></a></p>
|
|
75
75
|
|
76
76
|
<h3 id="label-CSV+based+Ruby+decision+tables">CSV based Ruby decision tables</h3>
|
77
77
|
|
78
|
-
<p><code>csv_decision</code> is a RubyGem for CSV
|
79
|
-
|
80
|
-
|
78
|
+
<p><code>csv_decision</code> is a RubyGem for CSV based <a
|
79
|
+
href="https://en.wikipedia.org/wiki/Decision_table">decision tables</a>. It
|
80
|
+
accepts decision tables implemented as a <a
|
81
81
|
href="https://en.wikipedia.org/wiki/Comma-separated_values">CSV file</a>,
|
82
82
|
which can then be used to execute complex conditional logic against an
|
83
83
|
input hash, producing a decision as an output hash.</p>
|
84
84
|
|
85
85
|
<h3 id="label-Why+use+csv_decision-3F">Why use <code>csv_decision</code>?</h3>
|
86
86
|
|
87
|
-
<p>Typical “business logic” is notoriously illogical
|
88
|
-
and one-off exceptions. A decision table can
|
87
|
+
<p>Typical “business logic” is notoriously illogical - full of corner cases
|
88
|
+
and one-off exceptions. A decision table can express data-based decisions
|
89
89
|
in a way that comes more naturally to subject matter experts, who typically
|
90
90
|
prefer spreadsheet models. Business logic may then be encapsulated,
|
91
91
|
avoiding the need to write tortuous conditional expressions in Ruby that
|
@@ -93,9 +93,9 @@ draw the ire of <code>rubocop</code> and its ilk.</p>
|
|
93
93
|
|
94
94
|
<p>This gem and the examples below take inspiration from <a
|
95
95
|
href="https://github.com/jmettraux/rufus-decision">rufus/decision</a>.
|
96
|
-
(
|
97
|
-
|
98
|
-
|
96
|
+
(That gem is no longer maintained and CSV Decision has better decision-time
|
97
|
+
performance, at the expense of slower table parse times and more memory –
|
98
|
+
see <code>benchmarks/rufus_decision.rb</code>.)</p>
|
99
99
|
|
100
100
|
<h3 id="label-Installation">Installation</h3>
|
101
101
|
|
@@ -109,27 +109,26 @@ more memory – see <code>benchmarks/rufus_decision.rb</code>)</p>
|
|
109
109
|
<h3 id="label-Simple+example">Simple example</h3>
|
110
110
|
|
111
111
|
<p>This table considers two input conditions: <code>topic</code> and
|
112
|
-
<code>region</code
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
sports
|
119
|
-
|
120
|
-
finance
|
121
|
-
finance
|
122
|
-
|
123
|
-
politics
|
124
|
-
politics
|
125
|
-
|
126
|
-
| | Zach</code></pre>
|
112
|
+
<code>region</code>, labeled <code>in:</code>. Certain combinations yield
|
113
|
+
an output value for <code>team_member</code>, labeled <code>out:</code>.</p>
|
114
|
+
|
115
|
+
<pre class="code ruby"><code class="ruby">in:topic | in:region | out:team_member
|
116
|
+
---------+------------+----------------
|
117
|
+
sports | Europe | Alice
|
118
|
+
sports | | Bob
|
119
|
+
finance | America | Charlie
|
120
|
+
finance | Europe | Donald
|
121
|
+
finance | | Ernest
|
122
|
+
politics | Asia | Fujio
|
123
|
+
politics | America | Gilbert
|
124
|
+
politics | | Henry
|
125
|
+
| | Zach</code></pre>
|
127
126
|
|
128
127
|
<p>When the topic is <code>finance</code> and the region is
|
129
128
|
<code>Europe</code> the team member <code>Donald</code> is selected.</p>
|
130
129
|
|
131
130
|
<p>This is a “first match” decision table in that as soon as a match is made
|
132
|
-
execution stops and a single output
|
131
|
+
execution stops and a single output row (hash) is returned.</p>
|
133
132
|
|
134
133
|
<p>The ordering of rows matters. <code>Ernest</code>, who is in charge of
|
135
134
|
<code>finance</code> for the rest of the world, except for
|
@@ -138,7 +137,7 @@ colleagues <code>Charlie</code> and <code>Donald</code>. <code>Zach</code>
|
|
138
137
|
has been placed last, catching all the input combos not matching any other
|
139
138
|
row.</p>
|
140
139
|
|
141
|
-
<p>Here
|
140
|
+
<p>Here is the example as code:</p>
|
142
141
|
|
143
142
|
<p>“`ruby # Valid CSV string data = <<~DATA in :topic, in :region,
|
144
143
|
out :team_member sports, Europe, Alice sports, , Bob finance, America,
|
@@ -147,13 +146,17 @@ politics, America, Gilbert politics, , Henry , , Zach DATA</p>
|
|
147
146
|
|
148
147
|
<p>table = CSVDecision.parse(data)</p>
|
149
148
|
|
150
|
-
<p>table.decide(topic: 'finance', region: 'Europe')
|
151
|
-
team_member: 'Donald' table.decide(topic: 'sports',
|
152
|
-
region: nil)
|
153
|
-
'culture', region: 'America')
|
154
|
-
“`</p>
|
149
|
+
<p>table.decide(topic: 'finance', region: 'Europe') #=> {
|
150
|
+
team_member: 'Donald' } table.decide(topic: 'sports',
|
151
|
+
region: nil) #=> { team_member: 'Bob' } table.decide(topic:
|
152
|
+
'culture', region: 'America') #=> { team_member:
|
153
|
+
'Zach' } “`</p>
|
155
154
|
|
156
|
-
<p>An empty <code>in
|
155
|
+
<p>An empty <code>in:</code> cell means “matches any value”, even nils.</p>
|
156
|
+
|
157
|
+
<p>Note that all column header names are symbolized, so it's actually more
|
158
|
+
accurate to write <code>in :topic</code>; however spaces before and after
|
159
|
+
the <code>:</code> do not matter.</p>
|
157
160
|
|
158
161
|
<p>If you have cloned this gem's git repo, then the example can also be
|
159
162
|
run by loading the table from a CSV file:</p>
|
@@ -163,12 +166,12 @@ CSVDecision.parse(Pathname('spec/data/valid/simple_example.csv'))
|
|
163
166
|
</code></p>
|
164
167
|
|
165
168
|
<p>We can also load this same table using the option: <code>first_match:
|
166
|
-
false</code>, which means that
|
167
|
-
an array of hashes.</p>
|
169
|
+
false</code>, which means that <em>all</em> matching rows will be
|
170
|
+
accumulated into an array of hashes.</p>
|
168
171
|
|
169
172
|
<p><code>ruby table = CSVDecision.parse(data, first_match: false)
|
170
|
-
table.decide(topic: 'finance', region: 'Europe')
|
171
|
-
team_member: %w[Donald Ernest Zach]
|
173
|
+
table.decide(topic: 'finance', region: 'Europe') #=> {
|
174
|
+
team_member: %w[Donald Ernest Zach] } </code></p>
|
172
175
|
|
173
176
|
<p>For more examples see <code>spec/csv_decision/table_spec.rb</code>.
|
174
177
|
Complete documentation of all table parameters is in the code - see
|
@@ -177,26 +180,41 @@ Complete documentation of all table parameters is in the code - see
|
|
177
180
|
|
178
181
|
<h3 id="label-CSV+Decision+features">CSV Decision features</h3>
|
179
182
|
<ul><li>
|
183
|
+
<p>Either returns the first matching row as a hash (default), or accumulates
|
184
|
+
all matches as an array of hashes (i.e., <code>parse</code> option
|
185
|
+
<code>first_match: false</code> or CSV file option
|
186
|
+
<code>accumulate</code>).</p>
|
187
|
+
</li><li>
|
180
188
|
<p>Fast decision-time performance (see <code>benchmarks</code> folder).</p>
|
181
189
|
</li><li>
|
182
|
-
<p>In addition to simple
|
183
|
-
|
190
|
+
<p>In addition to simple strings, <code>csv_decision</code> can match basic
|
191
|
+
Ruby constants (e.g., <code>=nil</code>), regular expressions (e.g.,
|
192
|
+
<code>=~ on|off</code>), comparisons (e.g., <code>> 100.0</code> ) and
|
193
|
+
Ruby-style ranges (e.g., <code>1..10</code>)</p>
|
194
|
+
</li><li>
|
195
|
+
<p>Can compare an input column versus another input hash key - e.g.,
|
196
|
+
<code>> :column</code>.</p>
|
197
|
+
</li><li>
|
198
|
+
<p>Any cell starting with <code>#</code> is treated as a comment, and comments
|
199
|
+
may appear anywhere in the table. (Comment cells are always interpreted as
|
200
|
+
the empty string.)</p>
|
184
201
|
</li><li>
|
185
|
-
<p>Can use column
|
186
|
-
|
202
|
+
<p>Can use column symbol expressions or Ruby methods (0-arity) in input
|
203
|
+
columns for matching - e.g., <code>:column.zero?</code> or <code>:column
|
204
|
+
== 0</code>.</p>
|
205
|
+
</li><li>
|
206
|
+
<p>May also use Ruby methods in output columns - e.g.,
|
207
|
+
<code>:column.length</code>.</p>
|
187
208
|
</li><li>
|
188
209
|
<p>Accepts data as a file, CSV string or an array of arrays. (For safety all
|
189
210
|
input data is force encoded to UTF-8, and non-ascii strings are converted
|
190
211
|
to empty strings.)</p>
|
191
212
|
</li><li>
|
192
213
|
<p>All CSV cells are parsed for correctness, and helpful error messages
|
193
|
-
generated for bad
|
194
|
-
</li><li>
|
195
|
-
<p>Either returns the first matching row as a hash, or accumulates all matches
|
196
|
-
as an array of hashes.</p>
|
214
|
+
generated for bad input.</p>
|
197
215
|
</li></ul>
|
198
216
|
|
199
|
-
<
|
217
|
+
<h4 id="label-Constants+other+than+strings">Constants other than strings</h4>
|
200
218
|
|
201
219
|
<p>Although <code>csv_decision</code> is string oriented, it does recognise
|
202
220
|
other types of constant present in the input hash. Specifically, the
|
@@ -217,10 +235,10 @@ value: nil<br> table.decide(constant: 0) # returns value: 0<br>
|
|
217
235
|
table.decide(constant: BigDecimal('100.0')) # returns value:
|
218
236
|
BigDecimal('100.0')<br> “`</p>
|
219
237
|
|
220
|
-
<
|
238
|
+
<h4 id="label-Column+header+symbols">Column header symbols</h4>
|
221
239
|
|
222
|
-
<p>All input and output column names are symbolized, and
|
223
|
-
simple expressions that refer to values in the input hash.</p>
|
240
|
+
<p>All input and output column names are symbolized, and those symbols may be
|
241
|
+
used to form simple expressions that refer to values in the input hash.</p>
|
224
242
|
|
225
243
|
<p>For example: “`ruby data = <<~DATA in :node, in :parent, out :top?
|
226
244
|
, == :node, yes , , no DATA</p>
|
@@ -234,7 +252,8 @@ simple expressions that refer to values in the input hash.</p>
|
|
234
252
|
|
235
253
|
<p>Note that there is no need to include an input column for
|
236
254
|
<code>:node</code> in the decision table - it just needs to be present in
|
237
|
-
the input hash.
|
255
|
+
the input hash. The expression, <code>== :node</code> should be read as
|
256
|
+
<code>:parent == :node</code>. It can also be shortened to just
|
238
257
|
<code>:node</code>, so the above decision table may be simplified to:</p>
|
239
258
|
|
240
259
|
<p><code>ruby data = <<~DATA in :parent, out :top?
|
@@ -243,9 +262,9 @@ operators are also supported: <code>!=</code>, <code>></code>,
|
|
243
262
|
<code>>=</code>, <code><</code>, <code><=</code>. For more simple
|
244
263
|
examples see <code>spec/csv_decision/examples_spec.rb</code>.</p>
|
245
264
|
|
246
|
-
<
|
265
|
+
<h4 id="label-Input+guard+conditions">Input guard conditions</h4>
|
247
266
|
|
248
|
-
<p>Sometimes it's more convenient to write guard
|
267
|
+
<p>Sometimes it's more convenient to write guard expressions in a single
|
249
268
|
column specialized for that purpose. For example:</p>
|
250
269
|
|
251
270
|
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='heredoc_beg'><<~DATA</span>
|
@@ -264,7 +283,39 @@ column specialized for that purpose. For example:</p>
|
|
264
283
|
<span class='comment'>#=> { ID: '123456789012', ID_type: 'ISIN', len: 12 }
|
265
284
|
</span></code></pre>
|
266
285
|
|
267
|
-
<p>
|
286
|
+
<p>Input <code>guard:</code> columns may be anonymous, and must contain
|
287
|
+
non-constant expressions. In addition to 0-arity Ruby methods, the
|
288
|
+
following comparison operators are allowed: <code>==</code>,
|
289
|
+
<code>!=</code>, <code>></code>, <code>>=</code>, <code><</code>
|
290
|
+
and <code><=</code>. Also, regular expressions are supported - i.e.,
|
291
|
+
<code>=~</code> and <code>!~</code>.</p>
|
292
|
+
|
293
|
+
<h4 id="label-Output+if+conditions">Output if conditions</h4>
|
294
|
+
|
295
|
+
<p>In some situations it is useful to apply filter conditions <em>after</em>
|
296
|
+
all the output columns have been derived. For example:</p>
|
297
|
+
|
298
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='heredoc_beg'><<~DATA</span>
|
299
|
+
<span class='tstring_content'> in :country, guard:, out :ID, out :ID_type, out :len, if:
|
300
|
+
</span><span class='tstring_content'> US, :CUSIP.present?, :CUSIP, CUSIP8, :ID.length, :len == 8
|
301
|
+
</span><span class='tstring_content'> US, :CUSIP.present?, :CUSIP, CUSIP9, :ID.length, :len == 9
|
302
|
+
</span><span class='tstring_content'> US, :CUSIP.present?, :CUSIP, DUMMY, :ID.length,
|
303
|
+
</span><span class='tstring_content'> , :ISIN.present?, :ISIN, ISIN, :ID.length, :len == 12
|
304
|
+
</span><span class='tstring_content'> , :ISIN.present?, :ISIN, DUMMY, :ID.length,
|
305
|
+
</span><span class='tstring_content'> , :CUSIP.present?, :CUSIP, DUMMY, :ID.length,
|
306
|
+
</span><span class='heredoc_end'> DATA
|
307
|
+
</span>
|
308
|
+
<span class='id identifier rubyid_table'>table</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="CSVDecision.html" title="CSVDecision (module)">CSVDecision</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="CSVDecision.html#parse-class_method" title="CSVDecision.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='id identifier rubyid_data'>data</span><span class='rparen'>)</span>
|
309
|
+
<span class='id identifier rubyid_table'>table</span><span class='period'>.</span><span class='id identifier rubyid_decide'>decide</span><span class='lparen'>(</span><span class='label'>country:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>US</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>CUSIP:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>123456789</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span> <span class='comment'>#=> {ID: '123456789', ID_type: 'CUSIP9', len: 9}
|
310
|
+
</span><span class='id identifier rubyid_table'>table</span><span class='period'>.</span><span class='id identifier rubyid_decide'>decide</span><span class='lparen'>(</span><span class='label'>CUSIP:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>12345678</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>ISIN:</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>1234567890</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span> <span class='comment'>#=> {ID: '1234567890', ID_type: 'DUMMY', len: 10}
|
311
|
+
</span></code></pre>
|
312
|
+
|
313
|
+
<p>Output <code>if:</code> columns may be anonymous, and must contain
|
314
|
+
non-constant expressions. In addition to 0-arity Ruby methods, the
|
315
|
+
following comparison operators are allowed: <code>==</code>,
|
316
|
+
<code>!=</code>, <code>></code>, <code>>=</code>, <code><</code>
|
317
|
+
and <code><=</code>. Also, regular expressions are supported - i.e.,
|
318
|
+
<code>=~</code> and <code>!~</code>.</p>
|
268
319
|
|
269
320
|
<h3 id="label-Testing">Testing</h3>
|
270
321
|
|
@@ -277,21 +328,40 @@ bundle install rspec </code></p>
|
|
277
328
|
<h3 id="label-Planned+features">Planned features</h3>
|
278
329
|
|
279
330
|
<p><code>csv_decision</code> is still a work in progress, and will be enhanced
|
280
|
-
to support the following features: *
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
331
|
+
to support the following features: * Text-only input columns may be
|
332
|
+
indexed for faster lookup performance. * Input hash values may be
|
333
|
+
(conditionally) defaulted with a constant or a function call. * Output
|
334
|
+
columns may construct interpolated strings referencing column symbols. *
|
335
|
+
Supply a pre-defined library of functions that can be called within input
|
336
|
+
columns to implement matching logic or from the output columns to
|
337
|
+
formulate the final decision. * Available functions may be extended with a
|
338
|
+
user-supplied library of Ruby methods for tailored logic.</p>
|
339
|
+
|
340
|
+
<h3 id="label-Reasons+for+the+limitations+of+column+expressions">Reasons for the limitations of column expressions</h3>
|
341
|
+
|
342
|
+
<p>The simple column expressions allowed by <code>csv_decision</code> are
|
343
|
+
purposely limited for reasons of understandability and maintainability. The
|
344
|
+
whole point of this gem is to make decision rules easier to express and
|
345
|
+
comprehend as declarative, tabular logic. While Ruby makes it easy to
|
346
|
+
execute arbitrary code embedded within a CSV file, this could easily result
|
347
|
+
in hard to debug logic that also poses safety risks.</p>
|
348
|
+
|
349
|
+
<h2 id="label-Changelog">Changelog</h2>
|
350
|
+
|
351
|
+
<p>See <a href="./CHANGELOG.md">CHANGELOG.md</a> for a list of changes.</p>
|
352
|
+
|
353
|
+
<h2 id="label-License">License</h2>
|
354
|
+
|
355
|
+
<p>CSV Decision © 2017-2018 by <a
|
356
|
+
href="mailto:brett@phillips-vickers.com">Brett Vickers</a>. CSV Decision is
|
357
|
+
licensed under the MIT license. Please see the <a
|
358
|
+
href="./LICENSE">LICENSE</a> document for more information.</p>
|
289
359
|
</div></div>
|
290
360
|
|
291
361
|
<div id="footer">
|
292
|
-
Generated on
|
362
|
+
Generated on Fri Jan 5 21:43:59 2018 by
|
293
363
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
294
|
-
0.9.12 (ruby-2.
|
364
|
+
0.9.12 (ruby-2.4.0).
|
295
365
|
</div>
|
296
366
|
|
297
367
|
</div>
|