module Scheme::Parser::Base
Attributes
errors[R]
this[R]
Public Instance Methods
import(xml)
click to toggle source
# File lib/scheme/parser/base.rb, line 12 def import xml model_attrs = parse(xml) #name = File.basename(attrs.keys.first, '_attributes') #model = name.singularize.camelize.constantize #model_attrs = attrs.values.first model = self key = current_options[:key].to_s || 'id' if model_attrs[key] if instance = model.where(key => model_attrs[key]).first instance.update!(model_attrs) else instance = model.new(model_attrs) instance.save! end # binding.pry # model_attrs.each do |name, value| # if value.is_a?(Array) # _update_array(name, value) # end # end # binding.pry end # rescue => e # err_text = "Failed to import record #{name} with messages '#{e.message}'" # if instance && !(errs = show_errors(instance.errors)).empty? # err_text += " and #{errs}" # end # err_text += " at #{e.backtrace.first}" # # Rails.logger.error(err_text) # error "", err_text end
import_attrs(attrs)
click to toggle source
def _update_array name, array
array.each do |value| if value['id'] name = File.basename(name, '_attributes') m = name.singularize.camelize.constantize i = m.where(id: value['id']).first binding.pry i.update!(value) end end array.delete_if { |value | value['id'] }
end
# File lib/scheme/parser/base.rb, line 73 def import_attrs attrs end
parse(xml)
click to toggle source
# File lib/scheme/parser/base.rb, line 48 def parse xml clean_errors filtered = xml.is_a?(String) && xml.gsub(/[\r\u{feff}]/,"") || xml doc = filtered.kind_of?(Nokogiri::XML::Element) && filtered || Nokogiri::XML.parse(filtered) @this = {} attrs = each_field_for(self.schemes[nil], doc) #binding.pry raise ParameterError if errors.present? attrs end
Protected Instance Methods
attributes_update(name, options, xml_context)
click to toggle source
# File lib/scheme/parser/base.rb, line 177 def attributes_update name, options, xml_context if options[:update] && options[:update_field] && ref = reference_value(name, options, xml_context) if is_update_required(name, xml_context, options, ref) { "id" => ref.id } else nil end elsif ref = reference_value(name, options, xml_context) # binding.pry if name =~ /lot/ if ref.is_a?(Array) ref.map { |r| { "id" => r.id } } else { "id" => ref.id } end else {} end end
clean_errors()
click to toggle source
# File lib/scheme/parser/base.rb, line 78 def clean_errors @errors = {} end
each_field_for(schema, xml_context)
click to toggle source
# File lib/scheme/parser/base.rb, line 117 def each_field_for schema, xml_context schema.map do |name, options| next unless name # skip settings v = type_value(name, options, xml_context) real_name = options[:multiple] && name.pluralize || name is_assign = [Array, Hash].any? { |x| x === v } key = is_assign && "#{real_name}_attributes" || real_name if handler = handler_for(options[:if]) v = handler[v] end @this[name] ||= [] @this[name] << v [ key, v ] end.compact.select {|_, v| !v.nil? }.to_h end
error(name, error)
click to toggle source
# File lib/scheme/parser/base.rb, line 299 def error name, error # binding.pry @errors ||= {} @errors[name] ||= [] @errors[name] << error nil end
find_new_contexts(name, xml_context, options)
click to toggle source
# File lib/scheme/parser/base.rb, line 228 def find_new_contexts name, xml_context, options new_contexts = self.filter_hashes(options[:contexts], Scheme::Parser::Methods::PURE_CONTEXT_KEYS) inx, index = select_value(name, xml_context, new_contexts, options) if inx.text inc = options[:contexts][index] end [inx, inc] end
handled_value(handler, value, name, xml_context, options)
click to toggle source
# File lib/scheme/parser/base.rb, line 363 def handled_value handler, value, name, xml_context, options method = handler_for(handler) # new_value = # if context[:by] # c = [ this_contexts(context).first.merge(handler: nil) ] # select_value(context[:by], value, c, options).first # else # value # end # if method new_value = if value.is_a?(Nokogiri::XML::NodeSet) new = Nokogiri::XML::NodeSet.new(value.document) new_value = value.map do |subvalue| args = [ subvalue, name, xml_context, options ] method[*args[0...method.arity]] # if subvalue.nil? || subvalue.is_a?(Nokogiri::XML::Searchable) # subvalue # else # binding.pry # Struct::Value.new(method[*args[0...method.arity]]) # end end.compact.reduce(new) { |new, x| new << x } new_value else args = [ value, name, xml_context, options ] Struct::Value.new(method[*args[0...method.arity]]) end else value end end
handler_for(handler)
click to toggle source
# File lib/scheme/parser/base.rb, line 352 def handler_for handler case handler when Proc, Method handler when NilClass nil else self.methods.include?(handler) && self.method(handler) end end
integrate(ary1, ary2)
click to toggle source
is_update_required(name, xml_context, options, object)
click to toggle source
# File lib/scheme/parser/base.rb, line 169 def is_update_required(name, xml_context, options, object) base = object.send(options[:update_field]) inx, inc = find_new_contexts(name, xml_context, options) o = select_value(options[:update], inx, this_contexts(inc), options).first base < Time.parse(o.text) end
model_for(name, options)
click to toggle source
# File lib/scheme/parser/base.rb, line 312 def model_for name, options (options[:as] || name).to_s.singularize.camelize.constantize end
paths(name, context)
click to toggle source
join_context
объединяет переданные строки контекста в единую строку в формате xpath.
Пример 1:
args: "ns2:documentationDelivery", "deliveryEndDateTime" out: ".//ns2:documentationDelivery//:deliveryEndDateTime"]
Пример 2:
args: "", "ns2:contact" out: ".//ns2:contact"
Пример 3:
args: nil, "contact", nil out: ".//:contact"
# File lib/scheme/parser/base.rb, line 432 def paths name, context froms = [ context[:from] || name ].flatten.compact ctxs = [ context[:reset_context] || context[:context] ].flatten.compact prefix = context[:reset_context] && "" || "." integrate(ctxs, froms).map do |from| from.map do |a| a.split('/') end.flatten.map do |a| /(:|\A..\z)/ =~ a && a || "#{a}" end.unshift(prefix).join("//") end end
reference_value(name, options, xml_context)
click to toggle source
# File lib/scheme/parser/base.rb, line 240 def reference_value name, options, xml_context inx, inc = find_new_contexts(name, xml_context, options) if inc && inc[:by] begin value, = select_value(inc[:by], inx, this_contexts(inc), options) rescue NoMethodError error(name, "field error for '#{inc[:by]}' in context: #{inx.inspect}") end model = model_for(name, options) if field = inc[:field] || inc[:by] # binding.pry if options[:multiple] && value.respond_to?(:size) rela = model.where(field => value.map(&:text)) else rela = model.where(field => value.text) end end # binding.pry if name.to_s =~ /placing_method/ if rela.empty? && field = inc[:re_field] begin rela = model.where("? ~* #{field}", value.text).order(code: :desc) rescue Java::JavaLang::NoSuchMethodError error(name, "reference is unavailable to find out via referenced field" + " '#{field}' with data: #{value.text}") [] end end # binding.pry if name =~ /lot/ if options[:multiple] rela_a = rela.empty? && [nil] || rela value = rela_a.map do |rela_v| if inc[:on_found] handled_value(inc[:on_found], rela_v, name, xml_context, options).text else rela_v end end else value = rela.first if inc[:on_found] value = handled_value(inc[:on_found], value, name, xml_context, options).text end end this['relations'] ||= {} this['relations'][name] ||= [] this['relations'][name] << value # binding.pry if name =~ /lot/ value end end
scheme_value(name, options, xml_context)
click to toggle source
# File lib/scheme/parser/base.rb, line 197 def scheme_value name, options, xml_context if attrs = attributes_update(name, options, xml_context) # binding.pry if name.to_s =~ /lot_apps/ value, i = select_value(name, xml_context, options[:contexts], options) # binding.pry if name =~ /lot/ if value.text.present? as = options[:contexts][i][:scheme] || options[:as] || name # binding.pry if name.to_s =~ /lot_item/ scheme_name = self.scheme_name(as) vvv = if options[:multiple] if attrs.is_a?(Array) values = [ value, attrs ].transpose values.map do |(v, attr)| # binding.pry each_field_for(self.schemes[scheme_name], v).merge(attr) end else value.map { |v| each_field_for(self.schemes[scheme_name], v) } end else each_field_for(self.schemes[scheme_name], value).merge(attrs) end # binding.pry if name =~ /lots?/ vvv end end end
search_in(xml_context, path, options)
click to toggle source
# File lib/scheme/parser/base.rb, line 316 def search_in xml_context, path, options # TODO since nokogiri 1.8.2 dones not understand namespaces in attribute names # we shold crop it from path, and traverse manually res = xml_context.xpath(path) options[:multiple] && res || res.first rescue Nokogiri::XML::XPath::SyntaxError => e err_text = "Failed to navigate path with messages '#{e.message}'" error path, err_text Rails.logger.error(err_text) nil end
select_value(name, xml_context, contexts, options)
click to toggle source
select_value
выборка общего обработчика контекста для заданного атрибута. Осуществляет выбор между обработчиками встроенным и заданным пользователем в подробностях (options).
# File lib/scheme/parser/base.rb, line 333 def select_value name, xml_context, contexts, options contexts.map.with_index do |c, i| [ c, i ] end.reduce([nil, nil]) do |(value, val_index), (context, index)| next [value, val_index] if value && value.text.present? new = if context[:on_proceed] midvalue = value(name, xml_context, context, options) handled_value(context[:on_proceed], midvalue, name, xml_context, options) else value(name, xml_context, context, options) end # binding.pry if name =~ /lot/ [ new, index ] end end
show_errors(errors)
click to toggle source
# File lib/scheme/parser/base.rb, line 82 def show_errors errors errors.messages.map do |field, msgs| msgs.map do |msg| "#{field} #{msg}" end end.flatten.join(", ") end
this_contexts(in_context = {})
click to toggle source
# File lib/scheme/parser/base.rb, line 308 def this_contexts in_context = {} [ in_context.merge({context: [""], from: nil}) ] end
touch_file(file) { |read| ... }
click to toggle source
# File lib/scheme/parser/base.rb, line 90 def touch_file file if file =~ /\.zip$/i Dir.mktmpdir do |dir| unzip(dir, file).each do |xml| Rails.logger.info("Xml file to proceed #{xml}") yield(IO.read(xml)) end end else yield(IO.read(file)) end end
type_value(name, options, xml_context)
click to toggle source
# File lib/scheme/parser/base.rb, line 138 def type_value name, options, xml_context value = case options[:type] when :field v = select_value(name, xml_context, options[:contexts], options).first v = ! v.respond_to?(:text) && v || v.text v = v.respond_to?(:strip) && v.strip || v v.present? && v || nil when :scheme scheme_value(name, options, xml_context) when :reference reference_value(name, options, xml_context) end if options[:on_complete] value = handled_value(options[:on_complete], value, name, xml_context, options).text end if options[:required] && value.nil? error(name, "field is required") end ### apply method defined by :map to the value if value && options[:map] value = value.send(options[:map].to_s) end value end
unzip(dir, file)
click to toggle source
# File lib/scheme/parser/base.rb, line 104 def unzip dir, file if defined?(Zip) Zip::File.open(file) do |zip_file| zip_file.map do |entry| tname = File.join(dir, file, entry.name) FileUtils.mkdir_p(File.dirname(tname)) entry.extract(tname) tname end end end end
value(name, xml_context, context, options)
click to toggle source
# File lib/scheme/parser/base.rb, line 398 def value name, xml_context, context, options paths = paths(name, context) new_context = paths.reduce(nil) do |new_context, path| new_context.blank? && search_in(xml_context, path, options) || new_context end if new_context.respond_to?(:text) new_context else Struct::Value.new(new_context) end end