Class: EDI::Interchange

Inherits:
Collection_HT show all
Defined in:
lib/edi4r.rb,
lib/edi4r/rexml.rb

Overview

Base class of all interchanges

Direct Known Subclasses

E::Interchange

Instance Attribute Summary collapse

Attributes inherited from Collection_HT

#header, #trailer

Attributes inherited from Object

#name, #parent, #root

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Collection_HT

#empty?, #root=, #to_din16557_4, #to_s, #to_xml_header, #to_xml_trailer, #validate

Methods inherited from Collection

#==, #[], #each, #find_all, #first, #index, #inspect, #last, #length, #map, #names, #normalized_class_name, #root=, #size

Constructor Details

#initialize(user_par = nil) ⇒ Interchange

Abstract class - don't instantiate directly


446
447
448
449
450
# File 'lib/edi4r.rb', line 446

def initialize( user_par=nil )
  super( nil, self, 'Interchange' )
  @illegal_charset_pattern = /^$/ # Default: Never match a non-empty string
  @content = nil # nil if empty, :messages, or :groups
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class EDI::Collection

Instance Attribute Details

#illegal_charset_patternObject (readonly)

Returns the value of attribute illegal_charset_pattern


442
443
444
# File 'lib/edi4r.rb', line 442

def illegal_charset_pattern
  @illegal_charset_pattern
end

#output_modeObject

Returns the value of attribute output_mode


441
442
443
# File 'lib/edi4r.rb', line 441

def output_mode
  @output_mode
end

#syntaxObject (readonly)

Returns the value of attribute syntax


442
443
444
# File 'lib/edi4r.rb', line 442

def syntax
  @syntax
end

#versionObject (readonly)

Returns the value of attribute version


442
443
444
# File 'lib/edi4r.rb', line 442

def version
  @version
end

Class Method Details

.detect(hnd) ⇒ Object

Auto-detect the given file format & content, return format key

Convenience method, intended for internal use only


507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/edi4r.rb', line 507

def Interchange.detect( hnd ) # :nodoc:
  buf = hnd.read( 256 )  #
  # NOTE: "rewind" fails when applied to $stdin!
  # If you really need to read from $stdin, call Interchange::E::parse()
  # and Interchange::E::peek() etc. directly to bypass auto-detection

  hnd.rewind

  re  = /(<\?xml.*?)?DOCTYPE\s+Interchange.*?\<Interchange\s+.*?standard\_key\s*=\s*(['"])(.)\2/m
  case buf
  when /^(UNA......)?\r?\n?U[IN]B.UNO[A-Z].[1-4]/ then 'E'  # UN/EDIFACT
  when /^EDI_DC/ then 'I'  # SAP IDoc
  when re then 'X'+$3     # XML, Doctype = Interchange, syntax standard key (E, I, ...) postfix
  when /^\037\213/n then 'GZ' # gzip
  when /^\037\235/n then 'Z'  # compress
  when /^\037\036/ then 'z'  # pack
  when /^BZh[0-\377]/n then  'BZ' # bzip2
  else; "?? (stream starts with: #{buf[0..15]})"
  end
end

.parse(hnd, auto_validate = true) ⇒ Object

Auto-detect file content, optionally decompress, return an Interchange object of the sub-class that matches the (unzipped) content.

This is a convenience method. When you know the file contents, consider a direct call to Interchange::E::parse etc.

NOTES:

  • Make sure to require 'zlib' when applying this method to gzipped files.

  • BZIP2 is indirectly supported by calling “bzcat”. Make sure that “bzcat” is available when applying this method to *.bz2 files.

  • Do not pass $stdin to this method - we could not “rewind” it!


466
467
468
469
470
471
472
473
474
475
476
# File 'lib/edi4r.rb', line 466

def Interchange.parse( hnd, auto_validate=true )
  case rc=Interchange.detect( hnd )
  when 'BZ' then Interchange.parse( EDI::Bzip2Reader.new( hnd ) ) # see "peek"
  when 'GZ' then Interchange.parse( Zlib::GzipReader.new( hnd ) )
  when 'E'  then  EDI::E::Interchange.parse( hnd, auto_validate )
  when 'I'  then  EDI::I::Interchange.parse( hnd, auto_validate )
  when 'XE' then EDI::E::Interchange.parse_xml( REXML::Document.new(hnd) )
  when 'XI' then EDI::I::Interchange.parse_xml( REXML::Document.new(hnd) )
  else raise "#{rc}: Unsupported format key - don\'t know how to proceed!"
  end
end

.parse_xml(hnd) ⇒ Object

This is a dispatcher method for your convenience, similar to EDI::Interchange.parse. It may be used for all supported EDI standards.

hnd

A REXML document or something that can be turned into one, i.e. an IO object or a String object with corresponding contents

Returns an Interchange object of the subclass specified by the “standard_key” atribute of the root element, e.g. a EDI::E::Interchange.


99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/edi4r/rexml.rb', line 99

def Interchange.parse_xml( hnd ) # Handle to REXML document
  unless hnd.is_a? REXML::Document or hnd.is_a? IO or hnd.is_a? String
    raise "Unsupported object type: #{hnd.class}"
  end
  hnd = REXML::Document.new( hnd ) if hnd.is_a? IO or hnd.is_a? String

  key = hnd.root.attributes['standard_key']
  raise "Unsupported standard key: #{key}" if key == 'generic'
  EDI::const_get(key)::const_get('Interchange').parse_xml( hnd )#      class_sym = (key+'Interchange').intern
#      EDI::const_get(class_sym).parse_xml( hnd )

end

.peek(hnd = $stdin) ⇒ Object

Auto-detect file content, optionally decompress, return an empty Interchange object of that sub-class with only the header filled.

This is a convenience method. When you know the file contents, consider a direct call to Interchange::E::peek etc.

NOTES: See Interchange.parse


487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/edi4r.rb', line 487

def Interchange.peek( hnd=$stdin)
  case rc=Interchange.detect( hnd )    # Does not exist yet!
#      when 'BZ': Interchange.peek( Zlib::Bzip2Reader.new( hnd ) )
    # Temporary substitute, Unix/Linux only, low performance:

  when 'BZ' then Interchange.peek( EDI::Bzip2Reader.new( hnd ) )

  when 'GZ' then Interchange.peek( Zlib::GzipReader.new( hnd ) )
  when 'E'  then EDI::E::Interchange.peek( hnd )
  when 'I'  then EDI::I::Interchange.peek( hnd )
  when 'XE' then EDI::E::Interchange.peek_xml( REXML::Document.new(hnd) )
  when 'XI' then EDI::I::Interchange.peek_xml( REXML::Document.new(hnd) )
  else raise "#{rc}: Unsupported format key - don\'t know how to proceed!"
  end
end

Instance Method Details

#add(obj, auto_validate = true) ⇒ Object

Add either Message objects or MsgGroup objects to an interchange; mixing both types raises a TypeError.


547
548
549
550
551
552
553
554
555
556
557
558
559
560
# File 'lib/edi4r.rb', line 547

def add( obj, auto_validate=true )
  err_msg = "Added object must also be a "
  if obj.is_a? Message
    @content = :messages unless @content
    raise TypeError, err_msg+"'Message'" if @content != :messages
  elsif obj.is_a? MsgGroup
    @content = :groups unless @content
    raise TypeError, err_msg+"'MsgGroup'" if @content != :groups
  else
	raise TypeError, "Only Message or MsgGroup allowed here"
  end
  obj.validate if auto_validate
  super( obj )
end

#each_BCDS(id, &b) ⇒ Object

:nodoc:


535
536
537
538
539
540
541
# File 'lib/edi4r.rb', line 535

def each_BCDS(id, &b) # :nodoc:
  begin
    @basedata.each_BCDS(id, &b )
  rescue EDILookupError # NoMethodError
    raise "Lookup failure for BCDS entry id '#{id}'"
  end
end

#fmt_of_DE(id) ⇒ Object

:nodoc:


529
530
531
532
# File 'lib/edi4r.rb', line 529

def fmt_of_DE(id) # :nodoc:
  de = @basedata.de(id)
  de.nil? ? nil : de.format
end

#to_xml(xel_parent) ⇒ Object


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/edi4r/rexml.rb', line 113

def to_xml( xel_parent )
  externalID = "PUBLIC\n" + " "*9
  externalID += "'-//FH Wiesbaden FB DCSM//DTD XML Representation of EDI data V1.2//EN'\n"
  externalID += " "*9
  externalID += "'http://edi01.informatik.fh-wiesbaden.de/edi4r/edi4r-1.2.dtd'"
  xel_parent << REXML::XMLDecl.new
  xel_parent << REXML::DocType.new( normalized_class_name, externalID )

  rc = super

  xel = rc.first
  pos = self.class.to_s =~ /EDI::((.*?)::)?Interchange/
  raise "This is not an Interchange object: #{rc}!" unless pos==0
  xel.attributes["standard_key"] = ($2 and not $2.empty?) ? $2 : "generic"
  xel.attributes["version"] = @version
  xel.attributes.delete "name"
  rc
end