ceml 0.2.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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +4 -0
- data/Makefile +5 -0
- data/README.markdown +86 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage +322 -0
- data/editors/CEML.tmbundle/info.plist +17 -0
- data/examples/breakfast-exchange.ceml +15 -0
- data/examples/citizen-investigation.ceml +24 -0
- data/examples/high-fives.ceml +19 -0
- data/lib/ceml/casting.rb +52 -0
- data/lib/ceml/engine.rb +138 -0
- data/lib/ceml/instructions.rb +31 -0
- data/lib/ceml/script.rb +103 -0
- data/lib/ceml/tt/casting.rb +618 -0
- data/lib/ceml/tt/casting.treetop +50 -0
- data/lib/ceml/tt/instructions.rb +320 -0
- data/lib/ceml/tt/instructions.treetop +42 -0
- data/lib/ceml/tt/lexer.rb +400 -0
- data/lib/ceml/tt/lexer.treetop +34 -0
- data/lib/ceml/tt/scripts.rb +345 -0
- data/lib/ceml/tt/scripts.treetop +32 -0
- data/lib/ceml.rb +35 -0
- data/test/helper.rb +55 -0
- data/test/test_casting.rb +78 -0
- data/test/test_engine.rb +30 -0
- data/test/test_instructions.rb +27 -0
- data/test/test_scripts.rb +57 -0
- metadata +107 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module CEML
|
|
5
|
+
module Scripts
|
|
6
|
+
include Treetop::Runtime
|
|
7
|
+
|
|
8
|
+
def root
|
|
9
|
+
@root || :scripts
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
include Lexer
|
|
13
|
+
|
|
14
|
+
include Casting
|
|
15
|
+
|
|
16
|
+
include Instructions
|
|
17
|
+
|
|
18
|
+
def _nt_scripts
|
|
19
|
+
start_index = index
|
|
20
|
+
if node_cache[:scripts].has_key?(index)
|
|
21
|
+
cached = node_cache[:scripts][index]
|
|
22
|
+
@index = cached.interval.end if cached
|
|
23
|
+
return cached
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
s0, i0 = [], index
|
|
27
|
+
loop do
|
|
28
|
+
r1 = _nt_script
|
|
29
|
+
if r1
|
|
30
|
+
s0 << r1
|
|
31
|
+
else
|
|
32
|
+
break
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
if s0.empty?
|
|
36
|
+
@index = i0
|
|
37
|
+
r0 = nil
|
|
38
|
+
else
|
|
39
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
node_cache[:scripts][start_index] = r0
|
|
43
|
+
|
|
44
|
+
r0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def _nt_script
|
|
48
|
+
start_index = index
|
|
49
|
+
if node_cache[:script].has_key?(index)
|
|
50
|
+
cached = node_cache[:script][index]
|
|
51
|
+
@index = cached.interval.end if cached
|
|
52
|
+
return cached
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
i0 = index
|
|
56
|
+
r1 = _nt_script_with_title
|
|
57
|
+
if r1
|
|
58
|
+
r0 = r1
|
|
59
|
+
r0.extend(Script)
|
|
60
|
+
else
|
|
61
|
+
r2 = _nt_script_with_instructions
|
|
62
|
+
if r2
|
|
63
|
+
r0 = r2
|
|
64
|
+
r0.extend(Script)
|
|
65
|
+
else
|
|
66
|
+
@index = i0
|
|
67
|
+
r0 = nil
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
node_cache[:script][start_index] = r0
|
|
72
|
+
|
|
73
|
+
r0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
module ScriptWithTitle0
|
|
77
|
+
def title
|
|
78
|
+
elements[1]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def casting_statement
|
|
82
|
+
elements[2]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def instructions
|
|
86
|
+
elements[3]
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def _nt_script_with_title
|
|
91
|
+
start_index = index
|
|
92
|
+
if node_cache[:script_with_title].has_key?(index)
|
|
93
|
+
cached = node_cache[:script_with_title][index]
|
|
94
|
+
@index = cached.interval.end if cached
|
|
95
|
+
return cached
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
i0, s0 = index, []
|
|
99
|
+
r2 = _nt_nl
|
|
100
|
+
if r2
|
|
101
|
+
r1 = r2
|
|
102
|
+
else
|
|
103
|
+
r1 = instantiate_node(SyntaxNode,input, index...index)
|
|
104
|
+
end
|
|
105
|
+
s0 << r1
|
|
106
|
+
if r1
|
|
107
|
+
r3 = _nt_title
|
|
108
|
+
s0 << r3
|
|
109
|
+
if r3
|
|
110
|
+
r5 = _nt_casting_statement
|
|
111
|
+
if r5
|
|
112
|
+
r4 = r5
|
|
113
|
+
else
|
|
114
|
+
r4 = instantiate_node(SyntaxNode,input, index...index)
|
|
115
|
+
end
|
|
116
|
+
s0 << r4
|
|
117
|
+
if r4
|
|
118
|
+
r7 = _nt_instructions
|
|
119
|
+
if r7
|
|
120
|
+
r6 = r7
|
|
121
|
+
else
|
|
122
|
+
r6 = instantiate_node(SyntaxNode,input, index...index)
|
|
123
|
+
end
|
|
124
|
+
s0 << r6
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
if s0.last
|
|
129
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
|
130
|
+
r0.extend(ScriptWithTitle0)
|
|
131
|
+
else
|
|
132
|
+
@index = i0
|
|
133
|
+
r0 = nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
node_cache[:script_with_title][start_index] = r0
|
|
137
|
+
|
|
138
|
+
r0
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
module ScriptWithInstructions0
|
|
142
|
+
def title
|
|
143
|
+
elements[1]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def casting_statement
|
|
147
|
+
elements[2]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def instructions
|
|
151
|
+
elements[3]
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def _nt_script_with_instructions
|
|
156
|
+
start_index = index
|
|
157
|
+
if node_cache[:script_with_instructions].has_key?(index)
|
|
158
|
+
cached = node_cache[:script_with_instructions][index]
|
|
159
|
+
@index = cached.interval.end if cached
|
|
160
|
+
return cached
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
i0, s0 = index, []
|
|
164
|
+
r2 = _nt_nl
|
|
165
|
+
if r2
|
|
166
|
+
r1 = r2
|
|
167
|
+
else
|
|
168
|
+
r1 = instantiate_node(SyntaxNode,input, index...index)
|
|
169
|
+
end
|
|
170
|
+
s0 << r1
|
|
171
|
+
if r1
|
|
172
|
+
r4 = _nt_title
|
|
173
|
+
if r4
|
|
174
|
+
r3 = r4
|
|
175
|
+
else
|
|
176
|
+
r3 = instantiate_node(SyntaxNode,input, index...index)
|
|
177
|
+
end
|
|
178
|
+
s0 << r3
|
|
179
|
+
if r3
|
|
180
|
+
r6 = _nt_casting_statement
|
|
181
|
+
if r6
|
|
182
|
+
r5 = r6
|
|
183
|
+
else
|
|
184
|
+
r5 = instantiate_node(SyntaxNode,input, index...index)
|
|
185
|
+
end
|
|
186
|
+
s0 << r5
|
|
187
|
+
if r5
|
|
188
|
+
r7 = _nt_instructions
|
|
189
|
+
s0 << r7
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
if s0.last
|
|
194
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
|
195
|
+
r0.extend(ScriptWithInstructions0)
|
|
196
|
+
else
|
|
197
|
+
@index = i0
|
|
198
|
+
r0 = nil
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
node_cache[:script_with_instructions][start_index] = r0
|
|
202
|
+
|
|
203
|
+
r0
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
module Title0
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
module Title1
|
|
210
|
+
def value
|
|
211
|
+
elements[1]
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def nl
|
|
215
|
+
elements[3]
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
module Title2
|
|
220
|
+
def value
|
|
221
|
+
super.text_value.gsub(/\\"/, '"')
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def _nt_title
|
|
226
|
+
start_index = index
|
|
227
|
+
if node_cache[:title].has_key?(index)
|
|
228
|
+
cached = node_cache[:title][index]
|
|
229
|
+
@index = cached.interval.end if cached
|
|
230
|
+
return cached
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
i0, s0 = index, []
|
|
234
|
+
if has_terminal?('"', false, index)
|
|
235
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
|
236
|
+
@index += 1
|
|
237
|
+
else
|
|
238
|
+
terminal_parse_failure('"')
|
|
239
|
+
r1 = nil
|
|
240
|
+
end
|
|
241
|
+
s0 << r1
|
|
242
|
+
if r1
|
|
243
|
+
s2, i2 = [], index
|
|
244
|
+
loop do
|
|
245
|
+
i3 = index
|
|
246
|
+
if has_terminal?('\\"', false, index)
|
|
247
|
+
r4 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
|
248
|
+
@index += 2
|
|
249
|
+
else
|
|
250
|
+
terminal_parse_failure('\\"')
|
|
251
|
+
r4 = nil
|
|
252
|
+
end
|
|
253
|
+
if r4
|
|
254
|
+
r3 = r4
|
|
255
|
+
else
|
|
256
|
+
i5, s5 = index, []
|
|
257
|
+
i6 = index
|
|
258
|
+
if has_terminal?('"', false, index)
|
|
259
|
+
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
|
260
|
+
@index += 1
|
|
261
|
+
else
|
|
262
|
+
terminal_parse_failure('"')
|
|
263
|
+
r7 = nil
|
|
264
|
+
end
|
|
265
|
+
if r7
|
|
266
|
+
r6 = nil
|
|
267
|
+
else
|
|
268
|
+
@index = i6
|
|
269
|
+
r6 = instantiate_node(SyntaxNode,input, index...index)
|
|
270
|
+
end
|
|
271
|
+
s5 << r6
|
|
272
|
+
if r6
|
|
273
|
+
if index < input_length
|
|
274
|
+
next_character = index + input[index..-1].match(/\A(.)/um).end(1)
|
|
275
|
+
r8 = instantiate_node(SyntaxNode,input, index...next_character)
|
|
276
|
+
@index = next_character
|
|
277
|
+
else
|
|
278
|
+
terminal_parse_failure("any character")
|
|
279
|
+
r8 = nil
|
|
280
|
+
end
|
|
281
|
+
s5 << r8
|
|
282
|
+
end
|
|
283
|
+
if s5.last
|
|
284
|
+
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
|
|
285
|
+
r5.extend(Title0)
|
|
286
|
+
else
|
|
287
|
+
@index = i5
|
|
288
|
+
r5 = nil
|
|
289
|
+
end
|
|
290
|
+
if r5
|
|
291
|
+
r3 = r5
|
|
292
|
+
else
|
|
293
|
+
@index = i3
|
|
294
|
+
r3 = nil
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
if r3
|
|
298
|
+
s2 << r3
|
|
299
|
+
else
|
|
300
|
+
break
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
if s2.empty?
|
|
304
|
+
@index = i2
|
|
305
|
+
r2 = nil
|
|
306
|
+
else
|
|
307
|
+
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
|
|
308
|
+
end
|
|
309
|
+
s0 << r2
|
|
310
|
+
if r2
|
|
311
|
+
if has_terminal?('"', false, index)
|
|
312
|
+
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
|
313
|
+
@index += 1
|
|
314
|
+
else
|
|
315
|
+
terminal_parse_failure('"')
|
|
316
|
+
r9 = nil
|
|
317
|
+
end
|
|
318
|
+
s0 << r9
|
|
319
|
+
if r9
|
|
320
|
+
r10 = _nt_nl
|
|
321
|
+
s0 << r10
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
if s0.last
|
|
326
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
|
327
|
+
r0.extend(Title1)
|
|
328
|
+
r0.extend(Title2)
|
|
329
|
+
else
|
|
330
|
+
@index = i0
|
|
331
|
+
r0 = nil
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
node_cache[:title][start_index] = r0
|
|
335
|
+
|
|
336
|
+
r0
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
class ScriptsParser < Treetop::Runtime::CompiledParser
|
|
342
|
+
include Scripts
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module CEML
|
|
2
|
+
grammar Scripts
|
|
3
|
+
include Lexer
|
|
4
|
+
include Casting
|
|
5
|
+
include Instructions
|
|
6
|
+
|
|
7
|
+
rule scripts
|
|
8
|
+
script+
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
rule script
|
|
12
|
+
(script_with_title / script_with_instructions) <Script>
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
rule script_with_title
|
|
16
|
+
nl? title casting_statement:casting_statement? instructions:instructions?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
rule script_with_instructions
|
|
20
|
+
nl? title:title? casting_statement:casting_statement? instructions
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
rule title
|
|
24
|
+
'"' value:('\\"' / !'"' .)+ '"' nl {
|
|
25
|
+
def value
|
|
26
|
+
super.text_value.gsub(/\\"/, '"')
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/ceml.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'treetop'
|
|
3
|
+
|
|
4
|
+
require 'ceml/casting'
|
|
5
|
+
require 'ceml/instructions'
|
|
6
|
+
require 'ceml/script'
|
|
7
|
+
require 'ceml/tt/lexer'
|
|
8
|
+
require 'ceml/tt/casting'
|
|
9
|
+
require 'ceml/tt/instructions'
|
|
10
|
+
require 'ceml/tt/scripts'
|
|
11
|
+
|
|
12
|
+
require 'ceml/engine'
|
|
13
|
+
|
|
14
|
+
module CEML
|
|
15
|
+
def parse(what, string)
|
|
16
|
+
result = nil
|
|
17
|
+
string.gsub!(/\n +/, ' ')
|
|
18
|
+
string << "\n"
|
|
19
|
+
p = ScriptsParser.new
|
|
20
|
+
p.root = what
|
|
21
|
+
result = p.parse(string)
|
|
22
|
+
raise "parse failed: \n#{p.failure_reason}" unless result
|
|
23
|
+
case what
|
|
24
|
+
when :scripts
|
|
25
|
+
raise "no scripts found" unless result.elements and !result.elements.empty?
|
|
26
|
+
result = result.elements
|
|
27
|
+
result.each{ |s| s.validate! }
|
|
28
|
+
when :script
|
|
29
|
+
result.validate!
|
|
30
|
+
end
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
extend self
|
|
35
|
+
end
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
6
|
+
require 'ceml'
|
|
7
|
+
|
|
8
|
+
COMPLIMENT_SCRIPT = <<END_OF_SCRIPT
|
|
9
|
+
"Overwhelm a specific person with compliments"
|
|
10
|
+
gather 5-20 players within 4 blocks
|
|
11
|
+
ask organizer re target: Describe their appearance and location
|
|
12
|
+
tell agents: Look for |otherguy.target| and compliment them briefly, then move on.
|
|
13
|
+
END_OF_SCRIPT
|
|
14
|
+
|
|
15
|
+
ASKCHAIN_SCRIPT = <<ENDOFSCRIPT
|
|
16
|
+
"Meet your neighbor"
|
|
17
|
+
gather 2 players within 1 block
|
|
18
|
+
ask players re color: what's your favorite color?
|
|
19
|
+
ask players re observation: find someone near you with the color |otherguy.color|. what are they wearing?
|
|
20
|
+
ask players re rightmatch: are you wearing |otherguy.observation|?
|
|
21
|
+
ask players re task: take your new partner and see if you can find something beautiful in the park.
|
|
22
|
+
|
|
23
|
+
ENDOFSCRIPT
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Test::Unit::TestCase
|
|
28
|
+
def play script
|
|
29
|
+
@e = CEML::Engine.new(script)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def player id, *roles
|
|
33
|
+
@e.add id, *roles
|
|
34
|
+
@e.run
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def asked id, rx
|
|
38
|
+
p = @e.parts[id]
|
|
39
|
+
assert_equal :ask, p[:said]
|
|
40
|
+
assert_match rx, p[:q]
|
|
41
|
+
p.delete :said
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def told id, rx
|
|
45
|
+
p = @e.parts[id]
|
|
46
|
+
assert_match rx, p[:msg]
|
|
47
|
+
p.delete :said
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def says id, str
|
|
51
|
+
@e.parts[id][:received] = str
|
|
52
|
+
@e.run
|
|
53
|
+
@e.parts[id][:received] = nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'ceml'
|
|
3
|
+
|
|
4
|
+
class TestCasting < Test::Unit::TestCase
|
|
5
|
+
def pcs text
|
|
6
|
+
CEML.parse(:casting_statement, text)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def assert_bad text
|
|
10
|
+
assert_raise(RuntimeError){ pcs text }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_bad
|
|
14
|
+
assert_bad "gather a-b runners"
|
|
15
|
+
assert_bad "gather 40a runners"
|
|
16
|
+
assert_bad "gather 3- runners"
|
|
17
|
+
assert_bad "gather -4 runners"
|
|
18
|
+
assert_bad "grab 4 runners"
|
|
19
|
+
assert_bad "gather 4 *runners"
|
|
20
|
+
assert_bad "gather 4 run*ners"
|
|
21
|
+
assert_bad "gather 4 runners*"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_range
|
|
25
|
+
cs = pcs "gather 3-4 runners"
|
|
26
|
+
assert cs.type == :gather
|
|
27
|
+
assert cs.roles.include? :runners
|
|
28
|
+
assert cs[:runners].min == 3
|
|
29
|
+
assert cs[:runners].max == 4
|
|
30
|
+
assert cs.max == 4
|
|
31
|
+
|
|
32
|
+
cs = pcs "gather 3+ runners"
|
|
33
|
+
assert cs.type == :gather
|
|
34
|
+
assert cs.roles.include? :runners
|
|
35
|
+
assert cs[:runners].min == 3
|
|
36
|
+
assert cs[:runners].max > 4
|
|
37
|
+
assert cs.min == 3
|
|
38
|
+
assert cs.max > 4
|
|
39
|
+
|
|
40
|
+
cs = pcs "gather 3 runners"
|
|
41
|
+
assert cs.type == :gather
|
|
42
|
+
assert cs.roles.include? :runners
|
|
43
|
+
assert cs[:runners].min == 3
|
|
44
|
+
assert cs[:runners].max == 3
|
|
45
|
+
assert cs.min == 3
|
|
46
|
+
assert cs.max == 3
|
|
47
|
+
|
|
48
|
+
cs = pcs "gather runners"
|
|
49
|
+
assert cs.type == :gather
|
|
50
|
+
assert cs.roles.include? :runners
|
|
51
|
+
assert cs[:runners].min == 2
|
|
52
|
+
assert cs[:runners].max > 10
|
|
53
|
+
assert cs.min == 2
|
|
54
|
+
assert cs.max > 10
|
|
55
|
+
|
|
56
|
+
cs = pcs "teams of 1-2 runners and 1 announcer"
|
|
57
|
+
assert cs.type == :teams
|
|
58
|
+
assert cs.roles.include? :runners
|
|
59
|
+
assert cs.roles.include? :announcer
|
|
60
|
+
assert cs[:runners].min == 1
|
|
61
|
+
assert cs[:runners].max == 2
|
|
62
|
+
assert cs.min == 2
|
|
63
|
+
assert cs.max > 20
|
|
64
|
+
|
|
65
|
+
cs = pcs "nab 1-2 runners within 4 mi"
|
|
66
|
+
assert cs.type == :nab
|
|
67
|
+
assert cs.nab?
|
|
68
|
+
assert !cs.in_teams?
|
|
69
|
+
assert cs[:runners].min == 1
|
|
70
|
+
assert cs[:runners].max == 2
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_radius
|
|
74
|
+
assert_equal 600, pcs("gather 3 runners and 5 hot_babes within 3 blocks").radius
|
|
75
|
+
assert pcs("gather 3 runners and 5 hot_babes").radius > 50000
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
data/test/test_engine.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'ceml'
|
|
2
|
+
require 'test/helper'
|
|
3
|
+
|
|
4
|
+
class TestEngine < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
def test_engine
|
|
7
|
+
play COMPLIMENT_SCRIPT
|
|
8
|
+
player :joe, :organizer, :agent
|
|
9
|
+
player :bill, :agent
|
|
10
|
+
|
|
11
|
+
asked :joe, /^Describe/
|
|
12
|
+
says :joe, 'red people'
|
|
13
|
+
|
|
14
|
+
told :bill, /^Look for red people/
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_askchain
|
|
18
|
+
play ASKCHAIN_SCRIPT
|
|
19
|
+
player :joe, :players, :agent
|
|
20
|
+
player :bill, :players, :agent
|
|
21
|
+
|
|
22
|
+
asked :joe, /favorite color/
|
|
23
|
+
asked :bill, /favorite color/
|
|
24
|
+
says :joe, "red"
|
|
25
|
+
says :bill, "green"
|
|
26
|
+
asked :joe, /with the color green/
|
|
27
|
+
asked :bill, /with the color red/
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'ceml'
|
|
2
|
+
|
|
3
|
+
class TestInstructions < Test::Unit::TestCase
|
|
4
|
+
def pi text
|
|
5
|
+
CEML.parse(:instructions, text)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def assert_bad text
|
|
9
|
+
assert_raise(RuntimeError){ pi text }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_bad
|
|
13
|
+
assert_bad "love your mother"
|
|
14
|
+
assert_bad "tell jim re susan: i hate you"
|
|
15
|
+
assert_bad "tell phil"
|
|
16
|
+
assert_bad "ask susan re clothing"
|
|
17
|
+
assert_bad "ask susan re clothing: "
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_instructions
|
|
21
|
+
assert_equal "run to the kitchen", pi('tell joe: run to the kitchen').tell([:joe]).text
|
|
22
|
+
assert_equal ["favorite color?", "favorite soup?"], pi(
|
|
23
|
+
"ask joe re color: favorite color?\nask joe re soup: favorite soup?"
|
|
24
|
+
).asks([:joe]).map(&:text)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'ceml'
|
|
2
|
+
|
|
3
|
+
class TestInstructions < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
SCRIPTS = <<END_OF_SCRIPTS
|
|
6
|
+
"Help moving |an object|" // okay?
|
|
7
|
+
gather 2-6 movers within 8 blocks
|
|
8
|
+
|
|
9
|
+
"Cleaning up |a public place|"
|
|
10
|
+
gather 3-10 cleaners within 2 miles
|
|
11
|
+
|
|
12
|
+
// the following are dedicated to my mom
|
|
13
|
+
|
|
14
|
+
"Overwhelm a specific person with compliments"
|
|
15
|
+
gather 5-20 players within 4 blocks
|
|
16
|
+
ask organizer re target: Describe their appearance and location
|
|
17
|
+
tell players: Look for |target| and compliment them briefly, then move on.
|
|
18
|
+
END_OF_SCRIPTS
|
|
19
|
+
|
|
20
|
+
def ps text
|
|
21
|
+
CEML.parse(:scripts, text)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_scripts
|
|
25
|
+
s = ps SCRIPTS
|
|
26
|
+
assert s.size == 3
|
|
27
|
+
s0 = s[0]
|
|
28
|
+
assert_equal "Help moving |an object|", s0.title
|
|
29
|
+
assert s0.allowed_roles.include? :movers
|
|
30
|
+
assert s0.radius == 1600
|
|
31
|
+
assert s0.dramatis_personae.min == 2
|
|
32
|
+
assert s0.dramatis_personae.max == 6
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_ceml_title
|
|
36
|
+
s = CEML.parse(:script, '"hello there"')
|
|
37
|
+
assert_equal "hello there", s.title
|
|
38
|
+
|
|
39
|
+
s = CEML.parse(:script, %q{"say: \"whoa the'a paps\""})
|
|
40
|
+
assert_equal %Q{say: "whoa the'a paps"}, s.title
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_ceml_tell
|
|
44
|
+
cs = CEML.parse(:script, "tell agents: run and jump")
|
|
45
|
+
assert cs.roles.include? :agents
|
|
46
|
+
assert_equal "run and jump", cs.instructions.tell([:agents]).text
|
|
47
|
+
assert cs.concludes_immediately?
|
|
48
|
+
assert !cs.title
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_ceml_questions
|
|
52
|
+
s = CEML.parse(:script, "ask agents: wassup party people?")
|
|
53
|
+
assert_equal "wassup party people?", s.instructions.asks([:agents]).first.text
|
|
54
|
+
assert !s.concludes_immediately?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|