class EDI::A::Interchange

Interchange: Class of the top-level objects of ANSI X12 data

Attributes

ce_sep[R]
de_sep[R]
groups_created[R]
re_ce_sep[R]
re_de_sep[R]
rep_sep[R]
seg_term[R]

Public Class Methods

new( user_par={} ) click to toggle source

Create an empty ANSI X.12 interchange

Supported parameters (passed hash-style):

Essentials, should not be changed later

:charset

Not applicable, do not use. Default = ‘UNOB’

:version

Sets I11 (ISA12), default = ‘00401’

Optional parameters affecting to_s, with corresponding setters

:output_mode

See setter output_mode=(), default = :verbatim

:ce_sep

Component element separator, default = ?\

:de_sep

Data element separator, default = ?*

:rep_sep

Repetition element separator, default = ?^ (version 5)

:seg_term

Segment terminator, default = ?~

Optional ISA presets for your convenience, may be changed later

:sender

Presets DE I07, default = nil

:recipient

Presets DE I09, default = nil

:interchange_control_reference

Presets DE I12, default = ‘1’

:interchange_control_standards_id

Presets DE I10, default = ‘U’

:acknowledgment_request

Presets DE I13, default = 0

:test_indicator

Presets DE I14, default = ‘P’

Notes

  • Date (I08) and time (I09) are set to the current values automatically.

  • Add or change any data element later.

Examples:

Calls superclass method EDI::Interchange::new
# File lib/edi4r/ansi_x12.rb, line 95
def initialize( user_par={} )
  super( user_par ) # just in case...
  if (illegal_keys = user_par.keys - @@interchange_default_keys) != []
    msg = "Illegal parameter(s) found: #{illegal_keys.join(', ')}\n"
    msg += "Valid param keys (symbols): #{@@interchange_default_keys.join(', ')}"
    raise ArgumentError, msg
  end
  par = @@interchange_defaults.merge( user_par )

  @groups_created = 0

  @syntax = 'A' # par[:syntax]      # A = ANSI X12
  @charset = par[:charset] # FIXME: Outdated?

  @version = par[:version]

  @ce_sep  = par[:ce_sep]
  @re_ce_sep = Regexp.new( Regexp.escape( @ce_sep.chr ) )
  @de_sep  = par[:de_sep]
  @re_de_sep = Regexp.new( Regexp.escape( @de_sep.chr ) )
  @rep_sep = par[:rep_sep]
  @seg_term = par[:seg_term]

  self.output_mode = par[:output_mode]

  check_consistencies
  init_ndb( @version )

  @header = new_segment('ISA')
  @trailer = new_segment('IEA')
  #@header.cS001.d0001 = par[:charset]

  @header.dI06 = par[:sender] unless par[:sender].nil?
  @header.dI07 = par[:recipient] unless par[:recip].nil?

  @header.dI10 = par[:interchange_control_standards_id]
  @header.dI11 = par[:version]
  @header.dI12 = par[:interchange_control_reference]
  @header.dI13 = par[:acknowledgment_request]
  @header.dI14 = par[:test_indicator]
  @header.dI15 = @ce_sep

  t = Time.now
  @header.dI08 = t.strftime('%y%m%d')
  @header.dI09 = t.strftime('%H%M')

  @trailer.dI16 = 0
end
parse( hnd=$stdin, auto_validate=true ) click to toggle source

Reads EDI data from given stream (default: $stdin), parses it and returns an Interchange object

# File lib/edi4r/ansi_x12.rb, line 148
def Interchange.parse( hnd=$stdin, auto_validate=true )
  builder = StreamingBuilder.new( auto_validate )
  builder.go( hnd )
  builder.interchange
end
parse_xml( xdoc ) click to toggle source

Returns a REXML document that represents the interchange

xdoc

REXML document that contains the XML representation of a ANSI X12 interchange

# File lib/edi4r/ansi_x12-rexml.rb, line 29
def Interchange.parse_xml( xdoc )
  _root = xdoc.root
  _header  = _root.elements["Header"]
  _trailer = _root.elements["Trailer"]
  _version = _root.attributes["version"]
  _ce_sep = REXML::XPath.first(xdoc, "/Interchange/Header/Segment/DE[@name='I15']").text.to_i
  params = { :ce_sep => _ce_sep, :version => _version }
  ic = Interchange.new( params )
  if _root.elements["Message"].nil? # correct ??
    _root.elements.each('MsgGroup') do |xel|
      ic.add( MsgGroup.parse_xml( ic, xel ), false )
    end
  else
    _root.elements.each('Message') do |xel|
      ic.add( Message.parse_xml( ic, xel ), false )
    end
  end

  ic.header  = Segment.parse_xml( ic, _header.elements["Segment"] )
  ic.header.dI15 = _ce_sep
  ic.trailer = Segment.parse_xml( ic, _trailer.elements["Segment"] )
  ic.validate
  ic
end
peek(hnd=$stdin, params={}) click to toggle source

Read maxlen bytes from $stdin (default) or from given stream (ANSI data expected), and peek into first segment (ISA).

Returns an empty Interchange object with a properly header filled.

Intended use:

Efficient routing by reading just ISA data: sender/recipient/ref/test
# File lib/edi4r/ansi_x12.rb, line 163
def Interchange.peek(hnd=$stdin, params={}) # Handle to input stream
  builder = StreamingBuilder.new( false )
  if params[:deep_peek]
    def builder.on_segment( s, tag )
    end
  else
    def builder.on_gs( s )
      throw :done
    end
    def builder.on_st( s, tag )
      throw :done  # FIXME: Redundant, since GS must occur?
    end
  end
  builder.go( hnd )
  builder.interchange
end
peek_xml(xdoc) click to toggle source

Read maxlen bytes from $stdin (default) or from given stream (ANSI X12 data expected), and peek into first segment (ISA).

Returns an empty Interchange object with a properly header filled.

Intended use:

Efficient routing by reading just ISA data: sender/recipient/ref/test
# File lib/edi4r/ansi_x12-rexml.rb, line 63
def Interchange.peek_xml(xdoc) # Handle to REXML document
  _root = xdoc.root
  _header  = _root.elements["Header"]
  _trailer = _root.elements["Trailer"]
  _version = _root.attributes["version"]
  _ce_sep = REXML::XPath.first(xdoc, "/Interchange/Header/Segment/DE[@name='I15']").text.to_i
  params = { :ce_sep => _ce_sep, :version => _version }
  ic = Interchange.new( params )

  ic.header  = Segment.parse_xml( ic, _header.elements["Segment"] )
  ic.header.dI15 = _ce_sep
  ic.trailer = Segment.parse_xml( ic, _trailer.elements["Segment"] )

  ic
end

Public Instance Methods

add( obj, auto_validate=true ) click to toggle source

Add a MsgGroup (Functional Group) object to the interchange.

GE counter is automatically incremented.

Calls superclass method EDI::Interchange#add
# File lib/edi4r/ansi_x12.rb, line 215
def add( obj, auto_validate=true )
  super
  @trailer.dI16 += 1 #if @trailer
  # FIXME: Warn/fail if ST id is not unique (at validation?)
end
inspect( indent='', symlist=[] ) click to toggle source

Yields a readable, properly indented list of all contained objects, including the empty ones. This may be a very long string!

Calls superclass method EDI::Collection#inspect
# File lib/edi4r/ansi_x12.rb, line 270
def inspect( indent='', symlist=[] )
  # symlist << :una
  super
end
new_msggroup(params={}) click to toggle source

Derive an empty message group from this interchange context. Parameters may be passed hash-like. See MsgGroup.new for details

# File lib/edi4r/ansi_x12.rb, line 225
def new_msggroup(params={}) # to be completed ...
  @groups_created += 1
  MsgGroup.new(self, params)
end
output_mode=( value ) click to toggle source

This method modifies the behaviour of method to_s(): ANSI X12 interchanges and their components are turned into strings either “verbatim” (default) or in some more readable way. This method corresponds to a parameter with the same name that may be set at creation time.

Valid values:

:linebreak

One-segment-per-line representation

:indented

Like :linebreak but with additional indentation (2 blanks per hierarchy level).

:verbatim

No linebreak (default), ISO compliant

Calls superclass method
# File lib/edi4r/ansi_x12.rb, line 194
def output_mode=( value )
  super( value )
  @e_linebreak = @e_indent = ''
  case value
  when :verbatim
    # NOP (default)
  when :linebreak
    @e_linebreak = "\n"
  when :indented
    @e_linebreak = "\n"
    @e_indent = '  '
  else
    raise "Unknown output mode '#{value}'. Supported modes: :linebreak, :indented, :verbatim (default)"
  end
end
to_s() click to toggle source

Returns the string representation of the interchange.

Type conversion and escaping are provided. See output_mode for modifiers.

Calls superclass method EDI::Collection_HT#to_s
# File lib/edi4r/ansi_x12.rb, line 260
def to_s
  s = ''
  postfix = '' << seg_term << @e_linebreak
  s << super( postfix )
end
to_xml( xdoc = REXML::Document.new ) click to toggle source

Returns a REXML document that represents the interchange

Calls superclass method EDI::Interchange#to_xml
# File lib/edi4r/ansi_x12-rexml.rb, line 82
    def to_xml( xdoc = REXML::Document.new )
      rc = super
      # Add parameter(s) to header in rc[1]
#      rc
      xdoc
    end
validate( err_count=0 ) click to toggle source

Returns the number of warnings found and logs them

Calls superclass method EDI::Collection_HT#validate
# File lib/edi4r/ansi_x12.rb, line 278
def validate( err_count=0 )
  if (h=self.size) != (t=@trailer.dI16)
    EDI::logger.warn "Counter IEA, DE I16 does not match content: #{t} vs. #{h}"
    EDI::logger.warn "classes: #{t.class} vs. #{h.class}"
    err_count += 1
  end
  #if (h=@header.cS001.d0001) != @charset
  #  warn "Charset UNZ/UIZ, S001/0001 mismatch: #{h} vs. #@charset"
  #  err_count += 1
  #end
  if (h=@header.dI11) != @version
    EDI::logger.warn "Syntax version number ISA, ISA12 mismatch: #{h} vs. #@version"
    err_count += 1
  end
  check_consistencies

  if (t=@trailer.dI12) != (h=@header.dI12)
    EDI::logger.warn "ISA/IEA mismatch in refno (I12): #{h} vs. #{t}"
    err_count += 1
  end

  # FIXME: Check if messages/groups are uniquely numbered

  super
end

Private Instance Methods

check_consistencies() click to toggle source

Private method: Check if basic UNB elements are set properly

# File lib/edi4r/ansi_x12.rb, line 317
    def check_consistencies
      # FIXME - @syntax should be completely avoided, use sub-module name
      if not ['A'].include?(@syntax) # More anticipated here
        raise "#{@syntax} - syntax not supported!"
      end
=begin
      case @version
      when 1
        if @charset != 'UNOA'
          raise "Syntax version 1 permits only charset UNOA!"
        end
      when 2
        if not @charset =~ /UNO[AB]/
          raise "Syntax version 2 permits only charsets UNOA, UNOB!"
        end
      when 3
        if not @charset =~ /UNO[A-F]/
          raise "Syntax version 3 permits only charsets UNOA...UNOF!"
        end
      when 4
        # A,B: ISO 646 subsets, C-K: ISO-8859-x, X: ISO 2022, Y: ISO 10646-1
        if not @charset =~ /UNO[A-KXY]/
          raise "Syntax version 4 permits only charsets UNOA...UNOZ!"
        end
      else
        raise "#{@version} - no such syntax version!"
      end
=end
      @illegal_charset_pattern = Illegal_Charset_Patterns['@version']
      # Add more rules ...
    end
init_ndb(d0002, d0076 = nil) click to toggle source

Private method: Loads EDI norm database

# File lib/edi4r/ansi_x12.rb, line 309
def init_ndb(d0002, d0076 = nil)
  @basedata = EDI::Dir::Directory.create(root.syntax,
                                         :ISA12   => @version )
end