rufus-decision 0.9 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +10 -0
- data/CREDITS.txt +7 -0
- data/README.txt +13 -3
- data/lib/rufus/decision.rb +484 -484
- data/lib/rufus/hashes.rb +143 -108
- data/lib/rufus-decision.rb +3 -0
- data/test/decision_0_test.rb +293 -293
- data/test/decision_1_test.rb +38 -38
- data/test/dmixin.rb +28 -28
- data/test/eval_test.rb +12 -12
- metadata +13 -6
data/lib/rufus/hashes.rb
CHANGED
@@ -8,10 +8,10 @@
|
|
8
8
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
9
|
# copies of the Software, and to permit persons to whom the Software is
|
10
10
|
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# The above copyright notice and this permission notice shall be included in
|
13
13
|
# all copies or substantial portions of the Software.
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
16
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
17
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
@@ -28,158 +28,193 @@
|
|
28
28
|
# John Mettraux at openwfe.org
|
29
29
|
#
|
30
30
|
|
31
|
-
require '
|
32
|
-
require 'rufus/eval'
|
31
|
+
require 'rufus/treechecker'
|
33
32
|
|
34
33
|
|
35
34
|
module Rufus
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
36
|
+
#
|
37
|
+
# In the Java world, this class would be considered abstract.
|
38
|
+
#
|
39
|
+
# It's used to build sequences of filter on hashes (or instances
|
40
|
+
# that respond to the [], []=, has_key? methods).
|
41
|
+
#
|
42
|
+
# It relies on 'prefixed string keys' like "x:y", where the prefix is 'x'
|
43
|
+
# and the partial key is then 'y'.
|
44
|
+
#
|
45
|
+
# Rufus::EvalHashFilter is an implementation of an HashFilter.
|
46
|
+
#
|
47
|
+
class HashFilter
|
48
|
+
|
49
|
+
def initialize (parent_hash)
|
50
|
+
|
51
|
+
@parent_hash = parent_hash
|
52
|
+
end
|
54
53
|
|
55
|
-
|
54
|
+
def [] (key)
|
56
55
|
|
57
|
-
|
56
|
+
p, k = do_split(key)
|
58
57
|
|
59
|
-
|
60
|
-
|
58
|
+
do_lookup(key, p, k)
|
59
|
+
end
|
61
60
|
|
62
|
-
|
61
|
+
def []= (key, value)
|
63
62
|
|
64
|
-
|
63
|
+
p, v = do_split(value)
|
65
64
|
|
66
|
-
|
67
|
-
|
65
|
+
do_put(key, value, p, v)
|
66
|
+
end
|
68
67
|
|
69
|
-
|
68
|
+
protected
|
70
69
|
|
71
|
-
|
70
|
+
def do_split (element)
|
72
71
|
|
73
|
-
|
72
|
+
return [ nil, element ] unless element.is_a?(String)
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
a = element.split(':', 2)
|
75
|
+
return [ nil ] + a if a.length == 1
|
76
|
+
a
|
77
|
+
end
|
79
78
|
|
80
|
-
|
79
|
+
def handles_prefix? (p)
|
81
80
|
|
82
|
-
|
83
|
-
|
81
|
+
false
|
82
|
+
end
|
84
83
|
|
85
|
-
|
84
|
+
def do_eval (key, p, k)
|
86
85
|
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
raise NotImplementedError.new(
|
87
|
+
"missing do_eval(key, p, k) implementation")
|
88
|
+
end
|
90
89
|
|
91
|
-
|
90
|
+
def do_lookup (key, p, k)
|
92
91
|
|
93
|
-
|
92
|
+
if handles_prefix?(p)
|
94
93
|
|
95
|
-
|
94
|
+
do_eval(key, p, k)
|
96
95
|
|
97
|
-
|
96
|
+
elsif @parent_hash.respond_to?(:do_lookup)
|
98
97
|
|
99
|
-
|
98
|
+
@parent_hash.do_lookup key, p, k
|
100
99
|
|
101
|
-
|
100
|
+
else
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
@parent_hash[key]
|
103
|
+
end
|
104
|
+
end
|
106
105
|
|
107
|
-
|
106
|
+
def do_put (key, value, p, v)
|
108
107
|
|
109
|
-
|
108
|
+
val = value
|
110
109
|
|
111
|
-
|
110
|
+
if handles_prefix?(p)
|
112
111
|
|
113
|
-
|
112
|
+
@parent_hash[key] = do_eval(value, p, v)
|
114
113
|
|
115
|
-
|
114
|
+
elsif @parent_hash.respond_to?(:do_put)
|
116
115
|
|
117
|
-
|
116
|
+
@parent_hash.do_put key, value, p, v
|
118
117
|
|
119
|
-
|
118
|
+
else
|
120
119
|
|
121
|
-
|
122
|
-
|
123
|
-
|
120
|
+
@parent_hash[key] = value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# Implements the r:, ruby: and reval: prefixes in lookups
|
127
|
+
#
|
128
|
+
# require 'rubygems'
|
129
|
+
# require 'rufus/hashes'
|
130
|
+
#
|
131
|
+
# h = {}
|
132
|
+
#
|
133
|
+
# eh = Rufus::EvalHashFilter.new(h, 0)
|
134
|
+
#
|
135
|
+
# eh['a'] = :a
|
136
|
+
# p h # => { 'a' => :a }
|
137
|
+
#
|
138
|
+
# eh['b'] = "r:5 * 5"
|
139
|
+
# p h # => { 'a' => :a, 'b' => 25 }
|
140
|
+
#
|
141
|
+
# assert_equal :a, eh['a']
|
142
|
+
# assert_equal 25, eh['b']
|
143
|
+
# assert_equal 72, eh['r:36+36']
|
144
|
+
#
|
145
|
+
class EvalHashFilter < HashFilter
|
146
|
+
|
147
|
+
def initialize (parent_hash)
|
148
|
+
|
149
|
+
super parent_hash
|
124
150
|
end
|
125
151
|
|
126
|
-
|
127
|
-
# Implements the r:, ruby: and reval: prefixes in lookups
|
128
|
-
#
|
129
|
-
# require 'rubygems'
|
130
|
-
# require 'rufus/hashes'
|
131
|
-
#
|
132
|
-
# h = {}
|
133
|
-
#
|
134
|
-
# eh = Rufus::EvalHashFilter.new(h, 0)
|
135
|
-
#
|
136
|
-
# eh['a'] = :a
|
137
|
-
# p h # => { 'a' => :a }
|
138
|
-
#
|
139
|
-
# eh['b'] = "r:5 * 5"
|
140
|
-
# p h # => { 'a' => :a, 'b' => 25 }
|
141
|
-
#
|
142
|
-
# assert_equal :a, eh['a']
|
143
|
-
# assert_equal 25, eh['b']
|
144
|
-
# assert_equal 72, eh['r:36+36']
|
145
|
-
#
|
146
|
-
class EvalHashFilter < HashFilter
|
147
|
-
|
148
|
-
def initialize (parent_hash, eval_safety_level=0)
|
149
|
-
|
150
|
-
super parent_hash
|
151
|
-
@safe_level = eval_safety_level
|
152
|
-
end
|
152
|
+
protected
|
153
153
|
|
154
|
-
|
154
|
+
RP = [ 'r', 'ruby', 'reval' ]
|
155
155
|
|
156
|
-
|
156
|
+
def handles_prefix? (prefix)
|
157
157
|
|
158
|
-
|
158
|
+
RP.include?(prefix)
|
159
|
+
end
|
159
160
|
|
160
|
-
|
161
|
-
|
161
|
+
#
|
162
|
+
# Ready for override.
|
163
|
+
#
|
164
|
+
def get_binding
|
162
165
|
|
163
|
-
|
164
|
-
|
165
|
-
#
|
166
|
-
def get_binding
|
166
|
+
binding()
|
167
|
+
end
|
167
168
|
|
168
|
-
|
169
|
-
end
|
169
|
+
def do_eval (key, p, k)
|
170
170
|
|
171
|
-
|
171
|
+
#Rufus::eval_safely(k, @safe_level, get_binding)
|
172
|
+
Rufus::check_and_eval(k, get_binding)
|
173
|
+
end
|
174
|
+
end
|
172
175
|
|
173
|
-
|
174
|
-
end
|
175
|
-
end
|
176
|
+
TREECHECKER = Rufus::TreeChecker.new do
|
176
177
|
|
177
|
-
|
178
|
+
exclude_fvccall :abort, :exit, :exit!
|
179
|
+
exclude_fvccall :system, :fork, :syscall, :trap, :require, :load
|
178
180
|
|
179
|
-
|
181
|
+
#exclude_call_to :class
|
182
|
+
exclude_fvcall :private, :public, :protected
|
180
183
|
|
181
|
-
|
182
|
-
|
184
|
+
exclude_def # no method definition
|
185
|
+
exclude_eval # no eval, module_eval or instance_eval
|
186
|
+
exclude_backquotes # no `rm -fR the/kitchen/sink`
|
187
|
+
exclude_alias # no alias or aliast_method
|
188
|
+
exclude_global_vars # $vars are off limits
|
189
|
+
exclude_module_tinkering # no module opening
|
190
|
+
exclude_raise # no raise or throw
|
191
|
+
|
192
|
+
exclude_rebinding Kernel # no 'k = Kernel'
|
193
|
+
|
194
|
+
exclude_access_to(
|
195
|
+
IO, File, FileUtils, Process, Signal, Thread, ThreadGroup)
|
196
|
+
|
197
|
+
exclude_class_tinkering
|
198
|
+
|
199
|
+
exclude_call_to :instance_variable_get, :instance_variable_set
|
200
|
+
end
|
201
|
+
TREECHECKER.freeze
|
202
|
+
|
203
|
+
def self.check_and_eval (ruby_code, bndng=binding())
|
204
|
+
|
205
|
+
TREECHECKER.check(ruby_code)
|
206
|
+
|
207
|
+
# OK, green for eval...
|
208
|
+
|
209
|
+
eval(ruby_code, bndng)
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def Rufus.unescape (text)
|
215
|
+
|
216
|
+
text.gsub("\\\\\\$\\{", "\\${")
|
217
|
+
end
|
183
218
|
|
184
219
|
end
|
185
220
|
|