class EDI::Diagram::NodeInstance
A
given segment of a real message instance needs an instance counter in addition to its location in the diagram. This applies recursively to all segment groups in which it is embedded. This class is equipped with the additional attributes (“co-ordinates”) of node instances.
We also use this class to determine the node instance of a segment when parsing a message. This is done in a sequential manner, starting from the current instance, by following the diagram branches up to the next matching segment tag/name.
Public Class Methods
A
new NodeInstance
is inititialized to a “virtual” 0th node before the first real node of the diagramm referenced by diag
.
# File lib/edi4r/diagrams.rb, line 460 def initialize( diag ) @diag = diag # Really needed later? # Init. to first segment of top branch, e.g. "UNH" or "EDI_DC40" @coord = NodeCoords.new(diag.branch, 0, 0) @coord_stack = [] @down_flag = false end
Public Instance Methods
# File lib/edi4r/diagrams.rb, line 490 def index; node.index; end
Returns the node’s instance counter
# File lib/edi4r/diagrams.rb, line 471 def inst_cnt @coord.inst_cnt end
true
if this is a TNode
(trigger node/segment)
# File lib/edi4r/diagrams.rb, line 512 def is_tnode? node.is_a? TNode end
Returns this node instance’s level in the diagram. Note that special UN/EDIFACT rules about level 0 are acknowledged: level == 0 for mandatory SNode
instances of the main branch with maxrep==1.
# File lib/edi4r/diagrams.rb, line 495 def level depth = @coord_stack.length+1 return 0 if depth == 1 and node.maxrep == 1 and node.required? and not is_tnode? # Special Level 0 case depth # Else: Level is depth of segment group stack + 1 (1 if no SG) end
# File lib/edi4r/diagrams.rb, line 489 def maxrep; node.maxrep; end
Delegate some getters to the underlying diagram node:
index, maxrep, name, status
# File lib/edi4r/diagrams.rb, line 487 def name; node.name; end
Returns diagram node corresponding to this instance’s co-ordinates
# File lib/edi4r/diagrams.rb, line 480 def node @coord.branch[@coord.offset] end
Main “workhorse”: Seek for next matching segment tag/name
Starts at current location, follows the diagram downstream while searching for next matching segment.
Returns updated location (self) when found, nil otherwise.
Notes:
-
Search fails when trying to skip a required node
-
Search fails if we hit the end of the diagram before a match
-
We might need to loop through segment groups repeatedly!
# File lib/edi4r/diagrams.rb, line 529 def seek!(seg) # Segment, Regexp or String expected name = (seg.is_a? EDI::Segment) ? seg.name : seg # name = (seg.is_a? String) ? seg : seg.name begin node = self.node # warn "Looking for #{name} in #{self.name} @ level #{self.level} while node.maxrep=#{node.maxrep}..." # # Case "match" # if node.nil? warn "#{name}: #{@coord.offset} #{@coord.branch.sg_name} #{@coord.branch.desc} #{@coord.branch.size}" raise "#{self}: no node!" end if name === node.name # == name # puts "match!" @coord.inst_cnt += 1 msg = "Segment #{name} at #{@coord.to_s}: More than #{node.maxrep}!" if @coord.inst_cnt > node.maxrep raise EDI::EDILookupError, msg else @down_flag = true if node.is_a? TNode return self# .node end end # # Missed a required node? # if node.required? and @coord.inst_cnt == 0 # @unmatched msg = "Missing required segment #{node.name} at #{@coord.to_s}\n" + \ " while looking for segment #{name}!" raise EDI::EDILookupError, msg end # puts end while self.next! # Already at top level - Error condition! raise "End of diagram exceeded!" end
Returns the branch name (segment group name)
# File lib/edi4r/diagrams.rb, line 503 def sg_name # (node.is_a? TNode) ? node.sg_name : nil if node.is_a? TNode return node.sg_name end @coord.branch.sg_name end
# File lib/edi4r/diagrams.rb, line 488 def status; node.status; end
Protected Instance Methods
Move to the first node of the tail branch of this TNode
. Returns self
, or nil
if there is no tail node.
# File lib/edi4r/diagrams.rb, line 593 def down! this_node = self.node return nil if (tail=this_node.tail).nil? or tail.empty? # Save current co-ordinates on stack @coord_stack.push( @coord ) # Init. co-ordinates for the new level: @coord = NodeCoords.new(tail, 0, 0) self end
Next: Move down if TNode
and same as last match (another SG instance), else right. Move up if neither possible. Returns self
, or nil
if end of diag encountered.
# File lib/edi4r/diagrams.rb, line 607 def next! loop do node = self.node; r = nil if node.is_a? TNode and @down_flag @down_flag = false r = self.down! end break if r # Down not applicable or available; now try "right!" break if r = self.right! # At end of this branch - try to move up: break if r = self.up! # Already at top level! return nil end self end
Move to the right of the current node in this branch. Returns self
, or nil
if already at the branch end.
# File lib/edi4r/diagrams.rb, line 583 def right! return nil if @coord.offset+1 == @coord.branch.size @coord.offset += 1 @coord.inst_cnt = 0 self end
Move “up” to the TNode
of this branch. Returns self
, or nil
if already at the top.
# File lib/edi4r/diagrams.rb, line 574 def up! return nil if @coord_stack.empty? @coord = @coord_stack.pop self end