representative 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +4 -9
- data/lib/representative/abstract_xml.rb +119 -0
- data/lib/representative/json.rb +14 -2
- data/lib/representative/nokogiri.rb +61 -0
- data/lib/representative/tilt_integration.rb +56 -0
- data/lib/representative/version.rb +1 -1
- data/lib/representative/xml.rb +10 -116
- data/spec/representative/json_spec.rb +49 -0
- data/spec/representative/nokogiri_spec.rb +74 -0
- data/spec/representative/tilt_integration_spec.rb +136 -0
- data/spec/representative/xml_behaviour.rb +270 -0
- data/spec/representative/xml_spec.rb +3 -264
- data/spec/spec_helper.rb +0 -3
- metadata +65 -41
@@ -53,6 +53,38 @@ describe Representative::Json do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
end
|
56
|
+
|
57
|
+
describe "with attributes" do
|
58
|
+
|
59
|
+
describe "and a block" do
|
60
|
+
|
61
|
+
it "generates labelled fields for the attributes" do
|
62
|
+
@book = OpenStruct.new(:lang => "fr", :title => "En Edge")
|
63
|
+
r.element :book, @book, :lang => :lang do
|
64
|
+
r.element :title
|
65
|
+
end
|
66
|
+
resulting_json.should == undent(<<-JSON)
|
67
|
+
{
|
68
|
+
"@lang": "fr",
|
69
|
+
"title": "En Edge"
|
70
|
+
}
|
71
|
+
JSON
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "and an explicit value" do
|
77
|
+
|
78
|
+
it "ignores the attributes" do
|
79
|
+
r.element :review, "Blah de blah", :lang => "fr"
|
80
|
+
resulting_json.should == undent(<<-JSON)
|
81
|
+
"Blah de blah"
|
82
|
+
JSON
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
56
88
|
|
57
89
|
describe "without an explicit value" do
|
58
90
|
|
@@ -199,6 +231,23 @@ describe Representative::Json do
|
|
199
231
|
|
200
232
|
end
|
201
233
|
|
234
|
+
describe "#attribute" do
|
235
|
+
|
236
|
+
it "generates labelled values, with a label prefix" do
|
237
|
+
r.element :author, Object.new do
|
238
|
+
r.attribute :href, "http://example.com/authors/1"
|
239
|
+
r.element :name, "Fred"
|
240
|
+
end
|
241
|
+
resulting_json.should == undent(<<-JSON)
|
242
|
+
{
|
243
|
+
"@href": "http://example.com/authors/1",
|
244
|
+
"name": "Fred"
|
245
|
+
}
|
246
|
+
JSON
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
202
251
|
describe "#comment" do
|
203
252
|
|
204
253
|
it "inserts a comment" do
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "representative/nokogiri"
|
5
|
+
require "representative/xml_behaviour"
|
6
|
+
|
7
|
+
describe Representative::Nokogiri do
|
8
|
+
|
9
|
+
def r
|
10
|
+
@representative ||= Representative::Nokogiri.new(@subject)
|
11
|
+
end
|
12
|
+
|
13
|
+
def resulting_xml
|
14
|
+
r.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION).rstrip
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_behave_like "an XML Representative"
|
18
|
+
|
19
|
+
describe "for some 'subject'" do
|
20
|
+
|
21
|
+
before do
|
22
|
+
@subject = OpenStruct.new(:name => "Fred", :width => 200, :vehicle => OpenStruct.new(:year => "1959", :make => "Chevrolet"))
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#attribute" do
|
26
|
+
|
27
|
+
describe "without a value argument" do
|
28
|
+
it "extracts the named field of the subject" do
|
29
|
+
r.element :person, @subject do
|
30
|
+
r.attribute :name
|
31
|
+
end
|
32
|
+
resulting_xml.should == %(<person name="Fred"/>)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "with an explicit value" do
|
37
|
+
it "attaches an attribute to the current element" do
|
38
|
+
r.element :person, @subject do
|
39
|
+
r.attribute :lang, "fr"
|
40
|
+
end
|
41
|
+
resulting_xml.should == %(<person lang="fr"/>)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with a value that supports #to_proc" do
|
46
|
+
it "calls the Proc on the subject to generate attribute value" do
|
47
|
+
r.element :person, @subject do
|
48
|
+
r.attribute :name, lambda { |person| person.name.reverse }
|
49
|
+
end
|
50
|
+
resulting_xml.should == %(<person name="derF"/>)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "dasherizes the attribute name" do
|
55
|
+
r.element :name do
|
56
|
+
r.attribute :sourced_from, "phonebook"
|
57
|
+
end
|
58
|
+
resulting_xml.should == %(<name sourced-from="phonebook"/>)
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "with value nil" do
|
62
|
+
it "omits the attribute" do
|
63
|
+
r.element :person, @subject do
|
64
|
+
r.attribute :name, nil
|
65
|
+
end
|
66
|
+
resulting_xml.should == %(<person/>)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require "ostruct"
|
4
|
+
require "representative/tilt_integration"
|
5
|
+
|
6
|
+
describe Representative::Tilt do
|
7
|
+
|
8
|
+
def with_template(file_name, content)
|
9
|
+
@template = Tilt.new(file_name, 1) { content }
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(*args, &block)
|
13
|
+
@output = @template.render(*args, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "XML template" do
|
17
|
+
|
18
|
+
def resulting_xml
|
19
|
+
@output.sub(/^<\?xml.*\n/, '')
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#render" do
|
23
|
+
|
24
|
+
it "generates XML" do
|
25
|
+
with_template("whatever.xml.rep", <<-RUBY)
|
26
|
+
r.element :foo, "bar"
|
27
|
+
RUBY
|
28
|
+
render
|
29
|
+
resulting_xml.should == %{<foo>bar</foo>\n}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "provides access to scope" do
|
33
|
+
|
34
|
+
with_template("whatever.xml.rep", <<-RUBY)
|
35
|
+
r.element :author, @mike do
|
36
|
+
r.element :name
|
37
|
+
end
|
38
|
+
RUBY
|
39
|
+
|
40
|
+
scope = Object.new
|
41
|
+
scope.instance_eval do
|
42
|
+
@mike = OpenStruct.new(:name => "Mike")
|
43
|
+
end
|
44
|
+
render(scope)
|
45
|
+
|
46
|
+
resulting_xml.should == undent(<<-XML)
|
47
|
+
<author>
|
48
|
+
<name>Mike</name>
|
49
|
+
</author>
|
50
|
+
XML
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
it "provides access to local variables" do
|
55
|
+
|
56
|
+
with_template("whatever.xml.rep", <<-RUBY)
|
57
|
+
r.element :author, author do
|
58
|
+
r.element :name
|
59
|
+
end
|
60
|
+
RUBY
|
61
|
+
|
62
|
+
render(Object.new, {:author => OpenStruct.new(:name => "Mike")})
|
63
|
+
|
64
|
+
resulting_xml.should == undent(<<-XML)
|
65
|
+
<author>
|
66
|
+
<name>Mike</name>
|
67
|
+
</author>
|
68
|
+
XML
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "JSON template" do
|
77
|
+
|
78
|
+
def resulting_json
|
79
|
+
@output.sub(/^<\?xml.*\n/, '')
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#render" do
|
83
|
+
|
84
|
+
it "generates JSON" do
|
85
|
+
with_template("whatever.json.rep", <<-RUBY)
|
86
|
+
r.element :foo, "bar"
|
87
|
+
RUBY
|
88
|
+
render
|
89
|
+
resulting_json.should == %{"bar"\n}
|
90
|
+
end
|
91
|
+
|
92
|
+
it "provides access to scope" do
|
93
|
+
|
94
|
+
with_template("whatever.json.rep", <<-RUBY)
|
95
|
+
r.element :author, @mike do
|
96
|
+
r.element :name
|
97
|
+
end
|
98
|
+
RUBY
|
99
|
+
|
100
|
+
scope = Object.new
|
101
|
+
scope.instance_eval do
|
102
|
+
@mike = OpenStruct.new(:name => "Mike")
|
103
|
+
end
|
104
|
+
render(scope)
|
105
|
+
|
106
|
+
resulting_json.should == undent(<<-JSON)
|
107
|
+
{
|
108
|
+
"name": "Mike"
|
109
|
+
}
|
110
|
+
JSON
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
it "provides access to local variables" do
|
115
|
+
|
116
|
+
with_template("whatever.json.rep", <<-RUBY)
|
117
|
+
r.element :author, author do
|
118
|
+
r.element :name
|
119
|
+
end
|
120
|
+
RUBY
|
121
|
+
|
122
|
+
render(Object.new, {:author => OpenStruct.new(:name => "Mike")})
|
123
|
+
|
124
|
+
resulting_json.should == undent(<<-JSON)
|
125
|
+
{
|
126
|
+
"name": "Mike"
|
127
|
+
}
|
128
|
+
JSON
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require "rexml/document"
|
4
|
+
|
5
|
+
shared_examples_for "an XML Representative" do
|
6
|
+
|
7
|
+
describe "for some 'subject'" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@subject = OpenStruct.new(:name => "Fred", :width => 200, :vehicle => OpenStruct.new(:year => "1959", :make => "Chevrolet"))
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#element" do
|
14
|
+
|
15
|
+
it "generates an element with content extracted from the subject" do
|
16
|
+
r.element :name
|
17
|
+
resulting_xml.should == %(<name>Fred</name>)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "dasherizes the property name" do
|
21
|
+
@subject.full_name = "Fredrick"
|
22
|
+
r.element :full_name
|
23
|
+
resulting_xml.should == %(<full-name>Fredrick</full-name>)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "with attributes" do
|
27
|
+
|
28
|
+
it "generates attributes on the element" do
|
29
|
+
r.element :name, :lang => "fr"
|
30
|
+
resulting_xml.should == %(<name lang="fr">Fred</name>)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "dasherizes the attribute name" do
|
34
|
+
r.element :name, :sourced_from => "phonebook"
|
35
|
+
resulting_xml.should == %(<name sourced-from="phonebook">Fred</name>)
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "whose value supports #to_proc" do
|
39
|
+
|
40
|
+
it "calls the Proc on the subject to generate a value" do
|
41
|
+
r.element :name, :rev => :reverse
|
42
|
+
resulting_xml.should == %(<name rev="derF">Fred</name>)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "with value nil" do
|
48
|
+
|
49
|
+
it "omits the attribute" do
|
50
|
+
r.element :name, :lang => nil
|
51
|
+
resulting_xml.should == %(<name>Fred</name>)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "with an explicit value" do
|
59
|
+
|
60
|
+
it "generates an element with explicitly provided content" do
|
61
|
+
r.element :name, "Bloggs"
|
62
|
+
resulting_xml.should == %(<name>Bloggs</name>)
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "AND attributes" do
|
66
|
+
|
67
|
+
it "generates attributes on the element" do
|
68
|
+
r.element :name, "Bloggs", :lang => "fr"
|
69
|
+
resulting_xml.should == %(<name lang="fr">Bloggs</name>)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "with a value argument that supports #to_proc" do
|
77
|
+
|
78
|
+
it "calls the Proc on the subject to generate a value" do
|
79
|
+
r.element :name, :width
|
80
|
+
resulting_xml.should == %(<name>200</name>)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "with value argument :self" do
|
86
|
+
|
87
|
+
it "doesn't alter the subject" do
|
88
|
+
r.element :info, :self do
|
89
|
+
r.element :name
|
90
|
+
end
|
91
|
+
resulting_xml.should == %(<info><name>Fred</name></info>)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "with value argument nil" do
|
97
|
+
|
98
|
+
it "builds an empty element" do
|
99
|
+
r.element :name, nil
|
100
|
+
resulting_xml.should == %(<name/>)
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "and attributes" do
|
104
|
+
|
105
|
+
it "omits attributes derived from the subject" do
|
106
|
+
r.element :name, nil, :size => :size
|
107
|
+
resulting_xml.should == %(<name/>)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "retains attributes with explicit values" do
|
111
|
+
r.element :name, nil, :lang => "en"
|
112
|
+
resulting_xml.should == %(<name lang="en"/>)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "and a block" do
|
118
|
+
|
119
|
+
it "doesn't call the block" do
|
120
|
+
r.element :name, nil do
|
121
|
+
raise "hell"
|
122
|
+
end
|
123
|
+
resulting_xml.should == %(<name/>)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "with a block" do
|
131
|
+
|
132
|
+
it "generates nested elements" do
|
133
|
+
r.element :vehicle do
|
134
|
+
r.element :year
|
135
|
+
r.element :make
|
136
|
+
end
|
137
|
+
resulting_xml.should == %(<vehicle><year>1959</year><make>Chevrolet</make></vehicle>)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "yields each new subject" do
|
141
|
+
r.element :vehicle do |vehicle|
|
142
|
+
r.element :year, vehicle.year
|
143
|
+
end
|
144
|
+
resulting_xml.should == %(<vehicle><year>1959</year></vehicle>)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "with an EMPTY block" do
|
150
|
+
|
151
|
+
it "generates an empty element" do
|
152
|
+
r.element :vehicle, :year => :year, &r.empty
|
153
|
+
resulting_xml.should == %(<vehicle year="1959"/>)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#list_of" do
|
161
|
+
|
162
|
+
before do
|
163
|
+
@subject.nick_names = ["Freddie", "Knucklenose"]
|
164
|
+
end
|
165
|
+
|
166
|
+
it "generates an array element" do
|
167
|
+
r.list_of(:nick_names)
|
168
|
+
resulting_xml.should == %(<nick-names type="array"><nick-name>Freddie</nick-name><nick-name>Knucklenose</nick-name></nick-names>)
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "with :list_attributes" do
|
172
|
+
|
173
|
+
it "attaches attributes to the array element" do
|
174
|
+
r.list_of(:nick_names, :list_attributes => {:color => "blue", :size => :size})
|
175
|
+
array_element_attributes = REXML::Document.new(resulting_xml).root.attributes
|
176
|
+
array_element_attributes["type"].should == "array"
|
177
|
+
array_element_attributes["color"].should == "blue"
|
178
|
+
array_element_attributes["size"].should == "2"
|
179
|
+
array_element_attributes.size.should == 3
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "with :item_attributes" do
|
185
|
+
|
186
|
+
it "attaches attributes to each item element" do
|
187
|
+
r.list_of(:nick_names, :item_attributes => {:length => :size})
|
188
|
+
resulting_xml.should == %(<nick-names type="array"><nick-name length="7">Freddie</nick-name><nick-name length="11">Knucklenose</nick-name></nick-names>)
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "with an explicit :item_name" do
|
194
|
+
it "uses the name provided" do
|
195
|
+
r.list_of(:nick_names, :item_name => :nick)
|
196
|
+
resulting_xml.should == %(<nick-names type="array"><nick>Freddie</nick><nick>Knucklenose</nick></nick-names>)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "with an argument that resolves to nil" do
|
201
|
+
|
202
|
+
it "omits the attribute" do
|
203
|
+
r.list_of(:services) do
|
204
|
+
r.date
|
205
|
+
end
|
206
|
+
resulting_xml.should == %(<services/>)
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
describe "with a block" do
|
212
|
+
|
213
|
+
it "generates a nested element for each list element" do
|
214
|
+
r.list_of(:nick_names) do
|
215
|
+
r.element :length
|
216
|
+
end
|
217
|
+
resulting_xml.should == %(<nick-names type="array"><nick-name><length>7</length></nick-name><nick-name><length>11</length></nick-name></nick-names>)
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "with an EMPTY block" do
|
223
|
+
|
224
|
+
it "generates empty elements for each list element" do
|
225
|
+
r.list_of(:nick_names, :item_attributes => {:value => :to_s}, &r.empty)
|
226
|
+
resulting_xml.should == %(<nick-names type="array"><nick-name value="Freddie"/><nick-name value="Knucklenose"/></nick-names>)
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
describe "with :item_attributes AND block" do
|
232
|
+
|
233
|
+
it "generates attributes and nested elements" do
|
234
|
+
r.list_of(:nick_names, :item_attributes => {:length => :size}) do
|
235
|
+
r.element :reverse
|
236
|
+
end
|
237
|
+
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>)
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "#representing" do
|
245
|
+
|
246
|
+
it "selects a new subject without generating an element" do
|
247
|
+
r.representing :vehicle do
|
248
|
+
r.element :make
|
249
|
+
end
|
250
|
+
resulting_xml.should == %(<make>Chevrolet</make>)
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
describe "#comment" do
|
256
|
+
|
257
|
+
it "inserts a comment" do
|
258
|
+
r.element :vehicle do
|
259
|
+
r.comment "Year of manufacture"
|
260
|
+
r.element :year
|
261
|
+
end
|
262
|
+
resulting_xml.should ==
|
263
|
+
%(<vehicle><!-- Year of manufacture --><year>1959</year></vehicle>)
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|