class LineParser

Public Class Methods

new(patterns=[], lines=nil, ignore_blank_lines: true, debug: false) click to toggle source
# File lib/lineparser.rb, line 10
def initialize(patterns=[], lines=nil, ignore_blank_lines: true, debug: false)

  @ibl, @debug = ignore_blank_lines, debug
  @h = {

    String: lambda do |s, pattern|

      labels = []

      pattern.gsub!('+',"\\\\+")
      r = s.match(/#{pattern.gsub(/:\w+/) {|x| labels << x; '([^\\n]*)'}}/)

      if r then
        params = Hash[*labels.zip(r.captures).flatten(1)]
      end

    end,

    Regexp: lambda do |s, regex|

      r = s.match(regex)

      if r then
        h = {captures: r.captures}          
        r.names.inject(h) {|rn,x| rn.merge(x.to_sym => r[x])} if r.names
      end
    end
  }

  @patterns = patterns.select {|x| x.first == :all}

  hpatterns = {root: []}.merge patterns.inject({}){|r,x| r.merge(x[2] => x)}

  hpatterns.reverse_each do |k,v| 
    hpatterns[v.first] << v if hpatterns[v.first]
  end

  @tree_patterns =  hpatterns[:root].reverse

  parse lines if lines

end

Public Instance Methods

parse(s) click to toggle source
# File lib/lineparser.rb, line 53
def parse(s)

  puts 'inside parse()' if @debug
  a = scan @tree_patterns, LineTree.new(s, ignore_blank_lines: @ibl).to_a
  @h2 = build_hash a
  @a = a
  
end
to_a() click to toggle source
# File lib/lineparser.rb, line 62
def to_a
  @a
end
to_h() click to toggle source
# File lib/lineparser.rb, line 66
def to_h()
  @h2
end
to_xml() click to toggle source
# File lib/lineparser.rb, line 70
def to_xml
  raw_doc = xmlize(@a).inject([:root, {}, '']){|r,x| r << x}
  puts 'raw_doc: ' + raw_doc.inspect if @debug
  Rexle.new(raw_doc).xml if @a
end

Private Instance Methods

build_hash(a) click to toggle source
# File lib/lineparser.rb, line 79
def build_hash(a)

  def filter(h2)
  
    h = {}
    puts 'h2: ' + h2.inspect if @debug
  
    h2.each do |k, v|
  
      puts 'v:' + v.inspect if @debug
  
        a3 = v.flat_map do |row| 

          a2 = []

          puts 'row: ' + row.inspect
          puts 'row[3]: ' + row[3].inspect

          if row[3] and row[3].any? then
            
            puts 'row[3][0][1]: ' + row[3][0][1].inspect if @debug
            
            if row[3][0][1].has_key? :captures and row[3][0][1][:captures].any? then
              
              a2 = row[3].map {|x| x[2].first }

            else
              a2 = filter(row[3].group_by {|x| x.first })
            end
            
          else
            a2 = row[1].values.first
          end

          key = row[1].values.first            
          key ||= a2
          (key.empty? or key == a2) ? a2 : {key => a2}

        end
        
        h[k] = a3.length > 1 ? a3 : a3.first
  
    end
  
    return h
  end
  
  h3 = a.group_by {|x| x.first }
      
  filter(h3)    
  
end
filter(h2) click to toggle source
# File lib/lineparser.rb, line 81
def filter(h2)

  h = {}
  puts 'h2: ' + h2.inspect if @debug

  h2.each do |k, v|

    puts 'v:' + v.inspect if @debug

      a3 = v.flat_map do |row| 

        a2 = []

        puts 'row: ' + row.inspect
        puts 'row[3]: ' + row[3].inspect

        if row[3] and row[3].any? then
          
          puts 'row[3][0][1]: ' + row[3][0][1].inspect if @debug
          
          if row[3][0][1].has_key? :captures and row[3][0][1][:captures].any? then
            
            a2 = row[3].map {|x| x[2].first }

          else
            a2 = filter(row[3].group_by {|x| x.first })
          end
          
        else
          a2 = row[1].values.first
        end

        key = row[1].values.first            
        key ||= a2
        (key.empty? or key == a2) ? a2 : {key => a2}

      end
      
      h[k] = a3.length > 1 ? a3 : a3.first

  end

  return h
end
join(lines, indent='') click to toggle source
# File lib/lineparser.rb, line 132
def join(lines, indent='')
  lines.map do |x|
    indent + (x.is_a?(Array) ? join(x, indent + '  ') : x)
  end.join("\n")
end
scan(xpatterns, items) click to toggle source
# File lib/lineparser.rb, line 138
def scan(xpatterns, items)
  
  puts 'inside scan()' if @debug

  records = []

  while items.any? do

    x = items.shift

    params, context = nil, nil

    xpatterns = [xpatterns] unless xpatterns[0].is_a? Array

    found = @patterns.detect do |_, pattern| 
      params = @h[pattern.class.to_s.to_sym].call x.first, pattern
    end
    
    puts 'found: ' + found.inspect if @debug

    if found then

      children = nil
      children = scan(found.last, x[1..-1]) if found.last.is_a? Array
      records << [found[2], params, x, children]

    else

      puts 'xpatterns: ' + xpatterns.inspect if @debug
      
      found = xpatterns.detect do |_, pattern, id|
      
        puts 'found2: ' + found.inspect if @debug

        if pattern == :root then 

          found = @tree_patterns.detect do |_, pattern2, id|
            params = @h[pattern2.class.to_s.to_sym].call x.first, pattern2
            context = id if params
          end
          
          puts 'found3: ' + found.inspect if @debug
          
        else

          if @debug then
            puts '@h: ' + @h.inspect
            puts 'pattern: ' + pattern.inspect
            puts 'x.first: ' + x.first.inspect
          end
          
          params = @h[pattern.class.to_s.to_sym].call x.first, pattern
          puts 'params: ' + params.inspect if @debug
          context = id if params
        end
      end
      
      if found then

        children = nil
        children = scan(found[3..-1], x[1..-1]) if found.last.is_a? Array
        records << [context, params, x, children]
      end
    end
  end

  return records
end
xmlize(rows) click to toggle source
# File lib/lineparser.rb, line 207
def xmlize(rows)

  r = rows.map do |row|

    label, h, lines, children = row

    new_h = h.inject({}) do |r,k| 

      if k.first == :captures and k.last.any? then
        
        puts 'k: ' + k.inspect if @debug
        
        k[-1].map.with_index.to_a.inject({}) do |r2,x|
          x[0] ? r.merge!(('captures' + x[-1].to_s).to_sym => x[0]) : r
        end
      else
        r.merge k[0][/\w+/] => k[-1]
      end
    end

    c = children ? xmlize(children) : []

    [label, new_h, join(lines), *c]
  end
 
  r
end