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.
- data/lib/saxaphone/element.rb +127 -9
- data/test/element_test.rb +49 -5
- metadata +5 -7
data/lib/saxaphone/element.rb
CHANGED
@@ -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)
|
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
|
-
|
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
|
38
|
-
|
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.
|
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.
|
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', '
|
46
|
+
element.add_element(Saxaphone::Element.new('faz', 'value1'))
|
47
|
+
element.add_element(Saxaphone::Element.new('foo', 'value2'))
|
47
48
|
|
48
|
-
assert_equal({'baz' => '
|
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
|
-
|
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
|
-
|
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.
|
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-
|
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: &
|
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: *
|
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.
|
62
|
+
rubygems_version: 1.8.10
|
65
63
|
signing_key:
|
66
64
|
specification_version: 3
|
67
65
|
summary: Object Oriented SAX Parsing
|