class GEDCOM::Parser

Constants

ANY

Attributes

auto_concat[RW]
callbacks[R]

Public Class Methods

new(&block) click to toggle source
# File lib/gedcom_ruby.rb, line 32
def initialize(&block)
  @callbacks = {
    :before => {},
    :after  => {}
  }

  @context_stack = []
  @data_stack = []
  @current_level = -1

  @auto_concat = true

  instance_eval(&block) if block_given?

  after_initialize
end

Public Instance Methods

after(tags, callback=nil, &block) click to toggle source
# File lib/gedcom_ruby.rb, line 61
def after(tags, callback=nil, &block)
  tags = [tags].flatten
  callback = check_proc_or_block(callback, &block)

  @callbacks[:after][tags] = default_empty(@callbacks[:after][tags])
  @callbacks[:after][tags].push(callback)
end
after_initialize() click to toggle source
# File lib/gedcom_ruby.rb, line 49
def after_initialize
  # Template
end
before(tags, callback=nil, &block) click to toggle source
# File lib/gedcom_ruby.rb, line 53
def before(tags, callback=nil, &block)
  tags = [tags].flatten
  callback = check_proc_or_block(callback, &block)

  @callbacks[:before][tags] = default_empty(@callbacks[:before][tags])
  @callbacks[:before][tags].push(callback)
end
context() click to toggle source
# File lib/gedcom_ruby.rb, line 84
def context
  @context_stack
end
parse(file) click to toggle source
# File lib/gedcom_ruby.rb, line 69
def parse(file)
  case file
  when String
    if file =~ /\n/mo
      parse_string(file)
    else
      parse_file(file)
    end
  when IO
    parse_io(file)
  else
    raise ArgumentError.new("requires a String or IO")
  end
end

Protected Instance Methods

check_proc_or_block(proc, &block) click to toggle source
# File lib/gedcom_ruby.rb, line 95
def check_proc_or_block(proc, &block)
  unless proc or block_given?
    raise ArgumentError.new("proc or block required")
  end
  proc = method(proc) if proc.kind_of? Symbol
  proc ||= Proc.new(&block)
end
concat_data(tag, rest) click to toggle source
# File lib/gedcom_ruby.rb, line 147
def concat_data(tag, rest)
  rest = rest || "" # Handle nil case
  @data_stack[-1] = case
  when @data_stack.last.empty?       then rest
  when @context_stack.last == 'BLOB' then "#{@data_stack.last}#{rest}"
  when tag == 'CONT'                 then "#{@data_stack.last}\n#{rest}"
  when tag == 'CONC'                 then "#{@data_stack.last}#{rest}"
  end
end
default_empty(arr) click to toggle source
# File lib/gedcom_ruby.rb, line 91
def default_empty(arr)
  arr || []
end
do_callbacks(context_sym, tags, data) click to toggle source
# File lib/gedcom_ruby.rb, line 157
def do_callbacks(context_sym, tags, data)
  return if tags == []
  tag_cbs = default_empty(@callbacks[context_sym][tags])
  any_cbs = default_empty(@callbacks[context_sym][ANY])
  relevant_callbacks = tag_cbs + any_cbs
  relevant_callbacks.each do |callback|
    callback.call(data)
  end
end
parse_file(file) click to toggle source
# File lib/gedcom_ruby.rb, line 103
def parse_file(file)
  File.open(file) do |io|
    parse_io(io)
  end
end
parse_io(io) click to toggle source
# File lib/gedcom_ruby.rb, line 113
def parse_io(io)
  io.each_line do |line|
    line = line.rstrip!
    next if line.empty?
    level, tag, rest = line.match(/^(\d) (\S+) ?(.*)$/).captures
    level = level.to_i

    if (tag == 'CONT' || tag == 'CONC') and @auto_concat
      concat_data(tag, rest)
      next
    end

    unwind_to(level)

    tag, rest = rest, tag if tag =~ /@.*@/

    @context_stack.push(tag)
    @data_stack.push(rest)
    @current_level = level

    do_callbacks(:before, @context_stack, rest)
  end
  unwind_to(-1)
end
parse_string(str) click to toggle source
# File lib/gedcom_ruby.rb, line 109
def parse_string(str)
  parse_io(StringIO.new(str))
end
unwind_to(level) click to toggle source
# File lib/gedcom_ruby.rb, line 138
def unwind_to(level)
  while @current_level >= level
    do_callbacks(:after, @context_stack, @data_stack.last)
    @context_stack.pop
    @data_stack.pop
    @current_level -= 1
  end
end