class EDI::Dir::Directory

A Directory object is currently a set of hashes representing all the entries for data elements, composites, segments, and messages.

Public Class Methods

caching?() click to toggle source

Tells if caching is currently activated (returns a boolean)

# File lib/edi4r/standards.rb, line 125
def Directory.caching?
  @@caching
end
caching_off() click to toggle source

As long as we employ plain CSV files to store directories, a Directory can become quite memory-consuming. Therefore Directorys are cached after creation, so that they need to be created and maintained only once when there are several messages of the same type in an interchange.

Turns off this caching mechanism, saving memory but costing time.

# File lib/edi4r/standards.rb, line 113
def Directory.caching_off
  @@caching = false
end
caching_on() click to toggle source

Turns on caching (default setting), saving time but costing memory.

# File lib/edi4r/standards.rb, line 119
def Directory.caching_on
  @@caching = true
end
create( std, params={} ) click to toggle source

Creates (and caches) a new directory. Returns reference to existing directory when already in cache.

std

The syntax standard key. Currently supported:

  • ‘A’ (ANSI X12),

  • ‘E’ (EDIFACT),

  • ‘I’ (SAP IDOC)

  • ‘S’ (SEDAS)

params

A hash of parameters that uniquely identify the selected dir. Hash parameters use following alternative key sets:

ISO9735

:d0002, :d0076 (default: “”, nil)

UN/TDID

:d0065, :d0052, :d0054, :d0051, :d0057; :is_iedi

SAP IDOC

:IDOCTYPE, :SAPTYPE, :EXTENSION (see EDI_DC fields)

SEDAS

(none so far)

UN/TDID: Elements of S009 or S320 are used:

d0065

Message type like “INVOIC”

d0052

Message version number, like “90” or “D”

d0054

Message release number, like “1” or “03A”

d0051

Controlling agency, like “UN” or “EN”

d0057

Association assigned code (optional), like “EAN008”

Interactive EDI (only limited supported so far):

is_iedi

Flag, true or false. Assumed false if missing.

# File lib/edi4r/standards.rb, line 163
def Directory.create( std, params={} )

  case std
  when 'A' # ANSI X12
    # par = { :ISA12 => '00401', :is_iedi => false }.update( params )
    par = { }.update( params )
  when 'E' # UN/EDIFACT
    par = {:d0051 => '',
           :d0057 => '',
           :is_iedi => false }.update( params )
  when 'I' # SAP IDocs
    par = { }.update( params )
  when 'S' # SEDAS
    par = { }.update( params )
  else
    raise "Unsupported syntax standard: #{std}"
  end

  if Directory.caching?

    # Use param set as key for caching
    #
    key = par.sort {|a,b| a.to_s <=> b.to_s}.hash
    obj = @@cache[key]
    # warn "Looking up  #{par.inspect} with key=#{key}"
    return obj unless obj.nil?

    obj = new( std, par )
    # warn "Caching for #{par.inspect} with key=#{key}"
    @@cache[key] = obj # cache & return it

  else
    new( std, par )
  end
end
flush_cache() click to toggle source

Releases memory by flushing the cache. Needed primarily for unit tests, where many if not all available diagrams are created.

# File lib/edi4r/standards.rb, line 132
def Directory.flush_cache
  @@cache = {}
end
path_finder( prefix, ext, selector ) click to toggle source

Helper method: Determine path of requested csv file

Will be generalized to a lookup scheme!

# File lib/edi4r/standards.rb, line 320
def Directory.path_finder( prefix, ext, selector )
  #
  # Subset requested:
  #  Try subset first, warn & fall back on standard before giving up
  #
  if prefix.is_a? Array
    raise "Only subset and regular prefix expected" if prefix.size != 2
    begin
      Directory.path_finder( prefix[0], ext, selector )
    rescue EDILookupError
      # warn "Subset data not found - falling back on standard"
      # $stderr.puts prefix.inspect, ext.inspect, selector.inspect
      Directory.path_finder( prefix[1], ext, selector )
    end
  else
    filename = prefix + selector + '.' + ext
    searchpath = ENV['EDI_NDB_PATH']

    searchpath.split(/#{File::PATH_SEPARATOR}/).each do |datadir|
      path = datadir + filename
      # warn "Looking for #{path}"
      return path if File.readable? path
    end
    raise EDILookupError, "No readable file '." + filename + "' found below any dir on '" + searchpath + "'"
  end
end
prefix_ext_finder( std, par ) click to toggle source

Helper method: Derive path fragments of CSV files from parameters

# File lib/edi4r/standards.rb, line 202
def Directory.prefix_ext_finder( std, par )
  ext = ''
  case std

  when 'I' # SAP IDocs
    prefix = '/sap'
    if par[:IDOCTYPE]
      prefix += '/idocs'+par[:SAPTYPE]+'/'+par[:IDOCTYPE]+'/'
      if par[:EXTENSION].is_a? String and not par[:EXTENSION].empty?
        if par[:EXTENSION] =~ /\/(.*\/)([^\/]+)/
          prefix += $1 + 'ED'
          ext = $2 + '.csv'
        else
          prefix += 'ED'
          ext = par[:EXTENSION] + '.csv'
        end              
      else
        prefix += 'ED'
        ext = '.csv'
      end              
    else
      case par[:SAPTYPE]
      when '40'; ext = '04000'
      else ; raise "Unsupported SAP Type: #{par[:SAPTYPE]}"
      end
      prefix += '/controls/SD'
      ext += '.csv'
    end

  when 'E' # UN/EDIFACT
    prefix, subset_prefix = '/edifact', nil
    if par[:d0002] # ISO9735 requested?
      case par[:d0002]
      when 1
        ext = '10000'
      when 2
        ext = '20000'
      when 3
        ext = '30000'
      when 4
        # Assume that any setting of d0076 implies SV 4-1
        # Revise when SV 4-2 arrives!
        ext = (par[:d0076] == nil) ? '40000' : '40100'
      else
        raise "Invalid syntax version: #{par[:d0002]}"
      end
      prefix += '/iso9735/SD'
      ext += '.csv'

    # Service messages? (AUTACK, CONTRL, KEYMAN): 2/2, D/3, 4/1 ok
    elsif %w/2 D 4/.include?(par[:d0052]) && %w/2 3 1/.include?(par[:d0054])
      if par[:d0052] == '2' && par[:d0054] == '2'
        ext = '20000'
      elsif par[:d0052] == 'D' && par[:d0054] == '3'
        ext = '30000'
      elsif par[:d0052] == '4' && par[:d0054] == '1'
        ext = (par[:d0076] == nil) ? '40000' : '40100'
      else
        raise "Invalid syntax version: #{par[:d0002]}"
      end
      prefix += '/iso9735/SD'
      ext += '.csv'

    else          # UN/TDID requested?
      prefix += par[:is_iedi] ? '/untdid/ID' : '/untdid/ED'
      ext = (par[:d0052].to_s+par[:d0054].to_s).downcase + '.csv'
      case par[:d0057]
      when /EAN\d\d\d/, /EDIT\d\d/
        subset_prefix = '/edifact/eancom/ED'
      when '', nil
      else
        # raise "Subset not supported: #{par[:d0057]}"
        EDI::logger.warn "Subset not supported: #{par[:d0057]}"
      end
    end
  when 'S' # SEDAS
    prefix, subset_prefix, ext = '/sedas/ED', nil, '.csv'

  when 'A' # ANSI X12
    prefix, subset_prefix = '/ansi', nil
    if par[:ISA12] # control segments requested?
      msg = "Syntax version not supported: #{par[:ISA12]}"
      case par[:ISA12]
      when /00[1-5]0\d/ # , '00401', '00501' etc.
        EDI::logger.warn msg if par[:ISA12] !~ /^00[45]01$/
        ext = par[:ISA12]
      else
        raise msg
      end
      prefix += '/x12/SD'
      ext += '.csv'

    else          # Standards directory requested?
      prefix += '/dir/ED'
      ext = par[:GS08][0,6] + '.csv' # Subset not supported
      case par[:GS08][6..-1]
      when 'X098', 'X098A1', 'X096A1', 'X093', 'X092', 'X091A1', 'X222A1', 'X223A2', /^X2\d\d(A[12])?/
        # Conceivable support of a major subset (like HIPAA)
        # subset_prefix = '/ansi/hipaa/ED'
      when '', nil
      else
        raise "Subset not supported: <<#{par[:GS08][6..-1]}>>"
      end
    end

  else
    raise "Unsupported syntax standard: #{std}"
  end

  return prefix, subset_prefix, ext
end

Public Instance Methods

cde( name ) click to toggle source

Returns CSV line for CDE called name.

# File lib/edi4r/standards.rb, line 446
def cde( name )
  @cde_dir[name]
end
cde_names() click to toggle source

Returns a sorted list of names of available CDE

# File lib/edi4r/standards.rb, line 452
def cde_names
  @cde_dir.keys.sort
end
de( name ) click to toggle source

Returns CSV line for DE called name. If name is a Regexp, returns the first match or nil.

# File lib/edi4r/standards.rb, line 429
def de( name )
  if name.is_a? Regexp
    @de_dir[ @de_dir.keys.find {|key| key =~ name} ]
  else
    @de_dir[name]
  end
end
de_names() click to toggle source

Returns a sorted list of names of available DE

# File lib/edi4r/standards.rb, line 439
def de_names
  @de_dir.keys.sort
end
each_BCDS( id, &b ) click to toggle source

Iterates over each branch (message), composite, data element, or segment found (hence: BCDS) that is matched by id.

id is a string. The object type requested by this string is not obvious. This method determines it through a naming convention. See source for details.

Fails with EDI::EDILookupError when nothing found.

# File lib/edi4r/standards.rb, line 506
def each_BCDS( id, &b )
  list = nil
  case id
  when /^[CES]\d{3}$/     # C)omposite
    list = cde(id)

  when /^\d{4}$/          # Simple D)E
    list = de(id)

  when /^[A-Z]{3}$/       # S)egment
    list = segment(id)

  when /^[A-Z]{6}:$/      # Message B)ranch
    list = message(id)

    # Workaround for the IDoc case:
    # We identify entry type by a (intermediate) prefix
    #
  when /^d(.*)$/          # Simple D)E
    list = de($1)

  when /^s(.*)$/          # S)egment, SAP IDOC
    list = segment($1)

  when /^m(.*)$/          # Message B)ranch
    list = message($1)

  else                    # Should never occur
    raise IndexError, "Not a legal BCDS entry id: '#{id}'"
  end

  raise EDILookupError, "#{id} not in directory!" if list.nil?
  list.each( &b )
end
message( name ) click to toggle source

Returns CSV line of top branch for message called name.

# File lib/edi4r/standards.rb, line 477
def message( name ) # Actually, only one branch!
  # p name
  # p @msg_dir# [name]
  rc = @msg_dir[name]
  return rc unless rc.nil?
  # Try without subset if nil:
  # ex.: CONTRL:D:3:UN:1.3c:SG1, CONTRL:D:3:UN::
  return nil unless name =~ /(.*:)([^:]{1,6})(:[^:]*)/
  EDI::logger.warn "Subset not supported: #$2 - falling back on standard}" if $3==':' # warn only at top branch
  # $stderr.puts "Using fallback name: #{$1+$3}"
  @msg_dir[$1+$3]
end
message_names() click to toggle source

Returns a sorted list of names of available messages

# File lib/edi4r/standards.rb, line 492
def message_names
  @msg_dir.keys.sort
end
segment( name ) click to toggle source

Returns CSV line for segment called name. If name is a Regexp, returns the first match or nil.

# File lib/edi4r/standards.rb, line 460
def segment( name )
  if name.is_a? Regexp
    @seg_dir[ @seg_dir.keys.find {|key| key =~ name} ]
  else
    @seg_dir[name]
  end
end
segment_names() click to toggle source

Returns a sorted list of names of available segments

# File lib/edi4r/standards.rb, line 470
def segment_names
  @seg_dir.keys.sort
end