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: {
    "2.0" => "#{SCHEMA_PATH}/qbxmlops20.xml",
    "CA3.0" => "#{SCHEMA_PATH}/qbxmlopsCA30.xml",
    "3.0" => "#{SCHEMA_PATH}/qbxmlops30.xml",
    "4.0" => "#{SCHEMA_PATH}/qbxmlops40.xml",
    "4.1" => "#{SCHEMA_PATH}/qbxmlops41.xml",
    "5.0" => "#{SCHEMA_PATH}/qbxmlops50.xml",
    "6.0" => "#{SCHEMA_PATH}/qbxmlops60.xml",
    "7.0" => "#{SCHEMA_PATH}/qbxmlops70.xml",
    "8.0" => "#{SCHEMA_PATH}/qbxmlops80.xml",
    "10.0" => "#{SCHEMA_PATH}/qbxmlops100.xml",
    "11.0" => "#{SCHEMA_PATH}/qbxmlops110.xml",
    "12.0" => "#{SCHEMA_PATH}/qbxmlops120.xml",
    "13.0" => "#{SCHEMA_PATH}/qbxmlops130.xml"
  },
  qbpos: {
    "3.0" => "#{SCHEMA_PATH}/qbposxmlops30.xml"
  }
}.freeze
HIDE_IVARS =
[:@doc].freeze
VERSION =
"0.2.0"

Constants included from Types

Types::ACRONYMS, Types::BIGDECIMAL_CAST, 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, version = "7.0") ⇒ Qbxml

Returns a new instance of Qbxml.



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

def initialize(key = :qb, version = "7.0")
  @schema  = key
  @version = version
  @doc     = parse_schema(key, version)
end

Instance Method Details

#describe(type) ⇒ Object

returns the xml node for the specified type



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

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

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

converts qbxml to a hash



63
64
65
66
67
# File 'lib/qbxml/qbxml.rb', line 63

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



72
73
74
75
76
77
78
79
80
# File 'lib/qbxml/qbxml.rb', line 72

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



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

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, version) ⇒ Object

private



84
85
86
# File 'lib/qbxml/qbxml.rb', line 84

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

#select_schema(schema_key, version) ⇒ Object



88
89
90
91
92
# File 'lib/qbxml/qbxml.rb', line 88

def select_schema(schema_key, version)
  raise "invalid schema '#{schema_key}', must be one of #{SCHEMAS.keys.inspect}" if !SCHEMAS.has_key?(schema_key)
  raise "invalid version '#{version}' for schema #{schema_key}, must be one of #{SCHEMAS[schema_key].keys.inspect}" if !SCHEMAS[schema_key].has_key?(version)
  return SCHEMAS[schema_key][version]
end

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

converts a hash to qbxml with optional validation



53
54
55
56
57
58
59
# File 'lib/qbxml/qbxml.rb', line 53

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, schema: XML_DIRECTIVES[@schema], version: @version)
end

#types(pattern = nil) ⇒ Object

returns all xml nodes matching a specified pattern



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

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



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/qbxml/qbxml.rb', line 104

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



116
117
118
119
# File 'lib/qbxml/qbxml.rb', line 116

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