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.
@@ -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
- def add_iota s
62
- raise Edoors::Exception.new "Iota #{s.name} already has #{s.parent.name} as parent" if not s.parent.nil? and s.parent!=self
63
- raise Edoors::Exception.new "Iota #{s.name} already exists in #{path}" if @iotas.has_key? s.name
64
- s.parent = self if s.parent.nil?
65
- @iotas[s.name]=s
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
- apply_link = link.cond_fields.nil? # unconditional link
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! 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 false, p
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
- def _send sys, p
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 false, p
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 true, p
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.from_particle_data p
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
@@ -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
- @debug_errors = o[:debug_errors]||o['debug_errors']||false
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, :debug_errors, :debug_routing
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
- 'debug_errors' => @debug_errors,
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
- @iotas.values.each do |iota| iota.start! end unless @hibernation
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
- @iotas.values.each do |iota| iota.stop! end unless @hibernation
223
+ stop!
149
224
  end
150
225
  #
151
- def stop!
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
@@ -21,7 +21,7 @@
21
21
  #
22
22
  module Edoors
23
23
  #
24
- VERSION = "0.0.6"
24
+ VERSION = "0.0.7"
25
25
  #
26
26
  end
27
27
  #
@@ -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 Edoors::Particle
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 Edoors::Particle
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.set_link_fields 'k0,k2'
33
- p0.link_value.should eql 'v0v2'
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.set_link_fields 'k0,k2'
39
- p1.link_value.should eql 'v0v2'
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.set_link_fields 'v0'
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) ) )