ardm-serializer 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module Serializer
3
+ VERSION = '1.2.2'
4
+ end
5
+ end
@@ -0,0 +1,56 @@
1
+ module DataMapper
2
+ module Serializer
3
+ module XML
4
+ # The supported XML Serializers
5
+ SERIALIZERS = {
6
+ :libxml => 'LibXML',
7
+ :nokogiri => 'Nokogiri',
8
+ :rexml => 'REXML'
9
+ }
10
+
11
+ #
12
+ # The current XML Serializer.
13
+ #
14
+ # @return [Module]
15
+ # The module within {DataMapper::Serialize::XML}.
16
+ #
17
+ # @since 1.1.0
18
+ #
19
+ def self.serializer
20
+ @serializer
21
+ end
22
+
23
+ #
24
+ # Sets the XML Serializer to use.
25
+ #
26
+ # @param [Symbol] name
27
+ # The name of the serializer to use. Must be either `:libxml`,
28
+ # `:nokogiri` or `:rexml`.
29
+ #
30
+ # @return [Module]
31
+ # The module within {DataMapper::Serialize::XML}.
32
+ #
33
+ # @since 1.1.0
34
+ #
35
+ def self.serializer=(name)
36
+ serializer_const = SERIALIZERS[name]
37
+
38
+ unless serializer_const
39
+ raise(ArgumentError,"unsupported XML Serializer #{name}")
40
+ end
41
+
42
+ require "dm-serializer/xml/#{name}"
43
+ @serializer = const_get(serializer_const)
44
+ end
45
+
46
+ [:nokogiri, :libxml, :rexml].each do |name|
47
+ # attempt to load the first available XML Serializer
48
+ begin
49
+ self.serializer = name
50
+ break
51
+ rescue LoadError
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ require 'libxml'
2
+
3
+ module DataMapper
4
+ module Serializer
5
+ module XML
6
+ module LibXML
7
+ def self.new_document
8
+ ::LibXML::XML::Document.new
9
+ end
10
+
11
+ def self.root_node(doc, name, attrs = {})
12
+ root = ::LibXML::XML::Node.new(name)
13
+
14
+ attrs.each do |attr_name, attr_val|
15
+ root[attr_name] = attr_val
16
+ end
17
+
18
+ doc.root.nil? ? doc.root = root : doc.root << root
19
+ root
20
+ end
21
+
22
+ def self.add_node(parent, name, value, attrs = {})
23
+ value_str = value.to_s unless value.nil?
24
+ node = ::LibXML::XML::Node.new(name, value_str)
25
+
26
+ attrs.each do |attr_name, attr_val|
27
+ node[attr_name] = attr_val
28
+ end
29
+
30
+ parent << node
31
+ node
32
+ end
33
+
34
+ def self.add_xml(parent, xml)
35
+ parent << xml.root.copy(true)
36
+ end
37
+
38
+ def self.output(doc)
39
+ doc.root.to_s
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ require 'nokogiri'
2
+
3
+ module DataMapper
4
+ module Serializer
5
+ module XML
6
+ module Nokogiri
7
+ def self.new_document
8
+ ::Nokogiri::XML::Document.new
9
+ end
10
+
11
+ def self.root_node(doc, name, attrs = {})
12
+ root = ::Nokogiri::XML::Node.new(name, doc)
13
+
14
+ attrs.each do |attr_name, attr_val|
15
+ root[attr_name] = attr_val
16
+ end
17
+
18
+ doc.root.nil? ? doc.root = root : doc.root << root
19
+ root
20
+ end
21
+
22
+ def self.add_node(parent, name, value, attrs = {})
23
+ node = ::Nokogiri::XML::Node.new(name, parent.document)
24
+ node << ::Nokogiri::XML::Text.new(value.to_s, parent.document) unless value.nil?
25
+
26
+ attrs.each do |attr_name, attr_val|
27
+ node[attr_name] = attr_val
28
+ end
29
+
30
+ parent << node
31
+ node
32
+ end
33
+
34
+ def self.add_xml(parent, xml)
35
+ parent << xml.root
36
+ end
37
+
38
+ def self.output(doc)
39
+ doc.root.to_s
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ require 'rexml/document'
2
+
3
+ module DataMapper
4
+ module Serializer
5
+ module XML
6
+ module REXML
7
+ def self.new_document
8
+ ::REXML::Document.new
9
+ end
10
+
11
+ def self.root_node(document, name, attrs = {})
12
+ add_node(document.root || document, name, nil, attrs)
13
+ end
14
+
15
+ def self.add_node(parent, name, value, attrs = {})
16
+ node = parent.add_element(name)
17
+
18
+ attrs.each do |attr_name, attr_val|
19
+ node.attributes[attr_name] = attr_val
20
+ end
21
+
22
+ node << ::REXML::Text.new(value.to_s) unless value.nil?
23
+ node
24
+ end
25
+
26
+ def self.add_xml(parent, xml)
27
+ parent.add(xml)
28
+ end
29
+
30
+ def self.output(doc)
31
+ doc.to_s
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ class Cow
2
+ include DataMapper::Resource
3
+
4
+ property :id, Integer, :key => true
5
+ property :composite, Integer, :key => true
6
+ property :name, String
7
+ property :breed, String
8
+
9
+ belongs_to :mother_cow, :model => self, :required => false
10
+ has n, :baby_cows, :model => self, :child_key => [ :mother_cow_id, :mother_cow_composite ]
11
+ end
@@ -0,0 +1,46 @@
1
+ class Planet
2
+ include DataMapper::Resource
3
+
4
+ property :name, String, :key => true
5
+ property :aphelion, Float
6
+
7
+ validates_length_of :name, :min => 2
8
+
9
+ # Sorry these associations don't make any sense
10
+ # I just needed a many-to-many association to test against
11
+ has n, :friended_planets
12
+ has n, :friend_planets, :through => :friended_planets, :model => 'Planet'
13
+
14
+ belongs_to :solar_system
15
+
16
+ def category
17
+ case self.name.downcase
18
+ when "mercury", "venus", "earth", "mars" then "terrestrial"
19
+ when "jupiter", "saturn", "uranus", "neptune" then "gas giants"
20
+ when "pluto" then "dwarf planets"
21
+ end
22
+ end
23
+
24
+ def has_known_form_of_life?
25
+ self.name.downcase == "earth"
26
+ end
27
+ end
28
+
29
+ class FriendedPlanet
30
+ include DataMapper::Resource
31
+
32
+ property :planet_name, String, :key => true
33
+ property :friend_planet_name, String, :key => true
34
+
35
+ belongs_to :planet, :child_key => [ :planet_name ]
36
+ belongs_to :friend_planet, :model => 'Planet', :child_key => [ :friend_planet_name ]
37
+ end
38
+
39
+ class SolarSystem
40
+ include DataMapper::Resource
41
+
42
+ property :id, Serial
43
+
44
+ property :name, String
45
+
46
+ end
@@ -0,0 +1,15 @@
1
+ # Yes, this crazy capitalization is intentional,
2
+ # to test xml root element name generation
3
+ module QuanTum
4
+ class Cat
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :name, String
9
+ property :location, String
10
+
11
+ repository(:alternate) do
12
+ property :is_dead, Boolean
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class Vehicle
2
+ include DataMapper::Resource
3
+ property :id, Serial
4
+ property :name, String
5
+ property :type, Discriminator
6
+ end
7
+
8
+ class Car < Vehicle
9
+
10
+ end
11
+
12
+ class Motorcycle < Vehicle
13
+
14
+ end
@@ -0,0 +1,290 @@
1
+ share_examples_for 'A serialization method that also serializes core classes' do
2
+ # This spec ensures that we don't break any serialization methods attached
3
+ # to core classes, such as Array
4
+ before(:all) do
5
+ %w[ @harness ].each do |ivar|
6
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
7
+ end
8
+
9
+ DataMapper.auto_migrate!
10
+ end
11
+
12
+ before(:each) do
13
+ DataMapper::Model.descendants.each { |model| model.destroy! }
14
+ end
15
+
16
+ it 'serializes an array of extended objects' do
17
+ Cow.create(
18
+ :id => 89,
19
+ :composite => 34,
20
+ :name => 'Berta',
21
+ :breed => 'Guernsey'
22
+ )
23
+ result = @harness.test(Cow.all.to_a)
24
+ result[0].values_at("id", "composite", "name", "breed").should ==
25
+ [89, 34, "Berta", "Guernsey"]
26
+ end
27
+
28
+ it 'serializes an array of collections' do
29
+ query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
30
+
31
+ keys = %w[ id composite name breed ]
32
+
33
+ resources = [
34
+ Hash[ keys.zip([ 1, 2, 'Betsy', 'Jersey' ]) ],
35
+ Hash[ keys.zip([ 89, 34, 'Berta', 'Guernsey' ]) ],
36
+ ]
37
+
38
+ collection = DataMapper::Collection.new(query, query.model.load(resources, query))
39
+
40
+ result = @harness.test(collection)
41
+ result[0].values_at(*keys).should == resources[0].values_at(*keys)
42
+ result[1].values_at(*keys).should == resources[1].values_at(*keys)
43
+ end
44
+ end
45
+
46
+ share_examples_for 'A serialization method' do
47
+ before(:all) do
48
+ %w[ @harness ].each do |ivar|
49
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
50
+ end
51
+
52
+ DataMapper.auto_migrate!
53
+ end
54
+
55
+ before(:each) do
56
+ DataMapper::Model.descendants.each { |model| model.destroy! }
57
+ end
58
+
59
+ describe '(serializing single resources)' do
60
+ it 'should serialize Model.first' do
61
+ # At the moment this is implied by serializing a resource, but this
62
+ # test ensures the contract even if dm-core changes
63
+ Cow.create(
64
+ :id => 89,
65
+ :composite => 34,
66
+ :name => 'Berta',
67
+ :breed => 'Guernsey'
68
+ )
69
+ result = @harness.test(Cow.first)
70
+ result.values_at("name", "breed").should == ["Berta", "Guernsey"]
71
+ end
72
+
73
+ it 'should serialize a resource' do
74
+ cow = Cow.new(
75
+ :id => 89,
76
+ :composite => 34,
77
+ :name => 'Berta',
78
+ :breed => 'Guernsey'
79
+ )
80
+
81
+ result = @harness.test(cow)
82
+ result.values_at("id", "composite", "name", "breed").should == [89, 34, 'Berta', 'Guernsey']
83
+ end
84
+
85
+ it 'should exclude nil properties' do
86
+ cow = Cow.new(
87
+ :id => 89,
88
+ :name => nil
89
+ )
90
+
91
+ result = @harness.test(cow)
92
+ result.values_at("id", "composite").should == [89, nil]
93
+ end
94
+
95
+ it "should only includes properties given to :only option" do
96
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
97
+ planet = Planet.new(
98
+ :name => "Mars",
99
+ :aphelion => 249_209_300.4
100
+ )
101
+
102
+ result = @harness.test(planet, :only => [:name])
103
+ result.values_at("name", "aphelion").should == ["Mars", nil]
104
+ end
105
+ end
106
+
107
+ it "should serialize values returned by an array of methods given to :methods option" do
108
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
109
+ planet = Planet.new(
110
+ :name => "Mars",
111
+ :aphelion => 249_209_300.4
112
+ )
113
+
114
+ result = @harness.test(planet, :methods => [:category, :has_known_form_of_life?])
115
+ # XML currently can't serialize ? at the end of method names
116
+ boolean_method_name = @harness.method_name == :to_xml ? "has_known_form_of_life" : "has_known_form_of_life?"
117
+ result.values_at("category", boolean_method_name).should == ["terrestrial", false]
118
+ end
119
+ end
120
+
121
+ it "should serialize values returned by a single method given to :methods option" do
122
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
123
+ planet = Planet.new(
124
+ :name => "Mars",
125
+ :aphelion => 249_209_300.4
126
+ )
127
+
128
+ result = @harness.test(planet, :methods => :category)
129
+ result.values_at("category").should == ["terrestrial"]
130
+ end
131
+ end
132
+
133
+ it "should only include properties given to :only option" do
134
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
135
+ planet = Planet.new(
136
+ :name => "Mars",
137
+ :aphelion => 249_209_300.4
138
+ )
139
+
140
+ result = @harness.test(planet, :only => [:name])
141
+ result.values_at("name", "aphelion").should == ["Mars", nil]
142
+ end
143
+ end
144
+
145
+ it "should exclude properties given to :exclude option" do
146
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
147
+ planet = Planet.new(
148
+ :name => "Mars",
149
+ :aphelion => 249_209_300.4
150
+ )
151
+
152
+ result = @harness.test(planet, :exclude => [:aphelion])
153
+ result.values_at("name", "aphelion").should == ["Mars", nil]
154
+ end
155
+ end
156
+
157
+ it "should give higher precendence to :only option over :exclude" do
158
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
159
+ planet = Planet.new(
160
+ :name => "Mars",
161
+ :aphelion => 249_209_300.4
162
+ )
163
+
164
+ result = @harness.test(planet, :only => [:name], :exclude => [:name])
165
+ result.values_at("name", "aphelion").should == ["Mars", nil]
166
+ end
167
+ end
168
+
169
+ it 'should support child associations included via the :methods parameter' do
170
+ pending_if 'Psych provides no way to pass in parameters', @ruby_192 && @to_yaml do
171
+ solar_system = SolarSystem.create(:name => "one")
172
+ planet = Planet.new(:name => "earth")
173
+ planet.solar_system = solar_system
174
+ result = @harness.test(planet, :methods => [:solar_system])
175
+ result['solar_system'].values_at('name', 'id').should == ['one', 1]
176
+ end
177
+ end
178
+ end
179
+
180
+ describe "(collections and proxies)" do
181
+ it 'should serialize Model.all' do
182
+ # At the moment this is implied by serializing a collection, but this
183
+ # test ensures the contract even if dm-core changes
184
+ Cow.create(
185
+ :id => 89,
186
+ :composite => 34,
187
+ :name => 'Berta',
188
+ :breed => 'Guernsey'
189
+ )
190
+ result = @harness.test(Cow.all)
191
+ result[0].values_at("name", "breed").should == ["Berta", "Guernsey"]
192
+ end
193
+
194
+ it 'should serialize a collection' do
195
+ query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
196
+
197
+ keys = %w[ id composite name breed ]
198
+
199
+ resources = [
200
+ Hash[ keys.zip([ 1, 2, 'Betsy', 'Jersey' ]) ],
201
+ Hash[ keys.zip([ 10, 20, 'Berta', 'Guernsey' ]) ],
202
+ ]
203
+
204
+ collection = DataMapper::Collection.new(query, query.model.load(resources, query))
205
+
206
+ result = @harness.test(collection)
207
+ result[0].values_at(*keys).should == resources[0].values_at(*keys)
208
+ result[1].values_at(*keys).should == resources[1].values_at(*keys)
209
+ end
210
+
211
+ it 'should serialize an empty collection' do
212
+ query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
213
+ collection = DataMapper::Collection.new(query)
214
+
215
+ result = @harness.test(collection)
216
+ result.should be_empty
217
+ end
218
+
219
+ it "serializes a one to many relationship" do
220
+ parent = Cow.new(:id => 1, :composite => 322, :name => "Harry", :breed => "Angus")
221
+ baby = Cow.new(:mother_cow => parent, :id => 2, :composite => 321, :name => "Felix", :breed => "Angus")
222
+
223
+ parent.save
224
+ baby.save
225
+
226
+ result = @harness.test(parent.baby_cows)
227
+ result.should be_kind_of(Array)
228
+
229
+ result[0].values_at(*%w{id composite name breed}).should == [2, 321, "Felix", "Angus"]
230
+ end
231
+
232
+ it "serializes a many to one relationship" do
233
+ parent = Cow.new(:id => 1, :composite => 322, :name => "Harry", :breed => "Angus")
234
+ baby = Cow.new(:mother_cow => parent, :id => 2, :composite => 321, :name => "Felix", :breed => "Angus")
235
+
236
+ parent.save
237
+ baby.save
238
+
239
+ result = @harness.test(baby.mother_cow)
240
+ result.should be_kind_of(Hash)
241
+ result.values_at(*%w{id composite name breed}).should == [1, 322, "Harry", "Angus"]
242
+ end
243
+
244
+ it "serializes a many to many relationship" do
245
+ pending 'TODO: fix many to many in dm-core' do
246
+ p1 = Planet.create(:name => 'earth')
247
+ p2 = Planet.create(:name => 'mars')
248
+
249
+ FriendedPlanet.create(:planet => p1, :friend_planet => p2)
250
+
251
+ result = @harness.test(p1.reload.friend_planets)
252
+ result.should be_kind_of(Array)
253
+
254
+ result[0]["name"].should == "mars"
255
+ end
256
+ end
257
+ end
258
+
259
+ with_alternate_adapter do
260
+
261
+ describe "(multiple repositories)" do
262
+ before(:all) do
263
+ [ :default, :alternate ].each do |repository_name|
264
+ DataMapper.repository(repository_name) do
265
+ QuanTum::Cat.auto_migrate!
266
+ QuanTum::Cat.destroy!
267
+ end
268
+ end
269
+ end
270
+
271
+ it "should use the repsoitory for the model" do
272
+ alternate_repo = DataMapper::Spec.spec_adapters[:alternate].name
273
+ gerry = QuanTum::Cat.create(:name => "gerry")
274
+ george = DataMapper.repository(alternate_repo){ QuanTum::Cat.create(:name => "george", :is_dead => false) }
275
+ @harness.test(gerry )['is_dead'].should be(nil)
276
+ @harness.test(george)['is_dead'].should be(false)
277
+ end
278
+ end
279
+
280
+ end
281
+
282
+ it 'should integrate with dm-validations' do
283
+ planet = Planet.create(:name => 'a')
284
+ results = @harness.test(planet.errors)
285
+ results.should == {
286
+ "name" => planet.errors[:name].map { |e| e.to_s },
287
+ "solar_system_id" => planet.errors[:solar_system_id].map { |e| e.to_s }
288
+ }
289
+ end
290
+ end