class Polyrex
Attributes
delimiter[RW]
format_masks[RW]
id_counter[RW]
schema[RW]
summary_fields[RW]
type[RW]
xslt[RW]
xslt_schema[RW]
Public Class Methods
new(location=nil, schema: nil, id_counter: '1', delimiter: '', debug: false)
click to toggle source
# File lib/polyrex.rb, line 47 def initialize(location=nil, schema: nil, id_counter: '1', delimiter: '', debug: false) @id_counter, @debug = id_counter, debug @format_masks = [] self.method(:schema=).call(schema) if schema if location then s, type = RXFReader.read(location) return import(s) if s =~ /^\<\?polyrex\b/ @local_filepath = location if type == :file or type == :dfs openx(s) puts 'before schema' if @debug if schema then fields = @schema[/\/.*/].scan(/\[([^\]]+)/).map \ {|x| x.first.split(',').map(&:strip)} refresh_records self.records, fields, 0 end @summary = RecordX.new @doc.root.xpath("summary/*") @summary_fields = @summary.keys end @polyrex_xslt = RecordxXSLT.new #@parent_node = @doc.root if @doc set_delimiter(delimiter) end
Public Instance Methods
add(pxobj)
click to toggle source
# File lib/polyrex.rb, line 84 def add(pxobj) self.record.add pxobj.node end
build(records, indent=0)
click to toggle source
# File lib/polyrex.rb, line 314 def build(records, indent=0) records.map do |item| summary = item.element 'summary' format_mask = summary.text('format_mask').to_s line = format_mask.gsub(/\[![^\]]+\]/){|x| summary.text(x[2..-2]).to_s} puts 'line: ' + line.inspect if @debug recordsx = item.element('records').elements.to_a if recordsx.length > 0 then line = line + "\n" + build(recordsx, indent + 1).join("\n") end (' ' * indent) + line end end
content(options={})
click to toggle source
# File lib/polyrex.rb, line 88 def content(options={}) CGI.unescapeHTML(to_xml(options)) end
create(id: @id_counter)
click to toggle source
# File lib/polyrex.rb, line 92 def create(id: @id_counter) puts 'id: ' + id.inspect if @debug @create = PolyrexCreateObject.new(id: id, record: @doc.root) end
delete(x=nil)
click to toggle source
# File lib/polyrex.rb, line 97 def delete(x=nil) if x.to_i.to_s == x.to_s then @doc.root.delete("//[@id='#{x}'") else @doc.root.xpath(x).each(&:delete) end end
delimiter=(separator)
click to toggle source
# File lib/polyrex.rb, line 106 def delimiter=(separator) @delimiter = separator @format_masks.map! do |format_mask| format_mask.to_s.gsub(/\s/, separator) end end
Also aliased as: set_delimiter
each_recursive(parent=self, level=0, &blk)
click to toggle source
# File lib/polyrex.rb, line 117 def each_recursive(parent=self, level=0, &blk) parent.records.each.with_index do |x, index| blk.call(x, parent, level, index) if block_given? each_recursive(x, level+1, &blk) if x.records.any? end end
element(s)
click to toggle source
# File lib/polyrex.rb, line 198 def element(s) @doc.root.element(s) end
export(filepath)
click to toggle source
# File lib/polyrex.rb, line 129 def export(filepath) FileX.write filepath, to_s() end
find_by_id(id)
click to toggle source
– start of crud methods –
# File lib/polyrex.rb, line 157 def find_by_id(id) puts 'inside find_by_id: ' + id if @debug #return @doc if @debug @parent_node = @doc.root.element("//[@id='#{id}']") @objects[@parent_node.name.to_sym].new(@parent_node, id: @id) end
id(id)
click to toggle source
# File lib/polyrex.rb, line 166 def id(id) @parent_node = @doc.root.element("//[@id='#{id}']") self end
leaf_nodes_to_dx()
click to toggle source
# File lib/polyrex.rb, line 202 def leaf_nodes_to_dx() schema, record_name = @summary.schema\ .match(/([^\/]+\/([^\/]+)\[[^\[]+$)/).captures xml = RexleBuilder.new xml.items do xml.summary do xml.schema schema.sub(/(\/\w+)\[([^\]]+)\]/,'\1(\2)') end xml.records end doc = Rexle.new xml.to_a body = doc.root.element 'records' a = self.xpath('//' + record_name) a.each do |record| body.add record.deep_clone end make_dynarex doc.root end
order=(val)
click to toggle source
# File lib/polyrex.rb, line 171 def order=(val) @order = val.to_s end
parse(x=nil, options={}) { || ... }
click to toggle source
# File lib/polyrex.rb, line 182 def parse(x=nil, options={}) buffer, type = RXFReader.read(x) if type == :unknown and buffer.lines.length <= 1 then raise PolyrexException, 'File not found: ' + x.inspect end buffer = yield if block_given? string_parse buffer.clone, options self end
Also aliased as: import
record()
click to toggle source
# File lib/polyrex.rb, line 133 def record() @parent_node end
records()
click to toggle source
# File lib/polyrex.rb, line 227 def records @doc.root.xpath("records/*").map do |node| Kernel.const_get(node.name.capitalize).new node, id: @id_counter end end
rxpath(s)
click to toggle source
# File lib/polyrex.rb, line 235 def rxpath(s) a = @doc.root.xpath s.split('/').map \ {|x| x.sub('[','[summary/').prepend('records/')}.join('/') a.map do |node| Kernel.const_get(node.name.capitalize).new node, id: node.attributes[:id] end end
save(filepath=nil, opt={}, options: opt, pretty: false) { |xml| ... }
click to toggle source
# File lib/polyrex.rb, line 142 def save(filepath=nil, opt={}, options: opt, pretty: false) refresh_summary filepath ||= @local_filepath @local_filepath = filepath options.merge!({pretty: pretty}) if options.empty? xml = @doc.to_s(options) buffer = block_given? ? yield(xml) : xml FileX.write filepath, buffer end
schema=(s)
click to toggle source
# File lib/polyrex.rb, line 246 def schema=(s) if s =~ /gem\[/ then raise PolyrexException, "invalid schema: cannot contain the " + "word gem as a record name" end openx(s) summary_h = Hash[*@doc.root.xpath("summary/*").\ map {|x| [x.name, x.text.to_s]}.flatten] @summary = RecordX.new summary_h @summary_fields = summary_h.keys.map(&:to_sym) self end
summary()
click to toggle source
# File lib/polyrex.rb, line 263 def summary @summary end
to_a()
click to toggle source
# File lib/polyrex.rb, line 267 def to_a() recordx_map @doc.root end
to_dynarex()
click to toggle source
# File lib/polyrex.rb, line 271 def to_dynarex() root = @doc.root.deep_clone summary = root.element('summary') #summary.delete('format_mask') #summary.element('recordx_type').text = 'dynarex' summary.add root.element('records/*/summary/format_mask').clone e = summary.element('schema') e.text = e.text[/[^\/]+\/[^\/]+/].sub(/(\/\w+)\[([^\]]+)\]/,'\1(\2)') make_dynarex(root) end
to_opml()
click to toggle source
# File lib/polyrex.rb, line 286 def to_opml() puts '@schema: ' + @schema.inspect if @debug head, body = @schema.split(/(?<=\])/,2) schema_body = body.gsub(/(?<=\[)[^\]]+/) do |x| x.split(/\s*,\s*/).map {|field| '@' + field + ':' + field}.join(', ') end schema_head = head.gsub(/(?<=\[)[^\]]+/) do |x| x.split(/\s*,\s*/).map {|field| field + ':' + field}.join(', ') end puts 'schema_body: ' + schema_body.inspect if @debug puts 'schema_head: ' + schema_head.inspect if @debug xslt_schema = schema_head.sub(/^\w+/,'opml>head') + schema_body.gsub(/\w+(?=\[)/,'outline')\ .sub(/\/(\w+)(?=\[)/,'/body>outline') puts 'xslt_schema: ' + xslt_schema.inspect if @debug recxslt = RecordxXSLT.new(schema: @schema, xslt_schema: xslt_schema) Rexslt.new(recxslt.to_xslt, self.to_xml).to_s end
to_s(header: true)
click to toggle source
# File lib/polyrex.rb, line 312 def to_s(header: true) def build(records, indent=0) records.map do |item| summary = item.element 'summary' format_mask = summary.text('format_mask').to_s line = format_mask.gsub(/\[![^\]]+\]/){|x| summary.text(x[2..-2]).to_s} puts 'line: ' + line.inspect if @debug recordsx = item.element('records').elements.to_a if recordsx.length > 0 then line = line + "\n" + build(recordsx, indent + 1).join("\n") end (' ' * indent) + line end end sumry = '' summary_fields = self.summary.to_h.keys %w(recordx_type schema format_mask).each {|x| summary_fields.delete x} sumry = summary_fields.map {|x| x.to_s + ': ' + \ self.summary.method(x.to_sym).call}.join("\n") + "\n" if @raw_header then declaration = @raw_header else smry_fields = %i(schema) if self.delimiter.length > 0 then smry_fields << :delimiter else smry_fields << :format_mask end s = smry_fields.map {|x| "%s=\"%s\"" % \ [x, self.summary.send(x).to_s.gsub('"', '\"') ]}.join ' ' declaration = %Q(<?polyrex %s?>\n) % s end docheader = declaration + "\n" + sumry out = build(self.records).join("\n") header ? docheader + "\n" + out : out end
to_tree()
click to toggle source
# File lib/polyrex.rb, line 365 def to_tree() s = @schema.gsub(/(?<=\[)[^\]]+/) do |x| x.split(/\s*,\s*/).map {|field| '@' + field + ':' + field}.join(', ') end xslt_schema = s.gsub(/\w+(?=\[)/,'item').sub(/^\w+/,'tree') recxslt = RecordxXSLT.new(schema: @schema, xslt_schema: xslt_schema) Rexslt.new(recxslt.to_xslt, self.to_xml).to_s end
to_xml(options={})
click to toggle source
# File lib/polyrex.rb, line 137 def to_xml(options={}) refresh_summary @doc.to_s(options) end
to_xslt()
click to toggle source
# File lib/polyrex.rb, line 377 def to_xslt() @polyrex_xslt.schema = @schema @polyrex_xslt.to_xslt end
xpath(s, &blk)
click to toggle source
# File lib/polyrex.rb, line 382 def xpath(s, &blk) if block_given? then @doc.root.xpath(s, &blk) else @doc.root.xpath s end end
xslt=(value)
click to toggle source
# File lib/polyrex.rb, line 391 def xslt=(value) @summary.xslt = value end
xslt_schema=(s)
click to toggle source
# File lib/polyrex.rb, line 397 def xslt_schema=(s) @polyrex_xslt.xslt_schema = s self end
Protected Instance Methods
doc()
click to toggle source
# File lib/polyrex.rb, line 404 def doc() @doc end
Private Instance Methods
attach_create_handlers(names)
click to toggle source
# File lib/polyrex.rb, line 708 def attach_create_handlers(names) methodx = names.map do |name| %Q( def create_#{name.downcase}(params, &blk) self.create.#{name.downcase}(params, &blk) end ) end self.instance_eval(methodx.join("\n")) end
attach_edit_handlers(objects)
click to toggle source
# File lib/polyrex.rb, line 721 def attach_edit_handlers(objects) objects.keys.each do |name| self.instance_eval( %Q( def #{name.downcase}() @objects['#{name}'].new(@parent_node, id: @id) end )) end end
format_line!(a, i=0)
click to toggle source
# File lib/polyrex.rb, line 596 def format_line!(a, i=0) records = Rexle::Element.new('records') # add code here for rowx @field_names = format_masks[i].to_s.scan(/\[!(\w+)\]/)\ .flatten.map(&:to_sym) rowx_fields = a.map{|x| x.first[/^\w+(?=:)/].to_s.to_sym}.uniq records = if (@field_names & rowx_fields).length >= 2 then # rowx implementation still to-do #vertical_fiedlparse(records, a, i) else horizontal_fieldparse(records, a, i) end end
horizontal_fieldparse(records, a, i)
click to toggle source
– end of full text edit methods
# File lib/polyrex.rb, line 618 def horizontal_fieldparse(records, a, i) a.each do |x| unless @recordx[i] then @recordx[i] = @recordx[-1].clone @format_masks[i] = @format_masks[-1] end tag_name = @recordx[i].to_s line = raw_line = x.shift line = raw_line if line[/\w+\s*---/] then node_name = line.sub(/\s*---/,'') ynode = Rexle::Element.new(node_name).add_text("---\n" + x.join("\n")) summary.add ynode next end puts '@schema: ' + @schema.inspect if @debug schema_a = @schema.split('/')[1..-1] if @debug then puts 'schema_a: ' + schema_a.inspect puts 'i: ' + i.inspect end unless @format_masks[i][/^\(.*\)$/] then @field_names, field_values = RXRawLineParser.new(format_masks[i])\ .parse(line) @field_names = schema_a[i] ? \ schema_a[i][/\[([^\]]+)/,1].split(/\s*,\s*/).map(&:to_sym) : \ schema_a[-1][/\[([^\]]+)/,1].split(/\s*,\s*/).map(&:to_sym) else format_masks = @format_masks[i][1..-2].split('|') patterns = format_masks.map do |x| regexify_fmask(x) end pattern = patterns.detect {|x| line.match(/#{x}/)} i = patterns.index(pattern) @field_names = format_masks[i].to_s.scan(/\[!(\w+)\]/)\ .flatten.map(&:to_sym) field_values = line.match(/#{pattern}/).captures end @id_counter.succ! record = Rexle::Element.new(tag_name) record.add_attribute(id: @id_counter.clone) summary = Rexle::Element.new('summary') @field_names.zip(field_values).each do |name, value| field = Rexle::Element.new(name.to_s) field.text = value summary.add field end format_mask = @format_masks[i].to_s index = i >= schema_a.length ? schema_a.length - 1 : i schema = schema_a[index..-1].join('/') summary.add Rexle::Element.new('format_mask').add_text(format_mask) summary.add Rexle::Element.new('schema').add_text(schema) summary.add Rexle::Element.new('recordx_type').add_text('polyrex') record.add summary child_records = format_line!(x, i+1) record.add child_records records.add record end records end
load_find_by(schema)
click to toggle source
# File lib/polyrex.rb, line 802 def load_find_by(schema) a = PolyrexObjectMethods.new(schema).to_a methodx = a.map do |class_name, methods| class_name.downcase! methods.map do |method_name| xpath = %Q(@doc.root.element("//%s[summary/%s='\#\{val\}']")) % \ [class_name, method_name] xpath2 = %Q(@doc.root.xpath("//%s[summary/%s='\#\{val\}']")) % \ [class_name, method_name] "def find_by_#{class_name}_#{method_name}(val) node = #{xpath} if node then Kernel.const_get(node.name.capitalize).new node, id: @id else nil end end def find_all_by_#{class_name}_#{method_name}(val) nodes = #{xpath2} if nodes then nodes.map do |node| Kernel.const_get(node.name.capitalize).new node, id: @id end else nil end end " end end self.instance_eval methodx.join("\n") end
load_handlers(schema)
click to toggle source
# File lib/polyrex.rb, line 583 def load_handlers(schema) objects = PolyrexObjects.new(schema, debug: @debug) h = objects.to_h puts 'h: ' + h.inspect if @debug @objects = h.inject({}){|r,x| r.merge x[0].downcase => x[-1]} @objects_a = objects.to_a attach_create_handlers(@objects.keys) #attach_edit_handlers(@objects) end
make_dynarex(root)
click to toggle source
# File lib/polyrex.rb, line 410 def make_dynarex(root) root.delete('summary/recordx_type') root.delete('summary/format_mask') root.xpath('records/*/summary/format_mask').each(&:delete) root.xpath('records/*/records').each(&:delete) xsl_buffer = ' <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:element name="summary"> <xsl:for-each select="summary/*"> <xsl:copy-of select="."/> </xsl:for-each> </xsl:element> <xsl:element name="records"> <xsl:for-each select="records/*"> <xsl:element name="{name()}"> <xsl:copy-of select="summary/*"/> </xsl:element> </xsl:for-each> </xsl:element> </xsl:element> </xsl:template> </xsl:stylesheet> ' buffer = Rexslt.new(xsl_buffer, root.xml).to_s Dynarex.new buffer end
openx(s)
click to toggle source
# File lib/polyrex.rb, line 733 def openx(s) puts 'inside openx' if @debug if s[/</] # xml buffer = s elsif s[/\[/] then # schema buffer = polyrex_new s elsif s[/^https?:\/\//] then # url buffer = URI.open(s, 'UserAgent' => 'Polyrex-Reader').read else # local file buffer = FileX.read s @local_filepath = s end buffer.gsub!(/<schema>[^<]+/, '<schema>' + @schema) if @schema @doc = Rexle.new buffer schema = @doc.root.text('summary/schema').to_s if schema.nil? then schema = PolyrexSchema.new.parse(buffer).to_schema e = @doc.root.element('summary') e.add Rexle::Element.new('schema').add_text(schema) end unless @format_masks schema_rpath = schema.gsub(/\[[^\]]+\]/,'') @recordx = schema_rpath.split('/') @recordx.shift end id = @doc.root.xpath('max(//@id)') @id_counter = id.to_s.succ if id if schema then load_handlers(schema) load_find_by(schema) unless schema[/^\w+[^\/]+\/\{/] end @parent_node = @doc.root.element('records') end
polyrex_new(schema)
click to toggle source
# File lib/polyrex.rb, line 462 def polyrex_new(schema) # -- required for the parsing feature doc = PolyrexSchema.new(schema).to_doc fm = doc.root.xpath('//format_mask/text()') @format_masks = fm.zip(@format_masks).map{|x,y| y || x } schema_rpath = schema.gsub(/\[[^\]]+\]/,'') @recordx = schema_rpath.split('/') summary = '' if @format_masks.length == @recordx.length then root_format_mask = @format_masks.shift field_names = root_format_mask.to_s.scan(/\[!(\w+)\]/).\ flatten.map(&:to_sym) summary = field_names.map {|x| "<%s/>" % x}.join end summary << "<recordx_type>polyrex</recordx_type><schema>#{schema}</schema>" #---- @schema = schema @id_counter = '0' root_name = @recordx.shift ("<%s><summary>%s</summary><records/></%s>" % \ [root_name, (summary || '') , root_name]) end
recordx_map(node)
click to toggle source
# File lib/polyrex.rb, line 494 def recordx_map(node) # get the summary fields = node.xpath('summary/*').map do |x| next if %w(schema format_mask recordx_type).include? x.name r = x.text.to_s.gsub(/^[\n\s]+/,'').length > 0 ? x.text.to_s : \ x.cdatas.join.strip r end # get the records a = node.xpath('records/*').map {|x| recordx_map x} [fields.compact, a] end
refresh_records(records, fields, level)
click to toggle source
# File lib/polyrex.rb, line 448 def refresh_records(records, fields, level) records.each do |record| level -= 1 unless fields[level] fields[level].each {|x| record.method(x).call } if record.records.any? then refresh_records record.records, fields, level+1 end end end
refresh_summary()
click to toggle source
refreshes the XML document with any new modification from
the summary object
# File lib/polyrex.rb, line 852 def refresh_summary() summary = @doc.root.element('summary') @summary.to_h.each do |k,v| puts "k: %s; v: %s" % [k, v] if @debug e = summary.element(k.to_s) if e then e.text = v else summary.add Rexle::Element.new(k.to_s).add_text(v) end end if @summary.xslt then @doc.instructions = [['xml-stylesheet', "title='XSL_formatting' type='text/xsl' href='#{@summary.xslt}'"]] end end
regexify_fmask(f)
click to toggle source
# File lib/polyrex.rb, line 778 def regexify_fmask(f) a = f.split(/(?=\[!\w+\])/).map do |x| aa = x.split(/(?=[^\]]+$)/) if aa.length == 2 and aa.first[/\[!\w+\]/] then field, delimiter = *aa delimiter ||= '$' d = delimiter[0] "('[^']+'|[^%s]+)%s" % ([d] * 2) else x.sub(/\[!\w+\]/,'(.*)') end end a.join end
string_parse(buffer, options={})
click to toggle source
# File lib/polyrex.rb, line 510 def string_parse(buffer, options={}) @raw_header = buffer.slice!(/<\?polyrex[^>]+>/) if @raw_header then header = @raw_header[/<?polyrex (.*)?>/,1] r1 = /([\w\[\]\-]+\s*\=\s*'[^']*)'/ r2 = /([\w\[\]\-]+\s*\=\s*"[^"]*)"/ a = header.scan(/#{r1}|#{r2}/).map(&:compact).flatten a.each do |x| attr, val = x.split(/\s*=\s*["']/,2) i = attr[/format_masks?\[(\d+)/,1] if i then @format_masks[i.to_i] = val else unless options.keys.include? attr[0..-2].to_sym then self.method((attr + '=').to_sym).call(unescape val) end end end options.each do |k,v| if options[k] then a.delete a.assoc(k) self.method(((k.to_s) + '=').to_sym).call(options[k]) end end end raw_lines = buffer.lstrip.lines.map(&:chomp) raw_summary = schema[/^\w+\[([^\]]+)/,1] if raw_summary then a_summary = raw_summary.split(',').map(&:strip) while raw_lines.first[/#{a_summary.join('|')}:\s+\w+/] do label, val = raw_lines.shift.match(/(\w+):\s+([^$]+)$/).captures @summary.send((label + '=').to_sym, val) end end @summary.format_mask = @format_masks records = @parent_node.root @parent_node = records.parent records.delete puts 'raw_lines: ' + raw_lines.inspect if @debug lines = LineTree.new(raw_lines.join("\n"), ignore_label: true).to_a puts 'lines: ' + lines.inspect if @debug @parent_node.root.add format_line!( lines) end
tail_map(a)
click to toggle source
# File lib/polyrex.rb, line 797 def tail_map(a) [a] + (a.length > 1 ? tail_map(a[0..-2]) : []) end
unescape(s)
click to toggle source
# File lib/polyrex.rb, line 579 def unescape(s) r = s.gsub('<', '<').gsub('>','>') end