summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/edoors/particle.rb241
1 files changed, 189 insertions, 52 deletions
diff --git a/lib/edoors/particle.rb b/lib/edoors/particle.rb
index 84f6ece..983af01 100644
--- a/lib/edoors/particle.rb
+++ b/lib/edoors/particle.rb
@@ -24,6 +24,33 @@ module Edoors
#
class Particle
#
+ # creates a Particle object from the arguments.
+ #
+ # @param [Hash] o a customizable set of options
+ #
+ # @option o 'ts' [String]
+ # Creation time
+ # @option o 'src' [String]
+ # Iota where it's originated from
+ # @option o 'dst' [String]
+ # Iota where it's heading to
+ # @option o 'room' [String]
+ # Room path part of the current destination
+ # @option o 'door' [String]
+ # Door path part of the current destination
+ # @option o 'action' [String]
+ # action part of the current destination
+ # @option o 'dsts' [String]
+ # fifo of path?action strings where to travel to
+ # @option o 'link_keys' [String]
+ # unordered keys used has payload keys to build link_value
+ # @option o 'payload' [String]
+ # the data carried by this particle
+ # @option o 'merged' [String]
+ # list of merged particles
+ #
+ # @see Spin#require_p require a Particle
+ #
def initialize o={}
@ts = Time.now # creation time
@src = nil # Iota where it's originated from
@@ -31,11 +58,10 @@ module Edoors
@room = nil # Room path part of the current destination
@door = nil # Door path part of the current destination
@action = nil # action part of the current destination
- @link_value = nil # the value computed with the link_fields values extracted from the payload
- # used for pearing Particles in Boards and linking in routing process
@dsts = [] # fifo of path?action strings where to travel to
- @link_fields = [] # the fields used to generate the link value
- @payload = {} # the actual data carried by this particle
+ @link_keys = [] # unordered keys used has payload keys to build link_value
+ @link_value = {} # the payload keys and values corresponding to the link keys
+ @payload = {} # the data carried by this particle
@merged = [] # list of merged particles
#
if not o.empty?
@@ -46,77 +72,113 @@ module Edoors
@payload = o['payload']||{}
@src = o['spin'].search_down o['src'] if o['src']
@dst = o['spin'].search_down o['dst'] if o['dst']
- o['dsts'].each do |dst| add_dsts dst end if o['dsts']
- set_link_fields *o['link_fields'] if o['link_fields']
+ add_dsts *o['dsts'] if o['dsts']
+ set_link_keys *o['link_keys'] if o['link_keys']
o['merged'].each do |particle|
merge! Particle.json_create(particle.merge!('spin'=>o['spin']))
end if o['merged']
end
end
#
+ # called by JSON#generate to serialize the Particle object into JSON data
+ #
+ # @param [Array] a belongs to JSON generator
+ #
def to_json *a
{
- 'kls' => self.class.name,
- 'ts' => @ts,
- 'src' => (@src ? @src.path : nil ),
- 'dst' => (@dst ? @dst.path : nil ),
- 'room' => @room,
- 'door' => @door,
- 'action' => @action,
- 'dsts' => @dsts,
- 'link_fields' => @link_fields,
- 'payload' => @payload,
- 'merged' => @merged
+ 'kls' => self.class.name,
+ 'ts' => @ts,
+ 'src' => (@src ? @src.path : nil ),
+ 'dst' => (@dst ? @dst.path : nil ),
+ 'room' => @room,
+ 'door' => @door,
+ 'action' => @action,
+ 'dsts' => @dsts,
+ 'link_keys' => @link_keys,
+ 'payload' => @payload,
+ 'merged' => @merged
}.to_json *a
end
#
+ # creates a Particle object from a JSON data
+ #
+ # @param [Hash] o belongs to JSON parser
+ #
def self.json_create o
raise Edoors::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
self.new o
end
#
- # called when released
+ # clears all attributes
+ #
+ # @see Spin#release_p called whe na Particle is released
+ #
def reset!
clear_merged! ( @src ? @src : ( @dst ? @dst : nil ) )
- @ts = @src = @dst = @room = @door = @action = @link_value = nil
+ @ts = @src = @dst = @room = @door = @action = nil
@dsts.clear
- @link_fields.clear
+ @link_value.clear
+ @link_keys.clear
@payload.clear
end
#
- # called when sent
+ # sets @src, @ts, and reset others
+ #
+ # @see Particle#apply_link! called when a Link is applied
+ # @see Door#_send called when a Door sends a Particle
+ #
def init! src
@src = src
@ts = Time.now
@dst = @room = @door = @action = nil
end
#
- attr_reader :ts, :src, :dst, :room, :door, :action, :link_value, :payload
+ attr_reader :ts, :src, :dst, :room, :door, :action, :payload, :link_value
#
- # routing
+ # returns the next destination
#
def next_dst
@dsts[0]
end
#
+ # clears the destination list
+ #
def clear_dsts!
@dsts.clear
end
#
- def add_dsts dsts
- dsts.split(Edoors::LINK_SEP).each do |dst|
- if dst.empty? or dst[0]==Edoors::PATH_SEP or dst[0]==Edoors::PATH_SEP or dst=~/\/\?/\
- or dst=~/\/{2,}/ or dst=~/\s+/ or dst==Edoors::ACT_SEP
+ # adds destinations to the destination list
+ #
+ # @param [Array] dsts destinations to add
+ #
+ # The parameters are checked before beeing added.
+ # they must not be empty or be '?' or start with '/'
+ # or contain '/?' or '//' or '\s+'
+ #
+ def add_dsts *dsts
+ dsts.each do |dst|
+ if dst.empty? or dst==Edoors::ACT_SEP or dst[0]==Edoors::PATH_SEP \
+ or dst=~/\/\?/ or dst=~/\/{2,}/ or dst=~/\s+/
raise Edoors::Exception.new "destination #{dst} is not acceptable"
end
@dsts << dst
end
end
#
+ # adds a destination to the destination list
+ #
+ # @param [String] a the action
+ # @param [String] d the destination
+ #
def add_dst a, d=''
add_dsts d+Edoors::ACT_SEP+a
end
#
+ # sets the current destination
+ #
+ # @param [String] a the action
+ # @param [String Iota] d the destination
+ #
def set_dst! a, d
@action = a
if d.is_a? Edoors::Iota
@@ -126,6 +188,11 @@ module Edoors
end
end
#
+ # splits the next destination into @room, @door, @action attributes
+ #
+ # the @dst attribute is set to nil
+ # the @room, @door, @action attributes are set to nil if not defined
+ #
def split_dst!
@dst = @room = @door = @action = nil
return if (n = next_dst).nil?
@@ -133,6 +200,10 @@ module Edoors
_split_path! p
end
#
+ # called by Particle#split_dst! to split the path part of the destination
+ #
+ # @param [String] p path to be splitted
+ #
def _split_path! p
i = p.rindex Edoors::PATH_SEP
if i.nil?
@@ -146,81 +217,147 @@ module Edoors
end
private :_split_path!
#
+ # sets the current destination and shift the head of destination list
+ #
+ # @param [Iota] dst the current destination
+ #
+ # @see Room#_route routing success
+ # @see Room#_send routing failure
+ #
def dst_routed! dst
@dst = dst
@dsts.shift
end
#
+ # sets the error message, the destination and action
+ #
+ # @param [String] e error message
+ # @param [Iota] dst the destination, @src if nil
+ #
+ # the error message is set into @payload[[Edoors::FIELD_ERROR_MSG]
+ #
def error! e, dst=nil
@action = Edoors::ACT_ERROR
@dst = dst||@src
@payload[Edoors::FIELD_ERROR_MSG]=e
end
#
+ # applies the effects of the given Link
+ #
+ # @param [Link] lnk the link to apply effects
+ #
+ # updates @src with Link @src, clears the destination list
+ # adds the Link destinations to @dsts, sets the @link_keys
+ #
def apply_link! lnk
init! lnk.door
clear_dsts!
- add_dsts lnk.dsts
- set_link_fields lnk.fields
+ add_dsts *lnk.dsts
+ set_link_keys *lnk.keys
end
#
- # data manipulation
+ # adds/updates a key value pair into payload
#
- def []= k, v
- @payload[k]=v
- compute_link_value! if @link_fields.include? k
- end
+ # @param [String] k the key
+ # @param [Object] v the value
+ #
+ # \@link_value attribute will be updated if impacted
#
- def set_data k, v
+ def []= k, v
+ @link_value[k] = v if @link_keys.include? k
@payload[k] = v
- compute_link_value! if @link_fields.include? k
end
+ alias :set_data :[]=
#
- def [] k
- @payload[k]
+ # destroys the value paired with a key
+ #
+ # @param [String] k the key
+ #
+ # @return the associated value
+ #
+ # \@link_value attribute will be updated if impacted
+ #
+ def del_data k
+ @link_value.delete k if @link_keys.include? k
+ @payload.delete k
end
#
- def get_data k
+ # retrieves a data value from a key
+ #
+ # @param [String] k the key
+ #
+ def [] k
@payload[k]
end
- alias :data :get_data
+ #
+ alias :get_data :[]
+ alias :data :[]
+ #
+ # clones the payload of the given Particle
+ #
+ # @param [Particle] p the Particle to clone the payload of
#
def clone_data p
@payload = p.payload.clone
end
#
- # link value and fields
+ # sets the links keys
+ #
+ # @param [Array] args list of keys to set
#
- def set_link_fields *args
- @link_fields.clear if not @link_fields.empty?
+ # \@link_value attribute will be updated
+ #
+ def set_link_keys *args
+ @link_keys.clear if not @link_keys.empty?
args.compact!
- args.each do |lfs|
- lfs.split(',').each do |lf|
- @link_fields << lf
- end
+ args.each do |lf|
+ @link_keys << lf
end
- compute_link_value!
+ @link_value = @payload.select { |k,v| @link_keys.include? k }
end
#
- def compute_link_value!
- @link_value = @link_fields.inject('') { |s,lf| s+=@payload[lf].to_s if @payload[lf]; s }
+ # tries to link the Particle with the given Link
+ #
+ # @param [Link] link the link to try to link with
+ #
+ # returns true if the value of the Link is nil
+ # otherwise checks if the extracted key values pairs from the Particle
+ # payload using the Link value keys as selectors, equals the Link value
+ #
+ # @return [Boolean] true if the Link links with the Particle
+ #
+ def link_with? link
+ return true if link.value.nil?
+ link.value.keys.inject({}) { |h,k| h[k]=@payload[k] if @payload.has_key?(k); h }.eql? link.value
end
#
- # merge particles management
+ # merges the given Particle in
+ #
+ # @param [Particle] p the Particle to merge in
#
def merge! p
@merged << p
end
#
+ # returns a merged Particle
+ #
+ # @param [Integer] i the index into the merged Particle list
+ #
def merged i
@merged[i]
end
#
+ # shifts the merged Particle list
+ #
def merged_shift
@merged.shift
end
#
- def clear_merged! r=nil
+ # recursively clears the merged Particle list
+ #
+ # @param [Boolean] r releases the cleared Particle if true
+ #
+ def clear_merged! r=false
@merged.each do |p|
p.clear_merged! r
r.release_p p if r