sexp_processor 3.0.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/History.txt +15 -0
- data/Manifest.txt +11 -0
- data/README.txt +48 -0
- data/Rakefile +15 -0
- data/lib/composite_sexp_processor.rb +49 -0
- data/lib/sexp.rb +270 -0
- data/lib/sexp_processor.rb +407 -0
- data/test/test_composite_sexp_processor.rb +70 -0
- data/test/test_environment.rb +85 -0
- data/test/test_sexp.rb +305 -0
- data/test/test_sexp_processor.rb +297 -0
- metadata +79 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
$TESTING = true
|
4
|
+
|
5
|
+
require 'composite_sexp_processor'
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
class FakeProcessor1 < SexpProcessor # ZenTest SKIP
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
self.warn_on_default = false
|
13
|
+
self.default_method = :default_processor
|
14
|
+
self.expected = Array
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_processor(exp)
|
18
|
+
result = []
|
19
|
+
result << exp.shift
|
20
|
+
until exp.empty? do
|
21
|
+
result << exp.shift.to_s + " woot"
|
22
|
+
end
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class TestCompositeSexpProcessor < Test::Unit::TestCase
|
28
|
+
|
29
|
+
def setup
|
30
|
+
@p = CompositeSexpProcessor.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_process_default
|
34
|
+
data = [1, 2, 3]
|
35
|
+
result = @p.process(data.dup)
|
36
|
+
assert_equal(data.dup, result)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_process_fake1
|
40
|
+
data = [:x, 1, 2, 3]
|
41
|
+
@p << FakeProcessor1.new
|
42
|
+
result = @p.process(data.dup)
|
43
|
+
assert_equal [:x, "1 woot", "2 woot", "3 woot"], result
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_process_fake1_twice
|
47
|
+
data = [:x, 1, 2, 3]
|
48
|
+
@p << FakeProcessor1.new
|
49
|
+
@p << FakeProcessor1.new
|
50
|
+
result = @p.process(data.dup)
|
51
|
+
assert_equal [:x, "1 woot woot", "2 woot woot", "3 woot woot"], result
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_processors
|
55
|
+
# everything is tested by test_append
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_append
|
59
|
+
assert_equal([], @p.processors)
|
60
|
+
|
61
|
+
assert_raises(ArgumentError) do
|
62
|
+
@p << 42
|
63
|
+
end
|
64
|
+
|
65
|
+
fp1 = FakeProcessor1.new
|
66
|
+
@p << fp1
|
67
|
+
assert_equal([fp1], @p.processors)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
$TESTING = true
|
4
|
+
|
5
|
+
require 'test/unit' if $0 == __FILE__
|
6
|
+
require 'test/unit/testcase'
|
7
|
+
require 'sexp_processor'
|
8
|
+
|
9
|
+
class TestEnvironment < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@env = SexpProcessor::Environment.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_all
|
16
|
+
@env.scope do
|
17
|
+
@env[:x] = 42
|
18
|
+
|
19
|
+
@env.scope do
|
20
|
+
@env[:y] = 3
|
21
|
+
@env[:x] = Math::PI
|
22
|
+
|
23
|
+
expected = { :x => Math::PI, :y => 3 }
|
24
|
+
assert_equal expected, @env.all
|
25
|
+
end
|
26
|
+
|
27
|
+
expected = { :x => Math::PI }
|
28
|
+
assert_equal expected, @env.all
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_depth
|
33
|
+
assert_equal 1, @env.depth
|
34
|
+
|
35
|
+
@env.scope do
|
36
|
+
assert_equal 2, @env.depth
|
37
|
+
end
|
38
|
+
|
39
|
+
assert_equal 1, @env.depth
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_index
|
43
|
+
test_index_equals
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_index_unknown
|
47
|
+
assert_nil @env[:unknown]
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_index_out_of_scope
|
51
|
+
@env.scope do
|
52
|
+
@env[:var] = 42
|
53
|
+
assert_equal 42, @env[:var]
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_nil @env[:var]
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_index_equals
|
60
|
+
@env[:var] = 42
|
61
|
+
|
62
|
+
assert_equal 42, @env[:var]
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_lookup_scope
|
66
|
+
@env[:var] = 42
|
67
|
+
assert_equal 42, @env[:var]
|
68
|
+
|
69
|
+
@env.scope do
|
70
|
+
assert_equal 42, @env[:var]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_scope
|
75
|
+
@env[:var] = 42
|
76
|
+
assert_equal 42, @env[:var]
|
77
|
+
|
78
|
+
@env.scope do
|
79
|
+
@env[:var] = Math::PI
|
80
|
+
assert_equal Math::PI, @env[:var]
|
81
|
+
end
|
82
|
+
|
83
|
+
assert_equal Math::PI, @env[:var]
|
84
|
+
end
|
85
|
+
end
|
data/test/test_sexp.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
$TESTING = true
|
4
|
+
|
5
|
+
require 'test/unit' if $0 == __FILE__ unless defined? $ZENTEST and $ZENTEST
|
6
|
+
require 'test/unit/testcase'
|
7
|
+
require 'sexp_processor'
|
8
|
+
require 'stringio'
|
9
|
+
require 'pp'
|
10
|
+
|
11
|
+
class SexpTestCase < Test::Unit::TestCase
|
12
|
+
|
13
|
+
unless defined? Mini then
|
14
|
+
alias :refute_nil :assert_not_nil
|
15
|
+
alias :refute_equal :assert_not_equal
|
16
|
+
alias :assert_raises :assert_raise
|
17
|
+
end
|
18
|
+
|
19
|
+
# KEY for regex tests
|
20
|
+
# :a == no change
|
21
|
+
# :b == will change (but sometimes ONLY once)
|
22
|
+
# :c == change to
|
23
|
+
|
24
|
+
include SexpMatchSpecials
|
25
|
+
|
26
|
+
def util_equals(x, y)
|
27
|
+
result = x == y
|
28
|
+
refute_nil result, "#{x.inspect} does not === #{y.inspect}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def util_equals3(x, y)
|
32
|
+
result = x === y
|
33
|
+
refute_nil result, "#{x.inspect} does not === #{y.inspect}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def setup
|
37
|
+
@any = ANY()
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_stupid
|
41
|
+
# shuts up test/unit
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TestSexp < SexpTestCase # ZenTest FULL
|
46
|
+
|
47
|
+
class SexpFor
|
48
|
+
def method
|
49
|
+
1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def util_pretty_print(expect, input)
|
54
|
+
io = StringIO.new
|
55
|
+
PP.pp(input, io)
|
56
|
+
io.rewind
|
57
|
+
assert_equal(expect, io.read.chomp)
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup
|
61
|
+
super
|
62
|
+
@sexp_class = Object.const_get(self.class.name[4..-1])
|
63
|
+
@processor = SexpProcessor.new
|
64
|
+
@sexp = @sexp_class.new(1, 2, 3)
|
65
|
+
@basic_sexp = s(:lasgn, :var, s(:lit, 42))
|
66
|
+
@re = s(:lit, 42)
|
67
|
+
@bad1 = s(:lit, 24)
|
68
|
+
@bad1 = s(:blah, 42)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_class_from_array
|
72
|
+
# raise NotImplementedError, 'Need to write test_class_from_array'
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_class_index
|
76
|
+
# raise NotImplementedError, 'Need to write test_class_index'
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_array_type_eh
|
80
|
+
assert_equal false, @sexp.array_type?
|
81
|
+
@sexp.unshift :array
|
82
|
+
assert_equal true, @sexp.array_type?
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_each_of_type
|
86
|
+
# TODO: huh... this tests fails if top level sexp :b is removed
|
87
|
+
@sexp = s(:b, s(:a, s(:b, s(:a), :a, s(:b, :a), s(:b, s(:a)))))
|
88
|
+
count = 0
|
89
|
+
@sexp.each_of_type(:a) do |exp|
|
90
|
+
count += 1
|
91
|
+
end
|
92
|
+
assert_equal(3, count, "must find 3 a's in #{@sexp.inspect}")
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_equals2_array
|
96
|
+
# can't use assert_equals because it uses array as receiver
|
97
|
+
refute_equal(@sexp, [1, 2, 3],
|
98
|
+
"Sexp must not be equal to equivalent array")
|
99
|
+
# both directions just in case
|
100
|
+
# HACK - this seems to be a bug in ruby as far as I'm concerned
|
101
|
+
# assert_not_equal([1, 2, 3], @sexp,
|
102
|
+
# "Sexp must not be equal to equivalent array")
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_equals2_not_body
|
106
|
+
sexp2 = s(1, 2, 5)
|
107
|
+
refute_equal(@sexp, sexp2)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_equals2_sexp
|
111
|
+
sexp2 = s(1, 2, 3)
|
112
|
+
unless @sexp.class == Sexp then
|
113
|
+
refute_equal(@sexp, sexp2)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_equals3_any
|
118
|
+
util_equals3 @any, s()
|
119
|
+
util_equals3 @any, s(:a)
|
120
|
+
util_equals3 @any, s(:a, :b, s(:c))
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_equals3_full_match
|
124
|
+
util_equals3 s(), s() # 0
|
125
|
+
util_equals3 s(:blah), s(:blah) # 1
|
126
|
+
util_equals3 s(:a, :b), s(:a, :b) # 2
|
127
|
+
util_equals3 @basic_sexp, @basic_sexp.dup # deeper structure
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_equals3_mismatch
|
131
|
+
assert_nil s() === s(:a)
|
132
|
+
assert_nil s(:a) === s()
|
133
|
+
assert_nil s(:blah1) === s(:blah2)
|
134
|
+
assert_nil s(:a) === s(:a, :b)
|
135
|
+
assert_nil s(:a, :b) === s(:a)
|
136
|
+
assert_nil s(:a1, :b) === s(:a2, :b)
|
137
|
+
assert_nil s(:a, :b1) === s(:a, :b2)
|
138
|
+
assert_nil @basic_sexp === @basic_sexp.dup.push(42)
|
139
|
+
assert_nil @basic_sexp.dup.push(42) === @basic_sexp
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_equals3_subset_match
|
143
|
+
util_equals3 s(:a), s(s(:a), s(:b)) # left
|
144
|
+
util_equals3 s(:a), s(:blah, s(:a ), s(:b)) # mid 1
|
145
|
+
util_equals3 s(:a, 1), s(:blah, s(:a, 1), s(:b)) # mid 2
|
146
|
+
util_equals3 @basic_sexp, s(:blah, @basic_sexp.dup, s(:b)) # mid deeper
|
147
|
+
util_equals3 @basic_sexp, s(@basic_sexp.dup, s(:a), s(:b)) # left deeper
|
148
|
+
|
149
|
+
util_equals3 s(:a), s(:blah, s(:blah, s(:a))) # left deeper
|
150
|
+
end
|
151
|
+
|
152
|
+
# def test_equalstilde_any
|
153
|
+
# result = @basic_sexp =~ s(:lit, ANY())
|
154
|
+
# p result
|
155
|
+
# assert result
|
156
|
+
# end
|
157
|
+
|
158
|
+
def test_equalstilde_fancy
|
159
|
+
assert_nil s(:b) =~ s(:a, s(:b), :c)
|
160
|
+
refute_nil s(:a, s(:b), :c) =~ s(:b)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_equalstilde_plain
|
164
|
+
result = @basic_sexp =~ @re
|
165
|
+
assert result
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_find_and_replace_all
|
169
|
+
@sexp = s(:a, s(:b, s(:a), s(:b), s(:b, s(:a))))
|
170
|
+
expected = s(:a, s(:a, s(:a), s(:a), s(:a, s(:a))))
|
171
|
+
|
172
|
+
@sexp.find_and_replace_all(:b, :a)
|
173
|
+
|
174
|
+
assert_equal(expected, @sexp)
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_gsub
|
178
|
+
assert_equal s(:c), s().gsub(s(), s(:c))
|
179
|
+
assert_equal s(:c), s(:b).gsub(s(:b), s(:c))
|
180
|
+
assert_equal s(:a), s(:a).gsub(s(:b), s(:c))
|
181
|
+
assert_equal s(:a, s(:c)), s(:a, s(:b)).gsub(s(:b), s(:c))
|
182
|
+
|
183
|
+
assert_equal(s(:a, s(:c), s(:c)),
|
184
|
+
s(:a, s(:b), s(:b)).gsub(s(:b), s(:c)))
|
185
|
+
assert_equal(s(:a, s(:c), s(:a, s(:c))),
|
186
|
+
s(:a, s(:b), s(:a, s(:b))).gsub(s(:b), s(:c)))
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_inspect
|
190
|
+
k = @sexp_class
|
191
|
+
n = k.name[0].chr.downcase
|
192
|
+
assert_equal("#{n}()",
|
193
|
+
k.new().inspect)
|
194
|
+
assert_equal("#{n}(:a)",
|
195
|
+
k.new(:a).inspect)
|
196
|
+
assert_equal("#{n}(:a, :b)",
|
197
|
+
k.new(:a, :b).inspect)
|
198
|
+
assert_equal("#{n}(:a, #{n}(:b))",
|
199
|
+
k.new(:a, k.new(:b)).inspect)
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_method_missing
|
203
|
+
assert_nil @sexp.not_there
|
204
|
+
assert_equal s(:lit, 42), @basic_sexp.lit
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_method_missing_ambigious
|
208
|
+
assert_raises NoMethodError do
|
209
|
+
pirate = s(:says, s(:arrr!), s(:arrr!), s(:arrr!))
|
210
|
+
pirate.arrr!
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_method_missing_deep
|
215
|
+
sexp = s(:blah, s(:a, s(:b, s(:c, :yay!))))
|
216
|
+
assert_equal(s(:c, :yay!), sexp.a.b.c)
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_method_missing_delete
|
220
|
+
sexp = s(:blah, s(:a, s(:b, s(:c, :yay!))))
|
221
|
+
|
222
|
+
assert_equal(s(:c, :yay!), sexp.a.b.c(true))
|
223
|
+
assert_equal(s(:blah, s(:a, s(:b))), sexp)
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_pretty_print
|
227
|
+
util_pretty_print("s()",
|
228
|
+
s())
|
229
|
+
util_pretty_print("s(:a)",
|
230
|
+
s(:a))
|
231
|
+
util_pretty_print("s(:a, :b)",
|
232
|
+
s(:a, :b))
|
233
|
+
util_pretty_print("s(:a, s(:b))",
|
234
|
+
s(:a, s(:b)))
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_sexp_body
|
238
|
+
assert_equal [2, 3], @sexp.sexp_body
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_shift
|
242
|
+
assert_equal(1, @sexp.shift)
|
243
|
+
assert_equal(2, @sexp.shift)
|
244
|
+
assert_equal(3, @sexp.shift)
|
245
|
+
|
246
|
+
assert_raises(RuntimeError) do
|
247
|
+
@sexp.shift
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_structure
|
252
|
+
@sexp = s(:a, 1, 2, s(:b, 3, 4), 5, 6)
|
253
|
+
backup = @sexp.deep_clone
|
254
|
+
expected = s(:a, s(:b))
|
255
|
+
|
256
|
+
assert_equal(expected, @sexp.structure)
|
257
|
+
assert_equal(backup, @sexp)
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_sub
|
261
|
+
assert_equal s(:c), s().sub(s(), s(:c))
|
262
|
+
assert_equal s(:c), s(:b).sub(s(:b), s(:c))
|
263
|
+
assert_equal s(:a), s(:a).sub(s(:b), s(:c))
|
264
|
+
assert_equal s(:a, s(:c)), s(:a, s(:c)).sub(s(:b), s(:c))
|
265
|
+
|
266
|
+
assert_equal s(:a, s(:c), s(:b)), s(:a, s(:b), s(:b)).sub(s(:b), s(:c))
|
267
|
+
|
268
|
+
assert_equal(s(:a, s(:c), s(:a)),
|
269
|
+
s(:a, s(:b), s(:a)).sub(s(:b), s(:c)))
|
270
|
+
assert_equal(s(:a, s(:c), s(:a, s(:a))),
|
271
|
+
s(:a, s(:b), s(:a, s(:a))).sub(s(:b), s(:c)))
|
272
|
+
assert_equal(s(:a, s(:a), s(:a, s(:c), s(:b))),
|
273
|
+
s(:a, s(:a), s(:a, s(:b), s(:b))).sub(s(:b), s(:c)))
|
274
|
+
assert_equal(s(:a, s(:c, s(:b))),
|
275
|
+
s(:a, s(:b)).sub(s(:b), s(:c, s(:b))))
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_to_a
|
279
|
+
assert_equal([1, 2, 3], @sexp.to_a)
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_to_s
|
283
|
+
test_inspect
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
class TestSexpAny < SexpTestCase
|
288
|
+
|
289
|
+
def setup
|
290
|
+
super
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_equals
|
294
|
+
util_equals @any, s()
|
295
|
+
util_equals @any, s(:a)
|
296
|
+
util_equals @any, s(:a, :b, s(:c))
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_equals3
|
300
|
+
util_equals3 @any, s()
|
301
|
+
util_equals3 @any, s(:a)
|
302
|
+
util_equals3 @any, s(:a, :b, s(:c))
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|