edoors-ruby 0.0.6 → 0.0.7
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/Changelog +17 -1
- data/Gemfile.lock +1 -1
- data/examples/board.json +52 -0
- data/examples/board.rb +133 -0
- data/examples/data.json +8 -0
- data/examples/hello_world.json +4 -5
- data/examples/hello_world.rb +2 -2
- data/examples/links.json +96 -0
- data/examples/links.rb +121 -0
- data/lib/edoors.rb +9 -9
- data/lib/edoors/board.rb +40 -1
- data/lib/edoors/door.rb +62 -5
- data/lib/edoors/iota.rb +23 -5
- data/lib/edoors/link.rb +42 -22
- data/lib/edoors/particle.rb +207 -52
- data/lib/edoors/room.rb +92 -16
- data/lib/edoors/spin.rb +93 -6
- data/lib/version.rb +1 -1
- data/spec/board_spec.rb +39 -8
- data/spec/door_spec.rb +3 -3
- data/spec/{spot_spec.rb → iota_spec.rb} +20 -0
- data/spec/link_spec.rb +10 -13
- data/spec/particle_spec.rb +61 -21
- data/spec/room_spec.rb +28 -10
- data/spec/spin_spec.rb +15 -5
- data/test/test_iotas.rb +5 -6
- metadata +17 -26
data/lib/edoors/room.rb
CHANGED
@@ -28,6 +28,11 @@ module Edoors
|
|
28
28
|
ERROR_ROUTE_SND = 'routing error: system no destination'.freeze
|
29
29
|
#
|
30
30
|
class Room < Iota
|
31
|
+
#
|
32
|
+
# creates a Room object from the arguments.
|
33
|
+
#
|
34
|
+
# @param [String] n the name of this Room
|
35
|
+
# @param [Iota] p the parent
|
31
36
|
#
|
32
37
|
def initialize n, p
|
33
38
|
super n, p
|
@@ -35,6 +40,10 @@ module Edoors
|
|
35
40
|
@links = {}
|
36
41
|
end
|
37
42
|
#
|
43
|
+
# called by JSON#generate to serialize the Room object into JSON data
|
44
|
+
#
|
45
|
+
# @param [Array] a belongs to JSON generator
|
46
|
+
#
|
38
47
|
def to_json *a
|
39
48
|
{
|
40
49
|
'kls' => self.class.name,
|
@@ -44,6 +53,12 @@ module Edoors
|
|
44
53
|
}.to_json *a
|
45
54
|
end
|
46
55
|
#
|
56
|
+
# creates a Room object from a JSON data
|
57
|
+
#
|
58
|
+
# @param [Hash] o belongs to JSON parser
|
59
|
+
#
|
60
|
+
# @raise Edoors::Exception if the json kls attribute is wrong
|
61
|
+
#
|
47
62
|
def self.json_create o
|
48
63
|
raise Edoors::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
|
49
64
|
room = self.new o['name'], o['parent']
|
@@ -58,29 +73,65 @@ module Edoors
|
|
58
73
|
room
|
59
74
|
end
|
60
75
|
#
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
76
|
+
# creates a Room object from the data of a particle
|
77
|
+
#
|
78
|
+
# @param [Particle] p the Particle to get Room attributes from
|
79
|
+
#
|
80
|
+
def self.from_particle p, s
|
81
|
+
Edoors::Room.new(p.get_data(Edoors::IOTA_NAME), s)
|
66
82
|
end
|
67
83
|
#
|
84
|
+
# adds the given Iota to this Room
|
85
|
+
#
|
86
|
+
# @param [Iota] i the Iota to add
|
87
|
+
#
|
88
|
+
# @raise Edoors::Exception if i already has a parent or if a Iota with the same name already exists
|
89
|
+
#
|
90
|
+
def add_iota i
|
91
|
+
raise Edoors::Exception.new "Iota #{i.name} already has #{i.parent.name} as parent" if not i.parent.nil? and i.parent!=self
|
92
|
+
raise Edoors::Exception.new "Iota #{i.name} already exists in #{path}" if @iotas.has_key? i.name
|
93
|
+
i.parent = self if i.parent.nil?
|
94
|
+
@iotas[i.name]=i
|
95
|
+
end
|
96
|
+
#
|
97
|
+
# adds the given Link to this Room
|
98
|
+
#
|
99
|
+
# @param [Link] l the Link to add
|
100
|
+
#
|
101
|
+
# @raise Edoors::Exception if the link source can't be found in this Room
|
102
|
+
#
|
68
103
|
def add_link l
|
69
104
|
l.door = @iotas[l.src]
|
70
105
|
raise Edoors::Exception.new "Link source #{l.src} does not exist in #{path}" if l.door.nil?
|
71
106
|
(@links[l.src] ||= [])<< l
|
72
107
|
end
|
73
108
|
#
|
109
|
+
# forward the call to each children
|
110
|
+
#
|
111
|
+
# @see Spin#spin! called on system bootup
|
112
|
+
#
|
74
113
|
def start!
|
75
114
|
puts " * start #{path}" if @spin.debug_routing
|
76
115
|
@iotas.values.each do |iota| iota.start! end
|
77
116
|
end
|
78
117
|
#
|
118
|
+
# forward the call to each children
|
119
|
+
#
|
120
|
+
# @see Spin#spin! called on system shutdown
|
121
|
+
#
|
79
122
|
def stop!
|
80
123
|
puts " * stop #{path}" if @spin.debug_routing
|
81
124
|
@iotas.values.each do |iota| iota.stop! end
|
82
125
|
end
|
83
126
|
#
|
127
|
+
# search through all children for a matching Iota
|
128
|
+
#
|
129
|
+
# @param [String] spath the full path of the earch Iota
|
130
|
+
#
|
131
|
+
# @return [Iota] if found
|
132
|
+
#
|
133
|
+
# @see Particle#initialize used to transform @src and @dst JSON data into refrences
|
134
|
+
#
|
84
135
|
def search_down spath
|
85
136
|
return self if spath==path
|
86
137
|
return nil if (spath=~/^#{path}\/(\w+)\/?/)!=0
|
@@ -91,21 +142,21 @@ module Edoors
|
|
91
142
|
nil
|
92
143
|
end
|
93
144
|
#
|
145
|
+
# search for a matching link
|
146
|
+
#
|
147
|
+
# @param [Particle] p the Particle searching for a matching link
|
148
|
+
#
|
94
149
|
def _try_links p
|
95
150
|
puts " -> try_links ..." if @spin.debug_routing
|
96
151
|
links = @links[p.src.name]
|
97
152
|
return false if links.nil?
|
98
153
|
pending_link = nil
|
99
|
-
apply_link = false
|
100
154
|
links.each do |link|
|
101
|
-
|
102
|
-
p.set_link_fields link.cond_fields if not apply_link
|
103
|
-
if apply_link or (p.link_value==link.cond_value)
|
104
|
-
# link matches !
|
155
|
+
if p.link_with? link
|
105
156
|
if pending_link
|
106
157
|
p2 = @spin.require_p p.class
|
107
158
|
p2.clone_data p
|
108
|
-
p2.apply_link!
|
159
|
+
p2.apply_link! pending_link
|
109
160
|
send_p p2
|
110
161
|
end
|
111
162
|
pending_link = link
|
@@ -113,12 +164,16 @@ module Edoors
|
|
113
164
|
end
|
114
165
|
if pending_link
|
115
166
|
p.apply_link! pending_link
|
116
|
-
_send
|
167
|
+
_send p
|
117
168
|
end
|
118
169
|
pending_link
|
119
170
|
end
|
120
171
|
private :_try_links
|
121
172
|
#
|
173
|
+
# route the given Particle
|
174
|
+
#
|
175
|
+
# @param [Particle] p the Particle to be routed
|
176
|
+
#
|
122
177
|
def _route p
|
123
178
|
if p.room.nil? or p.room==path
|
124
179
|
if door = @iotas[p.door]
|
@@ -134,7 +189,12 @@ module Edoors
|
|
134
189
|
end
|
135
190
|
private :_route
|
136
191
|
#
|
137
|
-
|
192
|
+
# send the given Particle
|
193
|
+
#
|
194
|
+
# @param [Particle] p the Particle to send
|
195
|
+
# @param [Boolean] sys if true send to system Particle fifo
|
196
|
+
#
|
197
|
+
def _send p, sys=false
|
138
198
|
if not sys and p.src.nil?
|
139
199
|
# do not route non system orphan particles !!
|
140
200
|
p.error! Edoors::ERROR_ROUTE_NS, @spin
|
@@ -162,23 +222,39 @@ module Edoors
|
|
162
222
|
end
|
163
223
|
private :_send
|
164
224
|
#
|
225
|
+
# send the given Particle to application Particle fifo
|
226
|
+
#
|
227
|
+
# @param [Particle] p the Particle to send
|
228
|
+
#
|
165
229
|
def send_p p
|
166
230
|
puts " * send_p #{(p.next_dst.nil? ? 'no dst' : p.next_dst)} ..." if @spin.debug_routing
|
167
|
-
_send
|
231
|
+
_send p
|
168
232
|
puts " -> #{p.dst.path}#{Edoors::ACT_SEP}#{p.action}" if @spin.debug_routing
|
169
233
|
@spin.post_p p
|
170
234
|
end
|
171
235
|
#
|
236
|
+
# send the given Particle to system Particle fifo
|
237
|
+
#
|
238
|
+
# @param [Particle] p the Particle to send
|
239
|
+
#
|
172
240
|
def send_sys_p p
|
173
241
|
puts " * send_sys_p #{(p.next_dst.nil? ? 'no dst' : p.next_dst)} ..." if @spin.debug_routing
|
174
|
-
_send
|
242
|
+
_send p, true
|
175
243
|
puts " -> #{p.dst.path}#{Edoors::ACT_SEP}#{p.action}" if @spin.debug_routing
|
176
244
|
@spin.post_sys_p p
|
177
245
|
end
|
178
246
|
#
|
247
|
+
# process the given system Particle
|
248
|
+
#
|
249
|
+
# @param [Particle] p the Particle to be processed
|
250
|
+
#
|
251
|
+
# @note the Particle is automatically released
|
252
|
+
#
|
179
253
|
def process_sys_p p
|
180
254
|
if p.action==Edoors::SYS_ACT_ADD_LINK
|
181
|
-
add_link Edoors::Link.
|
255
|
+
add_link Edoors::Link.from_particle p
|
256
|
+
elsif p.action==Edoors::SYS_ACT_ADD_ROOM
|
257
|
+
Edoors::Room.from_particle p, self
|
182
258
|
end
|
183
259
|
@spin.release_p p
|
184
260
|
end
|
data/lib/edoors/spin.rb
CHANGED
@@ -22,6 +22,25 @@
|
|
22
22
|
module Edoors
|
23
23
|
#
|
24
24
|
class Spin < Room
|
25
|
+
#
|
26
|
+
# creates a Spin object from the arguments.
|
27
|
+
#
|
28
|
+
# @param [String] n the name of this Spin
|
29
|
+
# @param [Hash] o a customizable set of options
|
30
|
+
#
|
31
|
+
# @option o 'debug_garbage' [String Symbol]
|
32
|
+
# output debug information about automatic garbage
|
33
|
+
# @option o 'debug_routing' [String Symbol]
|
34
|
+
# output debug information about routing
|
35
|
+
# @option o 'hibernation' [Boolean]
|
36
|
+
# if set to true Iota#start! won't be called within Spin#spin!
|
37
|
+
# @option o 'inner_room' [Hash]
|
38
|
+
# composed of 2 keys, 'iotas' and 'links' use to repopulate the super class Room
|
39
|
+
# @option o 'app_fifo' [Array]
|
40
|
+
# list of Particle to feed @app_fifo
|
41
|
+
# @option o 'sys_fifo' [Array]
|
42
|
+
# list of Particle to feed @sys_fifo
|
43
|
+
#
|
25
44
|
#
|
26
45
|
def initialize n, o={}
|
27
46
|
super n, nil
|
@@ -34,7 +53,7 @@ module Edoors
|
|
34
53
|
@run = false
|
35
54
|
@hibernation = o['hibernation']||false
|
36
55
|
@hibernate_path = 'edoors-hibernate-'+n+'.json'
|
37
|
-
@
|
56
|
+
@debug_garbage = o[:debug_garbage]||o['debug_garbage']||false
|
38
57
|
@debug_routing = o[:debug_routing]||o['debug_routing']||false
|
39
58
|
#
|
40
59
|
if not o.empty?
|
@@ -58,7 +77,11 @@ module Edoors
|
|
58
77
|
end
|
59
78
|
end
|
60
79
|
#
|
61
|
-
attr_accessor :run, :hibernate_path, :
|
80
|
+
attr_accessor :run, :hibernate_path, :debug_garbage, :debug_routing
|
81
|
+
#
|
82
|
+
# called by JSON#generate to serialize the Spin object into JSON data
|
83
|
+
#
|
84
|
+
# @param [Array] a belongs to JSON generator
|
62
85
|
#
|
63
86
|
def to_json *a
|
64
87
|
{
|
@@ -69,25 +92,46 @@ module Edoors
|
|
69
92
|
'inner_room' => { :iotas=>@iotas, :links=>@links },
|
70
93
|
'sys_fifo' => @sys_fifo,
|
71
94
|
'app_fifo' => @app_fifo,
|
72
|
-
'
|
95
|
+
'debug_garbage' => @debug_garbage,
|
73
96
|
'debug_routing' => @debug_routing
|
74
97
|
}.to_json(*a)
|
75
98
|
end
|
76
99
|
#
|
100
|
+
# creates a Spin object from a JSON data
|
101
|
+
#
|
102
|
+
# @param [Hash] o belongs to JSON parser
|
103
|
+
#
|
104
|
+
# @raise Edoors::Exception if the json kls attribute is wrong
|
105
|
+
#
|
77
106
|
def self.json_create o
|
78
107
|
raise Edoors::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
|
79
108
|
self.new o['name'], o
|
80
109
|
end
|
81
110
|
#
|
111
|
+
# add the given Iota to the global Hash
|
112
|
+
#
|
113
|
+
# @param [Iota] iota the Iota to register
|
114
|
+
#
|
115
|
+
# @see Room#_route @world hash is used for routing
|
116
|
+
#
|
82
117
|
def add_to_world iota
|
83
118
|
@world[iota.path] = iota
|
84
119
|
end
|
85
120
|
#
|
121
|
+
# search the global Hash for the matching Iota
|
122
|
+
#
|
123
|
+
# @param [String] path the path to the desired Iota
|
124
|
+
#
|
125
|
+
# @see Room#_route @world hash is used for routing
|
126
|
+
#
|
86
127
|
def search_world path
|
87
128
|
@world[path]
|
88
129
|
end
|
89
130
|
#
|
131
|
+
# clears all the structures
|
132
|
+
#
|
90
133
|
def clear!
|
134
|
+
@links.clear
|
91
135
|
@iotas.clear
|
92
136
|
@world.clear
|
93
137
|
@pool.clear
|
@@ -95,6 +139,13 @@ module Edoors
|
|
95
139
|
@app_fifo.clear
|
96
140
|
end
|
97
141
|
#
|
142
|
+
# releases the given Particle
|
143
|
+
#
|
144
|
+
# @parama [Particle] p the Particle to be released
|
145
|
+
#
|
146
|
+
# @note the Particle is stored into Hash @pool to be reused as soon as needed
|
147
|
+
#
|
148
|
+
# @see Particle#reset! the Particle is reseted before beeing stored
|
98
149
|
#
|
99
150
|
def release_p p
|
100
151
|
# hope there is no circular loop
|
@@ -105,6 +156,12 @@ module Edoors
|
|
105
156
|
( @pool[p.class] ||= [] ) << p
|
106
157
|
end
|
107
158
|
#
|
159
|
+
# requires a Particle of the given Class
|
160
|
+
#
|
161
|
+
# @param [Class] p_kls the desired Class of Particle
|
162
|
+
#
|
163
|
+
# @note if there is no Particle of the given Class, one is created
|
164
|
+
#
|
108
165
|
def require_p p_kls
|
109
166
|
l = @pool[p_kls]
|
110
167
|
return p_kls.new if l.nil?
|
@@ -113,14 +170,26 @@ module Edoors
|
|
113
170
|
p
|
114
171
|
end
|
115
172
|
#
|
173
|
+
# add the given Particle to the application Particle fifo
|
174
|
+
#
|
175
|
+
# @param [Particle] p the Particle to add
|
176
|
+
#
|
116
177
|
def post_p p
|
117
178
|
@app_fifo << p
|
118
179
|
end
|
119
180
|
#
|
181
|
+
# add the given Particle to the system Particle fifo
|
182
|
+
#
|
183
|
+
# @param [Particle] p the Particle to add
|
184
|
+
#
|
120
185
|
def post_sys_p p
|
121
186
|
@sys_fifo << p
|
122
187
|
end
|
123
188
|
#
|
189
|
+
# process the given particle
|
190
|
+
#
|
191
|
+
# @param [Particle] p the Particle to be processed
|
192
|
+
#
|
124
193
|
def process_sys_p p
|
125
194
|
if p.action==Edoors::SYS_ACT_HIBERNATE
|
126
195
|
stop!
|
@@ -130,8 +199,14 @@ module Edoors
|
|
130
199
|
end
|
131
200
|
end
|
132
201
|
#
|
202
|
+
# starts the system mainloop
|
203
|
+
#
|
204
|
+
# first Iota#start! is called on each children unless the system is resuming from hibernation
|
205
|
+
# then while there is Particle in the fifo, first process all system Particle then 1 application Particle
|
206
|
+
# after all Iota#stop! is called on each children, unless the system is going into hibernation
|
207
|
+
#
|
133
208
|
def spin!
|
134
|
-
|
209
|
+
start!
|
135
210
|
@run = true
|
136
211
|
@hibernation = false
|
137
212
|
while @run and (@sys_fifo.length>0 or @app_fifo.length>0)
|
@@ -145,18 +220,30 @@ module Edoors
|
|
145
220
|
break
|
146
221
|
end
|
147
222
|
end
|
148
|
-
|
223
|
+
stop!
|
149
224
|
end
|
150
225
|
#
|
151
|
-
|
226
|
+
# stops the spinning
|
227
|
+
#
|
228
|
+
def stop_spinning!
|
152
229
|
@run=false
|
153
230
|
end
|
154
231
|
#
|
232
|
+
# sends the system into hibernation
|
233
|
+
#
|
234
|
+
# @param [String] path the path to the hibernation file
|
235
|
+
#
|
236
|
+
# the system is serialized into JSON data and flushed to disk
|
237
|
+
#
|
155
238
|
def hibernate! path=nil
|
156
239
|
@hibernation = true
|
157
240
|
File.open(path||@hibernate_path,'w') do |f| f << JSON.pretty_generate(self) end
|
158
241
|
end
|
159
242
|
#
|
243
|
+
# resumes the system from the given hibernation file
|
244
|
+
#
|
245
|
+
# @param [String] path the hibernation file to load the system from
|
246
|
+
#
|
160
247
|
def self.resume! path
|
161
248
|
self.json_create JSON.load File.open(path,'r') { |f| f.read }
|
162
249
|
end
|
data/lib/version.rb
CHANGED
data/spec/board_spec.rb
CHANGED
@@ -16,11 +16,11 @@ describe Edoors::Board do
|
|
16
16
|
#
|
17
17
|
it "require_p release_p" do
|
18
18
|
board = Edoors::Board.new 'hell', @spin
|
19
|
-
p0 = board.require_p
|
19
|
+
p0 = board.require_p
|
20
20
|
p1 = board.require_p Edoors::Particle
|
21
21
|
(p0===p1).should be_false
|
22
22
|
board.release_p p0
|
23
|
-
p2 = board.require_p
|
23
|
+
p2 = board.require_p
|
24
24
|
(p0===p2).should be_true
|
25
25
|
end
|
26
26
|
#
|
@@ -29,21 +29,24 @@ describe Edoors::Board do
|
|
29
29
|
p0['k0'] = 'v0'
|
30
30
|
p0['k1'] = 'neither'
|
31
31
|
p0['k2'] = 'v2'
|
32
|
-
p0.
|
33
|
-
p0.link_value.should
|
32
|
+
p0.set_link_keys 'k0', 'k2'
|
33
|
+
p0.link_value.should == {'k0'=>'v0','k2'=>'v2'}
|
34
34
|
p1 = Edoors::Particle.new
|
35
35
|
p1['k0'] = 'v0'
|
36
36
|
p1['k1'] = 'nore'
|
37
37
|
p1['k2'] = 'v2'
|
38
|
-
p1.
|
39
|
-
p1.link_value.should
|
38
|
+
p1.set_link_keys 'k0', 'k2'
|
39
|
+
p1.link_value.should == {'k0'=>'v0','k2'=>'v2'}
|
40
40
|
P0 = p0
|
41
41
|
P1 = p1
|
42
42
|
class Board0 < Edoors::Board
|
43
|
-
attr_reader :ok, :follow
|
43
|
+
attr_reader :ok, :follow, :pass_through
|
44
44
|
def receive_p p
|
45
45
|
@ok = false
|
46
|
+
@pass_through = false
|
46
47
|
case p.action
|
48
|
+
when Edoors::ACT_PASS_THROUGH
|
49
|
+
@pass_through = true
|
47
50
|
when Edoors::ACT_FOLLOW
|
48
51
|
@follow = true
|
49
52
|
@ok = (p===P0 and p.merged(0)===P1)
|
@@ -72,6 +75,34 @@ describe Edoors::Board do
|
|
72
75
|
b0.process_p p1
|
73
76
|
b0.ok.should be_true
|
74
77
|
b0.follow.should be_true
|
78
|
+
p2 = b0.require_p
|
79
|
+
p2.set_dst! Edoors::ACT_PASS_THROUGH, b0
|
80
|
+
b0.process_p p2
|
81
|
+
b0.pass_through.should be true
|
82
|
+
end
|
83
|
+
#
|
84
|
+
it "keep! and flush!" do
|
85
|
+
b0 = Edoors::Board.new 'hell', @spin
|
86
|
+
def b0.receive_p p
|
87
|
+
keep! p
|
88
|
+
end
|
89
|
+
def b0.get k
|
90
|
+
@postponed[k]
|
91
|
+
end
|
92
|
+
p0 = Edoors::Particle.new
|
93
|
+
b0.process_p p0
|
94
|
+
p1 = Edoors::Particle.new
|
95
|
+
p1.set_dst! Edoors::ACT_FOLLOW, b0
|
96
|
+
b0.process_p p1
|
97
|
+
p2 = Edoors::Particle.new
|
98
|
+
p2.set_dst! Edoors::ACT_FOLLOW, b0
|
99
|
+
b0.process_p p2
|
100
|
+
p3 = Edoors::Particle.new
|
101
|
+
p3.set_dst! Edoors::ACT_FOLLOW, b0
|
102
|
+
b0.process_p p3
|
103
|
+
(b0.get({}).merged_length+1).should == 4
|
104
|
+
b0.flush!
|
105
|
+
b0.get({}).should be_nil
|
75
106
|
end
|
76
107
|
#
|
77
108
|
it "board->json->board" do
|
@@ -79,7 +110,7 @@ describe Edoors::Board do
|
|
79
110
|
p0 = Edoors::Particle.new
|
80
111
|
p1 = Edoors::Particle.new
|
81
112
|
p1['v0']=0
|
82
|
-
p1.
|
113
|
+
p1.set_link_keys 'v0'
|
83
114
|
board.process_p p0
|
84
115
|
board.process_p p1
|
85
116
|
hell = Edoors::Board.json_create( JSON.load( JSON.generate(board) ) )
|