Skip to content

Commit

Permalink
Updates to support also pulling the element value out along side attr…
Browse files Browse the repository at this point in the history
…ibutes
  • Loading branch information
krobertson committed Feb 15, 2011
1 parent ed2c901 commit 15adc32
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 12 deletions.
18 changes: 14 additions & 4 deletions lib/sax-machine/sax_config.rb
@@ -1,15 +1,17 @@
require "sax-machine/sax_attribute_config"
require "sax-machine/sax_element_value_config"
require "sax-machine/sax_element_config"
require "sax-machine/sax_collection_config"

module SAXMachine
class SAXConfig
attr_accessor :top_level_elements, :top_level_attributes, :collection_elements
attr_accessor :top_level_elements, :top_level_attributes, :top_level_element_value, :collection_elements

def initialize
@top_level_elements = {}
@top_level_attributes = []
@collection_elements = {}
@top_level_elements = {}
@top_level_attributes = []
@top_level_element_value = []
@collection_elements = {}
end

def columns
Expand All @@ -30,6 +32,10 @@ def add_top_level_attribute(name, options)
@top_level_attributes << AttributeConfig.new(options.delete(:name), options)
end

def add_top_level_element_value(name, options)
@top_level_element_value << ElementValueConfig.new(options.delete(:name), options)
end

def add_collection_element(name, options)
@collection_elements[name.to_s] = [] unless @collection_elements[name.to_s]
@collection_elements[name.to_s] << CollectionConfig.new(name, options)
Expand All @@ -44,6 +50,10 @@ def attribute_configs_for_element(attrs)
@top_level_attributes.select { |aa| aa.attrs_match?(attrs) }
end

def element_values_for_element
@top_level_element_value
end

def element_configs_for_attribute(name, attrs)
tes = @top_level_elements[name.to_s]
tes && tes.select { |ec| ec.has_value_and_attrs_match?(attrs) } || []
Expand Down
8 changes: 8 additions & 0 deletions lib/sax-machine/sax_document.rb
Expand Up @@ -38,6 +38,14 @@ def attribute(name, options = {})
attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
end

def value(name, options = {})
options[:as] ||= name
sax_config.add_top_level_element_value(self.class.to_s, options.merge(:name => name))

attr_reader options[:as] unless instance_methods.include?(options[:as].to_s)
attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
end

def columns
sax_config.columns
end
Expand Down
24 changes: 24 additions & 0 deletions lib/sax-machine/sax_element_value_config.rb
@@ -0,0 +1,24 @@
module SAXMachine
class SAXConfig

class ElementValueConfig
attr_reader :name, :setter

def initialize(name, options)
@name = name.to_s
@as = options[:as]
@setter = "#{@as}="
@required = options[:required]
end

def column
@as || @name.to_sym
end

def required?
@required
end
end

end
end
16 changes: 8 additions & 8 deletions lib/sax-machine/sax_handler.rb
Expand Up @@ -28,10 +28,8 @@ def start_element(name, attrs = [])
stack.push [object = collection_config.data_class.new, collection_config, ""]
object, sax_config, is_collection = object, object.class.sax_config, true

if !(attribute_config = object.class.respond_to?(:sax_config) && object.class.sax_config.attribute_configs_for_element(attrs)).empty?
attribute_config.each do |ac|
object.send(ac.setter, ac.value_from_attrs(attrs))
end
if (attribute_config = object.class.respond_to?(:sax_config) && object.class.sax_config.attribute_configs_for_element(attrs))
attribute_config.each { |ac| object.send(ac.setter, ac.value_from_attrs(attrs)) }
end
end
sax_config.element_configs_for_attribute(name, attrs).each do |ec|
Expand All @@ -44,10 +42,8 @@ def start_element(name, attrs = [])
new_object = element_config.data_class ? element_config.data_class.new : object
stack.push [new_object, element_config, ""]

if !(attribute_config = new_object.class.respond_to?(:sax_config) && new_object.class.sax_config.attribute_configs_for_element(attrs)).empty?
attribute_config.each do |ac|
new_object.send(ac.setter, ac.value_from_attrs(attrs))
end
if (attribute_config = new_object.class.respond_to?(:sax_config) && new_object.class.sax_config.attribute_configs_for_element(attrs))
attribute_config.each { |ac| new_object.send(ac.setter, ac.value_from_attrs(attrs)) }
end
end
end
Expand All @@ -58,6 +54,10 @@ def end_element(name)
return unless stack.size > 1 && config && config.name.to_s == name.to_s

unless parsed_config?(object, config)
if (element_value_config = config.data_class.respond_to?(:sax_config) && config.data_class.sax_config.element_values_for_element)
element_value_config.each { |evc| element.send(evc.setter, value) }
end

if config.respond_to?(:accessor)
object.send(config.accessor) << element
else
Expand Down
79 changes: 79 additions & 0 deletions spec/sax-machine/sax_document_spec.rb
Expand Up @@ -592,4 +592,83 @@ class ItemElement2
@item.authors.last.role.should == 'artist'
end
end

describe "with mixed attributes and element values" do
before do
@xml = %[
<item id="1">
<author role="writer">John Doe</author>
</item>
]
class AuthorElement3
include SAXMachine
value :name
attribute :role
end
class ItemElement3
include SAXMachine
element :author, :class => AuthorElement3
end
@item = ItemElement3.parse(@xml)
end

it 'should have the child elements' do
@item.author.should_not be_nil
end

it 'should have the author names' do
@item.author.name.should == 'John Doe'
end

it 'should have the author roles' do
@item.author.role.should == 'writer'
end
end

describe "with multiple mixed attributes and element values" do
before do
@xml = %[
<item id="1">
<title>sweet</title>
<author role="writer">John Doe</author>
<author role="artist">Jane Doe</author>
</item>
]
class AuthorElement4
include SAXMachine
value :name
attribute :role
end
class ItemElement4
include SAXMachine
element :title
elements :author, :as => :authors, :class => AuthorElement4

def title=(blah)
#raise 'woo'
@title = blah
end
end
@item = ItemElement4.parse(@xml)
end

it 'should have the title' do
@item.title.should == 'sweet'
end

it 'should have the child elements' do
@item.authors.should_not be_nil
@item.authors.count.should == 2
end

it 'should have the author names' do
@item.authors.first.name.should == 'John Doe'
@item.authors.last.name.should == 'Jane Doe'
end

it 'should have the author roles' do
@item.authors.first.role.should == 'writer'
@item.authors.last.role.should == 'artist'
end
end
end

0 comments on commit 15adc32

Please sign in to comment.