Class: EDI::Dir::Directory

Inherits:
Object
  • Object
show all
Defined in:
lib/edi4r/standards.rb

Overview

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

Constant Summary collapse

@@cache =

Some ingredients for Directory caching:

{}
@@caching =
true

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(std, par) ⇒ Directory

see Directory.create


267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/edi4r/standards.rb', line 267

def initialize ( std, par ) # :nodoc:

  prefix, ext = Directory.prefix_ext_finder( std, par )

  # Build DE directory

  prefix_ed = prefix.sub(/ID$/, 'ED') # There is no IDED.*.csv!
  csvFileName = Directory.path_finder(prefix_ed, ext, 'ED' )
  @de_dir = Hash.new
  IO.foreach(csvFileName) do |line|
    d = DE_Properties.new
    d.name, d.format, d.dummy, d.description = line.strip.split(/;/)
    $stderr.puts "ERR DE line", line if d.description.nil?
    @de_dir[d.name] = d 
  end

  # Build CDE directory

  csvFileName = Directory.path_finder(prefix, ext, 'CD' )
  @cde_dir = Hash.new
  IO.foreach(csvFileName) do |line|
    c = Named_list.new
    c.name, c.desc, list = line.split(/;/, 3)
    $stderr.puts "ERR CDE line", line if list.nil?
    list.sub(/;\s*$/,'').split(/;/).each_slice(4) do |item, code, status, fmt|
      $stderr.puts "ERR CDE list", line if fmt.nil?
      c << BCDS_entry.new( item, code, status, 1 )
    end
    @cde_dir[c.name] = c
  end

  # Build Segment directory

  csvFileName = Directory.path_finder(prefix, ext, 'SD' )
  @seg_dir = Hash.new
  IO.foreach(csvFileName) do |line|
    c = Named_list.new
    c.name, c.desc, list = line.split(/;/, 3)
    $stderr.puts "ERR SEG line", line if list.nil?
    list.sub(/;\s*$/,'').split(/;/).each_slice(4) do |item, code, status, maxrep|
      $stderr.puts "ERR SEG list", line if maxrep.nil?
      c << BCDS_entry.new( item, code, status, maxrep.to_i )
    end
    @seg_dir[c.name] = c
  end

  # Build Message directory
  
  csvFileName = Directory.path_finder(prefix, ext, 'MD' )
  @msg_dir = Hash.new
  re = if par[:d0065] and par[:d0065] =~ /([A-Z]{6})/ 
       then Regexp.new($1) else nil end
  IO.foreach(csvFileName) do |line|
    next if re and line !~ re # Only lines matching message type if given
    c = Named_list.new
    c.name, c.desc, list = line.split(/;/, 3)
    $stderr.puts "ERR MSG line", line if list.nil?
    list.sub(/;\s*$/,'').split(/;/).each_slice(3) do |code, status, maxrep|
      $stderr.puts "ERR MSG list", line if maxrep.nil?
      c << BCDS_entry.new( "0000", code, status, maxrep.to_i )
    end
    @msg_dir[c.name] = c
  end
end

Class Method Details

.caching?Boolean

Tells if caching is currently activated (returns a boolean)

Returns:

  • (Boolean)

119
120
121
# File 'lib/edi4r/standards.rb', line 119

def Directory.caching?
  @@caching
end

.caching_offObject

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 areeseveral messages of the same type in an interchange.

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


107
108
109
# File 'lib/edi4r/standards.rb', line 107

def Directory.caching_off
  @@caching = false
end

.caching_onObject

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


113
114
115
# File 'lib/edi4r/standards.rb', line 113

def Directory.caching_on
  @@caching = true
end

.create(std, params) ⇒ Object

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

std

The syntax standard key. Currently supported:

  • 'E' (EDIFACT),

  • 'I' (SAP IDOC)

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)

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.


154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/edi4r/standards.rb', line 154

def Directory.create( std, params )

  case std
  when 'E' # UN/EDIFACT
    par = {:d0051 => '', 
           :d0057 => '',
           :is_iedi => false }.update( params )
  when 'I' # SAP IDocs
    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]
    return obj unless obj.nil?

    obj = new( std, par )
    @@cache[key] = obj # cache & return it

  else
    new( std, par )
  end
end

.flush_cacheObject

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


126
127
128
# File 'lib/edi4r/standards.rb', line 126

def Directory.flush_cache
  @@cache = {}
end

.path_finder(prefix, ext, selector) ⇒ Object

Helper method: Determine path of requested csv file

Will be generalized to a lookup scheme!


253
254
255
256
257
258
259
260
261
262
# File 'lib/edi4r/standards.rb', line 253

def Directory.path_finder( prefix, ext, selector )
  filename = prefix + selector + '.' + ext
  searchpath = ENV['EDI_NDB_PATH']

  searchpath.split(/#{File::PATH_SEPARATOR}/).each do |datadir|
    path = datadir + filename
    return path if File.readable? path
  end
  raise "No readable file '." + filename + "' found below any dir on '" + searchpath + "'"
end

.prefix_ext_finder(std, par) ⇒ Object

Helper method: Derive path fragments of CSV files from parameters


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/edi4r/standards.rb', line 186

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 = '/edifact' 
    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'

    else		# UN/TDID requested?
      prefix += par[:is_iedi] ? '/untdid/ID' : '/untdid/ED'
      ext = (par[:d0052]+par[:d0054]).downcase + '.csv'
    end

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

  return prefix, ext
end

Instance Method Details

#cde(name) ⇒ Object

Returns CSV line for CDE called name.


353
354
355
# File 'lib/edi4r/standards.rb', line 353

def cde( name )
  @cde_dir[name]
end

#cde_namesObject

Returns a sorted list of names of available CDE


359
360
361
# File 'lib/edi4r/standards.rb', line 359

def cde_names
  @cde_dir.keys.sort
end

#de(name) ⇒ Object

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


336
337
338
339
340
341
342
# File 'lib/edi4r/standards.rb', line 336

def de( name )
  if name.is_a? Regexp
    @de_dir[ @de_dir.keys.find {|key| key =~ name} ]
  else
    @de_dir[name]
  end
end

#de_namesObject

Returns a sorted list of names of available DE


346
347
348
# File 'lib/edi4r/standards.rb', line 346

def de_names
  @de_dir.keys.sort
end

#each_BCDS(id, &b) ⇒ Object

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.

Raises:


405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/edi4r/standards.rb', line 405

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) ⇒ Object

Returns CSV line of top branch for message called name.


384
385
386
387
# File 'lib/edi4r/standards.rb', line 384

def message( name ) # Actually, only one branch!
#        $stderr.puts name
  @msg_dir[name]
end

#message_namesObject

Returns a sorted list of names of available messages


391
392
393
# File 'lib/edi4r/standards.rb', line 391

def message_names
  @msg_dir.keys.sort
end

#segment(name) ⇒ Object

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


367
368
369
370
371
372
373
# File 'lib/edi4r/standards.rb', line 367

def segment( name )
  if name.is_a? Regexp
    @seg_dir[ @seg_dir.keys.find {|key| key =~ name} ]
  else
    @seg_dir[name]
  end
end

#segment_namesObject

Returns a sorted list of names of available segments


377
378
379
# File 'lib/edi4r/standards.rb', line 377

def segment_names
  @seg_dir.keys.sort
end