class EDI::A::DE

Class EDI::A::DE

This class implements ANSI X12 data elements 1004, 2005 etc., including the service DEs I01, …, I16

For internal use only.

Public Class Methods

new( p, name, status, fmt ) click to toggle source
Calls superclass method EDI::DE::new
# File lib/edi4r/ansi_x12.rb, line 1051
def initialize( p, name, status, fmt )
  super( p, name, status, fmt )
  raise "Illegal DE name: #{name}" unless name =~ /\d{1,4}/
    # check if supported format syntax
    # check if supported status value
end

Public Instance Methods

parse( buf, already_escaped=false ) click to toggle source

Generate the DE content from the given string representation. buf contains a single DE string

# File lib/edi4r/ansi_x12.rb, line 1062
    def parse( buf, already_escaped=false ) # 2nd par is a dummy for X12
      return nil unless buf
      return @value = nil if buf.empty?
      self.value = buf
#      if format[0] == ?n
#        # Select appropriate Numeric, FIXME: Also match exponents!
#        self.value = @value=~/\d+\.\d+/ ? @value.to_f : @value.to_i
#      end
      @value
    end
to_s( no_escape=false ) click to toggle source
# File lib/edi4r/ansi_x12.rb, line 1074
def to_s( no_escape=false ) # Parameter is a dummy for X12
  location = "DE #{parent.name}/#{@name}"
  if @format =~ /^(AN|B|DT|ID|N\d+?|R|TM|XX) (\d+)\/(\d+)$/
    _type, min_size, max_size = $1, $2.to_i, $3.to_i
  else
    raise "#{location}: Illegal format #{format}"
  end
  case _type
  when 'AN', 'ID', 'DT', 'TM'
    if empty? then return( required?  ? ' '* min_size : '' ) end
    str = @value.to_s; fixlen = str.length
    return @value.to_s[0,max_size] if fixlen > max_size # Truncate if too long
    fixlen < min_size ? str + ' ' * (min_size - fixlen) : str # Right-pad with blanks if too short
  when /N(\d+)/
    x = @value.to_f
    $1.to_i.times { x *= 10 }
    str = (x+0.0001).to_i.to_s; fixlen = str.length
    raise "#{location}: '#{value}' too long (#{fixlen}) for fmt #{format}" if fixlen > max_size
    return '0' * (min_size - fixlen) + str if fixlen < min_size # Left-pad with zeroes
    str
  when 'R'
    @value.to_s
    # FIXME: Add length control!
  when 'XX'
    # @value.to_s
    @value
  else
    raise "#{location}: Format #{format} not supported"
  end
end
validate( err_count=0, fmt=@format ) click to toggle source

Performs various validation checks and returns the number of issues found (plus the value of err_count):

  • empty while mandatory?

  • character set limitations violated?

  • various format restrictions violated?

Note: X12 comes with its own format definitions, so we overwrite

validate() of the base class here entirely.
# File lib/edi4r/ansi_x12.rb, line 1157
    def validate( err_count=0, fmt=@format )
      location = "DE #{parent.name}/#{@name}"
      if empty?
        if required?
          EDI::logger.warn "#{location}: Empty though mandatory!"
          err_count += 1
        end
      else
        #
        # Charset check
        #
        if (pos = (value =~ root.illegal_charset_pattern)) # != nil
          EDI::logger.warn "#{location}: Illegal character: #{value[pos].chr} (#{value[pos]})"
          err_count += 1
        end
        #
        # Format check, raise error if not consistent!
        #
        if fmt =~ /^(AN|B|DT|ID|N\d|R|TM|XX) (\d+)\/(\d+)$/
          _type, min_size, max_size = $1, $2.to_i, $3.to_i
          case _type

          when 'R'
            strval = value.to_s
            re = Regexp.new('^(-)?(\d+)(\.\d+)?$')
            md = re.match strval
            if md.nil?
              raise "#{location}: '#{strval}' - not matching format #{fmt}"
              #              warn "#{strval} - not matching format #{fmt}"
#              err_count += 1
            end

            len = strval.length
            # Sign char does not go into length count:
            len -= 1 if md[1]=='-'
            # Decimal char does not go into length count:
            len -= 1 if not md[3].nil?

            # break if not required? and len == 0
           if required? or len != 0
            if len > max_size.to_i
#            if _upto.nil? and len != _size.to_i or len > _size.to_i
              EDI::logger.warn "Context in #{location}: #{_type}, #{min_size}, #{max_size}; #{md[1]}, #{md[2]}, #{md[3]}"
              EDI::logger.warn "Max length exceeded in #{location}: #{len} vs. #{max_size}"
              err_count += 1
              #            warn "  (strval was: '#{strval}')"
            end
            if md[1] =~/^0+/
              EDI::logger.warn "#{strval} contains leading zeroes"
              err_count += 1
            end
            if md[3] and md[3]=~ /.0+$/
              EDI::logger.warn "#{strval} contains trailing decimal sign/zeroes"
              err_count += 1
            end
           end

          when /N\d+/
            len = (str=value.to_s).length
            len -= 1 if str[0]==?- # Don't count sign in length
            if len > max_size  # len < min_size is ok, would be left-padded
              EDI::logger.warn "#{@name}: Value is '#{value}'"
              EDI::logger.warn "Length mismatch in #{location}: #{len} vs. #{min_size}/#{max_size}"
              err_count += 1
            end

          when 'AN'
            len = value.to_s.length
            if len > max_size
              EDI::logger.warn "#{@name}: Value is '#{value}'"
              EDI::logger.warn "Length mismatch in #{location}: #{len} vs. #{min_size}/#{max_size} - content will be truncated!"
              err_count += 1
            elsif len < min_size
              EDI::logger.warn "#{@name}: Value is '#{value}'"
              EDI::logger.warn "Length mismatch in #{location}: #{len} vs. #{min_size}/#{max_size}  (content will be right-padded)"
              # err_count += 1
            end

          when 'ID', 'DT', 'TM'
            len = value.to_s.length
            unless len.between?( min_size, max_size )
              EDI::logger.warn "#{@name}: Value is '#{value}'"
              EDI::logger.warn "Length mismatch in #{location}: #{len} vs. #{min_size}/#{max_size}"
              err_count += 1
            end
          when 'XX'
            # Currently, this case only affects I15, which is a Fixnum,
            # but represents a character
            if RUBY_VERSION < '1.9'
              x_from, x_to = 1, 255
            else
              x_from, x_to = "\001", "\377"
            end
            unless value.between?(x_from, x_to)
              EDI::logger.warn "#{@name}: Value is '#{value}'"
              EDI::logger.warn "Cannot be encoded as a character!"
              err_count += 1
            end
          else
            raise "#{location}: Illegal format prefix #{_type}"
            # err_count += 1
          end

        else
          EDI::logger.warn "#{location}: Illegal format: #{fmt}!"
          err_count += 1
        end
      end
      err_count
    end
value=( val ) click to toggle source

The proper method to assign values to a DE. The passed value must respond to to_i .

Calls superclass method
# File lib/edi4r/ansi_x12.rb, line 1108
def value=( val )
  if @format =~ /^(AN|B|DT|ID|N\d+?|R|TM|XX) (\d+)\/(\d+)$/
    _type, min_size, max_size = $1, $2.to_i, $3.to_i
  else
    location = "DE #{parent.name}/#{@name}"
    raise "#{location}: Illegal format #{format}"
  end

  case _type
  when 'AN', 'ID', 'DT', 'TM'
    # super
  when 'R'
    val = val.to_f
  when /N(\d+)/
    if $1==0
      val = val.to_i
    else
      val = val.to_f
      $1.to_i.times { val /= 10.0 }
    end
  when 'XX'
    # p "case XX: name, val = ", name, val
    val = val[0] if val.is_a?(String)
    # raise "#{location}: Illegal value #{val} for format XX" unless val.is_a? Fixnum
    # return super
  else
    location = "DE #{parent.name}/#{@name}"
    raise "#{location}: Format #{format} not supported"
  end
  # Suppress trailing decimal part if Integer value
  if val.is_a? Float
    ival = val.to_i
    val = ival if val == ival
  end
  EDI::logger.info "***** I15='#{val}'" if name == 'I15' && val.is_a?(String) && val.size > 1
  super
end