representative 0.1.3 → 0.2.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/README.markdown +15 -12
- data/examples/xml_demo.rb +9 -9
- data/lib/representative/version.rb +1 -1
- data/lib/representative/xml.rb +33 -39
- data/spec/representative/xml_spec.rb +62 -48
- metadata +4 -4
data/README.markdown
CHANGED
@@ -37,15 +37,18 @@ Given a Ruby data-structure:
|
|
37
37
|
Representative::Xml can be used to generate XML, in a declarative style:
|
38
38
|
|
39
39
|
xml = Builder::XmlMarkup.new(:indent => 2)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
|
41
|
+
Representative::Xml.new(xml) do |r|
|
42
|
+
|
43
|
+
r.list_of :books, books do
|
44
|
+
r.element :title
|
45
|
+
r.list_of :authors
|
46
|
+
r.element :published do
|
47
|
+
r.element :by
|
48
|
+
r.element :year
|
49
|
+
end
|
48
50
|
end
|
51
|
+
|
49
52
|
end
|
50
53
|
|
51
54
|
puts xml.target!
|
@@ -85,18 +88,18 @@ The resulting XML looks like this:
|
|
85
88
|
|
86
89
|
Notice that:
|
87
90
|
|
88
|
-
- Representative generates elements for each object-attribute you name (and not the ones you don't).
|
89
91
|
- The structure of the XML mirrors the structure described by the nested Ruby blocks.
|
90
|
-
-
|
92
|
+
- Representative walks the object-graph for you.
|
93
|
+
- Using `list_of` for a collection attribute generates an "array" element, which plays nicely
|
91
94
|
with most Ruby XML-to-hash converters.
|
92
95
|
- Where a named object-attribute is nil, you get an empty element.
|
93
96
|
|
94
97
|
Installation
|
95
98
|
------------
|
96
99
|
|
97
|
-
Representative is packaged as a Gem
|
100
|
+
Representative is packaged as a Gem. Install with:
|
98
101
|
|
99
|
-
|
102
|
+
gem install representative
|
100
103
|
|
101
104
|
Copyright
|
102
105
|
---------
|
data/examples/xml_demo.rb
CHANGED
@@ -29,15 +29,15 @@ books = [
|
|
29
29
|
]
|
30
30
|
|
31
31
|
xml = Builder::XmlMarkup.new(:indent => 2)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
Representative::Xml.new(xml) do |r|
|
33
|
+
r.list_of :books, books do
|
34
|
+
r.element :title
|
35
|
+
r.list_of :authors
|
36
|
+
r.element :published do
|
37
|
+
r.element :by
|
38
|
+
r.element :year
|
39
|
+
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
puts xml.target!
|
43
|
+
puts xml.target!
|
data/lib/representative/xml.rb
CHANGED
@@ -15,61 +15,40 @@ module Representative
|
|
15
15
|
yield self if block_given?
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
def represent(subject)
|
19
|
+
@subjects.push(subject)
|
20
|
+
begin
|
21
|
+
yield subject
|
22
|
+
ensure
|
23
|
+
@subjects.pop
|
23
24
|
end
|
24
25
|
end
|
25
|
-
|
26
|
-
def subject
|
26
|
+
|
27
|
+
def subject
|
27
28
|
@subjects.last
|
28
29
|
end
|
29
30
|
|
30
|
-
def
|
31
|
+
def element(name, *args, &block)
|
31
32
|
|
32
33
|
element_attributes = args.extract_options!
|
33
34
|
value_generator = if args.empty?
|
34
35
|
lambda do |subject|
|
35
|
-
@inspector.get_value(subject,
|
36
|
+
@inspector.get_value(subject, name)
|
36
37
|
end
|
37
38
|
else
|
38
39
|
args.shift
|
39
40
|
end
|
40
41
|
raise ArgumentError, "too many arguments" unless args.empty?
|
41
42
|
|
42
|
-
element_name = subject_attribute_name.to_s.dasherize
|
43
|
-
|
44
43
|
value = resolve_value(value_generator)
|
45
44
|
resolved_element_attributes = resolve_element_attributes(element_attributes, value)
|
46
|
-
resolved_element_attributes.merge!(@inspector.get_metadata(subject
|
45
|
+
resolved_element_attributes.merge!(@inspector.get_metadata(subject, name))
|
47
46
|
|
48
|
-
|
47
|
+
emit_element(name, value, resolved_element_attributes, &block)
|
49
48
|
|
50
49
|
end
|
51
50
|
|
52
|
-
def
|
53
|
-
content = content_generator = nil
|
54
|
-
if block && subject
|
55
|
-
unless block == Representative::EMPTY
|
56
|
-
content_generator = Proc.new do
|
57
|
-
@subjects.push(subject)
|
58
|
-
begin
|
59
|
-
block.call(self)
|
60
|
-
ensure
|
61
|
-
@subjects.pop
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
else
|
66
|
-
content = subject
|
67
|
-
end
|
68
|
-
tag_args = [content, options].compact
|
69
|
-
@xml.tag!(element_name, *tag_args, &content_generator)
|
70
|
-
end
|
71
|
-
|
72
|
-
def list_of!(attribute_name, *args, &block)
|
51
|
+
def list_of(attribute_name, *args, &block)
|
73
52
|
|
74
53
|
options = args.extract_options!
|
75
54
|
value_generator = args.empty? ? attribute_name : args.shift
|
@@ -90,19 +69,34 @@ module Representative
|
|
90
69
|
@xml.tag!(list_name, resolved_list_element_attributes.merge(:type => "array")) do
|
91
70
|
items.each do |item|
|
92
71
|
resolved_item_element_attributes = resolve_element_attributes(item_element_attributes, item)
|
93
|
-
|
72
|
+
emit_element(item_name, item, resolved_item_element_attributes, &block)
|
94
73
|
end
|
95
74
|
end
|
96
75
|
|
97
76
|
end
|
98
77
|
|
99
|
-
def empty
|
100
|
-
|
78
|
+
def empty
|
79
|
+
Representative::EMPTY
|
101
80
|
end
|
102
|
-
|
81
|
+
|
103
82
|
private
|
104
83
|
|
105
|
-
def
|
84
|
+
def emit_element(name, subject, options, &content_block)
|
85
|
+
content = content_generator = nil
|
86
|
+
if subject && content_block
|
87
|
+
unless content_block == Representative::EMPTY
|
88
|
+
content_generator = Proc.new do
|
89
|
+
represent(subject, &content_block)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
content = subject
|
94
|
+
end
|
95
|
+
tag_args = [content, options].compact
|
96
|
+
@xml.tag!(name.to_s.dasherize, *tag_args, &content_generator)
|
97
|
+
end
|
98
|
+
|
99
|
+
def resolve_value(value_generator, subject = subject)
|
106
100
|
if value_generator == :self
|
107
101
|
subject
|
108
102
|
elsif value_generator.respond_to?(:to_proc)
|
@@ -10,8 +10,8 @@ describe Representative::Xml do
|
|
10
10
|
@xml = Builder::XmlMarkup.new
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
@
|
13
|
+
def r
|
14
|
+
@representative ||= Representative::Xml.new(@xml, @subject)
|
15
15
|
end
|
16
16
|
|
17
17
|
def resulting_xml
|
@@ -22,38 +22,37 @@ describe Representative::Xml do
|
|
22
22
|
|
23
23
|
before do
|
24
24
|
@subject = OpenStruct.new(:name => "Fred", :width => 200, :vehicle => OpenStruct.new(:year => "1959", :make => "Chevrolet"))
|
25
|
-
@xml_representative = Representative::Xml.new(@xml, @subject)
|
26
25
|
end
|
27
26
|
|
28
|
-
describe "
|
27
|
+
describe "#element" do
|
29
28
|
|
30
29
|
it "generates an element with content extracted from the subject" do
|
31
|
-
|
30
|
+
r.element :name
|
32
31
|
resulting_xml.should == %(<name>Fred</name>)
|
33
32
|
end
|
34
33
|
|
35
|
-
it "dasherizes the
|
34
|
+
it "dasherizes the property name" do
|
36
35
|
@subject.full_name = "Fredrick"
|
37
|
-
|
36
|
+
r.element :full_name
|
38
37
|
resulting_xml.should == %(<full-name>Fredrick</full-name>)
|
39
38
|
end
|
40
39
|
|
41
|
-
describe "with
|
40
|
+
describe "with attributes" do
|
42
41
|
|
43
42
|
it "generates attributes on the element" do
|
44
|
-
|
43
|
+
r.element :name, :lang => "fr"
|
45
44
|
resulting_xml.should == %(<name lang="fr">Fred</name>)
|
46
45
|
end
|
47
46
|
|
48
47
|
it "dasherizes the attribute name" do
|
49
|
-
|
48
|
+
r.element :name, :sourced_from => "phonebook"
|
50
49
|
resulting_xml.should == %(<name sourced-from="phonebook">Fred</name>)
|
51
50
|
end
|
52
51
|
|
53
52
|
describe "whose value supports #to_proc" do
|
54
53
|
|
55
54
|
it "calls the Proc on the subject to generate a value" do
|
56
|
-
|
55
|
+
r.element :name, :rev => :reverse
|
57
56
|
resulting_xml.should == %(<name rev="derF">Fred</name>)
|
58
57
|
end
|
59
58
|
|
@@ -62,7 +61,7 @@ describe Representative::Xml do
|
|
62
61
|
describe "with value nil" do
|
63
62
|
|
64
63
|
it "omits the attribute" do
|
65
|
-
|
64
|
+
r.element :name, :lang => nil
|
66
65
|
resulting_xml.should == %(<name>Fred</name>)
|
67
66
|
end
|
68
67
|
|
@@ -70,17 +69,17 @@ describe Representative::Xml do
|
|
70
69
|
|
71
70
|
end
|
72
71
|
|
73
|
-
describe "with
|
72
|
+
describe "with an explicit value" do
|
74
73
|
|
75
74
|
it "generates an element with explicitly provided content" do
|
76
|
-
|
75
|
+
r.element :name, "Bloggs"
|
77
76
|
resulting_xml.should == %(<name>Bloggs</name>)
|
78
77
|
end
|
79
78
|
|
80
|
-
describe "AND
|
79
|
+
describe "AND attributes" do
|
81
80
|
|
82
81
|
it "generates attributes on the element" do
|
83
|
-
|
82
|
+
r.element :name, "Bloggs", :lang => "fr"
|
84
83
|
resulting_xml.should == %(<name lang="fr">Bloggs</name>)
|
85
84
|
end
|
86
85
|
|
@@ -88,37 +87,37 @@ describe Representative::Xml do
|
|
88
87
|
|
89
88
|
end
|
90
89
|
|
91
|
-
describe "with
|
90
|
+
describe "with a value argument that supports #to_proc" do
|
92
91
|
|
93
92
|
it "calls the Proc on the subject to generate a value" do
|
94
|
-
|
93
|
+
r.element :name, :width
|
95
94
|
resulting_xml.should == %(<name>200</name>)
|
96
95
|
end
|
97
96
|
|
98
97
|
end
|
99
98
|
|
100
|
-
describe "with argument :self" do
|
99
|
+
describe "with value argument :self" do
|
101
100
|
|
102
101
|
it "doesn't alter the subject" do
|
103
|
-
|
104
|
-
|
102
|
+
r.element :info, :self do
|
103
|
+
r.element :name
|
105
104
|
end
|
106
105
|
resulting_xml.should == %(<info><name>Fred</name></info>)
|
107
106
|
end
|
108
107
|
|
109
108
|
end
|
110
109
|
|
111
|
-
describe "with
|
110
|
+
describe "with value argument nil" do
|
112
111
|
|
113
112
|
it "builds an empty element" do
|
114
|
-
|
113
|
+
r.element :name, nil
|
115
114
|
resulting_xml.should == %(<name/>)
|
116
115
|
end
|
117
116
|
|
118
|
-
describe "and
|
117
|
+
describe "and attributes" do
|
119
118
|
|
120
|
-
it "omits the
|
121
|
-
|
119
|
+
it "omits the attributes" do
|
120
|
+
r.element :name, nil, :size => :size
|
122
121
|
resulting_xml.should == %(<name/>)
|
123
122
|
end
|
124
123
|
|
@@ -127,8 +126,8 @@ describe Representative::Xml do
|
|
127
126
|
describe "and a block" do
|
128
127
|
|
129
128
|
it "doesn't call the block" do
|
130
|
-
|
131
|
-
|
129
|
+
r.element :name, nil do
|
130
|
+
raise "hell"
|
132
131
|
end
|
133
132
|
resulting_xml.should == %(<name/>)
|
134
133
|
end
|
@@ -140,41 +139,47 @@ describe Representative::Xml do
|
|
140
139
|
describe "with a block" do
|
141
140
|
|
142
141
|
it "generates nested elements" do
|
143
|
-
|
144
|
-
|
145
|
-
|
142
|
+
r.element :vehicle do
|
143
|
+
r.element :year
|
144
|
+
r.element :make
|
146
145
|
end
|
147
146
|
resulting_xml.should == %(<vehicle><year>1959</year><make>Chevrolet</make></vehicle>)
|
148
147
|
end
|
149
148
|
|
149
|
+
it "yields each new subject" do
|
150
|
+
r.element :vehicle do |vehicle|
|
151
|
+
vehicle.should == @subject.vehicle
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
150
155
|
end
|
151
|
-
|
152
|
-
end
|
153
156
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
157
|
+
describe "with an EMPTY block" do
|
158
|
+
|
159
|
+
it "generates an empty element" do
|
160
|
+
r.element :vehicle, :year => :year, &r.empty
|
161
|
+
resulting_xml.should == %(<vehicle year="1959"/>)
|
162
|
+
end
|
163
|
+
|
159
164
|
end
|
160
165
|
|
161
166
|
end
|
162
167
|
|
163
|
-
describe "#list_of
|
168
|
+
describe "#list_of" do
|
164
169
|
|
165
170
|
before do
|
166
171
|
@subject.nick_names = ["Freddie", "Knucklenose"]
|
167
172
|
end
|
168
173
|
|
169
174
|
it "generates an array element" do
|
170
|
-
|
175
|
+
r.list_of(:nick_names)
|
171
176
|
resulting_xml.should == %(<nick-names type="array"><nick-name>Freddie</nick-name><nick-name>Knucklenose</nick-name></nick-names>)
|
172
177
|
end
|
173
178
|
|
174
179
|
describe "with :list_attributes" do
|
175
180
|
|
176
181
|
it "attaches attributes to the array element" do
|
177
|
-
|
182
|
+
r.list_of(:nick_names, :list_attributes => {:color => "blue", :size => :size})
|
178
183
|
array_element_attributes = REXML::Document.new(resulting_xml).root.attributes
|
179
184
|
array_element_attributes["type"].should == "array"
|
180
185
|
array_element_attributes["color"].should == "blue"
|
@@ -187,7 +192,7 @@ describe Representative::Xml do
|
|
187
192
|
describe "with :item_attributes" do
|
188
193
|
|
189
194
|
it "attaches attributes to each item element" do
|
190
|
-
|
195
|
+
r.list_of(:nick_names, :item_attributes => {:length => :size})
|
191
196
|
resulting_xml.should == %(<nick-names type="array"><nick-name length="7">Freddie</nick-name><nick-name length="11">Knucklenose</nick-name></nick-names>)
|
192
197
|
end
|
193
198
|
|
@@ -195,7 +200,7 @@ describe Representative::Xml do
|
|
195
200
|
|
196
201
|
describe "with an explicit :item_name" do
|
197
202
|
it "uses the name provided" do
|
198
|
-
|
203
|
+
r.list_of(:nick_names, :item_name => :nick)
|
199
204
|
resulting_xml.should == %(<nick-names type="array"><nick>Freddie</nick><nick>Knucklenose</nick></nick-names>)
|
200
205
|
end
|
201
206
|
end
|
@@ -203,7 +208,7 @@ describe Representative::Xml do
|
|
203
208
|
describe "with an argument that resolves to nil" do
|
204
209
|
|
205
210
|
it "omits the attribute" do
|
206
|
-
|
211
|
+
r.list_of(:flags)
|
207
212
|
resulting_xml.should == %(<flags/>)
|
208
213
|
end
|
209
214
|
|
@@ -212,19 +217,28 @@ describe Representative::Xml do
|
|
212
217
|
describe "with a block" do
|
213
218
|
|
214
219
|
it "generates a nested element for each list element" do
|
215
|
-
|
216
|
-
|
220
|
+
r.list_of(:nick_names) do
|
221
|
+
r.element :length
|
217
222
|
end
|
218
223
|
resulting_xml.should == %(<nick-names type="array"><nick-name><length>7</length></nick-name><nick-name><length>11</length></nick-name></nick-names>)
|
219
224
|
end
|
220
225
|
|
221
226
|
end
|
222
227
|
|
228
|
+
describe "with an EMPTY block" do
|
229
|
+
|
230
|
+
it "generates empty elements for each list element" do
|
231
|
+
r.list_of(:nick_names, :item_attributes => {:value => :to_s}, &r.empty)
|
232
|
+
resulting_xml.should == %(<nick-names type="array"><nick-name value="Freddie"/><nick-name value="Knucklenose"/></nick-names>)
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
223
237
|
describe "with :item_attributes AND block" do
|
224
238
|
|
225
239
|
it "generates attributes and nested elements" do
|
226
|
-
|
227
|
-
|
240
|
+
r.list_of(:nick_names, :item_attributes => {:length => :size}) do
|
241
|
+
r.element :reverse
|
228
242
|
end
|
229
243
|
resulting_xml.should == %(<nick-names type="array"><nick-name length="7"><reverse>eidderF</reverse></nick-name><nick-name length="11"><reverse>esonelkcunK</reverse></nick-name></nick-names>)
|
230
244
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Mike Williams
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-02 00:00:00 +10:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|