class Bismas::Parser

  1. Each record is terminated by 0x0D 0x0A (CHARS[:newline]).

  2. Each record starts with 0x01 (CHARS[:rs]) or, if it's a deleted record, with 0xFF (CHARS[:deleted]).

  3. Each field is terminated by 0x00 (CHARS[:fs]).

  4. Each field starts with the category “number”, a run of category_length characters except 0x00, 0x01, 0xDB or 0xFF; trailing space is stripped.

  5. The remaining characters of a field form the category content; trailing padding 0xDB (CHARS[:padding]) is stripped.

To quote the BISMAS handbook: “Konkret wird bei BISMAS jeder Datensatz durch ASCII(1) eingeleitet. Es folgt die erste Kategorienummer mit dem Kategorieinhalt. Abgeschlossen wird jede Kategorie mit ASCII(0), danach folgt die nächste Kategorienummer und -inhalt usw. Der gesamte Datensatz wird mit ASCII (13)(10) abgeschlossen.”

Public Class Methods

new(options = {}) click to toggle source
# File lib/bismas/parser.rb, line 79
def initialize(options = {})
  @regex = Bismas.regex(options)

  @strict, @silent = options.values_at(:strict, :silent)
end
parse(io, options = {}, &block) click to toggle source
# File lib/bismas/parser.rb, line 74
def self.parse(io, options = {}, &block)
  klass = options[:legacy] ? Legacy : self
  klass.new(options).parse(io, &block)
end

Public Instance Methods

parse(io, &block) click to toggle source
# File lib/bismas/parser.rb, line 85
def parse(io, &block)
  @input = StringScanner.new('')

  io.each { |input|
    @input << input

    parse_record(&block) while @input.check_until(@regex[:newline])
    @input.string = @input.string.byteslice(@input.pos..-1)
  }

  error('Unexpected data') unless @input.eos?

  self
end
parse_field() { |k, v| ... } click to toggle source
# File lib/bismas/parser.rb, line 115
def parse_field
  k = match(:category, 0) and k.rstrip!

  v = match(:field, 1) or error(k ?
    "Unclosed field `#{k}'" : 'Unexpected data', :rest)

  k ? block_given? ? yield(k, v) : [k, v] :
    v.empty? ? nil : error('Malformed field', :field)
end
parse_record() { |r| ... } click to toggle source
# File lib/bismas/parser.rb, line 100
def parse_record
  if match(:deleted)
    match(:skip_line)
    return
  elsif !match_record
    error('Malformed record', :line)
    return
  end

  r = Hash.new { |h, k| h[k] = [] }
  parse_field  { |k, v| r[k] << v } until match(:newline)

  block_given? ? yield(r) : r
end

Private Instance Methods

error(message, skip = nil) click to toggle source
# File lib/bismas/parser.rb, line 136
def error(message, skip = nil)
  err = parse_error(message)
  raise err unless skip && !@strict

  warn err.to_s unless @silent
  match(:"skip_#{skip}")
  nil
end
match(key, index = nil) click to toggle source
# File lib/bismas/parser.rb, line 127
def match(key, index = nil)
  res = @input.skip(@regex.fetch(key))
  res && index ? @input[index] : res
end
match_record() click to toggle source
# File lib/bismas/parser.rb, line 132
def match_record
  match(:rs)
end
parse_error(message) click to toggle source
# File lib/bismas/parser.rb, line 145
def parse_error(message)
  ParseError.new(@input, message)
end