Class: Qbxml

Inherits:
Object
  • Object
show all
Includes:
Types
Defined in:
lib/qbxml.rb,
lib/qbxml/qbxml.rb,
lib/qbxml/version.rb

Defined Under Namespace

Modules: Types Classes: Hash

Constant Summary collapse

SCHEMA_PATH =
File.expand_path('../../../schema', __FILE__)
SCHEMAS =
{
  qb:    "#{SCHEMA_PATH}/qbxmlops70.xml",
  qbpos: "#{SCHEMA_PATH}/qbposxmlops30.xml" 
}.freeze
HIDE_IVARS =
[:@doc].freeze
VERSION =
"1.0.2"

Constants included from Types

Types::ACRONYMS, Types::BOOL_CAST, Types::DATE_CAST, Types::FLOAT_CAST, Types::INT_CAST, Types::STR_CAST, Types::TIME_CAST, Types::TYPE_MAP, Types::XML_DIRECTIVES

Instance Method Summary collapse

Constructor Details

#initialize(key = :qb) ⇒ Qbxml

Returns a new instance of Qbxml.



13
14
15
16
# File 'lib/qbxml/qbxml.rb', line 13

def initialize(key = :qb)
  @schema = key
  @doc    = parse_schema(key)
end

Instance Method Details

#describe(type) ⇒ Object

returns the xml node for the specified type



30
31
32
# File 'lib/qbxml/qbxml.rb', line 30

def describe(type)
  @doc.xpath("//#{type}").first
end

#from_qbxml(xml, opts = {}) ⇒ Object

converts qbxml to a hash



46
47
48
49
50
# File 'lib/qbxml/qbxml.rb', line 46

def from_qbxml(xml, opts = {})
  hash = Qbxml::Hash.from_xml(xml, underscore: true, schema: @doc)

  opts[:no_namespace] ? hash : namespace_qbxml_hash(hash)
end

#inspectObject

making this more sane so that it doesn’t dump the whole schema doc to stdout every time



55
56
57
58
59
60
61
62
63
# File 'lib/qbxml/qbxml.rb', line 55

def inspect
  prefix = "#<#{self.class}:0x#{self.__id__.to_s(16)} "

  (instance_variables - HIDE_IVARS).each do |var|
    prefix << "#{var}=#{instance_variable_get(var).inspect}"
  end

  return "#{prefix}>"
end

#namespace_qbxml_hash(hash) ⇒ Object

hash to qbxml



77
78
79
80
81
82
83
# File 'lib/qbxml/qbxml.rb', line 77

def namespace_qbxml_hash(hash)
  node = describe(hash.keys.first)
  return hash unless node

  path = node.path.split('/')[1...-1].reverse
  path.inject(hash) { |h,p| Qbxml::Hash[ p => h ] }
end

#parse_schema(key) ⇒ Object

private



67
68
69
# File 'lib/qbxml/qbxml.rb', line 67

def parse_schema(key)
  File.open(select_schema(key)) { |f| Nokogiri::XML(f) }
end

#select_schema(schema_key) ⇒ Object



71
72
73
# File 'lib/qbxml/qbxml.rb', line 71

def select_schema(schema_key)
  SCHEMAS[schema_key] || raise("invalid schema, must be one of #{SCHEMA.keys.inspect}")
end

#to_qbxml(hash, opts = {}) ⇒ Object

converts a hash to qbxml with optional validation



36
37
38
39
40
41
42
# File 'lib/qbxml/qbxml.rb', line 36

def to_qbxml(hash, opts = {})
  hash = Qbxml::Hash.from_hash(hash, camelize: true)
  hash = namespace_qbxml_hash(hash) unless opts[:no_namespace] 
  validate_qbxml_hash(hash) if opts[:validate]

  Qbxml::Hash.to_xml(hash, xml_directive: XML_DIRECTIVES[@schema])
end

#types(pattern = nil) ⇒ Object

returns all xml nodes matching a specified pattern



20
21
22
23
24
25
26
# File 'lib/qbxml/qbxml.rb', line 20

def types(pattern = nil)
  @types ||= @doc.xpath("//*").map { |e| e.name }.uniq

  pattern ?
    @types.select { |t| t =~ Regexp.new(pattern) } :
    @types
end

#validate_qbxml_hash(hash, path = []) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/qbxml/qbxml.rb', line 85

def validate_qbxml_hash(hash, path = [])
  hash.each do |k,v|
    next if k == Qbxml::HASH::ATTR_ROOT
    key_path = path.dup << k
    if v.is_a?(Hash)
      validate_qbxml_hash(v, key_path)
    else
      validate_xpath(key_path)
    end
  end
end

#validate_xpath(path) ⇒ Object



97
98
99
100
# File 'lib/qbxml/qbxml.rb', line 97

def validate_xpath(path)
  xpath = "/#{path.join('/')}"
  raise "#{xpath} is not a valid type" if @doc.xpath(xpath).empty?
end