rufus-decision 1.0 → 1.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.
data/lib/rufus/hashes.rb CHANGED
@@ -1,6 +1,5 @@
1
- #
2
1
  #--
3
- # Copyright (c) 2008, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2008-2009, John Mettraux, jmettraux@gmail.com
4
3
  #
5
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -19,19 +18,17 @@
19
18
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
19
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
20
  # THE SOFTWARE.
22
- #++
23
21
  #
22
+ # Made in Japan.
23
+ #++
24
24
 
25
- #
26
- # "made in Japan"
27
- #
28
- # John Mettraux at openwfe.org
29
- #
30
25
 
26
+ require 'fileutils'
31
27
  require 'rufus/treechecker'
32
28
 
33
29
 
34
30
  module Rufus
31
+ module Decision
35
32
 
36
33
  #
37
34
  # In the Java world, this class would be considered abstract.
@@ -46,6 +43,8 @@ module Rufus
46
43
  #
47
44
  class HashFilter
48
45
 
46
+ attr_reader :parent_hash
47
+
49
48
  def initialize (parent_hash)
50
49
 
51
50
  @parent_hash = parent_hash
@@ -67,59 +66,59 @@ module Rufus
67
66
 
68
67
  protected
69
68
 
70
- def do_split (element)
69
+ def do_split (element)
71
70
 
72
- return [ nil, element ] unless element.is_a?(String)
71
+ return [ nil, element ] unless element.is_a?(String)
73
72
 
74
- a = element.split(':', 2)
75
- return [ nil ] + a if a.length == 1
76
- a
77
- end
73
+ a = element.split(':', 2)
74
+ return [ nil ] + a if a.length == 1
75
+ a
76
+ end
78
77
 
79
- def handles_prefix? (p)
78
+ def handles_prefix? (p)
80
79
 
81
- false
82
- end
80
+ false
81
+ end
83
82
 
84
- def do_eval (key, p, k)
83
+ def do_eval (key, p, k)
85
84
 
86
- raise NotImplementedError.new(
87
- "missing do_eval(key, p, k) implementation")
88
- end
85
+ raise NotImplementedError.new(
86
+ "missing do_eval(key, p, k) implementation")
87
+ end
89
88
 
90
- def do_lookup (key, p, k)
89
+ def do_lookup (key, p, k)
91
90
 
92
- if handles_prefix?(p)
91
+ if handles_prefix?(p)
93
92
 
94
- do_eval(key, p, k)
93
+ do_eval(key, p, k)
95
94
 
96
- elsif @parent_hash.respond_to?(:do_lookup)
95
+ elsif @parent_hash.respond_to?(:do_lookup)
97
96
 
98
- @parent_hash.do_lookup key, p, k
97
+ @parent_hash.do_lookup(key, p, k)
99
98
 
100
- else
99
+ else
101
100
 
102
- @parent_hash[key]
103
- end
101
+ @parent_hash[key]
104
102
  end
103
+ end
105
104
 
106
- def do_put (key, value, p, v)
105
+ def do_put (key, value, p, v)
107
106
 
108
- val = value
107
+ val = value
109
108
 
110
- if handles_prefix?(p)
109
+ if handles_prefix?(p)
111
110
 
112
- @parent_hash[key] = do_eval(value, p, v)
111
+ @parent_hash[key] = do_eval(value, p, v)
113
112
 
114
- elsif @parent_hash.respond_to?(:do_put)
113
+ elsif @parent_hash.respond_to?(:do_put)
115
114
 
116
- @parent_hash.do_put key, value, p, v
115
+ @parent_hash.do_put key, value, p, v
117
116
 
118
- else
117
+ else
119
118
 
120
- @parent_hash[key] = value
121
- end
119
+ @parent_hash[key] = value
122
120
  end
121
+ end
123
122
  end
124
123
 
125
124
  #
@@ -146,33 +145,33 @@ module Rufus
146
145
 
147
146
  def initialize (parent_hash)
148
147
 
149
- super parent_hash
148
+ super(parent_hash)
150
149
  end
151
150
 
152
151
  protected
153
152
 
154
- RP = [ 'r', 'ruby', 'reval' ]
153
+ RP = %w{ r ruby reval }
155
154
 
156
- def handles_prefix? (prefix)
155
+ def handles_prefix? (prefix)
157
156
 
158
- RP.include?(prefix)
159
- end
157
+ RP.include?(prefix)
158
+ end
160
159
 
161
- #
162
- # Ready for override.
163
- #
164
- def get_binding
160
+ # Ready for override.
161
+ #
162
+ def get_binding
165
163
 
166
- binding()
167
- end
164
+ binding()
165
+ end
168
166
 
169
- def do_eval (key, p, k)
167
+ def do_eval (key, p, k)
170
168
 
171
- #Rufus::eval_safely(k, @safe_level, get_binding)
172
- Rufus::check_and_eval(k, get_binding)
173
- end
169
+ Rufus::Decision.check_and_eval(k, get_binding)
170
+ end
174
171
  end
175
172
 
173
+ # An abstract syntax tree check (prior to any ruby eval)
174
+ #
176
175
  TREECHECKER = Rufus::TreeChecker.new do
177
176
 
178
177
  exclude_fvccall :abort, :exit, :exit!
@@ -200,6 +199,9 @@ module Rufus
200
199
  end
201
200
  TREECHECKER.freeze
202
201
 
202
+ # Given a string (of ruby code), first makes sure it doesn't contain
203
+ # harmful code, then evaluates it.
204
+ #
203
205
  def self.check_and_eval (ruby_code, bndng=binding())
204
206
 
205
207
  TREECHECKER.check(ruby_code)
@@ -209,12 +211,6 @@ module Rufus
209
211
  eval(ruby_code, bndng)
210
212
  end
211
213
 
212
- private
213
-
214
- def Rufus.unescape (text)
215
-
216
- text.gsub("\\\\\\$\\{", "\\${")
217
- end
218
-
214
+ end
219
215
  end
220
216
 
@@ -1,37 +1,28 @@
1
1
 
2
2
  #
3
- # Testing rufus-deciision
4
- #
5
- # John Mettraux at openwfe.org
3
+ # Testing rufus-decision
6
4
  #
7
5
  # Sun Oct 29 15:41:44 JST 2006
8
6
  #
9
7
 
10
8
  require 'test/unit'
11
9
 
12
- require 'dmixin'
10
+ require File.dirname(__FILE__) + '/test_base.rb'
13
11
 
14
12
 
15
- class DecisionTest < Test::Unit::TestCase
13
+ class Decision0Test < Test::Unit::TestCase
16
14
  include DecisionTestMixin
17
15
 
18
- #def setup
19
- #end
20
-
21
- #def teardown
22
- #end
23
-
24
- CSV0 = \
25
- """
16
+ CSV0 = %{
26
17
  ,,
27
18
  in:fx,in:fy,out:fz
28
19
  ,,
29
20
  a,b,0
30
21
  c,d,1
31
22
  e,f,2
32
- """
23
+ }
33
24
 
34
- def test_csv_0
25
+ def test_0
35
26
 
36
27
  wi = {
37
28
  "fx" => "c",
@@ -46,15 +37,13 @@ e,f,2
46
37
  do_test(CSV0, wi, {}, { "fz" => nil }, false)
47
38
  end
48
39
 
49
- CSV0B = \
50
- """
51
-
40
+ CSV0B = %{
52
41
  in:fx,in:fy,out:fz
53
42
 
54
43
  a,b,0
55
44
  c,d,1
56
45
  e,f,2
57
- """
46
+ }
58
47
 
59
48
  def test_0b
60
49
 
@@ -67,32 +56,24 @@ e,f,2
67
56
 
68
57
  # test 1 moved to decision_1_test.rb
69
58
 
70
- CSV2 = \
71
- """
59
+ CSV2 = %{
72
60
  in:fx, in:fy, out:fz
73
61
  ,,
74
62
  a, b, 0
75
63
  c, d, 1
76
64
  e, f, 2
77
- """
65
+ }
78
66
 
79
67
  def test_2
80
68
 
81
- wi = {
82
- "fx" => "c",
83
- "fy" => "d"
84
- }
69
+ wi = { "fx" => "c", "fy" => "d" }
85
70
  do_test(CSV2, wi, {}, { "fz" => "1" }, false)
86
71
 
87
- wi = {
88
- "fx" => "a",
89
- "fy" => "d"
90
- }
72
+ wi = { "fx" => "a", "fy" => "d" }
91
73
  do_test(CSV2, wi, {}, { "fz" => nil }, false)
92
74
  end
93
75
 
94
- CSV3 = \
95
- """
76
+ CSV3 = %{
96
77
  in:weather, in:month, out:take_umbrella?
97
78
  ,,
98
79
  raining, , yes
@@ -100,7 +81,7 @@ sunny, , no
100
81
  cloudy, june, yes
101
82
  cloudy, may, yes
102
83
  cloudy, , no
103
- """
84
+ }
104
85
 
105
86
  def test_3
106
87
 
@@ -143,24 +124,24 @@ cloudy, , no
143
124
 
144
125
  def test_3c
145
126
 
146
- table = Rufus::DecisionTable.new("""
147
- in:topic,in:region,out:team_member
148
- sports,europe,Alice
149
- sports,,Bob
150
- finance,america,Charly
151
- finance,europe,Donald
152
- finance,,Ernest
153
- politics,asia,Fujio
154
- politics,america,Gilbert
155
- politics,,Henry
156
- ,,Zach
157
- """)
158
-
159
- h = {}
160
- h["topic"] = "politics"
161
- table.transform! h
162
-
163
- assert_equal "Henry", h["team_member"]
127
+ table = Rufus::DecisionTable.new(%{
128
+ in:topic,in:region,out:team_member
129
+ sports,europe,Alice
130
+ sports,,Bob
131
+ finance,america,Charly
132
+ finance,europe,Donald
133
+ finance,,Ernest
134
+ politics,asia,Fujio
135
+ politics,america,Gilbert
136
+ politics,,Henry
137
+ ,,Zach
138
+ })
139
+
140
+ h = {}
141
+ h["topic"] = "politics"
142
+ table.transform! h
143
+
144
+ assert_equal "Henry", h["team_member"]
164
145
  end
165
146
 
166
147
  CSV3D = "http://spreadsheets.google.com/pub?key=pCkopoeZwCNsMWOVeDjR1TQ&output=csv&gid=0"
@@ -194,95 +175,83 @@ cloudy, , no
194
175
 
195
176
  def test_3e
196
177
 
197
- table = Rufus::DecisionTable.new("""
198
- in:topic,in:region,out:team_member
199
- sports,europe,Alice
200
- """)
178
+ table = Rufus::DecisionTable.new(%{
179
+ in:topic,in:region,out:team_member
180
+ sports,europe,Alice
181
+ })
201
182
 
202
- h0 = {}
203
- h0["topic"] = "politics"
204
- h1 = table.transform! h0
183
+ h0 = {}
184
+ h0["topic"] = "politics"
185
+ h1 = table.transform! h0
205
186
 
206
- assert_equal h0.object_id, h1.object_id
187
+ assert_equal h0.object_id, h1.object_id
207
188
 
208
- h0 = {}
209
- h0["topic"] = "politics"
210
- h1 = table.transform h0
189
+ h0 = {}
190
+ h0["topic"] = "politics"
191
+ h1 = table.transform h0
211
192
 
212
- assert_not_equal h0.object_id, h1.object_id
193
+ assert_not_equal h0.object_id, h1.object_id
213
194
  end
214
195
 
215
- # CSV4 = \
216
- #'''
217
- #"in:weather", "in:month", "out:take_umbrella?"
218
- #"","",""
219
- #"raining","","yes"
220
- #"sunny","","no"
221
- #"cloudy","june","yes"
222
- #"cloudy","may","yes"
223
- #"cloudy","","no"
224
- #'''
225
-
226
- #def test_4
227
- # h = {}
228
- # h["weather"] = "raining"
229
- # h["month"] = "december"
230
- # do_test(CSV4, h, { "take_umbrella?" => "yes" }, false)
231
- # h = {}
232
- # h["weather"] = "cloudy"
233
- # h["month"] = "june"
234
- # do_test(CSV4, h, { "take_umbrella?" => "yes" }, false)
235
- # h = {}
236
- # h["weather"] = "cloudy"
237
- # h["month"] = "march"
238
- # do_test(CSV4, h, { "take_umbrella?" => "no" }, false)
239
- #end
240
-
241
- CSV5 = \
242
- """
243
- through,ignorecase,,
244
- ,,,
245
- in:fx, in:fy, out:fX, out:fY
246
- ,,,
247
- a, , true,
248
- , a, , true
249
- b, , false,
250
- , b, , false
251
- """
252
196
 
253
- def test_5
197
+ def test_through_and_ignorecase
254
198
 
255
- wi = {
256
- "fx" => "a",
257
- "fy" => "a"
199
+ table = %{
200
+ through,ignorecase,,
201
+ ,,,
202
+ in:fx, in:fy, out:fX, out:fY
203
+ ,,,
204
+ a, , true,
205
+ , a, , true
206
+ b, , false,
207
+ , b, , false
258
208
  }
259
- do_test(CSV5, wi, {}, { "fX" => "true", "fY" => "true" }, false)
260
209
 
261
- wi = {
262
- "fx" => "a",
263
- "fy" => "b"
264
- }
265
- do_test(CSV5, wi, {}, { "fX" => "true", "fY" => "false" }, false)
210
+ wi = { 'fx' => 'a', 'fy' => 'a' }
211
+ do_test(table, wi, {}, { 'fX' => 'true', 'fY' => 'true' }, false)
266
212
 
267
- wi = {
268
- "fx" => "A",
269
- "fy" => "b"
213
+ wi = { 'fx' => 'a', 'fy' => 'b' }
214
+ do_test(table, wi, {}, { 'fX' => 'true', 'fY' => 'false' }, false)
215
+
216
+ wi = { 'fx' => 'A', 'fy' => 'b' }
217
+ do_test(table, wi, {}, { 'fX' => 'true', 'fY' => 'false' }, false)
218
+ end
219
+
220
+ def test_through_and_ignorecase_set_at_table_initialization
221
+
222
+ table = %{
223
+ in:fx, in:fy, out:fX, out:fY
224
+ ,,,
225
+ a, , true,
226
+ , a, , true
227
+ b, , false,
228
+ , b, , false
270
229
  }
271
- do_test(CSV5, wi, {}, { "fX" => "true", "fY" => "false" }, false)
230
+
231
+ table = Rufus::Decision::Table.new(
232
+ table, :through => true, :ignore_case => true)
233
+
234
+ wi = { 'fx' => 'a', 'fy' => 'a' }
235
+ do_test(table, wi, {}, { 'fX' => 'true', 'fY' => 'true' }, false)
236
+
237
+ wi = { 'fx' => 'a', 'fy' => 'b' }
238
+ do_test(table, wi, {}, { 'fX' => 'true', 'fY' => 'false' }, false)
239
+
240
+ wi = { 'fx' => 'A', 'fy' => 'b' }
241
+ do_test(table, wi, {}, { 'fX' => 'true', 'fY' => 'false' }, false)
272
242
  end
273
243
 
274
244
  #
275
245
  # TEST 6
276
246
 
277
- CSV6 = \
278
- """
247
+ CSV6 = %{
279
248
  ,
280
249
  in:fx, out:fy
281
250
  ,
282
251
  <10,a
283
252
  <=100,b
284
253
  ,c
285
- """
254
+ }
286
255
 
287
256
  def test_6
288
257
 
@@ -300,15 +269,14 @@ in:fx, out:fy
300
269
  #
301
270
  # TEST 7
302
271
 
303
- CSV7 = \
304
- """
272
+ CSV7 = %{
305
273
  ,
306
274
  in:fx, out:fy
307
275
  ,
308
276
  >100,a
309
277
  >=10,b
310
278
  ,c
311
- """
279
+ }
312
280
 
313
281
  def test_7
314
282
 
@@ -328,42 +296,44 @@ in:fx, out:fy
328
296
  do_test(CSV7, wi, {}, { "fy" => "a" }, false)
329
297
  end
330
298
 
331
- CSV8 = \
332
- """
299
+ CSV8 = %{
333
300
  in:efx,in:efy,out:efz
334
301
  a,b,0
335
302
  c,d,1
336
303
  e,f,2
337
- """
304
+ }
338
305
 
339
306
  def test_8
340
307
 
341
308
  assert_equal CSV8.strip, Rufus::DecisionTable.new(CSV8).to_csv.strip
342
309
  end
343
310
 
344
- CSV9 = \
345
- """
346
- in:fx,in:fy,out:fz
347
- a,b,0
348
- c,d,${r: 1 + 2}
349
- e,f,2
350
- """
311
+ CSV9 = %{
312
+ in:fx,in:fy,out:fz
313
+ a,b,0
314
+ c,d,${r: 1 + 2}
315
+ e,f,2
316
+ }
351
317
 
352
- def test_9
318
+ def test_ruby_eval
353
319
 
354
- wi = {
355
- "fx" => "c",
356
- "fy" => "d"
357
- }
358
- do_test(CSV9, wi, { :ruby_eval => true }, { "fz" => "3" }, false)
320
+ wi = { 'fx' => 'c', 'fy' => 'd' }
321
+ do_test(CSV9, wi, { :ruby_eval => true }, { 'fz' => '3' }, false)
322
+ end
323
+
324
+ def test_ruby_eval_set_at_table_initialization
325
+
326
+ table = Rufus::Decision::Table.new(CSV9, :ruby_eval => true)
327
+
328
+ wi = { 'fx' => 'c', 'fy' => 'd' }
329
+ do_test(table, wi, {}, { 'fz' => '3' }, false)
359
330
  end
360
331
 
361
- CSV10 = \
362
- """
332
+ CSV10 = %{
363
333
  in:fx,in:fx,out:fz
364
334
  >90,<92,ok
365
335
  ,,bad
366
- """
336
+ }
367
337
 
368
338
  def test_10
369
339
 
@@ -377,11 +347,7 @@ in:fx,in:fx,out:fz
377
347
  do_test(CSV10, wi, {}, { "fz" => "bad" }, false)
378
348
  end
379
349
 
380
- #
381
- # Fu Zhang's test case
382
-
383
- CSV11 = \
384
- '''
350
+ CSV11 = %{
385
351
  through
386
352
  in:f1,in:f1,in:f2,in:f3,out:o1,out:e1,out:e2
387
353
 
@@ -390,19 +356,15 @@ in:f1,in:f1,in:f2,in:f3,out:o1,out:e1,out:e2
390
356
  <100,>=95,>2.0,,"Expection1",,
391
357
  <100,>=95,,>2.0,,,"Expection2"
392
358
  <100,>=95,,>2.0,"Invalid",,
393
- '''
359
+ }
394
360
 
395
- def test_11
361
+ def test_fu_zhang
396
362
 
397
- wi = { "f1" => 97, "f2" => 5 }
398
- do_test CSV11, wi, {}, { "o1" => "Expection1" }, false
363
+ wi = { 'f1' => 97, 'f2' => 5 }
364
+ do_test CSV11, wi, {}, { 'o1' => 'Expection1' }, false
399
365
  end
400
366
 
401
- #
402
- # 'accumulate'
403
-
404
- CSV12 = \
405
- """
367
+ CSV12 = %{
406
368
  accumulate
407
369
  ,,,
408
370
  in:fx, in:fy, out:fX, out:fY
@@ -411,9 +373,9 @@ a, , red, green
411
373
  , a, blue, purple
412
374
  b, , yellow, beige
413
375
  , b, white, kuro
414
- """
376
+ }
415
377
 
416
- def test_12
378
+ def test_accumulate
417
379
 
418
380
  wi = { "fx" => "a", "fy" => "a" }
419
381
  do_test CSV12, wi, {}, { "fX" => "red;blue", "fY" => "green;purple" }, false
@@ -453,17 +415,13 @@ b, , yellow, beige
453
415
  assert (not r.include?("7"))
454
416
  end
455
417
 
456
- #
457
- # Testing ranges
458
-
459
- CSV13 = \
460
- """
418
+ CSV13 = %{
461
419
  in:fx,out:fz
462
420
  90..92,ok
463
421
  ,bad
464
- """
422
+ }
465
423
 
466
- def test_13
424
+ def test_range
467
425
 
468
426
  wi = { "fx" => "91" }
469
427
  do_test CSV13, wi, {}, { "fz" => "ok" }, false