Skip to content

Commit

Permalink
Merge c9d3905 into a659550
Browse files Browse the repository at this point in the history
  • Loading branch information
patleb committed Dec 1, 2017
2 parents a659550 + c9d3905 commit 2941d8a
Show file tree
Hide file tree
Showing 3 changed files with 579 additions and 0 deletions.
9 changes: 9 additions & 0 deletions lib/fog/parsers/base.rb
@@ -1,8 +1,17 @@
require "nokogiri"
require "fog/parsers/schema"

module Fog
module Parsers
class Base < Nokogiri::XML::SAX::Document
prepend Schema

def self.schema; end

def self.arrays
raise NotImplementedError
end

attr_reader :response

def initialize
Expand Down
178 changes: 178 additions & 0 deletions lib/fog/parsers/schema.rb
@@ -0,0 +1,178 @@
# frozen_string_literal: true

module Fog
module Parsers
module Schema
def reset
super
return unless (@schema = self.class.schema)

@stack = NodeStack.new(@response, @schema, self.class.arrays)
end

def start_element(name, attrs = [])
super
return unless @schema

@stack.start_element name
end

def end_element(name)
return super unless @schema

@stack.end_element name, value
end

class NodeStack < Array
alias_method :top, :last

def initialize(*args)
@response, @schema, @arrays = args
super()
end

def start_element(name)
if top
if @arrays.include? name
push top.new_item
elsif top.next_schema.key? name
push new_node(name, top.next_schema, top.next_result)
end
elsif @schema.key? name
push new_node(name, @schema, @response)
end
end

def end_element(name, value)
if top
if (@arrays + [top.name]).include? name
top.update_result(value)
pop
end
end
end

def new_node(name, schema_pointer, result_pointer)
node_class =
case schema_pointer[name]
when Hash
NodeHash
when Array
NodeArray
else
NodeValue
end
node_class.new(name, schema_pointer, result_pointer)
end
end

class Node
attr_reader :name

def initialize(name, schema_pointer, result_pointer, index = nil)
@name = name
@schema_pointer = schema_pointer
@result_pointer = result_pointer
@index = index
end

def update_result(_value); end

def next_schema
raise NotImplementedError
end

def next_result
raise NotImplementedError
end
end

class NodeHash < Node
def initialize(*_)
super
if @index
@result_pointer[name][@index] = {}
else
@result_pointer[name] = {}
end
end

def next_schema
_next_schema.is_a?(Hash) ? _next_schema : {}
end

def next_result
_next_schema.is_a?(Hash) ? _next_result : {}
end

private

def _next_schema
if @index
@schema_pointer[name].first
else
@schema_pointer[name]
end
end

def _next_result
if @index
@result_pointer[name][@index]
else
@result_pointer[name]
end
end
end

class NodeValue < Node
def next_schema
{}
end

def next_result
{}
end

def update_result(value)
if @index
@result_pointer[name][@index] = cast(value)
else
@result_pointer[name] = cast(value)
end
end

private

def cast(value)
case @schema_pointer[name]
when :boolean
value == "true"
when :time
Time.parse(value)
else
value
end
end
end

class NodeArray < Node
def initialize(*_)
super
@count = 0
@result_pointer[name] = []
end

def next_schema
@schema_pointer[name].first
end

def new_item
index = @count
@count += 1
item_class = next_schema.is_a?(Hash) ? NodeHash : NodeValue
item_class.new(name, @schema_pointer, @result_pointer, index)
end
end
end
end
end

0 comments on commit 2941d8a

Please sign in to comment.