ceml 0.6.4 → 0.7.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/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
|