pauldix-sax-machine 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
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