ceml 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/ceml.gemspec +2 -2
- data/lib/ceml/casting_statement.rb +0 -9
- data/lib/ceml/confluence.rb +3 -5
- data/lib/ceml/driver.rb +68 -39
- data/lib/ceml/incident.rb +6 -10
- data/lib/ceml/role.rb +16 -0
- data/lib/ceml/script.rb +5 -6
- data/test/helper.rb +10 -1
- data/test/test_incident.rb +7 -7
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
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.
|
8
|
+
s.version = "0.7.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-
|
12
|
+
s.date = %q{2011-02-12}
|
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 = [
|
@@ -1,13 +1,4 @@
|
|
1
1
|
module CEML
|
2
|
-
|
3
|
-
class Criteria < Struct.new :plus_tags, :minus_tags, :matching, :radius, :timewindow
|
4
|
-
def complexity; plus_tags.size; end
|
5
|
-
def =~(candidate)
|
6
|
-
candidate[:tags] ||= []
|
7
|
-
(plus_tags - candidate[:tags]).empty? and (minus_tags & candidate[:tags]).empty?
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
2
|
module CastingStatement
|
12
3
|
extend Forwardable
|
13
4
|
def_delegators :roles, :names, :[], :min
|
data/lib/ceml/confluence.rb
CHANGED
@@ -3,14 +3,13 @@ require 'forwardable'
|
|
3
3
|
|
4
4
|
module CEML
|
5
5
|
class Confluence
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :hash, :created, :roles_to_cast, :incident_id, :star
|
7
7
|
alias_method :launched?, :incident_id
|
8
8
|
|
9
|
-
def initialize
|
10
|
-
@script = script
|
9
|
+
def initialize roles_to_cast, candidate = nil
|
11
10
|
@hash = {}
|
12
11
|
@created = true
|
13
|
-
@roles_to_cast =
|
12
|
+
@roles_to_cast = roles_to_cast
|
14
13
|
push candidate if candidate
|
15
14
|
end
|
16
15
|
|
@@ -38,7 +37,6 @@ module CEML
|
|
38
37
|
candidate[:roles] = best_role.name.to_sym
|
39
38
|
best_role.casted << candidate
|
40
39
|
@star ||= candidate
|
41
|
-
@dirty = true
|
42
40
|
end
|
43
41
|
|
44
42
|
def full?
|
data/lib/ceml/driver.rb
CHANGED
@@ -14,60 +14,89 @@ module CEML
|
|
14
14
|
def with_incident(id, script = nil, metadata = {})
|
15
15
|
id ||= rand(36**10).to_s(36)
|
16
16
|
PLAYERS[id] ||= []
|
17
|
-
INCIDENTS[id] ||= CEML::Incident.new script, id if script
|
17
|
+
INCIDENTS[id] ||= CEML::Incident.new to_bytecode(script), id if script
|
18
18
|
raise "no incident #{id}" unless INCIDENTS[id]
|
19
19
|
yield INCIDENTS[id], PLAYERS[id], metadata if block_given?
|
20
20
|
id
|
21
21
|
end
|
22
22
|
alias_method :start, :with_incident
|
23
23
|
|
24
|
+
def to_bytecode bytecode_or_script
|
25
|
+
case bytecode_or_script
|
26
|
+
when String; return CEML.parse(:script, bytecode_or_script).bytecode
|
27
|
+
when CEML::Script; return bytecode_or_script.bytecode
|
28
|
+
when Array; return bytecode_or_script
|
29
|
+
else return nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
24
33
|
def log(s)
|
25
34
|
# puts s
|
26
35
|
end
|
27
36
|
|
37
|
+
SCRIPTS = Hash.new{ |h,k| h[k] = [] }
|
38
|
+
def add_script script_collection_id, script
|
39
|
+
SCRIPTS[script_collection_id] << script
|
40
|
+
end
|
41
|
+
|
42
|
+
def ping_all script_collection_id, candidate
|
43
|
+
SCRIPTS[script_collection_id].each{ |s| ping script_collection_id, s.roles_to_cast, candidate }
|
44
|
+
end
|
45
|
+
|
46
|
+
def launch script_collection_id, roleset, *cast
|
47
|
+
script = SCRIPTS[script_collection_id].select{ |s| s.roles_to_cast == roleset }.sort_by{ rand }.first
|
48
|
+
unless script
|
49
|
+
rolesets = SCRIPTS[script_collection_id].map(&:roles_to_cast)
|
50
|
+
raise "matching roleset not found: #{roleset.inspect} in #{rolesets.inspect}"
|
51
|
+
end
|
52
|
+
push nil, script.bytecode, *cast
|
53
|
+
end
|
54
|
+
|
55
|
+
|
28
56
|
LOCATIONS = Hash.new{ |h,k| h[k] = [] }
|
29
|
-
def
|
30
|
-
|
57
|
+
def with_confluences script_collection_id, roleset
|
58
|
+
yield LOCATIONS["#{script_collection_id}:#{roleset.hash}"]
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def ping script_collection_id, roleset, candidate
|
63
|
+
return unless roleset.any?{ |r| r.fits? candidate }
|
31
64
|
candidate[:ts] = CEML.clock
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
case c.stage_with_candidate(candidate)
|
56
|
-
when :launchable
|
57
|
-
log "start-launching..."
|
58
|
-
c.push candidate
|
59
|
-
push nil, script, candidate
|
60
|
-
when :listable
|
65
|
+
|
66
|
+
with_confluences script_collection_id, roleset do |confluences|
|
67
|
+
locs = confluences.group_by{ |l| l.stage_with_candidate(candidate) }
|
68
|
+
if locs[:joinable]
|
69
|
+
log "joining..."
|
70
|
+
first = locs[:joinable].shift
|
71
|
+
first.push candidate
|
72
|
+
push first.incident_id, nil, candidate # JOIN THEM
|
73
|
+
|
74
|
+
elsif locs[:launchable]
|
75
|
+
log "launching..."
|
76
|
+
first = locs[:launchable].shift
|
77
|
+
first.push candidate
|
78
|
+
cast = first.cast
|
79
|
+
first.incident_id = launch script_collection_id, roleset, *cast
|
80
|
+
(locs[:launchable] + (locs[:listable]||[])).each{ |l| l.rm *cast }
|
81
|
+
|
82
|
+
elsif locs[:listable]
|
83
|
+
log "listing..."
|
84
|
+
locs[:listable].each{ |l| l.push candidate }
|
85
|
+
|
86
|
+
else
|
87
|
+
c = Confluence.new(roleset)
|
61
88
|
log "start-listing..."
|
62
|
-
c.
|
63
|
-
|
64
|
-
|
89
|
+
if c.stage_with_candidate(candidate) == :launchable
|
90
|
+
log "start-launching..."
|
91
|
+
c.push candidate
|
92
|
+
c.incident_id = launch script_collection_id, roleset, candidate
|
93
|
+
else
|
94
|
+
c.push candidate
|
95
|
+
end
|
96
|
+
confluences << c
|
65
97
|
end
|
66
|
-
|
98
|
+
confluences.delete_if(&:full?)
|
67
99
|
end
|
68
|
-
|
69
|
-
LOCATIONS[script_id].delete_if(&:full?)
|
70
|
-
# save the changed ones and clear dirty flag
|
71
100
|
end
|
72
101
|
|
73
102
|
def push incident_id, script, *updated_players
|
data/lib/ceml/incident.rb
CHANGED
@@ -2,24 +2,20 @@ require 'set'
|
|
2
2
|
|
3
3
|
module CEML
|
4
4
|
class Incident
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :seq, :id, :this
|
6
|
+
def initialize(seq, id); @id = id; @seq = seq; end
|
7
|
+
|
6
8
|
def roles; this[:roles] ||= Set.new; end
|
7
9
|
def got; this[:received]; end
|
8
10
|
def recognized; this[:recognized]; end
|
9
11
|
def pc; this[:pc] ||= 0; end
|
10
12
|
def qs_answers; this[:qs_answers] ||= Hash.new; end
|
11
|
-
def seq; @seq ||= script.bytecode; end
|
12
13
|
|
13
14
|
def handled!
|
14
15
|
this.delete :received
|
15
16
|
this.delete :recognized
|
16
17
|
end
|
17
18
|
|
18
|
-
def initialize(script, id)
|
19
|
-
@id = id
|
20
|
-
@script = Script === script ? script : CEML.parse(:script, script)
|
21
|
-
end
|
22
|
-
|
23
19
|
def cb *stuff
|
24
20
|
@callback.call this, *stuff if @callback
|
25
21
|
end
|
@@ -61,9 +57,9 @@ module CEML
|
|
61
57
|
|
62
58
|
def expand(role, var)
|
63
59
|
case role
|
64
|
-
when 'his', 'her', 'their';
|
60
|
+
when 'his', 'her', 'their', 'my', 'its'; return qs_answers[var]
|
65
61
|
when 'world', 'game', 'exercise', 'group'; return (cb :world, var)
|
66
|
-
when 'somebody', 'someone', 'buddy';
|
62
|
+
when 'somebody', 'someone', 'buddy', 'teammate'; role = nil
|
67
63
|
end
|
68
64
|
role = role.to_sym if role
|
69
65
|
@players.each do |p|
|
@@ -146,8 +142,8 @@ module CEML
|
|
146
142
|
got or return false
|
147
143
|
if recognized == :done
|
148
144
|
cb :did_complete
|
149
|
-
say :ok
|
150
145
|
handled!
|
146
|
+
say :ok if pc == seq.size - 2
|
151
147
|
true
|
152
148
|
else
|
153
149
|
cb :did_report
|
data/lib/ceml/role.rb
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
module CEML
|
2
|
+
|
3
|
+
class Criteria < Struct.new :plus_tags, :minus_tags, :matching, :radius, :timewindow
|
4
|
+
def complexity; plus_tags.size; end
|
5
|
+
def =~(candidate)
|
6
|
+
candidate[:tags] ||= []
|
7
|
+
(plus_tags - candidate[:tags]).empty? and (minus_tags & candidate[:tags]).empty?
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
2
11
|
class Role < Struct.new :name, :criteria, :range, :casted
|
3
12
|
# def <=>(b); b.criteria.complexity <=> criteria.complexity; end
|
4
13
|
def affinity candidate, star
|
@@ -6,6 +15,13 @@ module CEML
|
|
6
15
|
[ criteria.complexity, -needed, -allowed ]
|
7
16
|
end
|
8
17
|
|
18
|
+
def comparable_object
|
19
|
+
[name, criteria, range]
|
20
|
+
end
|
21
|
+
|
22
|
+
def ==(other); comparable_object == other.comparable_object; end
|
23
|
+
def hash; comparable_object.hash; end
|
24
|
+
|
9
25
|
def filled?; needed == 0; end
|
10
26
|
def one_left?; needed == 1; end
|
11
27
|
|
data/lib/ceml/script.rb
CHANGED
@@ -6,10 +6,6 @@ module CEML
|
|
6
6
|
# = casting =
|
7
7
|
# ===========
|
8
8
|
|
9
|
-
def fits? candidate
|
10
|
-
roles_to_cast.any?{ |r| r.fits? candidate }
|
11
|
-
end
|
12
|
-
|
13
9
|
def roles_to_cast
|
14
10
|
return [] unless cast.type == :await
|
15
11
|
return cast.roles_to_cast(self)
|
@@ -114,8 +110,11 @@ module CEML
|
|
114
110
|
|
115
111
|
def bytecode
|
116
112
|
code = [[[:all], :start]]
|
117
|
-
|
118
|
-
|
113
|
+
if !instructions and title
|
114
|
+
code.concat [[[:all], :null_assign], [[:all], :complete_assign]]
|
115
|
+
elsif instructions
|
116
|
+
instructions.list.each{ |inst| code.concat inst.bytecode } if instructions
|
117
|
+
end
|
119
118
|
code << [[:all], :finish]
|
120
119
|
code
|
121
120
|
end
|
data/test/helper.rb
CHANGED
@@ -16,8 +16,17 @@ class Test::Unit::TestCase
|
|
16
16
|
CEML::Driver::INCIDENTS.clear
|
17
17
|
end
|
18
18
|
|
19
|
+
def scriptfam *scripts
|
20
|
+
fam_id = gen_code
|
21
|
+
scripts.each do |script|
|
22
|
+
script = CEML.parse(:script, script) if String === script
|
23
|
+
DRIVER.add_script fam_id, script
|
24
|
+
end
|
25
|
+
fam_id
|
26
|
+
end
|
27
|
+
|
19
28
|
def ping s, candidate
|
20
|
-
DRIVER.
|
29
|
+
DRIVER.ping_all s, candidate
|
21
30
|
end
|
22
31
|
|
23
32
|
def says id, str
|
data/test/test_incident.rb
CHANGED
@@ -72,7 +72,7 @@ XXX
|
|
72
72
|
class TestIncident < Test::Unit::TestCase
|
73
73
|
|
74
74
|
def test_sync
|
75
|
-
s =
|
75
|
+
s = scriptfam SYNC_SCRIPT
|
76
76
|
play do
|
77
77
|
ping s, :id => 'alpha'
|
78
78
|
ping s, :id => 'beta'
|
@@ -87,7 +87,7 @@ class TestIncident < Test::Unit::TestCase
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def test_jane
|
90
|
-
s =
|
90
|
+
s = scriptfam JANE_SCRIPT
|
91
91
|
play do
|
92
92
|
ping s, :id => 'fred', :tags => ['new'], :received => 'freddy'
|
93
93
|
asked 'fred', /Hello freddy. You are Level Zero./
|
@@ -117,7 +117,7 @@ class TestIncident < Test::Unit::TestCase
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def test_signup_1
|
120
|
-
s =
|
120
|
+
s = scriptfam "await 1 new signup\ntell signup: thanks"
|
121
121
|
play do
|
122
122
|
ping s, :id => 'fred', :tags => ['new']
|
123
123
|
told 'fred', /thanks/
|
@@ -125,7 +125,7 @@ class TestIncident < Test::Unit::TestCase
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def test_signup_2
|
128
|
-
s =
|
128
|
+
s = scriptfam "await 2 new signups\ntell signups: thanks"
|
129
129
|
play do
|
130
130
|
ping s, :id => 'fred', :tags => ['new']
|
131
131
|
silent 'fred'
|
@@ -138,7 +138,7 @@ class TestIncident < Test::Unit::TestCase
|
|
138
138
|
|
139
139
|
|
140
140
|
def test_inside_timewindow
|
141
|
-
s =
|
141
|
+
s = scriptfam "await 2 new signups over 10s\ntell signups: thanks"
|
142
142
|
play do
|
143
143
|
ping s, :id => 'fred', :tags => ['new']
|
144
144
|
silent 'fred'
|
@@ -149,7 +149,7 @@ class TestIncident < Test::Unit::TestCase
|
|
149
149
|
end
|
150
150
|
|
151
151
|
def test_outside_timewindow
|
152
|
-
s =
|
152
|
+
s = scriptfam "await 2 new signups over 10s\ntell signups: thanks"
|
153
153
|
play do
|
154
154
|
ping s, :id => 'fred', :tags => ['new']
|
155
155
|
silent 'fred'
|
@@ -177,7 +177,7 @@ class TestIncident < Test::Unit::TestCase
|
|
177
177
|
end
|
178
178
|
|
179
179
|
def test_await
|
180
|
-
s =
|
180
|
+
s = scriptfam "await a,b,c\ntell a: foo\ntell b: bar\ntell c: baz"
|
181
181
|
play do
|
182
182
|
ping s, :id => 'fred'
|
183
183
|
silent 'fred'
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 7
|
8
|
+
- 0
|
9
|
+
version: 0.7.0
|
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-02-
|
17
|
+
date: 2011-02-12 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|