class PolyrexSchema

Attributes

to_a[R]
to_doc[R]
to_h[R]
to_s[R]
to_schema[R]

Public Class Methods

new(s=nil) click to toggle source
# File lib/polyrex-schema.rb, line 12
def initialize(s=nil)

  if s then

    if s =~ /\// then
      s.prepend 'root/' if s[0] == '{'
      
      r = add_node split(s)
      r[3] << node('recordx_type', 'polyrex')  

      @doc = Rexle.new(r)
      
      @to_a = scan_to_a(@doc.root.xpath 'records/*')
      @to_h = scan_to_h(@doc.root.xpath 'records/*')
      @to_doc = @doc
      @to_s = @doc.to_s

    else

      a = [s[/^[^\[]+/], *s[/(?<=\[)[^\]]+/].split(/ *, */)].map(&:to_sym)
      @to_a = [a]
      
      h2 = {
        format_mask: a[1..-1].map {|x| "[!%s]" % x }.join(' '),
        schema: "%s[%s]" % [a[0], a[1..-1].join(', ')],
        recordx_type: 'polyrex'
      }
      
      h = {a[0] => {summary: a[1..-1]\
                    .zip(Array.new(a.length-1)).to_h.merge(h2),
                    records: nil }}
      @to_doc = Rexle.new(RexleBuilder.new(h, debug: false).to_a)
    end

  end
end

Public Instance Methods

parse(s) click to toggle source
# File lib/polyrex-schema.rb, line 49
def parse(s)
  doc = Rexle.new s
  @to_schema = scan_to_schema doc.root
  self
end

Private Instance Methods

add_node(a) click to toggle source
# File lib/polyrex-schema.rb, line 62
def add_node(a)

  return if a.empty?

  schema = a.join('/')
  line = a.shift
  raw_siblings = line[/\{.*/]

  if raw_siblings then      
    return split(raw_siblings[1..-2],';').map {|x| add_node split(x) + a}
  end

  name, raw_fields = line.split('[',2) 

  rows = if raw_fields then

    fields = raw_fields.chop.split(',')
    field_rows = fields.map {|field| node(field.strip) }
    field_rows << node('schema', schema)
    field_rows << node('format_mask', fields.map{|x| "[!%s]" % x.strip}\
                                                                .join(' '))
  end

  children = add_node(a)
  children = [children] if children and children[0].is_a? String

  node(name, '',
    node('summary', '', *rows), node('records', '', *children)
  )
end
node(name, val='', *children) click to toggle source
# File lib/polyrex-schema.rb, line 58
def node(name, val='', *children)
 [name, {}, val, *children]
end
scan_to_a(nodes) click to toggle source
# File lib/polyrex-schema.rb, line 93
def scan_to_a(nodes)

  nodes.map do |r|

    a = r.xpath('summary/*/name()') # => ["entry", "format_mask"]
    fields = (a - %w(schema format_mask)).map(&:to_sym)
    node = r.xpath 'records/*'

    if node.any? then
      children = scan_to_a(node)
      [r.name.to_sym, *fields, children]
    else
      [r.name.to_sym, *fields]
    end
  end

end
scan_to_h(nodes) click to toggle source
# File lib/polyrex-schema.rb, line 111
def scan_to_h(nodes)

  nodes.map do |r|

    a = r.xpath('summary/*/name()') # => ["entry", "format_mask"]
    schema = r.text('summary/schema')
    fields = (a - %w(schema format_mask)).map(&:to_sym)
    node = r.xpath 'records/*'

    if node.any? then
      children = scan_to_h(node)
      {name: r.name.to_sym, fields: fields, schema: schema, children: children}
    else
      {name: r.name.to_sym, fields: fields, schema: schema}
    end
  end

end
scan_to_schema(node) click to toggle source
# File lib/polyrex-schema.rb, line 130
def scan_to_schema(node)

  e = node.element('summary')
  fields = e.elements.map(&:name) - %w(schema recordx_type format_mask)
  recs = node.xpath('records/*')

  summary = fields.any? ? ("[%s]" % fields.join(', ')) : ''
  records = recs.any? ? '/' + recs\
              .uniq {|x| x.name <=> x.name}.map {|x| scan_to_schema(x)}.join('/') : ''
  
  node.name + summary + records
end
split(s, separator='/') click to toggle source

splits into levels identified by a slash (/) or a semicolon (;)

# File lib/polyrex-schema.rb, line 145
def split(s, separator='/')
  
  brace_count = 0
  
  s.each_char.inject(['']) do |r, c|

    case c
      when '{'
        brace_count += 1
      when '}'
        brace_count -= 1
    end

    if c != separator or brace_count > 0 then
      r.last << c
    else
      c = '' if c == separator
      r << c
    end
    r
  end

end