pauldix-sax-machine 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/sax-machine.rb CHANGED
@@ -7,5 +7,5 @@ require "sax-machine/sax_handler"
7
7
  require "sax-machine/sax_config"
8
8
 
9
9
  module SAXMachine
10
- VERSION = "0.0.12"
10
+ VERSION = "0.0.13"
11
11
  end
@@ -7,33 +7,32 @@ module SAXMachine
7
7
  @top_level_elements = []
8
8
  @collection_elements = []
9
9
  end
10
-
10
+
11
11
  def add_top_level_element(name, options)
12
12
  @top_level_elements << ElementConfig.new(name, options)
13
13
  end
14
-
14
+
15
15
  def add_collection_element(name, options)
16
16
  @collection_elements << CollectionConfig.new(name, options)
17
17
  end
18
-
18
+
19
19
  def collection_config(name)
20
20
  @collection_elements.detect { |ce| ce.name.to_s == name.to_s }
21
21
  end
22
22
 
23
- def element_config_for_attribute(name, attrs)
24
- element_configs = @top_level_elements.select do |element_config|
23
+ def element_configs_for_attribute(name, attrs)
24
+ @top_level_elements.select do |element_config|
25
25
  element_config.name == name &&
26
26
  element_config.has_value_and_attrs_match?(attrs)
27
27
  end
28
- element_configs.empty? ? nil : element_configs
29
28
  end
30
-
29
+
31
30
  def element_config_for_tag(name, attrs)
32
31
  @top_level_elements.detect do |element_config|
33
32
  element_config.name == name &&
34
33
  element_config.attrs_match?(attrs)
35
34
  end
36
35
  end
37
-
36
+
38
37
  end
39
38
  end
@@ -43,13 +43,15 @@ module SAXMachine
43
43
  sax_config.add_top_level_element(name, options.merge(:collection => true))
44
44
  end
45
45
 
46
+ if !instance_methods.include?(options[:as].to_s)
46
47
  class_eval <<-SRC
47
- def #{options[:as]}
48
- @#{options[:as]} ||= []
49
- end
50
- SRC
48
+ def #{options[:as]}
49
+ @#{options[:as]} ||= []
50
+ end
51
+ SRC
52
+ end
51
53
 
52
- attr_writer options[:as]
54
+ attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
53
55
  end
54
56
 
55
57
  def sax_config
@@ -31,7 +31,7 @@ module SAXMachine
31
31
  end
32
32
 
33
33
  def value_from_attrs(attrs)
34
- attrs[attrs.index(@value) + 1]
34
+ attrs.index(@value) ? attrs[attrs.index(@value) + 1] : nil
35
35
  end
36
36
 
37
37
  def attrs_match?(attrs)
@@ -3,12 +3,12 @@ require "nokogiri"
3
3
  module SAXMachine
4
4
  class SAXHandler < Nokogiri::XML::SAX::Document
5
5
  attr_reader :object
6
-
6
+
7
7
  def initialize(object)
8
8
  @object = object
9
9
  @parsed_configs = {}
10
10
  end
11
-
11
+
12
12
  def characters(string)
13
13
  if parsing_collection?
14
14
  @collection_handler.characters(string)
@@ -16,88 +16,99 @@ module SAXMachine
16
16
  @value << string
17
17
  end
18
18
  end
19
-
19
+
20
20
  def cdata_block(string)
21
21
  characters(string)
22
22
  end
23
-
23
+
24
24
  def start_element(name, attrs = [])
25
25
  @name = name
26
26
  @attrs = attrs
27
-
27
+
28
28
  if parsing_collection?
29
29
  @collection_handler.start_element(@name, @attrs)
30
-
30
+
31
31
  elsif @collection_config = sax_config.collection_config(@name)
32
32
  @collection_handler = @collection_config.handler
33
33
  @collection_handler.start_element(@name, @attrs)
34
-
35
- elsif @element_config = sax_config.element_config_for_attribute(@name, @attrs)
36
- parse_element_attribute
37
-
34
+
35
+ elsif (element_configs = sax_config.element_configs_for_attribute(@name, @attrs)).any?
36
+ parse_element_attributes(element_configs)
37
+ set_element_config_for_element_value
38
+
38
39
  else
39
- @value = ""
40
- @element_config = sax_config.element_config_for_tag(@name, @attrs)
40
+ set_element_config_for_element_value
41
41
  end
42
42
  end
43
-
43
+
44
44
  def end_element(name)
45
45
  if parsing_collection? && @collection_config.name == name
46
46
  @object.send(@collection_config.accessor) << @collection_handler.object
47
47
  reset_current_collection
48
-
48
+
49
49
  elsif parsing_collection?
50
50
  @collection_handler.end_element(name)
51
-
51
+
52
52
  elsif characaters_captured? && !parsed_config?
53
53
  mark_as_parsed
54
54
  @object.send(@element_config.setter, @value)
55
55
  end
56
-
56
+
57
57
  reset_current_tag
58
58
  end
59
-
59
+
60
60
  def characaters_captured?
61
61
  !@value.nil? && !@value.empty?
62
62
  end
63
-
63
+
64
64
  def parsing_collection?
65
65
  !@collection_handler.nil?
66
66
  end
67
-
68
- def parse_element_attribute
69
- unless parsed_config?
70
- mark_as_parsed
71
- @element_config.each do |config|
72
- @object.send(config.setter, config.value_from_attrs(@attrs))
67
+
68
+ def parse_collection_instance_attributes
69
+ instance = @collection_handler.object
70
+ @attrs.each_with_index do |attr_name,index|
71
+ instance.send("#{attr_name}=", @attrs[index + 1]) if index % 2 == 0 && instance.methods.include?("#{attr_name}=")
72
+ end
73
+ end
74
+
75
+ def parse_element_attributes(element_configs)
76
+ element_configs.each do |ec|
77
+ unless parsed_config?(ec)
78
+ @object.send(ec.setter, ec.value_from_attrs(@attrs))
79
+ mark_as_parsed(ec)
73
80
  end
74
81
  end
75
-
76
82
  @element_config = nil
77
83
  end
78
-
79
- def mark_as_parsed
80
- # TODO: make this code not suck like this
81
- @parsed_configs[@element_config] = true unless (@element_config.respond_to?(:collection?) && @element_config.collection?) ||
82
- (@element_config.class == Array && @element_config.first.collection?)
84
+
85
+ def set_element_config_for_element_value
86
+ @value = ""
87
+ @element_config = sax_config.element_config_for_tag(@name, @attrs)
83
88
  end
84
-
85
- def parsed_config?
86
- @parsed_configs[@element_config]
89
+
90
+ def mark_as_parsed(element_config=nil)
91
+ element_config ||= @element_config
92
+ @parsed_configs[element_config] = true unless element_config.collection?
93
+ end
94
+
95
+ def parsed_config?(element_config=nil)
96
+ element_config ||= @element_config
97
+ @parsed_configs[element_config]
87
98
  end
88
-
99
+
89
100
  def reset_current_collection
90
101
  @collection_handler = nil
91
102
  @collection_config = nil
92
103
  end
93
-
104
+
94
105
  def reset_current_tag
95
106
  @name = nil
96
107
  @attrs = nil
97
108
  @value = nil
98
109
  @element_config = nil
99
110
  end
100
-
111
+
101
112
  def sax_config
102
113
  @object.class.sax_config
103
114
  end
@@ -220,7 +220,37 @@ describe "SAXMachine" do
220
220
  document.first.should == "foo value"
221
221
  document.second.should == "bar value"
222
222
  end
223
+
224
+ it "should not fail if one of the attribute hasn't been defined" do
225
+ @klass = Class.new do
226
+ include SAXMachine
227
+ element :link, :value => :foo, :as => :first
228
+ element :link, :value => :bar, :as => :second
229
+ end
230
+ document = @klass.parse("<link foo='foo value'></link>")
231
+ document.first.should == "foo value"
232
+ document.second.should be_nil
233
+ end
234
+ end
235
+
236
+ describe "when desiring both the content and attributes of an element" do
237
+ before :each do
238
+ @klass = Class.new do
239
+ include SAXMachine
240
+ element :link
241
+ element :link, :value => :foo, :as => :link_foo
242
+ element :link, :value => :bar, :as => :link_bar
243
+ end
244
+ end
245
+
246
+ it "should parse the element and attribute values" do
247
+ document = @klass.parse("<link foo='test1' bar='test2'>hello</link>")
248
+ document.link.should == 'hello'
249
+ document.link_foo.should == 'test1'
250
+ document.link_bar.should == 'test2'
251
+ end
223
252
  end
253
+
224
254
  end
225
255
  end
226
256
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pauldix-sax-machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Dix