ceml 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Makefile +4 -0
- data/VERSION +1 -1
- data/ceml.gemspec +5 -3
- data/guide/guide.html +208 -0
- data/guide/guide.pdf +0 -0
- data/lib/ceml/driver.rb +1 -1
- data/lib/ceml/incident.rb +20 -42
- data/lib/ceml/script.rb +9 -1
- data/lib/ceml/tt/instructions.treetop +22 -7
- data/test/test_incident.rb +24 -0
- metadata +6 -4
- /data/{beginners-guide.md → guide/guide.md} +0 -0
data/Makefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.4
|
data/ceml.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ceml}
|
8
|
-
s.version = "0.6.
|
8
|
+
s.version = "0.6.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joe Edelman"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-02-11}
|
13
13
|
s.description = %q{a language for coordinating real world events}
|
14
14
|
s.email = %q{joe@citizenlogistics.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,13 +24,15 @@ Gem::Specification.new do |s|
|
|
24
24
|
"README.markdown",
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
|
-
"beginners-guide.md",
|
28
27
|
"ceml.gemspec",
|
29
28
|
"editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage",
|
30
29
|
"editors/CEML.tmbundle/info.plist",
|
31
30
|
"examples/breakfast-exchange.ceml",
|
32
31
|
"examples/citizen-investigation.ceml",
|
33
32
|
"examples/high-fives.ceml",
|
33
|
+
"guide/guide.html",
|
34
|
+
"guide/guide.md",
|
35
|
+
"guide/guide.pdf",
|
34
36
|
"lib/ceml.rb",
|
35
37
|
"lib/ceml/casting_statement.rb",
|
36
38
|
"lib/ceml/confluence.rb",
|
data/guide/guide.html
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC
|
3
|
+
"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
|
4
|
+
"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
|
5
|
+
<html xmlns:svg='http://www.w3.org/2000/svg' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
|
6
|
+
<head><meta content='application/xhtml+xml;charset=utf-8' http-equiv='Content-type' /><title>Beginners Guide to CEML</title></head>
|
7
|
+
<body>
|
8
|
+
<h1 id='beginners_guide_to_ceml'>Beginners Guide to CEML</h1>
|
9
|
+
|
10
|
+
<p>Thanks for taking an interest in CEML, the Coordinated Event Modeling Language. Using CEML you’ll be able to get people to do whatever you want, whether it’s evacuating a submarine, finding a gym buddy, helping people nearby, or just throwing a great party.</p>
|
11
|
+
|
12
|
+
<p>A CEML <em>script</em> is a recipe for action. Just like a recipe, it has three parts: a title, a list of ingredients, and then a section that says what to do with the ingredients. Here’s an example:</p>
|
13
|
+
|
14
|
+
<pre><code>"Trade favorite colors"
|
15
|
+
gather 1 guy and 1 girl within 50 feet
|
16
|
+
ask guy re favorite_color:
|
17
|
+
What's your favorite color?
|
18
|
+
tell girl:
|
19
|
+
Someone nearby likes the color |guy.favorite_color|. Find them.</code></pre>
|
20
|
+
|
21
|
+
<p>In the example, the first line is the title, which is written in double quotes. The second line is the ingredients and how they are obtained. In CEML, the ingredients are usually people (although sometimes they can be places, things, or notes). The remaining lines are the instructions.</p>
|
22
|
+
|
23
|
+
<p>A good way to learn how flexible CEML is is to write the same script a different way. Then you can see which parts can change and which parts have to stay the same:</p>
|
24
|
+
|
25
|
+
<pre><code>"Trade favorite colors"
|
26
|
+
gather a, b within 50ft
|
27
|
+
ask a re x: What's your favorite color?
|
28
|
+
tell b: Someone nearby likes the color |a.x|. Find them.</code></pre>
|
29
|
+
|
30
|
+
<p>Whether you write a script compactly with short names for roles and answers or long names, it runs exactly the same.</p>
|
31
|
+
|
32
|
+
<h2 id='commands'>Commands</h2>
|
33
|
+
|
34
|
+
<p>The above script only uses three CEML commands–<em>gather</em>, <em>ask</em>, and <em>tell</em>–but there aren’t many more commands to learn. Only four more, actually: besides <em>gather</em>, the other ingredients commands are <em>await</em> and <em>nab</em>. Besides <em>ask</em> and <em>tell</em>, the other instructions commands are <em>assign</em> and <em>certify</em>.</p>
|
35
|
+
|
36
|
+
<p>As a sneak preview, here’s an example that uses the other commands:</p>
|
37
|
+
|
38
|
+
<pre><code>"Emergency Medicine"
|
39
|
+
await 1 concerned patient
|
40
|
+
nab a doctor within 5 miles
|
41
|
+
ask patient re problem: What's wrong?
|
42
|
+
assign doctor to patient: Attend to patient's |problem|.
|
43
|
+
certify doctor as responsive</code></pre>
|
44
|
+
|
45
|
+
<h2 id='texts'>Texts</h2>
|
46
|
+
|
47
|
+
<p>Commands like <em>ask</em>, <em>tell</em>, and <em>assign</em> contain texts which are delivered to the player who is the subject of the command. These texts appears after a colon, and can appear on the same or the following lines. If they appears on the following lines, they must be indented, as in the very first example above or the one following.</p>
|
48
|
+
|
49
|
+
<pre><code>"Signups"
|
50
|
+
await 1 new signup
|
51
|
+
tell signup:
|
52
|
+
We are so glad
|
53
|
+
that you have
|
54
|
+
signed up.</code></pre>
|
55
|
+
|
56
|
+
<p>Texts may also contain hyperlinks, which if the player has a smartphone with a web browser, will be openable.</p>
|
57
|
+
|
58
|
+
<pre><code>"Hostility"
|
59
|
+
gather enemy, reporter within 1 block
|
60
|
+
ask reporter re clothing: What are you wearing?
|
61
|
+
assign enemy: Find someone wearing |clothing| and harass them.
|
62
|
+
assign reporter:
|
63
|
+
Someone will harass you. Notice how it feels.
|
64
|
+
Then fill out this google spreadsheet form
|
65
|
+
to describe your experience.
|
66
|
+
http://spreadsheet.google.com/foo
|
67
|
+
tell both: thanks so much for participating!</code></pre>
|
68
|
+
|
69
|
+
<h2 id='roles'>Roles</h2>
|
70
|
+
|
71
|
+
<p>In the examples so far, the words like ‘enemy’, ‘reporter’, ‘guy’, ‘girl’, ‘a’, ‘b’, ‘signup’, ‘patient’, and ‘doctor’ are <em>role names</em>. Most of the time, a role name can be any word you like. They are just a placeholder to connect <em>casting commands</em> like <em>gather</em> and <em>await</em>, with <em>coordination commands</em> like <em>tell</em>.</p>
|
72
|
+
|
73
|
+
<p>Squads on Groundcrew, however, can define special meanings for certain roles. So on a particular squad, a ‘doctor’ might mean someone who’s been tagged/certified with the tag ‘doctor’, and a patient might mean anyone else.</p>
|
74
|
+
|
75
|
+
<p>Some role names are always special. For instance, if you use the role name ‘organizer’, it always means someone who’s an official organizer for that squad. And if you use the role names ‘both’, ‘all’, ‘each’, or ‘everyone’, it means that the instruction applies to everyone regardless of how they were <em>cast</em>.</p>
|
76
|
+
|
77
|
+
<pre><code>"Get Help"
|
78
|
+
await concerned user
|
79
|
+
nab organizer
|
80
|
+
tell organizer: someone's not doing well.</code></pre>
|
81
|
+
|
82
|
+
<p>When there is only one kind of role in a script, it is possible to omit the role name in instructional commands.</p>
|
83
|
+
|
84
|
+
<pre><code>await 1 tired user
|
85
|
+
ask re cause: why are you tired?
|
86
|
+
tell: i hope you feel better</code></pre>
|
87
|
+
|
88
|
+
<h2 id='social_information'>Social Information</h2>
|
89
|
+
|
90
|
+
<p>Texts (see above) may contain <em>social information</em> that’s inserted from answers by another player. To do this, we use a section surrounded by vertical bars (|). In the text that’s sent to the player, this section will be replaced by the other player’s answer.</p>
|
91
|
+
|
92
|
+
<pre><code>"Empire"
|
93
|
+
gather emperor and 2-5 servants
|
94
|
+
ask emperor re tasks: What should your servants do today?
|
95
|
+
assign servants: The emperor has asked you to do |tasks|. Do them now.</code></pre>
|
96
|
+
|
97
|
+
<p>In situations where there may be confusion about which answer you mean, you can specify a particular role by using a dot (.) in between the role and the answer names.</p>
|
98
|
+
|
99
|
+
<pre><code>"Cheese Monte"
|
100
|
+
gather a,b,c
|
101
|
+
ask each re cheese: What kind of cheese do you have?
|
102
|
+
tell a: Someone near you has |c.cheese|. Take it!
|
103
|
+
tell b: Someone near you has |a.cheese|. Take it!
|
104
|
+
tell c: Someone near you has |b.cheese|. Take it!</code></pre>
|
105
|
+
|
106
|
+
<h2 id='assign'>Assign</h2>
|
107
|
+
|
108
|
+
<p>It is probably clear what <em>ask</em> and <em>tell</em> do, but we haven’t exactly covered <em>assign</em>. <em>Assign</em> gives a task which is expected to last a certain duration. While a <em>tell</em> command for a particular player completes immediately and goes on to the next command, an <em>assign</em> will wait for the player to say they’ve completed the task, and collect photo and textual reports as they do it. There are different representations for this depending on whether the player is connected to the script via text messaging, the iphone, or the mobile web.</p>
|
109
|
+
|
110
|
+
<p>A special form of <em>assign</em> will additionally direct the player to a person or place where they are supposed to go.</p>
|
111
|
+
|
112
|
+
<pre><code>"Streetcorner Observation"
|
113
|
+
gather player, streetcorner within 5 blocks
|
114
|
+
assign player to streetcorner:
|
115
|
+
Go there and report what you observe.</code></pre>
|
116
|
+
|
117
|
+
<p>On iPhone or mobile web, the player will get a little map to direct them. There are several special <em>role names</em> which are used to indicate places rather than people. These include “streetcorner”, “park”, “field”, and “landmark”.</p>
|
118
|
+
|
119
|
+
<h2 id='choosing_players_await_gather_and_nab'>Choosing Players: Await, Gather, and Nab.</h2>
|
120
|
+
|
121
|
+
<p>So what is really the difference between <em>await</em>, <em>gather</em>, and <em>nab</em>, you may be asking? Or perhaps you have already figured it out.</p>
|
122
|
+
|
123
|
+
<p><em>Await</em> defines a kind of trigger–as soon as the conditions awaited for are met, the script will run.</p>
|
124
|
+
|
125
|
+
<pre><code>await 2-5 level1 players within 50ft
|
126
|
+
assign: shout out "woo-hoo!"
|
127
|
+
certify as level2 not level1</code></pre>
|
128
|
+
|
129
|
+
<p>Unless there’s an await statement in your script, it will have to be executed manually by an organizer.</p>
|
130
|
+
|
131
|
+
<p><em>Gather</em> issues invitations. It will keep issuing invitations and processing people’s replies to them until it has the requisite number of players for its roles.</p>
|
132
|
+
|
133
|
+
<pre><code>"Pick-up basketball"
|
134
|
+
gather 4-8 basketball players within 4 blocks</code></pre>
|
135
|
+
|
136
|
+
<p><em>Nab</em> just involves people, straight up, without asking their permission or issuing them an invitation.</p>
|
137
|
+
|
138
|
+
<p>By default, the people that triggered an <em>await</em> script are nabbed, not gathered. That means they will never receive an invitation. If you want to make sure they accept, you need an <em>await</em> line and a <em>gather</em> line for the same role name.</p>
|
139
|
+
|
140
|
+
<pre><code>"A study about vomitting"
|
141
|
+
await 5 sick users
|
142
|
+
gather 2-5 users
|
143
|
+
ask re feeling: how do you feel?</code></pre>
|
144
|
+
|
145
|
+
<h2 id='qualifying_players'>Qualifying players</h2>
|
146
|
+
|
147
|
+
<p>You may have noticed that some of the <em>await</em>, <em>gather</em>, and <em>nab</em> statements have adjectives or qualifiers before the role name. For instance, the word “sick” in “sick users” above is such a qualifier. So is “basketball”, “level1”, “tired”, “concerned”, and “new”.</p>
|
148
|
+
|
149
|
+
<p>Some of these have special meanings: the qualifier <em>new</em> is automatically applied to new signups. So if your script has an <em>await</em> command that looks for someone new, it will automatically run on signup.</p>
|
150
|
+
|
151
|
+
<pre><code>await 3 new signups
|
152
|
+
assign:
|
153
|
+
You have all just signed up!
|
154
|
+
Take a photo of something you
|
155
|
+
love and share with one another.</code></pre>
|
156
|
+
|
157
|
+
<p>Another qualifier with a special meaning is <em>concerned</em>. This is applied to players who, because of their text messaging or their tweeting or their interaction with the iphone or web apps, seem like are confused or have an urgent question or issue.</p>
|
158
|
+
|
159
|
+
<p>The other qualifiers don’t mean anythings special, but they select only players who have been certified or tagged with that particular word. So “gather 5-20 level1 users” will only invite users who have been tagged or certified as level1.</p>
|
160
|
+
|
161
|
+
<h2 id='certifying'>Certifying</h2>
|
162
|
+
|
163
|
+
<p>When a player has successfully completed their role in your script, you can add or change the tags associated with that player using the <em>certify</em> command.</p>
|
164
|
+
|
165
|
+
<pre><code>await 3 new signups
|
166
|
+
assign:
|
167
|
+
You have all just signed up!
|
168
|
+
Take a photo of something you
|
169
|
+
love and share with one another.
|
170
|
+
certify as photo_sharing</code></pre>
|
171
|
+
|
172
|
+
<h2 id='making_connections_between_scripts'>Making Connections between Scripts</h2>
|
173
|
+
|
174
|
+
<p><em>Certify</em> and qualifications can be used to link scripts together. The certification at the end of the first script can trigger the <em>await</em> statement in the next script. Here’s an example:</p>
|
175
|
+
|
176
|
+
<pre><code>await 20 photo_sharing users
|
177
|
+
ask re opinion:
|
178
|
+
How did you like sharing photos just now?
|
179
|
+
certify as signed_up not photo_sharing</code></pre>
|
180
|
+
|
181
|
+
<h2 id='congratulations'>Congratulations</h2>
|
182
|
+
|
183
|
+
<p>You now know the basics of CEML and can start brainstorming your own scripts. If you don’t have a squad already, contact us at Groundcrew and we’ll get you set up.</p>
|
184
|
+
|
185
|
+
<p>We will also be creating a google group for CEML developers soon. Write info@groundcrew.us to make sure you’re on it.</p>
|
186
|
+
<hr />
|
187
|
+
<h2 id='faq'>FAQ</h2>
|
188
|
+
|
189
|
+
<h3 id='do_i_need_a_title_for_every_script'>Do I need a title for every script?</h3>
|
190
|
+
|
191
|
+
<p>You may have noticed that some of the script examples given in this guide do not have titles. Titles can be omitted under certain conditions. The main issue is that if a script has a <em>gather</em> statement then it MUST have a title. This is because the invitations that are issued contain the script title. Otherwise, titles are still often good to have: if the script is run manually it must have a title so that organizers can select it, and when users are running one of our smartphone clients like the iPhone app or the HTML5 webpage, they will see the title if there is one. The title will also be associated with any long-lasting media and reports that come from running the script.</p>
|
192
|
+
|
193
|
+
<h3 id='what_if_i_want_to_share_documents_or_notes_in_a_script'>What if I want to share documents or notes in a script?</h3>
|
194
|
+
|
195
|
+
<p>The February or March 2011 version of CEML will support passing and curating notes and documents between scripts. This will allow for a mix of flashmob and knowledge work-style coordination. Syntax is not finalized, but something like:</p>
|
196
|
+
|
197
|
+
<pre><code>await designer
|
198
|
+
assign:
|
199
|
+
sketch out a design for something you
|
200
|
+
want to build and take a photo
|
201
|
+
document as designer_photo
|
202
|
+
certify designer_photo as unreviewed
|
203
|
+
|
204
|
+
await 6 reviewers and unreviewed designer_photo document
|
205
|
+
ask reviewers re opinion:
|
206
|
+
What do you think of this idea? |designer_photo|
|
207
|
+
certify designer_photo as reviewed not unreviewed</code></pre>
|
208
|
+
</body></html>
|
data/guide/guide.pdf
ADDED
Binary file
|
data/lib/ceml/driver.rb
CHANGED
@@ -86,7 +86,7 @@ module CEML
|
|
86
86
|
updated_players.each do |player|
|
87
87
|
player_id = player[:id]
|
88
88
|
player[:roles] = Set.new([*player[:roles] || []])
|
89
|
-
player[:roles] << :agents << :players
|
89
|
+
player[:roles] << :agents << :players << :both << :all << :each << :everyone
|
90
90
|
if existing_player = players.find{ |p| p[:id] == player_id }
|
91
91
|
existing_player[:roles] += player.delete :roles
|
92
92
|
existing_player.update player
|
data/lib/ceml/incident.rb
CHANGED
@@ -8,6 +8,7 @@ module CEML
|
|
8
8
|
def recognized; this[:recognized]; end
|
9
9
|
def pc; this[:pc] ||= 0; end
|
10
10
|
def qs_answers; this[:qs_answers] ||= Hash.new; end
|
11
|
+
def seq; @seq ||= script.bytecode; end
|
11
12
|
|
12
13
|
def handled!
|
13
14
|
this.delete :received
|
@@ -23,13 +24,23 @@ module CEML
|
|
23
24
|
@callback.call this, *stuff if @callback
|
24
25
|
end
|
25
26
|
|
27
|
+
def rolematch(specified_roles)
|
28
|
+
expanded = roles.map{ |r| r == :agent ? [:agent, :agents] : r }.flatten.concat([:both, :all, :everyone])
|
29
|
+
not (expanded & specified_roles).empty?
|
30
|
+
end
|
31
|
+
|
26
32
|
def run(players, &blk)
|
27
33
|
@players = players
|
28
34
|
@callback = blk
|
29
35
|
:loop while players.any? do |@this|
|
30
36
|
# puts "seq for roles: #{roles.inspect} #{seq.inspect}"
|
31
|
-
next unless
|
32
|
-
|
37
|
+
next unless instr = seq[pc]
|
38
|
+
instr = instr.dup
|
39
|
+
if rolematch(instr.shift)
|
40
|
+
instr << role_info if instr.first == :start #tmp hack
|
41
|
+
next unless send(*instr)
|
42
|
+
cb(*instr)
|
43
|
+
end
|
33
44
|
this[:pc]+=1
|
34
45
|
end
|
35
46
|
@callback = @players = nil
|
@@ -40,57 +51,19 @@ module CEML
|
|
40
51
|
end
|
41
52
|
|
42
53
|
def is_transient?
|
43
|
-
|
54
|
+
seq.none? do |roles, opcode, arg|
|
44
55
|
case opcode
|
45
56
|
when :start_delay, :ask_q, :assign, :null_assign then true
|
46
57
|
end
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
50
|
-
def main_seq
|
51
|
-
bytecode = []
|
52
|
-
instrs = script.instructions_for(roles)
|
53
|
-
instrs.each do |inst|
|
54
|
-
if inst.delay
|
55
|
-
bytecode << [:start_delay, inst.delay]
|
56
|
-
bytecode << [:complete_delay]
|
57
|
-
end
|
58
|
-
case inst.cmd
|
59
|
-
when :record
|
60
|
-
bytecode << [:answered_q, {:key => inst.key}]
|
61
|
-
when :set
|
62
|
-
bytecode << [:set, {:key => inst.key, :value => inst.text}]
|
63
|
-
when :ask
|
64
|
-
bytecode << [:ask_q, {:text => inst.text}]
|
65
|
-
bytecode << [:answered_q, {:key => inst.key}]
|
66
|
-
when :tell
|
67
|
-
bytecode << [:send_msg, {:text=>inst.text}]
|
68
|
-
when :assign
|
69
|
-
bytecode << [:assign, {:text=>inst.text}]
|
70
|
-
bytecode << [:complete_assign, {:text=>inst.text}]
|
71
|
-
end
|
72
|
-
end
|
73
|
-
if instrs.empty? and script.title
|
74
|
-
bytecode << [:null_assign]
|
75
|
-
bytecode << [:complete_assign]
|
76
|
-
end
|
77
|
-
bytecode
|
78
|
-
end
|
79
|
-
|
80
|
-
def seq
|
81
|
-
@seq ||= {}
|
82
|
-
@seq[roles] ||= begin
|
83
|
-
bytecode = [[:start, role_info]]
|
84
|
-
bytecode.concat main_seq
|
85
|
-
bytecode << [:finish]
|
86
|
-
end
|
87
|
-
end
|
88
61
|
|
89
62
|
def expand(role, var)
|
90
63
|
case role
|
91
64
|
when 'his', 'her', 'their'; return qs_answers[var]
|
92
65
|
when 'world', 'game', 'exercise', 'group'; return (cb :world, var)
|
93
|
-
when 'somebody', 'someone';
|
66
|
+
when 'somebody', 'someone', 'buddy'; role = nil
|
94
67
|
end
|
95
68
|
role = role.to_sym if role
|
96
69
|
@players.each do |p|
|
@@ -134,6 +107,11 @@ module CEML
|
|
134
107
|
true
|
135
108
|
end
|
136
109
|
|
110
|
+
def sync
|
111
|
+
this[:synced] = pc
|
112
|
+
return true if @players.all?{ |p| p[:synced] == pc }
|
113
|
+
end
|
114
|
+
|
137
115
|
def ask_q q
|
138
116
|
text = interpolate(q[:text]) or return false
|
139
117
|
say :ask, :q => text
|
data/lib/ceml/script.rb
CHANGED
@@ -91,7 +91,7 @@ module CEML
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def allowed_roles
|
94
|
-
allowed_roles = [:organizer, :agents]
|
94
|
+
allowed_roles = [:organizer, :agents, :both, :all, :everyone, :each, :players]
|
95
95
|
allowed_roles += cast.rolenames
|
96
96
|
allowed_roles.uniq
|
97
97
|
end
|
@@ -112,6 +112,14 @@ module CEML
|
|
112
112
|
return instructions.for(expand_roles(roles))
|
113
113
|
end
|
114
114
|
|
115
|
+
def bytecode
|
116
|
+
code = [[[:all], :start]]
|
117
|
+
return [[[:all], :null_assign], [[:all], :complete_assign]] if !instructions and title
|
118
|
+
instructions.list.each{ |inst| code.concat inst.bytecode } if instructions
|
119
|
+
code << [[:all], :finish]
|
120
|
+
code
|
121
|
+
end
|
122
|
+
|
115
123
|
def asks(roles)
|
116
124
|
return [] unless instructions
|
117
125
|
instructions.i_asks([*roles])
|
@@ -3,7 +3,7 @@ grammar Instructions
|
|
3
3
|
include Lexer
|
4
4
|
|
5
5
|
rule basic_statement
|
6
|
-
(ask_stmt / tell_stmt / assign_stmt / record_stmt / set_stmt) {
|
6
|
+
(ask_stmt / tell_stmt / assign_stmt / record_stmt / set_stmt / sync_stmt) {
|
7
7
|
|
8
8
|
def delay
|
9
9
|
if parent.respond_to? :later and not parent.later.empty?
|
@@ -18,12 +18,23 @@ grammar Instructions
|
|
18
18
|
(!defined?(:about) || about.empty?) ? nil : about.varname.text_value;
|
19
19
|
end
|
20
20
|
def key; var || text; end
|
21
|
-
def cmd;
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
def cmd; text_value.split.first.to_sym; end
|
22
|
+
|
23
|
+
def bytecode
|
24
|
+
code = []
|
25
|
+
code.concat [[[role], :start_delay, delay],
|
26
|
+
[[role], :complete_delay]] if delay
|
27
|
+
code.concat case cmd
|
28
|
+
when :record; [[[role], :answered_q, {:key => key}]]
|
29
|
+
when :set; [[[role], :set, {:key => key, :value => text}]]
|
30
|
+
when :ask; [[[role], :ask_q, {:text => text}],
|
31
|
+
[[role], :answered_q, {:key => key}]]
|
32
|
+
when :tell; [[[role], :send_msg, {:text => text}]]
|
33
|
+
when :assign; [[[role], :assign, {:text => text}],
|
34
|
+
[[role], :complete_assign, {:text => text}]]
|
35
|
+
when :sync; [[[role], :sync]]
|
36
|
+
end
|
37
|
+
code
|
27
38
|
end
|
28
39
|
}
|
29
40
|
end
|
@@ -55,5 +66,9 @@ grammar Instructions
|
|
55
66
|
rule set_stmt
|
56
67
|
'set' ws id ws varname:id ':' ws? text
|
57
68
|
end
|
69
|
+
|
70
|
+
rule sync_stmt
|
71
|
+
'sync' ws id
|
72
|
+
end
|
58
73
|
end
|
59
74
|
end
|
data/test/test_incident.rb
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
require 'ceml'
|
2
2
|
require 'test/helper'
|
3
3
|
|
4
|
+
SYNC_SCRIPT = <<XXX
|
5
|
+
await 1 alpha and 1 beta
|
6
|
+
ask alpha re color: What color?
|
7
|
+
ask beta re color: What color?
|
8
|
+
sync both
|
9
|
+
tell alpha: Hi there
|
10
|
+
tell beta: Goodbye
|
11
|
+
XXX
|
12
|
+
|
4
13
|
COMPLIMENT_SCRIPT = <<XXX
|
5
14
|
"Overwhelm a specific person with compliments"
|
6
15
|
gather 5-20 players within 4 blocks
|
@@ -62,6 +71,21 @@ XXX
|
|
62
71
|
|
63
72
|
class TestIncident < Test::Unit::TestCase
|
64
73
|
|
74
|
+
def test_sync
|
75
|
+
s = CEML.parse(:script, SYNC_SCRIPT)
|
76
|
+
play do
|
77
|
+
ping s, :id => 'alpha'
|
78
|
+
ping s, :id => 'beta'
|
79
|
+
asked 'alpha', /olor/
|
80
|
+
asked 'beta', /olor/
|
81
|
+
says 'alpha', "red"
|
82
|
+
silent 'alpha'
|
83
|
+
says 'beta', "blue"
|
84
|
+
told 'alpha', /Hi/
|
85
|
+
told 'beta', /Goodbye/
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
65
89
|
def test_jane
|
66
90
|
s = CEML.parse(:script, JANE_SCRIPT)
|
67
91
|
play do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 6
|
8
|
-
-
|
9
|
-
version: 0.6.
|
8
|
+
- 4
|
9
|
+
version: 0.6.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Joe Edelman
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-02-11 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -46,13 +46,15 @@ files:
|
|
46
46
|
- README.markdown
|
47
47
|
- Rakefile
|
48
48
|
- VERSION
|
49
|
-
- beginners-guide.md
|
50
49
|
- ceml.gemspec
|
51
50
|
- editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage
|
52
51
|
- editors/CEML.tmbundle/info.plist
|
53
52
|
- examples/breakfast-exchange.ceml
|
54
53
|
- examples/citizen-investigation.ceml
|
55
54
|
- examples/high-fives.ceml
|
55
|
+
- guide/guide.html
|
56
|
+
- guide/guide.md
|
57
|
+
- guide/guide.pdf
|
56
58
|
- lib/ceml.rb
|
57
59
|
- lib/ceml/casting_statement.rb
|
58
60
|
- lib/ceml/confluence.rb
|
File without changes
|