class EDI::Diagram::NodeInstance

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

new( diag ) click to toggle source

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

index() click to toggle source
# File lib/edi4r/diagrams.rb, line 490
def index;  node.index;  end
inst_cnt() click to toggle source

Returns the node’s instance counter

# File lib/edi4r/diagrams.rb, line 471
def inst_cnt
  @coord.inst_cnt
end
Also aliased as: rep
is_tnode?() click to toggle source

true if this is a TNode (trigger node/segment)

# File lib/edi4r/diagrams.rb, line 512
def is_tnode?
  node.is_a? TNode
end
level() click to toggle source

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
maxrep() click to toggle source
# File lib/edi4r/diagrams.rb, line 489
def maxrep; node.maxrep; end
name() click to toggle source

Delegate some getters to the underlying diagram node:

index, maxrep, name, status
# File lib/edi4r/diagrams.rb, line 487
def name;   node.name;   end
node() click to toggle source

Returns diagram node corresponding to this instance’s co-ordinates

# File lib/edi4r/diagrams.rb, line 480
def node
  @coord.branch[@coord.offset]
end
rep()
Alias for: inst_cnt
seek!(seg) click to toggle source

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:

  1. Search fails when trying to skip a required node

  2. Search fails if we hit the end of the diagram before a match

  3. 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
sg_name() click to toggle source

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
status() click to toggle source
# File lib/edi4r/diagrams.rb, line 488
def status; node.status; end

Protected Instance Methods

down!() click to toggle source

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!() click to toggle source

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
right!() click to toggle source

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
up!() click to toggle source

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