ceml 0.7.13 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/Makefile +1 -1
  2. data/VERSION +1 -1
  3. data/ceml.gemspec +62 -50
  4. data/guide/guide.html +69 -14
  5. data/guide/guide.md +74 -15
  6. data/guide/guide.pdf +0 -0
  7. data/lib/ceml/driver.rb +0 -181
  8. data/lib/ceml/lang/basic_instruction.rb +49 -0
  9. data/lib/ceml/{casting_statement.rb → lang/casting_statement.rb} +19 -9
  10. data/lib/ceml/{instruction_statements.rb → lang/instruction_statements.rb} +5 -16
  11. data/lib/ceml/{script.rb → lang/script.rb} +53 -43
  12. data/lib/ceml/lang/tt/casting.rb +432 -0
  13. data/lib/ceml/lang/tt/casting.treetop +29 -0
  14. data/lib/ceml/lang/tt/instructions.rb +1130 -0
  15. data/lib/ceml/lang/tt/instructions.treetop +86 -0
  16. data/lib/ceml/lang/tt/lexer.rb +1804 -0
  17. data/lib/ceml/{tt → lang/tt}/lexer.treetop +70 -7
  18. data/lib/ceml/lang/tt/scripts.rb +647 -0
  19. data/lib/ceml/{tt → lang/tt}/scripts.treetop +2 -2
  20. data/lib/ceml/lang.rb +10 -0
  21. data/lib/ceml/models/audition.rb +65 -0
  22. data/lib/ceml/models/bundle.rb +64 -0
  23. data/lib/ceml/models/cast.rb +108 -0
  24. data/lib/ceml/models/castable.rb +81 -0
  25. data/lib/ceml/{incident.rb → models/incident.rb} +63 -15
  26. data/lib/ceml/models/incident_model.rb +100 -0
  27. data/lib/ceml/models/incident_role_slot.rb +16 -0
  28. data/lib/ceml/models/player.rb +80 -0
  29. data/lib/ceml/models/queue.rb +12 -0
  30. data/lib/ceml/models/waiting_room.rb +40 -0
  31. data/lib/ceml/models.rb +16 -0
  32. data/lib/ceml/processor.rb +162 -0
  33. data/lib/ceml.rb +7 -14
  34. data/test/askchain.ceml +6 -0
  35. data/test/compliment.ceml +4 -0
  36. data/test/dialogues/accept.ceml +24 -0
  37. data/test/dialogues/basic_seed.ceml +26 -0
  38. data/test/dialogues/jordan.ceml +121 -0
  39. data/test/helper.rb +44 -39
  40. data/test/jane.ceml +48 -0
  41. data/test/{test_casting.rb → lang/test_casting.rb} +5 -0
  42. data/test/lang/test_instructions.rb +42 -0
  43. data/test/{test_scripts.rb → lang/test_scripts.rb} +3 -2
  44. data/test/sync.ceml +6 -0
  45. data/test/test_castable.rb +20 -0
  46. data/test/test_dialogues.rb +58 -0
  47. data/test/test_incident.rb +64 -127
  48. metadata +54 -30
  49. data/.gitignore +0 -23
  50. data/lib/ceml/confluence.rb +0 -63
  51. data/lib/ceml/role.rb +0 -61
  52. data/lib/ceml/tt/casting.treetop +0 -65
  53. data/lib/ceml/tt/instructions.treetop +0 -91
  54. data/test/test_instructions.rb +0 -27
  55. data/test/test_release.rb +0 -78
data/Makefile CHANGED
@@ -1,5 +1,5 @@
1
1
  ceml:
2
- tt lib/ceml/tt/*.treetop
2
+ tt lib/ceml/lang/tt/*.treetop
3
3
 
4
4
  test:
5
5
  testrb test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.13
1
+ 0.8.0
data/ceml.gemspec CHANGED
@@ -1,77 +1,89 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ceml}
8
- s.version = "0.7.13"
8
+ s.version = "0.8.0"
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-02-24}
12
+ s.date = %q{2011-05-27}
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 = [
16
16
  "LICENSE",
17
- "README.markdown"
17
+ "README.markdown"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "Makefile",
24
- "README.markdown",
25
- "Rakefile",
26
- "VERSION",
27
- "ceml.gemspec",
28
- "editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage",
29
- "editors/CEML.tmbundle/info.plist",
30
- "examples/breakfast-exchange.ceml",
31
- "examples/citizen-investigation.ceml",
32
- "examples/high-fives.ceml",
33
- "guide/guide.html",
34
- "guide/guide.md",
35
- "guide/guide.pdf",
36
- "lib/ceml.rb",
37
- "lib/ceml/casting_statement.rb",
38
- "lib/ceml/confluence.rb",
39
- "lib/ceml/driver.rb",
40
- "lib/ceml/incident.rb",
41
- "lib/ceml/instruction_statements.rb",
42
- "lib/ceml/role.rb",
43
- "lib/ceml/script.rb",
44
- "lib/ceml/tt/casting.treetop",
45
- "lib/ceml/tt/instructions.treetop",
46
- "lib/ceml/tt/lexer.treetop",
47
- "lib/ceml/tt/scripts.treetop",
48
- "test/helper.rb",
49
- "test/test_casting.rb",
50
- "test/test_incident.rb",
51
- "test/test_instructions.rb",
52
- "test/test_release.rb",
53
- "test/test_scripts.rb",
54
- "try"
21
+ "LICENSE",
22
+ "Makefile",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "ceml.gemspec",
27
+ "editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage",
28
+ "editors/CEML.tmbundle/info.plist",
29
+ "examples/breakfast-exchange.ceml",
30
+ "examples/citizen-investigation.ceml",
31
+ "examples/high-fives.ceml",
32
+ "guide/guide.html",
33
+ "guide/guide.md",
34
+ "guide/guide.pdf",
35
+ "lib/ceml.rb",
36
+ "lib/ceml/driver.rb",
37
+ "lib/ceml/lang.rb",
38
+ "lib/ceml/lang/basic_instruction.rb",
39
+ "lib/ceml/lang/casting_statement.rb",
40
+ "lib/ceml/lang/instruction_statements.rb",
41
+ "lib/ceml/lang/script.rb",
42
+ "lib/ceml/lang/tt/casting.rb",
43
+ "lib/ceml/lang/tt/casting.treetop",
44
+ "lib/ceml/lang/tt/instructions.rb",
45
+ "lib/ceml/lang/tt/instructions.treetop",
46
+ "lib/ceml/lang/tt/lexer.rb",
47
+ "lib/ceml/lang/tt/lexer.treetop",
48
+ "lib/ceml/lang/tt/scripts.rb",
49
+ "lib/ceml/lang/tt/scripts.treetop",
50
+ "lib/ceml/models.rb",
51
+ "lib/ceml/models/audition.rb",
52
+ "lib/ceml/models/bundle.rb",
53
+ "lib/ceml/models/cast.rb",
54
+ "lib/ceml/models/castable.rb",
55
+ "lib/ceml/models/incident.rb",
56
+ "lib/ceml/models/incident_model.rb",
57
+ "lib/ceml/models/incident_role_slot.rb",
58
+ "lib/ceml/models/player.rb",
59
+ "lib/ceml/models/queue.rb",
60
+ "lib/ceml/models/waiting_room.rb",
61
+ "lib/ceml/processor.rb",
62
+ "test/askchain.ceml",
63
+ "test/compliment.ceml",
64
+ "test/dialogues/accept.ceml",
65
+ "test/dialogues/basic_seed.ceml",
66
+ "test/dialogues/jordan.ceml",
67
+ "test/helper.rb",
68
+ "test/jane.ceml",
69
+ "test/lang/test_casting.rb",
70
+ "test/lang/test_instructions.rb",
71
+ "test/lang/test_scripts.rb",
72
+ "test/sync.ceml",
73
+ "test/test_castable.rb",
74
+ "test/test_dialogues.rb",
75
+ "test/test_incident.rb",
76
+ "try"
55
77
  ]
56
78
  s.homepage = %q{http://github.com/citizenlogistics/ceml}
57
- s.rdoc_options = ["--charset=UTF-8"]
58
79
  s.require_paths = ["lib"]
59
- s.rubygems_version = %q{1.3.6}
80
+ s.rubygems_version = %q{1.6.2}
60
81
  s.summary = %q{a language for coordinating real world events}
61
- s.test_files = [
62
- "test/helper.rb",
63
- "test/test_casting.rb",
64
- "test/test_incident.rb",
65
- "test/test_instructions.rb",
66
- "test/test_release.rb",
67
- "test/test_scripts.rb"
68
- ]
69
82
 
70
83
  if s.respond_to? :specification_version then
71
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
72
84
  s.specification_version = 3
73
85
 
74
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
86
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
75
87
  s.add_runtime_dependency(%q<treetop>, [">= 0"])
76
88
  else
77
89
  s.add_dependency(%q<treetop>, [">= 0"])
data/guide/guide.html CHANGED
@@ -31,7 +31,7 @@ tell b: Someone nearby likes the color |a.x|. Find them.</code></pre>
31
31
 
32
32
  <h2 id='commands'>Commands</h2>
33
33
 
34
- <p>The above script only uses three CEML commands&#8211;<em>gather</em>, <em>ask</em>, and <em>tell</em>&#8211;but there aren&#8217;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>
34
+ <p>The above script only uses three CEML commands&#8211;<em>gather</em>, <em>ask</em>, and <em>tell</em>&#8211;but there aren&#8217;t many more commands to learn. Only six 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>, <em>release</em>, <em>expect</em>, and <em>sync</em>.</p>
35
35
 
36
36
  <p>As a sneak preview, here&#8217;s an example that uses the other commands:</p>
37
37
 
@@ -40,7 +40,7 @@ await 1 concerned patient
40
40
  nab a doctor within 5 miles
41
41
  ask patient re problem: What&#39;s wrong?
42
42
  assign doctor to patient: Attend to patient&#39;s |problem|.
43
- certify doctor as responsive</code></pre>
43
+ release doctor as responsive</code></pre>
44
44
 
45
45
  <h2 id='texts'>Texts</h2>
46
46
 
@@ -70,7 +70,7 @@ tell both: thanks so much for participating!</code></pre>
70
70
 
71
71
  <p>In the examples so far, the words like &#8216;enemy&#8217;, &#8216;reporter&#8217;, &#8216;guy&#8217;, &#8216;girl&#8217;, &#8216;a&#8217;, &#8216;b&#8217;, &#8216;signup&#8217;, &#8216;patient&#8217;, and &#8216;doctor&#8217; 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
72
 
73
- <p>Squads on Groundcrew, however, can define special meanings for certain roles. So on a particular squad, a &#8216;doctor&#8217; might mean someone who&#8217;s been tagged/certified with the tag &#8216;doctor&#8217;, and a patient might mean anyone else.</p>
73
+ <p>Squads on Groundcrew, however, can define special meanings for certain roles. So on a particular squad, a &#8216;doctor&#8217; might mean someone who&#8217;s been tagged/released with the tag &#8216;doctor&#8217;, and a patient might mean anyone else.</p>
74
74
 
75
75
  <p>Some role names are always special. For instance, if you use the role name &#8216;organizer&#8217;, it always means someone who&#8217;s an official organizer for that squad. And if you use the role names &#8216;both&#8217;, &#8216;all&#8217;, &#8216;each&#8217;, or &#8216;everyone&#8217;, it means that the instruction applies to everyone regardless of how they were <em>cast</em>.</p>
76
76
 
@@ -116,15 +116,38 @@ assign player to streetcorner:
116
116
 
117
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 &#8220;streetcorner&#8221;, &#8220;park&#8221;, &#8220;field&#8221;, and &#8220;landmark&#8221;.</p>
118
118
 
119
+ <h2 id='expect'>Expect</h2>
120
+
121
+ <p>When you ask a question using <em>ask</em>, you may not want to let a player proceed unless they&#8217;ve answered in a way you understand or recognize. This can be accomplished using <em>expect</em>:</p>
122
+
123
+ <pre><code>ask player re path:
124
+ Do you prefer to the path to the left or the right?
125
+ expect /left|right/ from player:
126
+ Please say &quot;left&quot; or &quot;right&quot;!</code></pre>
127
+
128
+ <p>The expect statement, like the release statement described below, can be passed strings, certain keywords, or regular expressions.</p>
129
+
130
+ <h2 id='sync_up'>Sync up</h2>
131
+
132
+ <p>There also may be times when you want to sync up several players and make sure they have both completed assignments or answered questions before they each proceed with the script:</p>
133
+
134
+ <pre><code>assign redcoat:
135
+ March briskly towards Concord
136
+ assign minuteman:
137
+ Hide in the bushes
138
+ sync up redcoat and minuteman
139
+ tell both:
140
+ Prepare to be surprised.</code></pre>
141
+
119
142
  <h2 id='choosing_players_await_gather_and_nab'>Choosing Players: Await, Gather, and Nab.</h2>
120
143
 
121
144
  <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
145
 
123
146
  <p><em>Await</em> defines a kind of trigger&#8211;as soon as the conditions awaited for are met, the script will run.</p>
124
147
 
125
- <pre><code>await 2-5 level1 players within 50ft
148
+ <pre><code>await 2-5 level=1 players within 50ft
126
149
  assign: shout out &quot;woo-hoo!&quot;
127
- certify as level2 not level1</code></pre>
150
+ release as level=2</code></pre>
128
151
 
129
152
  <p>Unless there&#8217;s an await statement in your script, it will have to be executed manually by an organizer.</p>
130
153
 
@@ -156,27 +179,59 @@ assign:
156
179
 
157
180
  <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
181
 
159
- <p>The other qualifiers don&#8217;t mean anythings special, but they select only players who have been certified or tagged with that particular word. So &#8220;gather 5-20 level1 users&#8221; will only invite users who have been tagged or certified as level1.</p>
182
+ <p>The other qualifiers don&#8217;t mean anythings special, but they select only players who have been released or tagged with that particular word. So &#8220;gather 5-20 level=1 users&#8221; will only invite users who have been tagged or released as level=1.</p>
183
+
184
+ <h2 id='finer_control_of_matching'>Finer control of matching</h2>
185
+
186
+ <p>The <em>await</em> keyword supports a variety of options that let you match players with more specificity. For instance, you may wish to only match players that text in within 10 minutes of one another:</p>
160
187
 
161
- <h2 id='certifying'>Certifying</h2>
188
+ <pre><code>await 2 new players over 10 minutes</code></pre>
162
189
 
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>
190
+ <p>Or players that have the same favorite color:</p>
191
+
192
+ <pre><code>await 2 new players with matching favorite_color</code></pre>
193
+
194
+ <p>Here&#8217;s two scripts that cooperate to put people in groups by favorite color:</p>
195
+
196
+ <pre><code>await new signup
197
+ ask signup re name: What&#39;s your name?
198
+ ask signup re favorite_color: What&#39;s your favorite color?
199
+
200
+ await 2 players with matching favorite_color
201
+ tell players: |buddy.name| also likes |favorite_color|.</code></pre>
202
+
203
+ <h2 id='releasing'>Releasing</h2>
204
+
205
+ <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>release</em> command.</p>
164
206
 
165
207
  <pre><code>await 3 new signups
166
208
  assign:
167
209
  You have all just signed up!
168
210
  Take a photo of something you
169
211
  love and share with one another.
170
- certify as photo_sharing</code></pre>
212
+ release as photo_sharing</code></pre>
213
+
214
+ <p>You can also release a player early, subject to some conditions, by using <em>if</em> or <em>unless</em>:</p>
215
+
216
+ <pre><code>await 1 boss and 1 worker
217
+ ask worker:
218
+ Do you feel good about working today?
219
+ release worker unless yes
220
+ ask worker re skill:
221
+ What are you good at?
222
+ ask boss re job:
223
+ You have a worker with skill |skill|. What should they do?</code></pre>
224
+
225
+ <p>There are some special keywords you can use after if or unless. These include &#8220;yes&#8221;, &#8220;no&#8221;, &#8220;done&#8221;, &#8220;okay&#8221;. You can also use a string in quotes (&#8220;activate&#8221;), in which case their answer is compared to the string case insensitively and with whitespace trimmed. Or you can use a <a href='http://en.wikipedia.org/wiki/Regular_expression'>regular expression</a> surrounded by forward slashes (/^red|blue|green$/) for more exact matching.</p>
171
226
 
172
227
  <h2 id='making_connections_between_scripts'>Making Connections between Scripts</h2>
173
228
 
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&#8217;s an example:</p>
229
+ <p><em>Release</em> and qualifications can be used to link scripts together. The release at the end of the first script can trigger the <em>await</em> statement in the next script. Here&#8217;s an example:</p>
175
230
 
176
- <pre><code>await 20 photo_sharing users
231
+ <pre><code>await 20 stage=photo_sharing users
177
232
  ask re opinion:
178
233
  How did you like sharing photos just now?
179
- certify as signed_up not photo_sharing</code></pre>
234
+ release as stage=signed_up</code></pre>
180
235
 
181
236
  <h2 id='congratulations'>Congratulations</h2>
182
237
 
@@ -199,10 +254,10 @@ assign:
199
254
  sketch out a design for something you
200
255
  want to build and take a photo
201
256
  document as designer_photo
202
- certify designer_photo as unreviewed
257
+ release designer_photo as unreviewed
203
258
 
204
259
  await 6 reviewers and unreviewed designer_photo document
205
260
  ask reviewers re opinion:
206
261
  What do you think of this idea? |designer_photo|
207
- certify designer_photo as reviewed not unreviewed</code></pre>
262
+ release designer_photo as reviewed not unreviewed</code></pre>
208
263
  </body></html>
data/guide/guide.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Beginners Guide to CEML
2
2
  =======================
3
3
 
4
- 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.
4
+ Thanks for taking an interest in CEML, the Coordinated Event Messaging 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.
5
5
 
6
6
  A CEML _script_ 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:
7
7
 
@@ -26,7 +26,7 @@ Whether you write a script compactly with short names for roles and answers or l
26
26
  Commands
27
27
  --------
28
28
 
29
- The above script only uses three CEML commands--*gather*, *ask*, and *tell*--but there aren't many more commands to learn. Only four more, actually: besides *gather*, the other ingredients commands are *await* and *nab*. Besides *ask* and *tell*, the other instructions commands are *assign* and *certify*.
29
+ The above script only uses three CEML commands--*gather*, *ask*, and *tell*--but there aren't many more commands to learn. Only six more, actually: besides *gather*, the other ingredients commands are *await* and *nab*. Besides *ask* and *tell*, the other instructions commands are *assign*, *release*, *expect*, and *sync*.
30
30
 
31
31
  As a sneak preview, here's an example that uses the other commands:
32
32
 
@@ -35,7 +35,7 @@ As a sneak preview, here's an example that uses the other commands:
35
35
  nab a doctor within 5 miles
36
36
  ask patient re problem: What's wrong?
37
37
  assign doctor to patient: Attend to patient's |problem|.
38
- certify doctor as responsive
38
+ release doctor as responsive
39
39
 
40
40
  Texts
41
41
  -----
@@ -67,7 +67,7 @@ Roles
67
67
 
68
68
  In the examples so far, the words like 'enemy', 'reporter', 'guy', 'girl', 'a', 'b', 'signup', 'patient', and 'doctor' are *role names*. Most of the time, a role name can be any word you like. They are just a placeholder to connect *casting commands* like *gather* and *await*, with *coordination commands* like *tell*.
69
69
 
70
- 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.
70
+ 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/released with the tag 'doctor', and a patient might mean anyone else.
71
71
 
72
72
  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 *cast*.
73
73
 
@@ -115,6 +115,31 @@ A special form of *assign* will additionally direct the player to a person or pl
115
115
 
116
116
  On iPhone or mobile web, the player will get a little map to direct them. There are several special *role names* which are used to indicate places rather than people. These include "streetcorner", "park", "field", and "landmark".
117
117
 
118
+ Expect
119
+ ------
120
+
121
+ When you ask a question using *ask*, you may not want to let a player proceed unless they've answered in a way you understand or recognize. This can be accomplished using *expect*:
122
+
123
+ ask player re path:
124
+ Do you prefer to the path to the left or the right?
125
+ expect /left|right/ from player:
126
+ Please say "left" or "right"!
127
+
128
+ The expect statement, like the release statement described below, can be passed strings, certain keywords, or regular expressions.
129
+
130
+ Sync up
131
+ -------
132
+
133
+ There also may be times when you want to sync up several players and make sure they have both completed assignments or answered questions before they each proceed with the script:
134
+
135
+ assign redcoat:
136
+ March briskly towards Concord
137
+ assign minuteman:
138
+ Hide in the bushes
139
+ sync up redcoat and minuteman
140
+ tell both:
141
+ Prepare to be surprised.
142
+
118
143
  Choosing Players: Await, Gather, and Nab.
119
144
  ----------------------------------------------
120
145
 
@@ -122,9 +147,9 @@ So what is really the difference between *await*, *gather*, and *nab*, you may b
122
147
 
123
148
  *Await* defines a kind of trigger--as soon as the conditions awaited for are met, the script will run.
124
149
 
125
- await 2-5 level1 players within 50ft
150
+ await 2-5 level=1 players within 50ft
126
151
  assign: shout out "woo-hoo!"
127
- certify as level2 not level1
152
+ release as level=2
128
153
 
129
154
  Unless there's an await statement in your script, it will have to be executed manually by an organizer.
130
155
 
@@ -157,29 +182,63 @@ Some of these have special meanings: the qualifier *new* is automatically appli
157
182
 
158
183
  Another qualifier with a special meaning is *concerned*. 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.
159
184
 
160
- 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.
185
+ The other qualifiers don't mean anythings special, but they select only players who have been released or tagged with that particular word. So "gather 5-20 level=1 users" will only invite users who have been tagged or released as level=1.
186
+
187
+ Finer control of matching
188
+ -------------------------
189
+
190
+ The *await* keyword supports a variety of options that let you match players with more specificity. For instance, you may wish to only match players that text in within 10 minutes of one another:
161
191
 
162
- Certifying
192
+ await 2 new players over 10 minutes
193
+
194
+ Or players that have the same favorite color:
195
+
196
+ await 2 new players with matching favorite_color
197
+
198
+ Here's two scripts that cooperate to put people in groups by favorite color:
199
+
200
+ await new signup
201
+ ask signup re name: What's your name?
202
+ ask signup re favorite_color: What's your favorite color?
203
+
204
+ await 2 players with matching favorite_color
205
+ tell players: |buddy.name| also likes |favorite_color|.
206
+
207
+
208
+ Releasing
163
209
  ----------
164
210
 
165
- When a player has successfully completed their role in your script, you can add or change the tags associated with that player using the *certify* command.
211
+ When a player has successfully completed their role in your script, you can add or change the tags associated with that player using the *release* command.
166
212
 
167
213
  await 3 new signups
168
214
  assign:
169
215
  You have all just signed up!
170
216
  Take a photo of something you
171
217
  love and share with one another.
172
- certify as photo_sharing
218
+ release as photo_sharing
219
+
220
+ You can also release a player early, subject to some conditions, by using *if* or *unless*:
221
+
222
+ await 1 boss and 1 worker
223
+ ask worker:
224
+ Do you feel good about working today?
225
+ release worker unless yes
226
+ ask worker re skill:
227
+ What are you good at?
228
+ ask boss re job:
229
+ You have a worker with skill |skill|. What should they do?
230
+
231
+ There are some special keywords you can use after if or unless. These include "yes", "no", "done", "okay". You can also use a string in quotes ("activate"), in which case their answer is compared to the string case insensitively and with whitespace trimmed. Or you can use a [regular expression](http://en.wikipedia.org/wiki/Regular_expression) surrounded by forward slashes (/^red|blue|green$/) for more exact matching.
173
232
 
174
233
  Making Connections between Scripts
175
234
  ----------------------------------
176
235
 
177
- *Certify* and qualifications can be used to link scripts together. The certification at the end of the first script can trigger the *await* statement in the next script. Here's an example:
236
+ *Release* and qualifications can be used to link scripts together. The release at the end of the first script can trigger the *await* statement in the next script. Here's an example:
178
237
 
179
- await 20 photo_sharing users
238
+ await 20 stage=photo_sharing users
180
239
  ask re opinion:
181
240
  How did you like sharing photos just now?
182
- certify as signed_up not photo_sharing
241
+ release as stage=signed_up
183
242
 
184
243
  Congratulations
185
244
  ---------------
@@ -206,9 +265,9 @@ The February or March 2011 version of CEML will support passing and curating not
206
265
  sketch out a design for something you
207
266
  want to build and take a photo
208
267
  document as designer_photo
209
- certify designer_photo as unreviewed
268
+ release designer_photo as unreviewed
210
269
 
211
270
  await 6 reviewers and unreviewed designer_photo document
212
271
  ask reviewers re opinion:
213
272
  What do you think of this idea? |designer_photo|
214
- certify designer_photo as reviewed not unreviewed
273
+ release designer_photo as reviewed not unreviewed
data/guide/guide.pdf CHANGED
Binary file
data/lib/ceml/driver.rb CHANGED
@@ -1,32 +1,5 @@
1
- require 'set'
2
-
3
- module Kernel
4
- def gen_code(size = 8)
5
- rand(36**size).to_s(36)
6
- end
7
- end
8
-
9
1
  module CEML
10
2
  class Driver
11
-
12
- PLAYERS = {}
13
- INCIDENTS = {}
14
- def with_incident(id, script = nil, metadata = {})
15
- id ||= rand(36**10).to_s(36)
16
- PLAYERS[id] ||= []
17
- INCIDENTS[id] ||= CEML::Incident.new to_bytecode(script), id if script
18
- raise "no incident #{id}" unless INCIDENTS[id]
19
- yield INCIDENTS[id], PLAYERS[id], metadata if block_given?
20
-
21
- PLAYERS[id].select{ |p| p[:released] }.each do |p|
22
- release p
23
- ping_all p[:script_collection_id], p
24
- end
25
-
26
- id
27
- end
28
- alias_method :start, :with_incident
29
-
30
3
  def to_bytecode bytecode_or_script
31
4
  case bytecode_or_script
32
5
  when String; return CEML.parse(:script, bytecode_or_script).bytecode
@@ -35,159 +8,5 @@ module CEML
35
8
  else return nil
36
9
  end
37
10
  end
38
-
39
- def log(s)
40
- # puts s
41
- end
42
-
43
- SCRIPTS = Hash.new{ |h,k| h[k] = [] }
44
- def add_script script_collection_id, script
45
- SCRIPTS[script_collection_id] << script
46
- end
47
-
48
- def ping_all script_collection_id, candidate, release = false
49
- candidate[:script_collection_id] = script_collection_id
50
- SCRIPTS[script_collection_id].each{ |s| ping script_collection_id, s.roles_to_cast, candidate, release }
51
- end
52
-
53
- def released_from_all script_collection_id, candidate
54
- SCRIPTS[script_collection_id].each{ |s| release script_collection_id, s.roles_to_cast, candidate }
55
- end
56
-
57
- def release p
58
- p[:tags] -= ['new']
59
- if p[:released] =~ /^(\w+)=/
60
- p[:tags].delete_if{ |t| t =~ /^#{$1}=/ }
61
- end
62
- p[:tags] += [p[:released]]
63
- [:pc, :roles, :released].each{ |sym| p.delete(sym) }
64
- (p[:matchables]||={}).update (p[:qs_answers]||{})
65
- end
66
-
67
- def launch id, script_collection_id, roleset, *cast
68
- script = SCRIPTS[script_collection_id].select{ |s| s.roles_to_cast == roleset }.sort_by{ rand }.first
69
- unless script
70
- rolesets = SCRIPTS[script_collection_id].map(&:roles_to_cast)
71
- raise "matching roleset not found: #{roleset.inspect} in #{rolesets.inspect}"
72
- end
73
- log "launching #{script.bytecode.inspect} with cast #{cast.inspect}"
74
- push id, script.bytecode, *cast
75
- end
76
-
77
-
78
- LOCATIONS = Hash.new{ |h,k| h[k] = [] }
79
- def with_confluences script_collection_id, roleset
80
- yield LOCATIONS["#{script_collection_id}:#{roleset.hash}"]
81
- end
82
-
83
- def ping script_collection_id, roleset, candidate, involvement = :sticky
84
- return unless roleset.any?{ |r| r.fits? candidate }
85
- candidate[:ts] = CEML.clock
86
- already_launched_with = nil
87
- run_after = []
88
-
89
- with_confluences script_collection_id, roleset do |confluences|
90
- already_launched_with = nil
91
- # live_with = confluences.select{ |c| c.live_with?(candidate) }
92
- # if not live_with.empty?
93
- # already_launched_with = live_with.first.incident_id
94
- # live_with.each{ |c| c.rm candidate } if involvement != :sticky
95
- # break if involvement != :released
96
- # end
97
-
98
- locs = confluences.group_by{ |l| l.stage_with_candidate(candidate) }
99
- if locs[:joinable]
100
- log "joining..."
101
- first = locs[:joinable].shift
102
- first.push candidate unless first.incident_id == already_launched_with
103
- # JOIN THEM
104
- run_after << [:push, first.incident_id, nil, candidate]
105
-
106
- elsif locs[:launchable]
107
- log "launching..."
108
- first = locs[:launchable].shift
109
- first.push candidate
110
- cast = first.cast
111
- first.incident_id = gen_code
112
- (locs[:launchable] + (locs[:listable]||[])).each{ |l| l.rm *cast }
113
- # LAUNCH
114
- run_after << [:launch, first.incident_id, script_collection_id, roleset, *cast]
115
-
116
- elsif locs[:listable]
117
- log "listing..."
118
- locs[:listable].each{ |l| l.push candidate }
119
-
120
- else
121
- c = Confluence.new(roleset)
122
- log "start-listing..."
123
- if c.stage_with_candidate(candidate) == :launchable
124
- log "start-launching..."
125
- c.push candidate
126
- c.incident_id = gen_code
127
- run_after << [:launch, c.incident_id, script_collection_id, roleset, candidate]
128
- else
129
- c.push candidate
130
- end
131
- confluences << c
132
- end
133
- confluences.delete_if(&:over?)
134
- end
135
-
136
- run_after.each do |cmd|
137
- send(*cmd)
138
- end
139
-
140
- # if already_launched_with and involvement == :sticky
141
- # puts "PUSHING INSTEAD"
142
- # push already_launched_with, nil, candidate
143
- # end
144
- end
145
-
146
- def push incident_id, script, *updated_players
147
- with_incident incident_id, script do |incident, players, metadata|
148
- subpost incident, players, metadata, *updated_players
149
- end
150
- end
151
-
152
- def post incident_id, *updated_players
153
- push incident_id, nil, *updated_players
154
- end
155
-
156
- alias_method :run, :post
157
-
158
- def subpost incident, players, metadata, *updated_players
159
- updated_players.each do |player|
160
- player_id = player[:id]
161
- player[:roles] = Set.new([*player[:roles] || []])
162
- player[:roles] << :agents << :players << :both << :all << :each << :everyone
163
- if existing_player = players.find{ |p| p[:id] == player_id }
164
- existing_player[:roles] += player.delete :roles
165
- existing_player.update player
166
- else
167
- players << player
168
- end
169
- end
170
- incident.run(players) do |player, meth, what|
171
- meth = "player_#{meth}"
172
- log "[#{incident.id}] #{meth}: #{player[:id]} #{what.inspect}"
173
- if respond_to? meth
174
- metadata.update :player => player, :players => players, :id => incident.id
175
- result = send(meth, metadata, what)
176
- metadata.delete :player
177
- metadata.delete :players
178
- result
179
- end
180
- end
181
- end
182
-
183
- JUST_SAID = {}
184
- def player_said(data, what)
185
- JUST_SAID[data[:player][:id]] = what
186
- puts "Said #{what.inspect}"
187
- end
188
-
189
- # def player_start(data, what)
190
- # puts "STARTED #{data[:player].inspect}"
191
- # end
192
11
  end
193
12
  end