iotas 0.0.2

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/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
data/iotas.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
3
+ #
4
+ $:.push File.expand_path("../lib", __FILE__)
5
+ require 'version'
6
+ #
7
+ Gem::Specification.new do |s|
8
+ s.name = "iotas"
9
+ s.version = Iotas::VERSION
10
+ s.authors = ["Jérémy Zurcher"]
11
+ s.email = ["jeremy@asynk.ch"]
12
+ s.homepage = "http://github.com/jeremyz/iotas"
13
+ s.summary = %q{ruby rewrite of C++ application framework evenja (http://www.revena.com/evenja)}
14
+ s.description = %q{Evenja propose a data centric paradigm. A traditional programm composed of many functions
15
+ is decomposed into small autonomous modifications applied on the data implemented in different instances of Door base class.
16
+ Routing between these doors is handled through links or user application destinations.}
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_runtime_dependency "json"
24
+ s.add_development_dependency "rspec", ["~> 2.6"]
25
+ s.add_development_dependency "rake"
26
+ end
27
+ #
28
+ # EOF
@@ -0,0 +1,69 @@
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 iotas.
7
+ #
8
+ # iotas 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
+ # iotas 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 iotas. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ #
22
+ module Iotas
23
+ #
24
+ ACT_FOLLOW = 'follow'.freeze
25
+ #
26
+ class Board < Door
27
+ #
28
+ def initialize n, p
29
+ super n, p
30
+ @postponed = {}
31
+ end
32
+ #
33
+ def to_json *a
34
+ {
35
+ 'kls' => self.class.name,
36
+ 'name' => @name,
37
+ 'postponed' => @postponed
38
+ }.merge(hibernate!).to_json *a
39
+ end
40
+ #
41
+ def self.json_create o
42
+ raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
43
+ board = self.new o['name'], o['parent']
44
+ o['postponed'].each do |link_value,particle|
45
+ board.process_p Iotas::Particle.json_create(particle.merge!('spin'=>board.spin))
46
+ end
47
+ board.resume! o
48
+ board
49
+ end
50
+ #
51
+ def process_p p
52
+ @viewer.receive_p p if @viewer
53
+ if p.action!=Iotas::ACT_ERROR
54
+ p2 = @postponed[p.link_value] ||= p
55
+ return if p2==p
56
+ @postponed.delete p.link_value
57
+ p,p2 = p2,p if p.action==Iotas::ACT_FOLLOW
58
+ p.merge! p2
59
+ end
60
+ @saved = p
61
+ receive_p p
62
+ garbage if not @saved.nil?
63
+ end
64
+ #
65
+ end
66
+ #
67
+ end
68
+ #
69
+ # EOF
data/lib/iotas/door.rb ADDED
@@ -0,0 +1,91 @@
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 iotas.
7
+ #
8
+ # iotas 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
+ # iotas 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 iotas. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ #
22
+ module Iotas
23
+ #
24
+ class Door < Iota
25
+ #
26
+ def initialize n, p
27
+ super n, p
28
+ @saved = nil
29
+ end
30
+ #
31
+ def to_json *a
32
+ {
33
+ 'kls' => self.class.name,
34
+ 'name' => @name
35
+ }.merge(hibernate!).to_json *a
36
+ end
37
+ #
38
+ def self.json_create o
39
+ raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
40
+ door = self.new o['name'], o['parent']
41
+ door.resume! o
42
+ door
43
+ end
44
+ #
45
+ def require_p p_kls
46
+ p = @spin.require_p p_kls
47
+ p.src = self
48
+ p
49
+ end
50
+ #
51
+ def release_p p
52
+ @saved=nil if @saved==p # particle is released, all is good
53
+ @spin.release_p p
54
+ end
55
+ #
56
+ def garbage
57
+ puts " ! #{path} didn't give back #{@saved}" if @spin.debug_errors
58
+ puts "\t#{@saved.data Iotas::FIELD_ERROR_MSG}" if @saved.action==Iotas::ACT_ERROR
59
+ release_p @saved
60
+ @saved = nil
61
+ end
62
+ #
63
+ def process_p p
64
+ @viewer.receive_p p if @viewer
65
+ @saved = p
66
+ receive_p p
67
+ garbage if not @saved.nil?
68
+ end
69
+ #
70
+ def process_sys_p p
71
+ # nothing todo with it now
72
+ @spin.release_p p
73
+ end
74
+ #
75
+ def send_p p
76
+ p.src = self
77
+ @saved=nil if @saved==p # particle is sent back the data, all is good
78
+ @parent.send_p p # daddy will know what to do
79
+ end
80
+ #
81
+ def send_sys_p p
82
+ p.src = self
83
+ @saved=nil if @saved==p # particle is sent back the data, all is good
84
+ @parent.send_sys_p p # daddy will know what to do
85
+ end
86
+ #
87
+ end
88
+ #
89
+ end
90
+ #
91
+ # EOF
data/lib/iotas/iota.rb ADDED
@@ -0,0 +1,64 @@
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 iotas.
7
+ #
8
+ # iotas 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
+ # iotas 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 iotas. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ #
22
+ module Iotas
23
+ #
24
+ class Iota
25
+ #
26
+ def initialize n, p
27
+ @name = n # unique in it's room
28
+ @parent = p # single direct parent
29
+ @viewer = nil # particle going through that position will be sent there readonly
30
+ @path = ( @parent ? @parent.path+Iotas::PATH_SEP : '') + @name
31
+ @spin = ( @parent ? @parent.spin : self )
32
+ @parent.add_iota self if @parent
33
+ raise Iotas::Exception.new "Iota name #{name} is not valid" if @name.include? Iotas::PATH_SEP
34
+ end
35
+ #
36
+ attr_reader :name, :path, :spin
37
+ attr_accessor :viewer, :parent
38
+ #
39
+ def start!
40
+ # override this to initialize your object on system start
41
+ end
42
+ #
43
+ def stop!
44
+ # override this to initialize your object on system stop
45
+ end
46
+ #
47
+ def hibernate!
48
+ # override this to save your object state on hibernate
49
+ {}
50
+ end
51
+ #
52
+ def resume! o
53
+ # override this to restore your object state on resume
54
+ end
55
+ #
56
+ def receive_p p
57
+ raise NoMethodError.new "receive_p(p) must be overridden"
58
+ end
59
+ #
60
+ end
61
+ #
62
+ end
63
+ #
64
+ # EOF
data/lib/iotas/link.rb ADDED
@@ -0,0 +1,70 @@
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 iotas.
7
+ #
8
+ # iotas 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
+ # iotas 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 iotas. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ #
22
+ module Iotas
23
+ #
24
+ LNK_SRC = 'edoors_lnk_src'.freeze
25
+ LNK_DSTS = 'edoors_lnk_dsts'.freeze
26
+ LNK_FIELDS = 'edoors_lnk_fields'.freeze
27
+ LNK_CONDF = 'edoors_lnk_condf'.freeze
28
+ LNK_CONDV = 'edoors_lnk_condv'.freeze
29
+ #
30
+ class Link
31
+ #
32
+ def initialize src, dsts, fields=nil, cond_fields=nil, cond_value=nil
33
+ @src = src # link source name
34
+ @dsts = dsts # , separated destinations to apply to the particle on linking success
35
+ @fields = fields # , separated fields to apply to the particle on linking success
36
+ @cond_fields = cond_fields # , separated fields used to generate the link value with particle payload
37
+ @cond_value = cond_value # value which will be compared to the particle link value to link or not
38
+ @door = nil # pointer to the source
39
+ end
40
+ #
41
+ def to_json *a
42
+ {
43
+ 'kls' => self.class.name,
44
+ 'src' => @src,
45
+ 'dsts' => @dsts,
46
+ 'fields' => @fields,
47
+ 'cond_fields' => @cond_fields,
48
+ 'cond_value' => @cond_value
49
+ }.to_json *a
50
+ end
51
+ #
52
+ def self.json_create o
53
+ raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
54
+ self.new o['src'], o['dsts'], o['fields'], o['cond_fields'], o['cond_value']
55
+ end
56
+ #
57
+ def self.from_particle_data p
58
+ Iotas::Link.new(p.get_data(Iotas::LNK_SRC), p.get_data(Iotas::LNK_DSTS),
59
+ p.get_data(Iotas::LNK_FIELDS), p.get_data(Iotas::LNK_CONDF),
60
+ p.get_data(Iotas::LNK_CONDV))
61
+ end
62
+ #
63
+ attr_accessor :door
64
+ attr_reader :src, :dsts, :fields, :cond_fields, :cond_value
65
+ #
66
+ end
67
+ #
68
+ end
69
+ #
70
+ # EOF
@@ -0,0 +1,213 @@
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 iotas.
7
+ #
8
+ # iotas 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
+ # iotas 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 iotas. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ require 'time'
22
+ #
23
+ module Iotas
24
+ #
25
+ class Particle
26
+ #
27
+ def initialize o={}
28
+ @ts = Time.now # creation time
29
+ @src = nil # Iota where it's originated from
30
+ @dst = nil # Iota where it's heading to
31
+ @room = nil # Room path part of the current destination
32
+ @door = nil # Door path part of the current destination
33
+ @action = nil # action part of the current destination
34
+ @link_value = nil # the value computed with the link_fields values extracted from the payload
35
+ # used for pearing Particles in Boards and linking in routing process
36
+ @dsts = [] # fifo of path?action strings where to travel to
37
+ @link_fields = [] # the fields used to generate the link value
38
+ @payload = {} # the actual data carried by this particle
39
+ @merged = [] # list of merged particles
40
+ #
41
+ if not o.empty?
42
+ @ts = Time.parse(o['ts']) if o['ts']
43
+ @room = o['room']
44
+ @door = o['door']
45
+ @action = o['action']
46
+ @payload = o['payload']||{}
47
+ @src = o['spin'].search_down o['src'] if o['src']
48
+ @dst = o['spin'].search_down o['dst'] if o['dst']
49
+ o['dsts'].each do |dst| add_dsts dst end if o['dsts']
50
+ set_link_fields *o['link_fields'] if o['link_fields']
51
+ o['merged'].each do |particle|
52
+ merge! Particle.json_create(particle.merge!('spin'=>o['spin']))
53
+ end if o['merged']
54
+ end
55
+ end
56
+ #
57
+ def to_json *a
58
+ {
59
+ 'kls' => self.class.name,
60
+ 'ts' => @ts,
61
+ 'src' => (@src ? @src.path : nil ),
62
+ 'dst' => (@dst ? @dst.path : nil ),
63
+ 'room' => @room,
64
+ 'door' => @door,
65
+ 'action' => @action,
66
+ 'dsts' => @dsts,
67
+ 'link_fields' => @link_fields,
68
+ 'payload' => @payload,
69
+ 'merged' => @merged
70
+ }.to_json *a
71
+ end
72
+ #
73
+ def self.json_create o
74
+ raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
75
+ self.new o
76
+ end
77
+ #
78
+ def reset!
79
+ @ts = Time.now
80
+ @src = @dst = @room = @door = @action = @link_value = nil
81
+ @dsts.clear
82
+ @link_fields.clear
83
+ @payload.clear
84
+ @merged.clear
85
+ end
86
+ #
87
+ attr_accessor :src
88
+ attr_reader :ts, :dst, :room, :door, :action, :link_value, :payload
89
+ #
90
+ # routing
91
+ #
92
+ def next_dst
93
+ @dsts[0]
94
+ end
95
+ #
96
+ def clear_dsts!
97
+ @dsts.clear
98
+ end
99
+ #
100
+ def add_dsts dsts
101
+ dsts.split(Iotas::LINK_SEP).each do |dst|
102
+ if dst.empty? or dst[0]==Iotas::PATH_SEP or dst[0]==Iotas::PATH_SEP or dst=~/\/\?/\
103
+ or dst=~/\/{2,}/ or dst=~/\s+/ or dst==Iotas::ACT_SEP
104
+ raise Iotas::Exception.new "destination #{dst} is not acceptable"
105
+ end
106
+ @dsts << dst
107
+ end
108
+ end
109
+ #
110
+ def set_dst! a, d=''
111
+ @dst = @room = @door = @action = nil
112
+ clear_dsts!
113
+ add_dsts d+Iotas::ACT_SEP+a
114
+ end
115
+ #
116
+ def split_dst!
117
+ @dst = @room = @door = @action = nil
118
+ return if (n = next_dst).nil?
119
+ p, @action = n.split Iotas::ACT_SEP
120
+ i = p.rindex Iotas::PATH_SEP
121
+ if i.nil?
122
+ @room = nil
123
+ @door = p
124
+ else
125
+ @room = p[0..i-1]
126
+ @door = p[i+1..-1]
127
+ end
128
+ @door = nil if @door.empty?
129
+ end
130
+ #
131
+ def dst_routed! dst
132
+ @dst = dst
133
+ @dsts.shift
134
+ end
135
+ #
136
+ def error! e, dst=nil
137
+ @action = Iotas::ACT_ERROR
138
+ @dst = dst||@src
139
+ @payload[Iotas::FIELD_ERROR_MSG]=e
140
+ end
141
+ #
142
+ def apply_link! lnk
143
+ @src = lnk.door
144
+ clear_dsts!
145
+ add_dsts lnk.dsts
146
+ set_link_fields lnk.fields
147
+ end
148
+ #
149
+ # data manipulation
150
+ #
151
+ def []= k, v
152
+ @payload[k]=v
153
+ compute_link_value! if @link_fields.include? k
154
+ end
155
+ #
156
+ def set_data k, v
157
+ @payload[k] = v
158
+ compute_link_value! if @link_fields.include? k
159
+ end
160
+ #
161
+ def [] k
162
+ @payload[k]
163
+ end
164
+ #
165
+ def get_data k
166
+ @payload[k]
167
+ end
168
+ alias :data :get_data
169
+ #
170
+ def clone_data p
171
+ @payload = p.payload.clone
172
+ end
173
+ #
174
+ # link value and fields
175
+ #
176
+ def set_link_fields *args
177
+ @link_fields.clear if not @link_fields.empty?
178
+ args.compact!
179
+ args.each do |lfs|
180
+ lfs.split(',').each do |lf|
181
+ @link_fields << lf
182
+ end
183
+ end
184
+ compute_link_value!
185
+ end
186
+ #
187
+ def compute_link_value!
188
+ @link_value = @link_fields.inject('') { |s,lf| s+=@payload[lf].to_s if @payload[lf]; s }
189
+ end
190
+ #
191
+ # merge particles management
192
+ #
193
+ def merge! p
194
+ @merged << p
195
+ end
196
+ #
197
+ def merged i
198
+ @merged[i]
199
+ end
200
+ #
201
+ def merged_shift
202
+ @merged.shift
203
+ end
204
+ #
205
+ def clear_merged!
206
+ @merged.clear
207
+ end
208
+ #
209
+ end
210
+ #
211
+ end
212
+ #
213
+ # EOF