saxaphone 0.3.1 → 0.4.0

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.
@@ -8,36 +8,149 @@ module Saxaphone
8
8
  end
9
9
 
10
10
  class << self
11
+ # A block can be passed to <tt>setup</tt>,
12
+ # which is called after the element is initialized.
13
+ #
14
+ # WidgetElement < Saxaphone::Element
15
+ # attr_accessor :foo
16
+ #
17
+ # setup do
18
+ # self.foo = 'bar'
19
+ # end
20
+ # end
21
+ #
22
+ # It is recommended to use setup rather than
23
+ # overriding initialize.
24
+ #
11
25
  def setup(&block)
12
26
  define_method(:setup, &block)
13
27
  end
14
28
 
29
+ # Define elements that should be stored as attributes:
30
+ #
31
+ # WidgetElement < Saxaphone::Element
32
+ # element_attributes %w(color price)
33
+ # end
34
+ #
35
+ # element = WidgetElement.parse %{
36
+ # <widget>
37
+ # <color>red</color>
38
+ # <price>4.33</price>
39
+ # </widget>
40
+ # }
41
+ #
42
+ # element.attributes # => {"color" => "red", "price" => "4.33"}
43
+ #
15
44
  def element_attributes(element_names)
16
45
  element_names.each do |element_name|
17
46
  element_attribute(element_name)
18
47
  end
19
48
  end
20
49
 
50
+ # Define a single element that should be stored as an attribute.
51
+ #
52
+ # WidgetElement < Saxaphone::Element
53
+ # element_attribute 'price'
54
+ # end
55
+ #
56
+ # element = WidgetElement.parse %{
57
+ # <widget>
58
+ # <price>4.33</price>
59
+ # </widget>
60
+ # }
61
+ #
62
+ # element.attributes # => {"price" => "4.33"}
63
+ #
64
+ # The name of the stored attribute can optionally be changed
65
+ # with the <tt>:as</tt> option:
66
+ #
67
+ # WidgetElement < Saxaphone::Element
68
+ # element_attribute 'price', as: 'dollars'
69
+ # end
70
+ #
71
+ # element = WidgetElement.parse %{
72
+ # <widget>
73
+ # <price>4.33</price>
74
+ # </widget>
75
+ # }
76
+ #
77
+ # element.attributes # => {"dollars" => "4.33"}
21
78
  def element_attribute(element_name, options = {})
22
- converted_name = options.delete(:as) || element_name
23
- logic = proc { |element| attributes[converted_name] = element.content }
24
- element_handler = ElementHandler.new(@@base_class_name, logic)
79
+ converted_name = options.delete(:as)
25
80
 
26
- element_handlers[element_name] = element_handler
81
+ has_element(element_name) do |element|
82
+ attributes[converted_name || element.name] = element.content
83
+ end
27
84
  end
28
85
 
86
+ # Define what to do for a particular child element.
87
+ # After the element is parsed, it is passed to the block:
88
+ #
89
+ # WidgetElement < Saxaphone::Element
90
+ # attr_accessor :cents
91
+ #
92
+ # has_element 'price' do |element|
93
+ # self.cents = element.content.to_f * 100
94
+ # end
95
+ # end
96
+ #
97
+ # element = WidgetElement.parse %{
98
+ # <widget>
99
+ # <price>4.33</price>
100
+ # </widget>
101
+ # }
102
+ #
103
+ # element.cents # => 433.0
104
+ #
105
+ # It is possible to define the class name that is used
106
+ # to parse the child element:
107
+ #
108
+ # PriceElement < Saxaphone::Element
109
+ # def cents
110
+ # content.to_f * 100
111
+ # end
112
+ # end
113
+ #
114
+ # WidgetElement < Saxaphone::Element
115
+ # attr_accessor :cents
116
+ #
117
+ # has_element 'price', 'PriceElement' do |element|
118
+ # self.cents = element.cents
119
+ # end
120
+ # end
121
+ #
122
+ # The children elements can have children of their own,
123
+ # and each uses has_element to define what to do.
124
+ #
29
125
  def has_element(element_name, class_name = @@base_class_name, &block)
30
126
  element_handlers[element_name] = ElementHandler.new(class_name, block)
31
127
  end
32
128
 
129
+ # Define a white list of the attributes that are extracted
130
+ # from the XML element and stored in the attribute hash:
131
+ #
132
+ # WidgetElement < Saxaphone::Element
133
+ # store_attributes 'name', 'color'
134
+ # end
135
+ #
136
+ # element = WidgetElement.parse %{
137
+ # <widget name="Acme" color="red" price="3.21">
138
+ # ...
139
+ # </widget>
140
+ # }
141
+ #
142
+ # element.attributes # => {"name" => "Acme", "color" => "red"}
143
+ #
144
+ # Notice that the "price" attribute is not stored.
145
+ #
33
146
  def store_attributes(*attribute_names)
34
147
  @stored_attributes = attribute_names.flatten.to_set
35
148
  end
36
149
 
37
- def element_handlers
38
- @element_handlers ||= {}
150
+ def handler_for(element_name)
151
+ element_handlers[element_name] || element_handlers['*']
39
152
  end
40
-
153
+
41
154
  def stored_attributes
42
155
  @stored_attributes ||= Set.new
43
156
  end
@@ -45,6 +158,11 @@ module Saxaphone
45
158
  def parse(xml)
46
159
  Saxaphone::Document.parse(xml, self)
47
160
  end
161
+
162
+ private
163
+ def element_handlers
164
+ @element_handlers ||= {}
165
+ end
48
166
  end
49
167
 
50
168
  attr_accessor :name, :content, :attributes
@@ -59,13 +177,13 @@ module Saxaphone
59
177
  end
60
178
 
61
179
  def add_element(element)
62
- if element_handler = self.class.element_handlers[element.name]
180
+ if element_handler = self.class.handler_for(element.name)
63
181
  instance_exec(element, &element_handler.proc) if element_handler.proc
64
182
  end
65
183
  end
66
184
 
67
185
  def element_for(element_name)
68
- if element_handler = self.class.element_handlers[element_name]
186
+ if element_handler = self.class.handler_for(element_name)
69
187
  Saxaphone::Util.constantize(element_handler.class_name)
70
188
  else
71
189
  Saxaphone::Element
data/test/element_test.rb CHANGED
@@ -43,12 +43,42 @@ class Saxaphone::ElementTest < MiniTest::Spec
43
43
  element_attribute 'faz', as: 'baz'
44
44
  end
45
45
 
46
- element.add_element(Saxaphone::Element.new('faz', 'value'))
46
+ element.add_element(Saxaphone::Element.new('faz', 'value1'))
47
+ element.add_element(Saxaphone::Element.new('foo', 'value2'))
47
48
 
48
- assert_equal({'baz' => 'value'}, element.attributes)
49
+ assert_equal({'baz' => 'value1'}, element.attributes)
50
+ end
51
+
52
+ def test_element_attribute_with_any
53
+ element = define_element do
54
+ element_attribute 'faz', as: 'baz'
55
+ element_attribute '*'
56
+ end
57
+
58
+ element.add_element(Saxaphone::Element.new('faz', 'value1'))
59
+ element.add_element(Saxaphone::Element.new('foo', 'value2'))
60
+
61
+ assert_equal({'baz' => 'value1', 'foo' => 'value2'}, element.attributes)
49
62
  end
50
63
 
51
64
  def test_has_element_with_block
65
+ element = define_element do
66
+ attr_accessor :child_content
67
+
68
+ has_element 'omg' do |element|
69
+ self.child_content = element.content
70
+ end
71
+ end
72
+
73
+ child_element = element.element_for('omg').new('omg')
74
+ child_element.content = 'weee'
75
+ element.add_element(child_element)
76
+
77
+ assert_kind_of Saxaphone::Element, child_element
78
+ assert_equal 'weee', element.child_content
79
+ end
80
+
81
+ def test_has_element_with_block_and_custom_element
52
82
  element = define_element do
53
83
  attr_accessor :child_special
54
84
 
@@ -58,14 +88,28 @@ class Saxaphone::ElementTest < MiniTest::Spec
58
88
  end
59
89
 
60
90
  child_element = element.element_for('omg').new('omg')
91
+ child_element.special = 'weee'
92
+ element.add_element(child_element)
61
93
 
62
94
  assert_kind_of TestChildElement, child_element
63
- child_element.special = 'weee'
95
+ assert_equal 'weee', element.child_special
96
+ end
97
+
98
+ def test_has_element_with_any
99
+ element = define_element do
100
+ has_element '*' do |element|
101
+ self.attributes[element.name.upcase] = element.content
102
+ end
103
+ end
104
+
105
+ child_element = element.element_for('faz').new('faz')
106
+ child_element.content = 'weee'
64
107
  element.add_element(child_element)
65
108
 
66
- assert_equal 'weee', element.child_special
109
+ assert_kind_of Saxaphone::Element, child_element
110
+ assert_equal({'FAZ' => 'weee'}, element.attributes)
67
111
  end
68
-
112
+
69
113
  def test_has_element_without_block
70
114
  element = define_element do
71
115
  has_element 'wtf', 'Saxaphone::ElementTest::TestChildElement'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saxaphone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-18 00:00:00.000000000 -07:00
13
- default_executable:
12
+ date: 2011-11-08 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: nokogiri
17
- requirement: &2162445820 !ruby/object:Gem::Requirement
16
+ requirement: &70201937138840 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ! '>='
@@ -22,7 +21,7 @@ dependencies:
22
21
  version: '0'
23
22
  type: :runtime
24
23
  prerelease: false
25
- version_requirements: *2162445820
24
+ version_requirements: *70201937138840
26
25
  description: Use objects
27
26
  email: developer@matthewhiggins.com
28
27
  executables: []
@@ -40,7 +39,6 @@ files:
40
39
  - test/document_test.rb
41
40
  - test/element_test.rb
42
41
  - test/test_helper.rb
43
- has_rdoc: true
44
42
  homepage: http://github.com/matthuhiggins/saxaphone
45
43
  licenses: []
46
44
  post_install_message:
@@ -61,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
59
  version: 1.3.5
62
60
  requirements: []
63
61
  rubyforge_project:
64
- rubygems_version: 1.6.2
62
+ rubygems_version: 1.8.10
65
63
  signing_key:
66
64
  specification_version: 3
67
65
  summary: Object Oriented SAX Parsing