edoors-ruby 0.0.6

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.
@@ -0,0 +1,168 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+ # Copyright 2012 Jérémy Zurcher <jeremy@asynk.ch>
5
+ #
6
+ # This file is part of edoors-ruby.
7
+ #
8
+ # edoors-ruby is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU Affero General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # edoors-ruby is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Affero General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Affero General Public License
19
+ # along with edoors-ruby. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ #
22
+ module Edoors
23
+ #
24
+ class Spin < Room
25
+ #
26
+ def initialize n, o={}
27
+ super n, nil
28
+ #
29
+ @pool = {} # per particle class free list
30
+ @world = {} # global iotas index
31
+ @sys_fifo = [] # system particles fifo list
32
+ @app_fifo = [] # application particles fifo list
33
+ #
34
+ @run = false
35
+ @hibernation = o['hibernation']||false
36
+ @hibernate_path = 'edoors-hibernate-'+n+'.json'
37
+ @debug_errors = o[:debug_errors]||o['debug_errors']||false
38
+ @debug_routing = o[:debug_routing]||o['debug_routing']||false
39
+ #
40
+ if not o.empty?
41
+ room = o['inner_room']
42
+ if room
43
+ room['iotas'].each do |name,iota|
44
+ eval( iota['kls'] ).json_create(iota.merge!('parent'=>self))
45
+ end
46
+ room['links'].each do |src,links|
47
+ links.each do |link|
48
+ add_link Edoors::Link.json_create(link)
49
+ end
50
+ end
51
+ end
52
+ o['app_fifo'].each do |particle|
53
+ @app_fifo << Edoors::Particle.json_create(particle.merge!('spin'=>self))
54
+ end if o['app_fifo']
55
+ o['sys_fifo'].each do |particle|
56
+ @sys_fifo << Edoors::Particle.json_create(particle.merge!('spin'=>self))
57
+ end if o['sys_fifo']
58
+ end
59
+ end
60
+ #
61
+ attr_accessor :run, :hibernate_path, :debug_errors, :debug_routing
62
+ #
63
+ def to_json *a
64
+ {
65
+ 'kls' => self.class.name,
66
+ 'timestamp' => Time.now,
67
+ 'name' => @name,
68
+ 'hibernation' => @hibernation,
69
+ 'inner_room' => { :iotas=>@iotas, :links=>@links },
70
+ 'sys_fifo' => @sys_fifo,
71
+ 'app_fifo' => @app_fifo,
72
+ 'debug_errors' => @debug_errors,
73
+ 'debug_routing' => @debug_routing
74
+ }.to_json(*a)
75
+ end
76
+ #
77
+ def self.json_create o
78
+ raise Edoors::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
79
+ self.new o['name'], o
80
+ end
81
+ #
82
+ def add_to_world iota
83
+ @world[iota.path] = iota
84
+ end
85
+ #
86
+ def search_world path
87
+ @world[path]
88
+ end
89
+ #
90
+ def clear!
91
+ @iotas.clear
92
+ @world.clear
93
+ @pool.clear
94
+ @sys_fifo.clear
95
+ @app_fifo.clear
96
+ end
97
+ #
98
+ #
99
+ def release_p p
100
+ # hope there is no circular loop
101
+ while p2=p.merged_shift
102
+ release_p p2
103
+ end
104
+ p.reset!
105
+ ( @pool[p.class] ||= [] ) << p
106
+ end
107
+ #
108
+ def require_p p_kls
109
+ l = @pool[p_kls]
110
+ return p_kls.new if l.nil?
111
+ p = l.pop
112
+ return p_kls.new if p.nil?
113
+ p
114
+ end
115
+ #
116
+ def post_p p
117
+ @app_fifo << p
118
+ end
119
+ #
120
+ def post_sys_p p
121
+ @sys_fifo << p
122
+ end
123
+ #
124
+ def process_sys_p p
125
+ if p.action==Edoors::SYS_ACT_HIBERNATE
126
+ stop!
127
+ hibernate! p[FIELD_HIBERNATE_PATH]
128
+ else
129
+ super p
130
+ end
131
+ end
132
+ #
133
+ def spin!
134
+ @iotas.values.each do |iota| iota.start! end unless @hibernation
135
+ @run = true
136
+ @hibernation = false
137
+ while @run and (@sys_fifo.length>0 or @app_fifo.length>0)
138
+ while @run and @sys_fifo.length>0
139
+ p = @sys_fifo.shift
140
+ p.dst.process_sys_p p
141
+ end
142
+ while @run and @app_fifo.length>0
143
+ p = @app_fifo.shift
144
+ p.dst.process_p p
145
+ break
146
+ end
147
+ end
148
+ @iotas.values.each do |iota| iota.stop! end unless @hibernation
149
+ end
150
+ #
151
+ def stop!
152
+ @run=false
153
+ end
154
+ #
155
+ def hibernate! path=nil
156
+ @hibernation = true
157
+ File.open(path||@hibernate_path,'w') do |f| f << JSON.pretty_generate(self) end
158
+ end
159
+ #
160
+ def self.resume! path
161
+ self.json_create JSON.load File.open(path,'r') { |f| f.read }
162
+ end
163
+ #
164
+ end
165
+ #
166
+ end
167
+ #
168
+ # EOF
@@ -0,0 +1,28 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+ # Copyright 2012 Jérémy Zurcher <jeremy@asynk.ch>
5
+ #
6
+ # This file is part of edoors-ruby.
7
+ #
8
+ # edoors-ruby is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU Affero General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # edoors-ruby is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Affero General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Affero General Public License
19
+ # along with edoors-ruby. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ #
22
+ module Edoors
23
+ #
24
+ VERSION = "0.0.6"
25
+ #
26
+ end
27
+ #
28
+ # EOF
@@ -0,0 +1,92 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+
5
+ require 'spec_helper'
6
+ #
7
+ describe Edoors::Board do
8
+ #
9
+ before (:all) do
10
+ @spin = Edoors::Spin.new 'dom0'
11
+ end
12
+ #
13
+ before(:each) do
14
+ @spin.clear!
15
+ end
16
+ #
17
+ it "require_p release_p" do
18
+ board = Edoors::Board.new 'hell', @spin
19
+ p0 = board.require_p Edoors::Particle
20
+ p1 = board.require_p Edoors::Particle
21
+ (p0===p1).should be_false
22
+ board.release_p p0
23
+ p2 = board.require_p Edoors::Particle
24
+ (p0===p2).should be_true
25
+ end
26
+ #
27
+ it "particle wait and merge" do
28
+ p0 = Edoors::Particle.new
29
+ p0['k0'] = 'v0'
30
+ p0['k1'] = 'neither'
31
+ p0['k2'] = 'v2'
32
+ p0.set_link_fields 'k0,k2'
33
+ p0.link_value.should eql 'v0v2'
34
+ p1 = Edoors::Particle.new
35
+ p1['k0'] = 'v0'
36
+ p1['k1'] = 'nore'
37
+ p1['k2'] = 'v2'
38
+ p1.set_link_fields 'k0,k2'
39
+ p1.link_value.should eql 'v0v2'
40
+ P0 = p0
41
+ P1 = p1
42
+ class Board0 < Edoors::Board
43
+ attr_reader :ok, :follow
44
+ def receive_p p
45
+ @ok = false
46
+ case p.action
47
+ when Edoors::ACT_FOLLOW
48
+ @follow = true
49
+ @ok = (p===P0 and p.merged(0)===P1)
50
+ else
51
+ @follow = false
52
+ @ok = (p===P1 and p.merged(0)===P0)
53
+ end
54
+ end
55
+ end
56
+ b0 = Board0.new 'door0', @spin
57
+ b0.process_p p0
58
+ p0.merged(0).should be_nil
59
+ b0.process_p p1
60
+ b0.ok.should be_true
61
+ b0.follow.should be_false
62
+ #
63
+ p1.merged_shift
64
+ #
65
+ b0.process_p p0
66
+ p0.merged(0).should be_nil
67
+ # need to set it to p0 too, so case in Board0 is ok
68
+ p0.add_dst Edoors::ACT_FOLLOW
69
+ p0.split_dst!
70
+ p1.add_dst Edoors::ACT_FOLLOW
71
+ p1.split_dst!
72
+ b0.process_p p1
73
+ b0.ok.should be_true
74
+ b0.follow.should be_true
75
+ end
76
+ #
77
+ it "board->json->board" do
78
+ board = Edoors::Board.new 'hell', @spin
79
+ p0 = Edoors::Particle.new
80
+ p1 = Edoors::Particle.new
81
+ p1['v0']=0
82
+ p1.set_link_fields 'v0'
83
+ board.process_p p0
84
+ board.process_p p1
85
+ hell = Edoors::Board.json_create( JSON.load( JSON.generate(board) ) )
86
+ board.name.should eql hell.name
87
+ JSON.generate(board).should eql JSON.generate(hell)
88
+ end
89
+ #
90
+ end
91
+ #
92
+ # EOF
@@ -0,0 +1,95 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+
5
+ require 'spec_helper'
6
+ #
7
+ describe Edoors::Door do
8
+ #
9
+ before (:all) do
10
+ @spin = Edoors::Spin.new 'dom0'
11
+ end
12
+ #
13
+ before(:each) do
14
+ @spin.clear!
15
+ end
16
+ #
17
+ it "require_p release_p" do
18
+ door = Edoors::Door.new 'hell', @spin
19
+ p0 = door.require_p Edoors::Particle
20
+ p1 = door.require_p Edoors::Particle
21
+ (p0===p1).should be_false
22
+ door.release_p p0
23
+ p2 = door.require_p Edoors::Particle
24
+ (p0===p2).should be_true
25
+ end
26
+ #
27
+ it "NoMethodError when receive_p not overridden" do
28
+ class Door0 < Edoors::Door
29
+ end
30
+ f = Fake.new 'fake', @spin
31
+ d0 = Door0.new 'door0', f
32
+ p0 = d0.require_p Edoors::Particle
33
+ lambda { d0.process_p p0 }.should raise_error(NoMethodError)
34
+ end
35
+ #
36
+ it "send_p, send_sys_p, release_p and release of lost particles" do
37
+ class Door0 < Edoors::Door
38
+ def receive_p p
39
+ case p.action
40
+ when 'RELEASE'
41
+ release_p p
42
+ when 'SEND'
43
+ send_p p
44
+ when 'SEND_SYS'
45
+ send_sys_p p
46
+ else
47
+ # lost!!
48
+ end
49
+ end
50
+ end
51
+ f = Fake.new 'fake', @spin
52
+ d0 = Door0.new 'door0', f
53
+ p0 = d0.require_p Edoors::Particle
54
+ #
55
+ p0.add_dst 'SEND'
56
+ p0.split_dst!
57
+ d0.process_p p0
58
+ f.p.should eql p0
59
+ p0.clear_dsts!
60
+ #
61
+ p0.add_dst 'SEND_SYS'
62
+ p0.split_dst!
63
+ d0.process_p p0
64
+ f.sp.should eql p0
65
+ p0.clear_dsts!
66
+ #
67
+ p0.add_dst 'RELEASE'
68
+ p0.split_dst!
69
+ d0.process_p p0
70
+ p1 = d0.require_p Edoors::Particle
71
+ p1.should be p0
72
+ p0.clear_dsts!
73
+ #
74
+ p0.add_dst 'LOST'
75
+ p0.split_dst!
76
+ d0.process_p p0
77
+ p1 = d0.require_p Edoors::Particle
78
+ p1.should be p0
79
+ p0.clear_dsts!
80
+ #
81
+ d0.process_sys_p p0
82
+ p1 = @spin.require_p Edoors::Particle
83
+ p1.should be p0
84
+ end
85
+ #
86
+ it "door->json->door" do
87
+ door = Edoors::Door.new 'hell', @spin
88
+ hell = Edoors::Door.json_create( JSON.load( JSON.generate(door) ) )
89
+ door.name.should eql hell.name
90
+ JSON.generate(door).should eql JSON.generate(hell)
91
+ end
92
+ #
93
+ end
94
+ #
95
+ # EOF
@@ -0,0 +1,38 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+
5
+ require 'spec_helper'
6
+ #
7
+ describe Edoors::Link do
8
+ #
9
+ it "from particle data" do
10
+ @spin = Edoors::Spin.new 'dom0'
11
+ p = @spin.require_p Edoors::Particle
12
+ p.set_data Edoors::LNK_SRC, 'input1'
13
+ p.set_data Edoors::LNK_DSTS, 'concat1?follow,output1'
14
+ p.set_data Edoors::LNK_FIELDS, 'f0,f2'
15
+ p.set_data Edoors::LNK_CONDF, 'f0,f1,f2'
16
+ p.set_data Edoors::LNK_CONDV, 'v0v1v2'
17
+ lnk = Edoors::Link.from_particle_data p
18
+ lnk.src.should eql 'input1'
19
+ lnk.dsts.should eql 'concat1?follow,output1'
20
+ lnk.fields.should eql 'f0,f2'
21
+ lnk.cond_fields.should eql 'f0,f1,f2'
22
+ lnk.cond_value.should eql 'v0v1v2'
23
+ end
24
+ #
25
+ it "link->json->link" do
26
+ link = Edoors::Link.new 'input1', 'concat1?follow,output1', 'f0,f2', 'f0,f1,f2', 'v0v1v2'
27
+ lnk = Edoors::Link.json_create( JSON.load( JSON.generate(link) ) )
28
+ link.src.should eql lnk.src
29
+ link.dsts.should eql lnk.dsts
30
+ link.fields.should eql lnk.fields
31
+ link.cond_fields.should eql lnk.cond_fields
32
+ link.cond_value.should eql lnk.cond_value
33
+ JSON.generate(link).should eql JSON.generate(lnk)
34
+ end
35
+ #
36
+ end
37
+ #
38
+ # EOF
@@ -0,0 +1,266 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+
5
+ require 'spec_helper'
6
+ #
7
+ describe Edoors::Particle do
8
+ #
9
+ it "payload manipulation" do
10
+ p = Edoors::Particle.new
11
+ #
12
+ p['key']=666
13
+ p['key'].should eql 666
14
+ p.data('key').should eql 666
15
+ p.get_data('key').should eql 666
16
+ #
17
+ p.set_data 'key', 69
18
+ p['key'].should eql 69
19
+ p.data('key').should eql 69
20
+ p.get_data('key').should eql 69
21
+ end
22
+ #
23
+ it "payload clone" do
24
+ p = Edoors::Particle.new
25
+ p['k00'] = { 'k0'=>0,'k1'=>1}
26
+ p['k11'] = [1,2,3]
27
+ o = Edoors::Particle.new
28
+ o.clone_data p
29
+ p['k00']=nil
30
+ p['k00'].should be_nil
31
+ o['k00']['k0'].should eql 0
32
+ o['k00']['k1'].should eql 1
33
+ p['k11']=nil
34
+ p['k11'].should be_nil
35
+ o['k11'][0].should eql 1
36
+ o['k11'][1].should eql 2
37
+ o['k11'][2].should eql 3
38
+ end
39
+ #
40
+ it "particle merge" do
41
+ spin = Edoors::Spin.new 'dom0'
42
+ p = Edoors::Particle.new
43
+ q = Edoors::Particle.new
44
+ o = Edoors::Particle.new
45
+ p.merge! q
46
+ p.merge! o
47
+ p.merged(0).should be q
48
+ p.merged(1).should be o
49
+ p.merged(2).should be_nil
50
+ p.merged_shift.should be q
51
+ p.merged(0).should be o
52
+ p.merged(1).should be_nil
53
+ p.merged_shift.should be o
54
+ p.merged(0).should be_nil
55
+ p.merge! q
56
+ p.merge! o
57
+ p.merged(0).should be q
58
+ p.merged(1).should be o
59
+ p.clear_merged!
60
+ p.merged(0).should be_nil
61
+ p.merge! q
62
+ p.merge! o
63
+ p.merged(0).should be q
64
+ p.merged(1).should be o
65
+ p.clear_merged! spin
66
+ p.merged(0).should be_nil
67
+ spin.require_p(Edoors::Particle).should be o
68
+ spin.require_p(Edoors::Particle).should be q
69
+ end
70
+ #
71
+ it "routing: add_dsts, next_dst and dst_routed!" do
72
+ p = Edoors::Particle.new
73
+ d0 = Edoors::Door.new 'door0', nil
74
+ d1 = Edoors::Door.new 'door1', nil
75
+ p.dst.should be_nil
76
+ p.next_dst.should be_nil
77
+ p.add_dsts 'some?where,room0/room1/door?action,room/door,door'
78
+ p.next_dst.should eql 'some?where'
79
+ p.dst_routed! d0
80
+ p.dst.should be d0
81
+ p.next_dst.should eql 'room0/room1/door?action'
82
+ p.dst_routed! d1
83
+ p.dst.should be d1
84
+ p.next_dst.should eql 'room/door'
85
+ p.dst_routed! nil
86
+ p.dst.should be_nil
87
+ p.next_dst.should eql 'door'
88
+ end
89
+ #
90
+ it "wrong path should raise exeption" do
91
+ p = Edoors::Particle.new
92
+ lambda { p.add_dst 'action', '/room' }.should raise_error(Edoors::Exception)
93
+ lambda { p.add_dst 'action', 'room/' }.should raise_error(Edoors::Exception)
94
+ lambda { p.add_dst '', 'room/' }.should raise_error(Edoors::Exception)
95
+ lambda { p.add_dst 'action', 'room//door' }.should raise_error(Edoors::Exception)
96
+ lambda { p.add_dst ' ' }.should raise_error(Edoors::Exception)
97
+ lambda { p.add_dst ' ', '' }.should raise_error(Edoors::Exception)
98
+ lambda { p.add_dst 'f f' }.should raise_error(Edoors::Exception)
99
+ lambda { p.add_dst '', ' d' }.should raise_error(Edoors::Exception)
100
+ lambda { p.add_dst '' }.should raise_error(Edoors::Exception)
101
+ lambda { p.add_dst '', '' }.should raise_error(Edoors::Exception)
102
+ lambda { p.add_dst nil }.should raise_error(TypeError)
103
+ lambda { p.add_dst 'action', nil }.should raise_error(NoMethodError)
104
+ end
105
+ #
106
+ it "routing: set_dst!" do
107
+ p = Edoors::Particle.new
108
+ d0 = Edoors::Door.new 'door0', nil
109
+ #
110
+ p.set_dst! 'action', d0
111
+ p.action.should eql 'action'
112
+ p.dst.should be d0
113
+ end
114
+ #
115
+ it "routing: add_dst and split_dst!" do
116
+ p = Edoors::Particle.new
117
+ d0 = Edoors::Door.new 'door0', nil
118
+ #
119
+ p.split_dst!
120
+ p.room.should be_nil
121
+ p.door.should be_nil
122
+ p.action.should be_nil
123
+ #
124
+ p.add_dst 'action', 'room0/room1/door'
125
+ p.split_dst!
126
+ p.room.should eql 'room0/room1'
127
+ p.door.should eql 'door'
128
+ p.action.should eql 'action'
129
+ p.clear_dsts!
130
+ #
131
+ p.add_dst 'action', 'room/door'
132
+ p.split_dst!
133
+ p.room.should eql 'room'
134
+ p.door.should eql 'door'
135
+ p.action.should eql 'action'
136
+ p.clear_dsts!
137
+ #
138
+ p.add_dst 'action', ''
139
+ p.split_dst!
140
+ p.room.should be_nil
141
+ p.door.should be_nil
142
+ p.action.should eql 'action'
143
+ p.clear_dsts!
144
+ #
145
+ p.add_dst 'action'
146
+ p.split_dst!
147
+ p.room.should be_nil
148
+ p.door.should be_nil
149
+ p.action.should eql 'action'
150
+ p.clear_dsts!
151
+ #
152
+ p.add_dsts 'door?action,?action'
153
+ p.split_dst!
154
+ p.room.should be_nil
155
+ p.door.should eql 'door'
156
+ p.action.should eql 'action'
157
+ #
158
+ p.dst_routed! d0
159
+ #
160
+ p.dst.should be d0
161
+ p.split_dst!
162
+ p.room.should be_nil
163
+ p.door.should be_nil
164
+ p.action.should eql 'action'
165
+ #
166
+ end
167
+ #
168
+ it "routing: error!" do
169
+ p = Edoors::Particle.new
170
+ d = Edoors::Door.new 'door', nil
171
+ p.init! d
172
+ p.add_dsts 'door?action,?action'
173
+ p.next_dst.should eql 'door?action'
174
+ p.error! 'err_msg'
175
+ p[Edoors::FIELD_ERROR_MSG].should eql 'err_msg'
176
+ p.action.should eq Edoors::ACT_ERROR
177
+ p.dst.should be d
178
+ end
179
+ #
180
+ it "link fields and link value" do
181
+ p = Edoors::Particle.new
182
+ p['k0'] = 'v0'
183
+ p['k1'] = 'v1'
184
+ p['k2'] = 'v2'
185
+ p.set_link_fields 'k0,k2'
186
+ p.link_value.should eql 'v0v2'
187
+ p.set_link_fields 'k1,k0'
188
+ p.link_value.should eql 'v1v0'
189
+ p['k0']='vx'
190
+ p.link_value.should eql 'v1vx'
191
+ end
192
+ #
193
+ it "apply_link!" do
194
+ p = Edoors::Particle.new
195
+ p['k0'] = 'v0'
196
+ p['k1'] = 'v1'
197
+ p['k2'] = 'v2'
198
+ p.set_link_fields 'k0,k2'
199
+ p.add_dsts 'door?action,?action'
200
+ p.src.should be_nil
201
+ p.link_value.should eql 'v0v2'
202
+ p.next_dst.should eql 'door?action'
203
+ lnk = Edoors::Link.new('door0', 'door1?get,door2', 'k1', 'f0,f1', 'v0v1')
204
+ f = Fake.new 'fake', nil
205
+ lnk.door = f
206
+ p.apply_link! lnk
207
+ p.src.should be f
208
+ p.next_dst.should eql 'door1?get'
209
+ p.link_value.should eql 'v1'
210
+ end
211
+ #
212
+ it "particle->json->particle" do
213
+ s0 = Edoors::Spin.new 'top'
214
+ s1 = Edoors::Room.new 'room0', s0
215
+ s2 = Edoors::Room.new 'room1', s1
216
+ s3 = Edoors::Door.new 'doora', s2
217
+ s4 = Edoors::Door.new 'doorb', s1
218
+ p0 = Edoors::Particle.new
219
+ p0['k0'] = 'v0'
220
+ p0['k1'] = 'v1'
221
+ p0['k2'] = 'v2'
222
+ p0.init! s3
223
+ p0.set_link_fields 'k0,k2'
224
+ p0.add_dsts 'room0/room1/room2/doorX?myaction,door?action,?action'
225
+ p0.split_dst!
226
+ p1 = Edoors::Particle.new
227
+ p1['k3'] = 'v6'
228
+ p1['k4'] = 'v7'
229
+ p1['k5'] = 'v8'
230
+ p1.init! s3
231
+ p1.dst_routed! s4
232
+ p1.set_link_fields 'k5,k4,k3'
233
+ p1.add_dsts 'room0/room1/door?action,output?action'
234
+ p0.merge! p1
235
+ o = JSON.load( JSON.generate(p0) )
236
+ o['spin'] = s0
237
+ px = Edoors::Particle.json_create( o )
238
+ ((px.ts-p0.ts)<0.5).should be_true
239
+ px.src.should be s3
240
+ px.dst.should be_nil
241
+ px.room.should eql 'room0/room1/room2'
242
+ px.door.should eql 'doorX'
243
+ px.action.should eql 'myaction'
244
+ px.next_dst.should eql 'room0/room1/room2/doorX?myaction'
245
+ px.link_value.should eql 'v0v2'
246
+ px['k0'].should eql 'v0'
247
+ px['k1'].should eql 'v1'
248
+ px['k2'].should eql 'v2'
249
+ py = px.merged(0)
250
+ ((py.ts-p1.ts)<0.5).should be_true
251
+ py.src.should be s3
252
+ py.dst.should be s4
253
+ py.room.should be_nil
254
+ py.door.should be_nil
255
+ py.action.should be_nil
256
+ py.next_dst.should eql 'room0/room1/door?action'
257
+ py.link_value.should eql 'v8v7v6'
258
+ py['k3'].should eql 'v6'
259
+ py['k4'].should eql 'v7'
260
+ py['k5'].should eql 'v8'
261
+ JSON.generate(p0).should eql JSON.generate(px)
262
+ end
263
+ #
264
+ end
265
+ #
266
+ # EOF