ceml 0.8.0 → 0.9.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 +6 -3
- data/cemltest +15 -0
- data/lib/ceml.rb +65 -0
- data/lib/ceml/models.rb +2 -1
- data/lib/ceml/models/bundle.rb +48 -19
- data/lib/ceml/models/cast.rb +1 -0
- data/lib/ceml/models/castable.rb +9 -27
- data/lib/ceml/models/casting_pool.rb +26 -0
- data/lib/ceml/models/casting_tokens.rb +51 -0
- data/lib/ceml/models/incident.rb +8 -6
- data/lib/ceml/models/incident_model.rb +7 -6
- data/lib/ceml/models/player.rb +14 -6
- data/lib/ceml/models/waiting_room.rb +3 -15
- data/lib/ceml/processor.rb +21 -15
- data/lib/ceml/recognizer.rb +9 -0
- data/test/dialogues/jordan.ceml +40 -38
- data/test/helper.rb +2 -2
- data/test/test_dialogues.rb +13 -44
- metadata +8 -5
- data/lib/ceml/models/audition.rb +0 -65
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.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.9.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-
|
12
|
+
s.date = %q{2011-06-07}
|
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,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
"Rakefile",
|
25
25
|
"VERSION",
|
26
26
|
"ceml.gemspec",
|
27
|
+
"cemltest",
|
27
28
|
"editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage",
|
28
29
|
"editors/CEML.tmbundle/info.plist",
|
29
30
|
"examples/breakfast-exchange.ceml",
|
@@ -48,10 +49,11 @@ Gem::Specification.new do |s|
|
|
48
49
|
"lib/ceml/lang/tt/scripts.rb",
|
49
50
|
"lib/ceml/lang/tt/scripts.treetop",
|
50
51
|
"lib/ceml/models.rb",
|
51
|
-
"lib/ceml/models/audition.rb",
|
52
52
|
"lib/ceml/models/bundle.rb",
|
53
53
|
"lib/ceml/models/cast.rb",
|
54
54
|
"lib/ceml/models/castable.rb",
|
55
|
+
"lib/ceml/models/casting_pool.rb",
|
56
|
+
"lib/ceml/models/casting_tokens.rb",
|
55
57
|
"lib/ceml/models/incident.rb",
|
56
58
|
"lib/ceml/models/incident_model.rb",
|
57
59
|
"lib/ceml/models/incident_role_slot.rb",
|
@@ -59,6 +61,7 @@ Gem::Specification.new do |s|
|
|
59
61
|
"lib/ceml/models/queue.rb",
|
60
62
|
"lib/ceml/models/waiting_room.rb",
|
61
63
|
"lib/ceml/processor.rb",
|
64
|
+
"lib/ceml/recognizer.rb",
|
62
65
|
"test/askchain.ceml",
|
63
66
|
"test/compliment.ceml",
|
64
67
|
"test/dialogues/accept.ceml",
|
data/cemltest
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ceml'
|
4
|
+
|
5
|
+
f = ARGV.shift
|
6
|
+
name = File.basename(f, '.ceml')
|
7
|
+
err, log = CEML.test(File.new(f).read)
|
8
|
+
if !err
|
9
|
+
puts "PASS cemltest #{name}. logged #{log.split("\n").size} lines"
|
10
|
+
elsif RuntimeError === err
|
11
|
+
puts log
|
12
|
+
raise "ERROR with cemltest #{name}: #{err.message}!"
|
13
|
+
else
|
14
|
+
raise err
|
15
|
+
end
|
data/lib/ceml.rb
CHANGED
@@ -2,17 +2,40 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
require 'ceml/models'
|
4
4
|
require 'ceml/lang'
|
5
|
+
require 'ceml/recognizer'
|
5
6
|
require 'ceml/processor'
|
7
|
+
require 'stringio'
|
6
8
|
|
7
9
|
module CEML
|
8
10
|
extend self
|
9
11
|
@extra_seconds = 0
|
12
|
+
@log_io = STDERR
|
13
|
+
attr_reader :tells
|
10
14
|
def clock; Time.now.utc.to_i + @extra_seconds; end
|
11
15
|
def incr_clock(s); @extra_seconds += s; end
|
12
16
|
def dur(n, unit)
|
13
17
|
n * case unit
|
14
18
|
when /^h/; 60*60; when /^mi/; 60; else 1; end
|
15
19
|
end
|
20
|
+
|
21
|
+
def capture_log
|
22
|
+
log = ""
|
23
|
+
err = nil
|
24
|
+
prev_io, @log_io = @log_io, StringIO.new(log)
|
25
|
+
yield
|
26
|
+
rescue Exception => err
|
27
|
+
@log_io.puts "\nERROR: #{err}\n\n\n"
|
28
|
+
ensure
|
29
|
+
@log_io = prev_io
|
30
|
+
return err, log
|
31
|
+
end
|
32
|
+
|
33
|
+
def log lvl, msg
|
34
|
+
if lvl > 1
|
35
|
+
msg = " #{msg}"
|
36
|
+
end
|
37
|
+
@log_io.puts msg
|
38
|
+
end
|
16
39
|
end
|
17
40
|
|
18
41
|
module CEML
|
@@ -39,4 +62,46 @@ module CEML
|
|
39
62
|
end
|
40
63
|
result
|
41
64
|
end
|
65
|
+
|
66
|
+
def test test, p = CEML::Processor
|
67
|
+
scripts, test = test.split("\n---\n")
|
68
|
+
s = CEML.parse(:scripts, scripts).map(&:castable)
|
69
|
+
bundle_id = gen_code # s.hash.to_s
|
70
|
+
@tells = Hash.new{ |h,k| h[k] = [] }
|
71
|
+
p.set_bundle(bundle_id, s)
|
72
|
+
p.reset_bundle(bundle_id)
|
73
|
+
pl = Set.new
|
74
|
+
CEML.capture_log do
|
75
|
+
test.each_line do |line|
|
76
|
+
line = line.strip
|
77
|
+
next if line =~ /^#/ or line =~ /^\s*$/
|
78
|
+
CEML.log 1, "#{line}"
|
79
|
+
case line
|
80
|
+
when /^(\w+) *< *(.*)$/
|
81
|
+
player_id, msg = $1, $2
|
82
|
+
heard = tells[player_id].shift
|
83
|
+
next if msg.empty? and !heard
|
84
|
+
raise "Expected silence from #{player_id}, got #{heard}" if msg.empty? and heard
|
85
|
+
raise "Expected #{player_id} < #{msg}, got silence" if !msg.empty? and !heard
|
86
|
+
heard = (heard||={})[:msg] || (heard||={})[:q] || ''
|
87
|
+
raise "Expected #{player_id} < #{msg}, got #{heard}" unless heard =~ /#{msg}/
|
88
|
+
next
|
89
|
+
when /^(\w+) *> *(.*)$/
|
90
|
+
player_id, msg = $1, $2
|
91
|
+
player = {:id => player_id, :received => msg }
|
92
|
+
if !pl.include?(player_id)
|
93
|
+
player[:tags] = ['new']
|
94
|
+
p.reset_player(bundle_id, player_id)
|
95
|
+
pl << player_id
|
96
|
+
end
|
97
|
+
player[:recognized] = CEML::Recognizer.recognize(msg)
|
98
|
+
p.ping(bundle_id, player)
|
99
|
+
when /^\((\d+)\s*(\w+)\)$/
|
100
|
+
CEML.incr_clock CEML.dur($1.to_i, $2)
|
101
|
+
p.run_latest
|
102
|
+
end
|
103
|
+
p.run
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
42
107
|
end
|
data/lib/ceml/models.rb
CHANGED
@@ -6,7 +6,8 @@ Redis::Objects.redis = Redis.new
|
|
6
6
|
require 'ceml/models/cast'
|
7
7
|
require 'ceml/models/castable'
|
8
8
|
require 'ceml/models/incident'
|
9
|
-
require 'ceml/models/
|
9
|
+
require 'ceml/models/casting_pool'
|
10
|
+
require 'ceml/models/casting_tokens'
|
10
11
|
require 'ceml/models/incident_model'
|
11
12
|
require 'ceml/models/incident_role_slot'
|
12
13
|
require 'ceml/models/player'
|
data/lib/ceml/models/bundle.rb
CHANGED
@@ -3,31 +3,68 @@ module CEML
|
|
3
3
|
include Redis::Objects
|
4
4
|
value :castables, :marshal => true
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
# =============
|
7
|
+
# = castables =
|
8
|
+
# =============
|
9
9
|
|
10
10
|
def find_castables(stanza_name = nil)
|
11
11
|
return castables.value unless stanza_name
|
12
12
|
return [castables.value.find{ |c| c.stanza_name == stanza_name }]
|
13
13
|
end
|
14
14
|
|
15
|
+
|
16
|
+
# =================
|
17
|
+
# = waiting rooms =
|
18
|
+
# =================
|
19
|
+
|
20
|
+
def clear_from_all_rooms(player_id)
|
21
|
+
CastingPool.destroy_everywhere(id, player_id)
|
22
|
+
end
|
23
|
+
|
15
24
|
def all_rooms
|
16
25
|
find_castables.map(&:all_rooms).flatten.uniq
|
17
26
|
end
|
18
27
|
|
19
28
|
def reset
|
20
|
-
|
29
|
+
# puts "TOTAL RESET"
|
30
|
+
CastingTokens.destroy_all(id)
|
31
|
+
all_rooms.each{ |room| room.waiting_incident_roles.clear }
|
21
32
|
end
|
22
33
|
|
23
34
|
def rooms_for_player(player, stanza_name = nil)
|
24
|
-
|
25
|
-
|
35
|
+
find_castables(stanza_name).map{ |c| c.waiting_rooms_for_player(player, stanza_name) }.flatten.uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
def register_in_rooms(player, stanza_name = nil)
|
39
|
+
room_ids = rooms_for_player(player, stanza_name)
|
40
|
+
CastingPool.new(room_ids).post(id, player[:id])
|
26
41
|
end
|
27
42
|
|
43
|
+
def reset_player(player_id)
|
44
|
+
CastingPool.destroy_everywhere(id, player_id)
|
45
|
+
Player.new(player_id).reset
|
46
|
+
end
|
47
|
+
|
48
|
+
def grab_cast?(player, castable, seeded_p)
|
49
|
+
room_ids = castable.hot_waiting_rooms_given_player(player, seeded_p)
|
50
|
+
# CEML.log 1, "Checking cast for #{castable.stanza_name}: #{room_ids.inspect}"
|
51
|
+
casting_pool = CastingPool.new(room_ids)
|
52
|
+
loop do
|
53
|
+
hot_players = casting_pool.hot_players + [player]
|
54
|
+
# CEML.log 1, "Hot players: #{hot_players.inspect}"
|
55
|
+
return nil unless cast = castable.cast_from(hot_players)
|
56
|
+
return cast if casting_pool.claim(cast.player_ids - [player[:id]])
|
57
|
+
sleep 0.02
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# ==============================
|
62
|
+
# = incident joining/launching =
|
63
|
+
# ==============================
|
64
|
+
|
28
65
|
def join_running_incident?(player, stanza_name = nil)
|
29
|
-
rooms_for_player(player, stanza_name).each do |
|
30
|
-
if incident_id =
|
66
|
+
rooms_for_player(player, stanza_name).each do |room_id|
|
67
|
+
if incident_id = WaitingRoom.new(room_id).audition_for_incidents(player)
|
31
68
|
return incident_id
|
32
69
|
end
|
33
70
|
end
|
@@ -37,7 +74,8 @@ module CEML
|
|
37
74
|
def cast_player?(player, stanza_name = nil)
|
38
75
|
incident_id = gen_code
|
39
76
|
find_castables(stanza_name).each do |castable|
|
40
|
-
if cast =
|
77
|
+
if cast = grab_cast?(player, castable, seeded=stanza_name)
|
78
|
+
castable.advertise_roles(incident_id, cast)
|
41
79
|
i = IncidentModel.new(incident_id)
|
42
80
|
i.bytecode.value = castable.bytecode
|
43
81
|
i.add_castings(cast.castings)
|
@@ -48,16 +86,7 @@ module CEML
|
|
48
86
|
end
|
49
87
|
|
50
88
|
def absorb?(player, stanza_name = nil)
|
51
|
-
|
52
|
-
puts "X1: #{x.inspect}"
|
53
|
-
return x if x
|
54
|
-
x = cast_player?(player, stanza_name)
|
55
|
-
puts "X2: #{x.inspect}"
|
56
|
-
x
|
57
|
-
end
|
58
|
-
|
59
|
-
def register_in_rooms(player, stanza_name = nil)
|
60
|
-
Audition.new("#{player[:id]}").list_in_rooms(rooms_for_player(player, stanza_name)) ##{gen_code}:
|
89
|
+
join_running_incident?(player, stanza_name) or cast_player?(player, stanza_name)
|
61
90
|
end
|
62
91
|
|
63
92
|
end
|
data/lib/ceml/models/cast.rb
CHANGED
@@ -102,6 +102,7 @@ module CEML
|
|
102
102
|
|
103
103
|
class Tagspec < Struct.new :with, :without
|
104
104
|
def =~(c)
|
105
|
+
return false if (c[:tags]||[]).include?('new') and not with.include?('new')
|
105
106
|
with.all?{ |t| (c[:tags]||[]).include?(t) } and without.all?{ |t| !(c[:tags]||[]).include?(t) }
|
106
107
|
end
|
107
108
|
end
|
data/lib/ceml/models/castable.rb
CHANGED
@@ -1,30 +1,12 @@
|
|
1
1
|
module CEML
|
2
|
-
class Castable < Struct.new :type, :stanza_name, :matching, :radius, :timewindow, :roles, :bytecode
|
2
|
+
class Castable < Struct.new :type, :stanza_name, :matching, :radius, :timewindow, :roles, :bytecode, :bundle_id
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
hot_players = hotties.keys.map{ |id| Player.new(id).data.value } + [player]
|
9
|
-
# puts "casting from #{hot_players.inspect}"
|
10
|
-
if cast = cast_from(hot_players)
|
11
|
-
puts "...cast with cast #{cast.player_ids.inspect}"
|
12
|
-
audition_ids = (cast.player_ids & hotties.keys).map{ |id| hotties[id] }
|
13
|
-
puts "consuming #{audition_ids.inspect}"
|
14
|
-
if Audition.consume(audition_ids, room_ids)
|
15
|
-
# post audition signs in waiting rooms for remaining parts
|
16
|
-
with_open_roles(cast) do |idx, role, count|
|
17
|
-
waiting_rooms_to_watch(role, cast).each do |room|
|
18
|
-
room.list_job(incident_id, idx, role.name, count)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
return cast
|
22
|
-
else
|
23
|
-
sleep 0.02
|
24
|
-
return cast_player?(incident_id, player)
|
4
|
+
def advertise_roles(incident_id, cast)
|
5
|
+
with_open_roles(cast) do |idx, role, count|
|
6
|
+
waiting_rooms_to_watch(role, cast).each do |room|
|
7
|
+
room.list_job(incident_id, idx, role.name, count)
|
25
8
|
end
|
26
9
|
end
|
27
|
-
return
|
28
10
|
end
|
29
11
|
|
30
12
|
def waiting_rooms_for_player(player, seeded=false)
|
@@ -37,8 +19,8 @@ module CEML
|
|
37
19
|
|
38
20
|
def hot_waiting_rooms_given_player(player, seeded=false)
|
39
21
|
rooms = waiting_rooms_for_player(player, seeded)
|
40
|
-
roles.each{ |r| rooms.concat(["#{stanza_name}:#{r.name}", *r.tagspec.with]) }
|
41
|
-
rooms << "#{stanza_name}:*"
|
22
|
+
roles.each{ |r| rooms.concat(["#{bundle_id}:#{stanza_name}:#{r.name}", *r.tagspec.with]) }
|
23
|
+
rooms << "#{bundle_id}:#{stanza_name}:*"
|
42
24
|
# rooms << 'generic'
|
43
25
|
rooms.uniq
|
44
26
|
end
|
@@ -47,8 +29,8 @@ module CEML
|
|
47
29
|
# skip for now: radius, timewindow, matching, general
|
48
30
|
result = []
|
49
31
|
if stanza_name
|
50
|
-
result << "#{stanza_name}:#{role.name}"
|
51
|
-
result << "#{stanza_name}:*"
|
32
|
+
result << "#{bundle_id}:#{stanza_name}:#{role.name}"
|
33
|
+
result << "#{bundle_id}:#{stanza_name}:*"
|
52
34
|
end
|
53
35
|
if !role.tagspec.with.empty?
|
54
36
|
result.concat role.tagspec.with
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module CEML
|
2
|
+
class CastingPool < Struct.new :room_ids
|
3
|
+
def self.destroy_everywhere(bundle_id, player_id)
|
4
|
+
CastingTokens.destroy([player_id])
|
5
|
+
end
|
6
|
+
|
7
|
+
def player_ids
|
8
|
+
tokens = CastingTokens.all_tokens(room_ids)
|
9
|
+
@tokens_by_player_id = tokens.inject({}){ |m,o| m[o]=o; m }
|
10
|
+
@tokens_by_player_id.keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def hot_players
|
14
|
+
player_ids.map{ |id| Player.new(id).data.value }
|
15
|
+
end
|
16
|
+
|
17
|
+
def claim(player_ids)
|
18
|
+
tokens = @tokens_by_player_id.values_at(*player_ids)
|
19
|
+
CastingTokens.collect(tokens)
|
20
|
+
end
|
21
|
+
|
22
|
+
def post(bundle_id, player_id)
|
23
|
+
CastingTokens.post(bundle_id, player_id, room_ids)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CEML
|
2
|
+
class Audition < Struct.new(:id)
|
3
|
+
include Redis::Objects
|
4
|
+
set :rooms
|
5
|
+
end
|
6
|
+
|
7
|
+
module CastingTokens
|
8
|
+
def self.post(bundle_id, token, room_ids)
|
9
|
+
room_ids << bundle_id
|
10
|
+
room_ids.each do |room_id|
|
11
|
+
Audition.new(token).rooms << room_id
|
12
|
+
WaitingRoom.new(room_id).waiting_auditions << token
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.all_tokens(room_ids)
|
17
|
+
rooms = room_ids.map{ |r| WaitingRoom.new(r) }
|
18
|
+
rooms.map{ |r| r.waiting_auditions.members }.flatten.uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.destroy_all(bundle_id)
|
22
|
+
all = WaitingRoom.new(bundle_id).waiting_auditions.members
|
23
|
+
# puts "DESTROYING tokens: #{all.inspect}"
|
24
|
+
destroy(all)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.destroy(tokens)
|
28
|
+
roomsets = tokens.map{ |id| Audition.new(id).rooms }
|
29
|
+
rooms = roomsets.map(&:members).flatten.uniq
|
30
|
+
# puts "Consuming ids #{ids.inspect} from rooms #{rooms.inspect}"
|
31
|
+
# TODO: install new redis and re-enable watchlist
|
32
|
+
# redis.watch(*roomsets.map(&:key))
|
33
|
+
# redis.multi do
|
34
|
+
# rooms = roomsets.first.union(roomsets[1,-1]) || []
|
35
|
+
rooms.product(tokens).each do |r, id|
|
36
|
+
# puts "DELETING #{id} from room #{r}"
|
37
|
+
WaitingRoom.new(r).waiting_auditions.delete(id)
|
38
|
+
end
|
39
|
+
roomsets.map(&:clear)
|
40
|
+
# end
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# this one should collect none unless all can be collected
|
45
|
+
# using multi/exec
|
46
|
+
def self.collect(tokens)
|
47
|
+
destroy(tokens)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/lib/ceml/models/incident.rb
CHANGED
@@ -31,13 +31,14 @@ module CEML
|
|
31
31
|
guyroles = roles.to_a - [:everyone, :players, :them, :all, :either, :each, :agents, :both]
|
32
32
|
instr ||= []
|
33
33
|
|
34
|
-
|
34
|
+
# CEML.log 3, "#{p[:id]}: #{state} -- #{instr[1]}/#{instr[0]} -- #{instr[2].inspect} -- #{id}##{pc}(#{guyroles})"
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
37
|
def run(players, &blk)
|
39
38
|
@players = players
|
40
39
|
@callback = blk
|
40
|
+
was_blocked = {}
|
41
|
+
# CEML.log 1, "running players: #{players.inspect}"
|
41
42
|
|
42
43
|
loop do
|
43
44
|
players = @players
|
@@ -45,24 +46,25 @@ module CEML
|
|
45
46
|
players.each do |p|
|
46
47
|
@this = p
|
47
48
|
instr = seq[pc]
|
49
|
+
# log "running: #{pc}: #{instr.inspect}"
|
48
50
|
unless instr = seq[pc]
|
49
|
-
log 'off schedule'
|
50
51
|
@players.delete(p)
|
51
|
-
cb :released
|
52
52
|
next
|
53
53
|
end
|
54
54
|
instr = instr.dup
|
55
55
|
rolespec = instr.shift
|
56
56
|
if not rolematch(rolespec)
|
57
|
-
log "skipping[#{rolespec}]"
|
57
|
+
# log "skipping[#{rolespec}]"
|
58
58
|
this[:pc]+=1
|
59
59
|
advanced = true
|
60
60
|
else
|
61
61
|
instr << role_info if instr.first == :start #tmp hack
|
62
62
|
if send(*instr)
|
63
63
|
log 'completed'
|
64
|
+
was_blocked[p] = false
|
64
65
|
else
|
65
|
-
log 'blocked'
|
66
|
+
log 'blocked' unless was_blocked[p]
|
67
|
+
was_blocked[p] = true
|
66
68
|
next
|
67
69
|
end
|
68
70
|
cb(*instr)
|
@@ -20,13 +20,13 @@ module CEML
|
|
20
20
|
folks.each do |player|
|
21
21
|
Player.new(player[:id]).touch(id)
|
22
22
|
player_roles[player[:id]] = [rolename.to_sym]
|
23
|
-
|
23
|
+
CEML.log 3, "#{player[:id]}: added as #{rolename.to_sym} (#{id})"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def release(player_id)
|
29
|
-
|
29
|
+
CEML.log 3, "#{player_id}: releasing from incident #{id}"
|
30
30
|
Player.new(player_id).clear_incident(id)
|
31
31
|
player_roles.delete(player_id)
|
32
32
|
end
|
@@ -51,17 +51,17 @@ module CEML
|
|
51
51
|
metadata, player_data = *data.value
|
52
52
|
metadata ||= { :id => id }
|
53
53
|
player_data ||= {}
|
54
|
-
puts "[#{id}] Player data loaded: #{player_data.inspect}"
|
55
54
|
players = []
|
56
55
|
|
57
|
-
|
56
|
+
CEML.log 3, ">>> #{player_roles.all.inspect} (#{id})"
|
58
57
|
player_roles.each do |player_id, roles|
|
59
|
-
|
58
|
+
CEML.log 3, "#{player_id}: casted as #{roles.inspect} -- #{id}: #{player_data[player_id].inspect}"
|
60
59
|
player = { :id => player_id, :roles => Set.new(roles) }
|
61
60
|
player[:roles] << :agents << :players << :both << :all << :each << :everyone << :them << :either
|
62
61
|
player.merge! player_data[player_id] if player_data[player_id]
|
63
62
|
p = Player.new(player_id)
|
64
63
|
stored_player = p.data.value
|
64
|
+
PLAYER_THREAD_FIELDS.each{ |x| stored_player.delete x }
|
65
65
|
msg = p.message.value
|
66
66
|
player.merge! msg if msg
|
67
67
|
player.merge! stored_player if stored_player
|
@@ -86,8 +86,9 @@ module CEML
|
|
86
86
|
players.each do |p|
|
87
87
|
Player.new(p[:id]).message.value = p.like(:received, :recognized, :situation)
|
88
88
|
player_data[p[:id]] = p.like *PLAYER_THREAD_FIELDS
|
89
|
+
# PLAYER_THREAD_FIELDS.each{ |x| p.delete x }
|
89
90
|
end
|
90
|
-
|
91
|
+
# CEML.log 1, "Player data saving: #{player_data.inspect}"
|
91
92
|
data.value = [metadata, player_data]
|
92
93
|
|
93
94
|
if next_run = players.map{ |p| p[:continue_at] }.compact.min
|
data/lib/ceml/models/player.rb
CHANGED
@@ -6,17 +6,20 @@ module CEML
|
|
6
6
|
value :message, :marshal => true
|
7
7
|
sorted_set :current_incidents
|
8
8
|
|
9
|
-
def touch(incident_id)
|
10
|
-
current_incidents[incident_id] = Time.now.to_i
|
11
|
-
end
|
12
|
-
|
13
9
|
def reset
|
14
|
-
Audition.new(id).clear_from_all_rooms
|
15
10
|
data.clear
|
16
11
|
message.clear
|
17
12
|
current_incidents.clear
|
18
13
|
end
|
19
14
|
|
15
|
+
# =============
|
16
|
+
# = incidents =
|
17
|
+
# =============
|
18
|
+
|
19
|
+
def touch(incident_id)
|
20
|
+
current_incidents[incident_id] = Time.now.to_i
|
21
|
+
end
|
22
|
+
|
20
23
|
def top_incident_id
|
21
24
|
current_incidents.last
|
22
25
|
end
|
@@ -31,6 +34,11 @@ module CEML
|
|
31
34
|
current_incidents.delete(id)
|
32
35
|
end
|
33
36
|
|
37
|
+
|
38
|
+
# ========
|
39
|
+
# = data =
|
40
|
+
# ========
|
41
|
+
|
34
42
|
def self.update bundle_id, player, cb_obj, &blk
|
35
43
|
player[:bundle_id] = player[:squad_id] = bundle_id
|
36
44
|
new(player[:id].to_s).update player, cb_obj, &blk
|
@@ -69,7 +77,7 @@ module CEML
|
|
69
77
|
new_message, player = split(player)
|
70
78
|
merge_new_player_data(player)
|
71
79
|
cmd = new_message[:recognized]
|
72
|
-
if cmd and cb_obj.recognize_override(cmd, new_message, player, self)
|
80
|
+
if cmd and cb_obj and cb_obj.recognize_override(cmd, new_message, player, self)
|
73
81
|
message.delete
|
74
82
|
else
|
75
83
|
message.value = new_message
|
@@ -5,18 +5,11 @@ module CEML
|
|
5
5
|
set :waiting_auditions
|
6
6
|
set :waiting_incident_roles
|
7
7
|
|
8
|
-
def clear
|
9
|
-
waiting_auditions.each do |audition_id|
|
10
|
-
Audition.new(audition_id).clear_from_all_rooms(id)
|
11
|
-
end
|
12
|
-
waiting_incident_roles.clear
|
13
|
-
end
|
14
|
-
|
15
8
|
def audition_for_incidents(player)
|
16
|
-
|
17
|
-
|
9
|
+
reorder = waiting_incident_roles.members.sort_by{ |irs| irs.split(':')[1] }
|
10
|
+
reorder.each do |key|
|
18
11
|
incident_id, idx, role, count = *key.split(':')
|
19
|
-
|
12
|
+
CEML.log 3, "#{player[:id]}: auditioning against #{incident_id}: #{role}"
|
20
13
|
count = count.to_i
|
21
14
|
role_slot = IncidentRoleSlot.new(incident_id, role, count)
|
22
15
|
next unless role_slot.reserve_spot!
|
@@ -30,11 +23,6 @@ module CEML
|
|
30
23
|
def list_job(incident_id, idx, rolename, count)
|
31
24
|
waiting_incident_roles << [incident_id, idx, rolename, count].join(':')
|
32
25
|
end
|
33
|
-
|
34
|
-
def add(audition_id)
|
35
|
-
puts "adding #{audition_id} to waiting room #{id.inspect}"
|
36
|
-
waiting_auditions << audition_id
|
37
|
-
end
|
38
26
|
end
|
39
27
|
|
40
28
|
end
|
data/lib/ceml/processor.rb
CHANGED
@@ -15,6 +15,7 @@ module CEML
|
|
15
15
|
|
16
16
|
def set_bundle(id, castables)
|
17
17
|
# log "set_bundle(): #{id}, #{castables.inspect}"
|
18
|
+
castables.each{ |c| c.bundle_id = id }
|
18
19
|
Bundle.new(id).castables = castables
|
19
20
|
end
|
20
21
|
|
@@ -62,7 +63,7 @@ module CEML
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def reset_player(bundle_id, player_id)
|
65
|
-
|
66
|
+
Bundle.new(bundle_id).reset_player(player_id)
|
66
67
|
end
|
67
68
|
|
68
69
|
# =============
|
@@ -70,9 +71,10 @@ module CEML
|
|
70
71
|
# =============
|
71
72
|
|
72
73
|
def simple_audition(bundle_id, player)
|
73
|
-
log "audition(): #{bundle_id}, #{player[:id]}"
|
74
|
+
# log "audition(): #{bundle_id}, #{player[:id]}"
|
74
75
|
b = Bundle.new(bundle_id)
|
75
|
-
b.clear_from_all_rooms(player)
|
76
|
+
b.clear_from_all_rooms(player[:id])
|
77
|
+
|
76
78
|
if incident_id = b.absorb?(player)
|
77
79
|
IncidentModel.new(incident_id).run(self)
|
78
80
|
return true
|
@@ -82,13 +84,20 @@ module CEML
|
|
82
84
|
end
|
83
85
|
|
84
86
|
def seed(bundle_id, stanza_name, player)
|
85
|
-
log "seed(): #{bundle_id}, #{stanza_name}, #{player[:id]}"
|
87
|
+
# log "seed(): #{bundle_id}, #{stanza_name}, #{player[:id]}"
|
88
|
+
player[:tags].delete('new')
|
89
|
+
Player.new(player[:id]).merge_new_player_data(player)
|
90
|
+
|
91
|
+
# CEML.log 1, "UPDATED"
|
92
|
+
|
86
93
|
b = Bundle.new(bundle_id)
|
87
94
|
if incident_id = b.absorb?(player, stanza_name)
|
88
95
|
IncidentModel.new(incident_id).run(self)
|
89
|
-
|
96
|
+
true
|
97
|
+
else
|
98
|
+
b.register_in_rooms(player, stanza_name)
|
99
|
+
false
|
90
100
|
end
|
91
|
-
b.register_in_rooms(player, stanza_name)
|
92
101
|
end
|
93
102
|
|
94
103
|
# =============
|
@@ -107,16 +116,16 @@ module CEML
|
|
107
116
|
if incident
|
108
117
|
incident.release(player_obj.id)
|
109
118
|
unlatch(player[:squad_id], player[:id], incident.id)
|
110
|
-
|
119
|
+
reset_player(player[:squad_id], player[:id])
|
111
120
|
tell(player[:squad_id], player[:id], :message, :msg => 'aborted')
|
112
121
|
else
|
113
|
-
|
122
|
+
reset_player(player[:squad_id], player[:id])
|
114
123
|
tell(player[:squad_id], player[:id], :message, :msg => 'nothing to abort from')
|
115
124
|
end
|
116
125
|
end
|
117
126
|
|
118
127
|
def log(s)
|
119
|
-
|
128
|
+
CEML.log 1, s
|
120
129
|
end
|
121
130
|
|
122
131
|
def player_said(data, what)
|
@@ -127,11 +136,8 @@ module CEML
|
|
127
136
|
#no op
|
128
137
|
end
|
129
138
|
|
130
|
-
JUST_SAID = {}
|
131
139
|
def tell(sqid, player_id, key, meta)
|
132
|
-
|
133
|
-
JUST_SAID[player_id] << meta.merge(:key => key)
|
134
|
-
# puts "Said #{key} #{meta.inspect}"
|
140
|
+
CEML.tells[player_id] << meta.merge(:key => key) if CEML.tells
|
135
141
|
end
|
136
142
|
|
137
143
|
def player_answered_q(data, what)
|
@@ -142,8 +148,8 @@ module CEML
|
|
142
148
|
def player_seeded(data, what)
|
143
149
|
p = data[:player].dup
|
144
150
|
p.delete(:roles)
|
145
|
-
p[:seeded] = "#{what[:target]}:#{what[:role]}"
|
146
|
-
|
151
|
+
p[:seeded] = "#{p[:bundle_id]}:#{what[:target]}:#{what[:role]}"
|
152
|
+
CEML.log 3, "#{p[:id]}: seeded as #{p[:seeded]}"
|
147
153
|
|
148
154
|
self.class.seed(p[:bundle_id], what[:target], p)
|
149
155
|
end
|
data/test/dialogues/jordan.ceml
CHANGED
@@ -81,41 +81,43 @@ D < Please text
|
|
81
81
|
D > done
|
82
82
|
D <
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
84
|
+
K > Kiley
|
85
|
+
|
86
|
+
P > Paul
|
87
|
+
P < Welcome
|
88
|
+
P < You wanna
|
89
|
+
P > Yes
|
90
|
+
|
91
|
+
# P < Awesome!
|
92
|
+
# (20s)
|
93
|
+
# P < If you want to opt out
|
94
|
+
#
|
95
|
+
# K < Welcome
|
96
|
+
# K < You wanna
|
97
|
+
# K > Yes
|
98
|
+
# K < Awesome!
|
99
|
+
# (20s)
|
100
|
+
# K < If you want to opt out
|
101
|
+
#
|
102
|
+
# D < Amazing work
|
103
|
+
# D > Yes
|
104
|
+
# D < new challenge
|
105
|
+
# D > Wave and smile at three strangers on the street
|
106
|
+
# D < Thanks for playing
|
107
|
+
# K < Another player has issued
|
108
|
+
# K > Yes
|
109
|
+
# K < Please text
|
110
|
+
# K > done
|
111
|
+
# K <
|
112
|
+
#
|
113
|
+
# (challenge_loop2)
|
114
|
+
# K < Amazing work
|
115
|
+
# K > Yes
|
116
|
+
# K < new challenge
|
117
|
+
# K > Wave and smile at three strangers on the street
|
118
|
+
# K < Thanks for playing
|
119
|
+
# P < Another player has issued
|
120
|
+
# P > Yes
|
121
|
+
# P < Please text
|
122
|
+
# P > done
|
123
|
+
# P <
|
data/test/helper.rb
CHANGED
@@ -18,7 +18,7 @@ class Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
if script
|
20
20
|
@iid = gen_code
|
21
|
-
puts "launching w. bytecode #{script.bytecode.inspect}"
|
21
|
+
# puts "launching w. bytecode #{script.bytecode.inspect}"
|
22
22
|
CEML::Processor.launch(@iid, script.bytecode)
|
23
23
|
CEML::Processor.run
|
24
24
|
end
|
@@ -40,7 +40,7 @@ class Test::Unit::TestCase
|
|
40
40
|
player = {:id => id.to_s, :received => str}
|
41
41
|
player[:recognized] = :yes if str.downcase == 'y' || str.downcase == 'yes'
|
42
42
|
player[:recognized] = :abort if str == 'abort'
|
43
|
-
puts "SAYING(#{id}): #{str}"
|
43
|
+
# puts "SAYING(#{id}): #{str}"
|
44
44
|
CEML::Processor.ping(nil, player)
|
45
45
|
CEML::Processor.run
|
46
46
|
end
|
data/test/test_dialogues.rb
CHANGED
@@ -8,51 +8,20 @@ class TestCemlTests < Test::Unit::TestCase
|
|
8
8
|
CEML::Queue.new.calls.clear
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
puts
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
CEML::Processor.set_bundle(bundle_id, s)
|
22
|
-
CEML::Processor.reset_bundle(bundle_id)
|
23
|
-
pl = Set.new
|
24
|
-
play do
|
25
|
-
test.each_line do |line|
|
26
|
-
puts ">>>> #{line}"
|
27
|
-
case line.strip
|
28
|
-
when /^(\w+) *< *(.*)$/
|
29
|
-
if $2.empty?
|
30
|
-
silent $1
|
31
|
-
else
|
32
|
-
told $1, /#{$2}/
|
33
|
-
end
|
34
|
-
when /^(\w+) *> *(.*)$/
|
35
|
-
player_id, msg = $1, $2
|
36
|
-
player = {:id => player_id, :received => msg }
|
37
|
-
if !pl.include?(player_id)
|
38
|
-
player[:tags] = ['new']
|
39
|
-
pl << player_id
|
40
|
-
end
|
41
|
-
player[:recognized] = :yes if msg == 'y' || msg =~ /^yes/i
|
42
|
-
player[:recognized] = :abort if msg == 'abort'
|
43
|
-
player[:recognized] = :done if msg =~ /^done/i || msg == 'd'
|
44
|
-
CEML::Processor.ping(bundle_id, player)
|
45
|
-
CEML::Processor.run
|
46
|
-
when /^\((\d+)\s*(\w+)\)$/
|
47
|
-
CEML.incr_clock CEML.dur($1.to_i, $2)
|
48
|
-
CEML::Processor.run_latest
|
49
|
-
CEML::Processor.run
|
50
|
-
when /^#/
|
51
|
-
else "Skipping line #{line}..."
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
11
|
+
def run_cemltest f
|
12
|
+
name = File.basename(f, '.ceml')
|
13
|
+
err, log = CEML.test(File.new(f).read)
|
14
|
+
if !err
|
15
|
+
puts "PASS cemltest #{name}. logged #{log.split("\n").size} lines"
|
16
|
+
elsif RuntimeError === err
|
17
|
+
puts log
|
18
|
+
raise "ERROR with cemltest #{name}: #{err.message}!"
|
19
|
+
else
|
20
|
+
raise err
|
55
21
|
end
|
56
22
|
end
|
57
23
|
|
24
|
+
def test_cemltests
|
25
|
+
Dir["test/dialogues/*.ceml"].each{ |f| run_cemltest(f) }
|
26
|
+
end
|
58
27
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ceml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 59
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 9
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.9.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joe Edelman
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-06-07 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- Rakefile
|
50
50
|
- VERSION
|
51
51
|
- ceml.gemspec
|
52
|
+
- cemltest
|
52
53
|
- editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage
|
53
54
|
- editors/CEML.tmbundle/info.plist
|
54
55
|
- examples/breakfast-exchange.ceml
|
@@ -73,10 +74,11 @@ files:
|
|
73
74
|
- lib/ceml/lang/tt/scripts.rb
|
74
75
|
- lib/ceml/lang/tt/scripts.treetop
|
75
76
|
- lib/ceml/models.rb
|
76
|
-
- lib/ceml/models/audition.rb
|
77
77
|
- lib/ceml/models/bundle.rb
|
78
78
|
- lib/ceml/models/cast.rb
|
79
79
|
- lib/ceml/models/castable.rb
|
80
|
+
- lib/ceml/models/casting_pool.rb
|
81
|
+
- lib/ceml/models/casting_tokens.rb
|
80
82
|
- lib/ceml/models/incident.rb
|
81
83
|
- lib/ceml/models/incident_model.rb
|
82
84
|
- lib/ceml/models/incident_role_slot.rb
|
@@ -84,6 +86,7 @@ files:
|
|
84
86
|
- lib/ceml/models/queue.rb
|
85
87
|
- lib/ceml/models/waiting_room.rb
|
86
88
|
- lib/ceml/processor.rb
|
89
|
+
- lib/ceml/recognizer.rb
|
87
90
|
- test/askchain.ceml
|
88
91
|
- test/compliment.ceml
|
89
92
|
- test/dialogues/accept.ceml
|
data/lib/ceml/models/audition.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
module CEML
|
2
|
-
|
3
|
-
class Audition < Struct.new(:id) # "#{code}:#{player_id}"
|
4
|
-
include Redis::Objects
|
5
|
-
set :rooms
|
6
|
-
|
7
|
-
def list_in_rooms(da_rooms)
|
8
|
-
# p "Listing in rooms #{da_rooms.map(&:id)}"
|
9
|
-
da_rooms.each{ |room| self.rooms << room.id; room.add(id) }
|
10
|
-
end
|
11
|
-
|
12
|
-
def clear_from_all_rooms(*extra_rooms)
|
13
|
-
rooms_to_clear = rooms.members + extra_rooms
|
14
|
-
redis.multi do
|
15
|
-
rooms_to_clear.each do |r|
|
16
|
-
WaitingRoom.new(r).waiting_auditions.delete(id)
|
17
|
-
end
|
18
|
-
redis.del rooms.key
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.consume(ids, extra_rooms = [])
|
23
|
-
roomsets = ids.map{ |id| Audition.new(id).rooms }
|
24
|
-
rooms = (roomsets.map(&:members) + extra_rooms).flatten.uniq
|
25
|
-
# puts "Consuming ids #{ids.inspect} from rooms #{rooms.inspect}"
|
26
|
-
# TODO: install new redis and re-enable watchlist
|
27
|
-
# redis.watch(*roomsets.map(&:key))
|
28
|
-
# redis.multi do
|
29
|
-
# rooms = roomsets.first.union(roomsets[1,-1]) || []
|
30
|
-
rooms.each do |r|
|
31
|
-
# puts "PROCESSING ROOM #{r.key}"
|
32
|
-
ids.each do |id|
|
33
|
-
# puts "DELETING #{id} from room #{r}"
|
34
|
-
WaitingRoom.new(r).waiting_auditions.delete(id)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
roomsets.map(&:clear)
|
38
|
-
# end
|
39
|
-
true
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.from_rooms(room_ids)
|
43
|
-
players = {}
|
44
|
-
rooms = room_ids.map{ |r| WaitingRoom.new(r) }
|
45
|
-
auditions = rooms.map{ |r| r.waiting_auditions.members }.flatten
|
46
|
-
|
47
|
-
# clear old style
|
48
|
-
auditions.each do |a|
|
49
|
-
next unless a =~ /:/
|
50
|
-
Audition.new(a).rooms.clear
|
51
|
-
rooms.each{ |r| r.waiting_auditions.delete(a) }
|
52
|
-
end
|
53
|
-
|
54
|
-
puts "Auditions found: #{auditions.inspect}"
|
55
|
-
auditions.each do |audition|
|
56
|
-
# next if audition =~ /:/
|
57
|
-
# code, player_id = audition.split(':')
|
58
|
-
player_id = audition
|
59
|
-
players[player_id] ||= audition
|
60
|
-
end
|
61
|
-
players
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|