representable 1.2.3 → 1.2.4

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/.gitignore CHANGED
@@ -5,3 +5,8 @@ doc
5
5
  Rake.config
6
6
  pkg
7
7
  .project
8
+ .bundle
9
+ Gemfile.lock
10
+ *.swp
11
+ *.swo
12
+ bin
@@ -1,3 +1,9 @@
1
- rvm: 1.9.2
2
1
  notifications:
3
2
  irc: "irc.freenode.org#cells"
3
+ matrix:
4
+ include:
5
+ - rvm: 1.8.7
6
+ gemfile: gemfiles/Gemfile.mongoid-2.4
7
+ - rvm: 1.9.3
8
+ gemfile: Gemfile
9
+
@@ -1,3 +1,8 @@
1
+ h2. 1.2.4
2
+
3
+ * ObjectBinding no longer tries to extend nil values when rendering and @:render_nil@ is set.
4
+ * In XML you can now use @:wrap@ to define an additional container tag around properties and collections.
5
+
1
6
  h2. 1.2.3
2
7
 
3
8
  * Using virtus for coercion now works in both classes and modules. Thanks to @solnic for a great collaboration. Open-source rocks!
@@ -15,7 +15,7 @@ This keeps your representation knowledge in one place when implementing REST ser
15
15
  * Bidirectional - rendering and parsing
16
16
  * OOP access to documents
17
17
  * Support for JSON and XML
18
- * Coercion support with virtus[https://github.com/solnic/virtus.]
18
+ * Coercion support with virtus[https://github.com/solnic/virtus]
19
19
 
20
20
 
21
21
  == Example
@@ -317,6 +317,26 @@ You can also map properties to tag attributes in representable.
317
317
 
318
318
  Naturally, this works for both ways.
319
319
 
320
+ === Wrapping collections
321
+
322
+ It is sometimes unavoidable to wrap tag lists in a container tag.
323
+
324
+ module AlbumRepresenter
325
+ include Representable::XML
326
+
327
+ collection :songs, :from => :song, :wrap => :songs
328
+ end
329
+
330
+ Note that +:wrap+ defines the container tag name.
331
+
332
+ Album.new.to_xml #=>
333
+ <album>
334
+ <songs>
335
+ <song>Laundry Basket</song>
336
+ <song>Two Kevins</song>
337
+ <song>Wright and Rong</song>
338
+ </songs>
339
+ </album>
320
340
 
321
341
  == Coercion
322
342
 
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in roar-rails.gemspec
4
+ gemspec :path => '../'
5
+
6
+ gem 'mongoid', '~> 2.4.0'
@@ -44,5 +44,25 @@ module Representable
44
44
  object
45
45
  end
46
46
  end
47
+
48
+ module Object
49
+ include Binding::Extend # provides #serialize/#deserialize with extend.
50
+
51
+ def serialize(object)
52
+ return object if object.nil?
53
+
54
+ super(object).send(serialize_method, :wrap => false)
55
+ end
56
+
57
+ def deserialize(data)
58
+ # DISCUSS: does it make sense to skip deserialization of nil-values here?
59
+ super(create_object).send(deserialize_method, data)
60
+ end
61
+
62
+ def create_object
63
+ definition.sought_type.new
64
+ end
65
+ end
66
+
47
67
  end
48
68
  end
@@ -3,19 +3,14 @@ require 'representable/binding'
3
3
  module Representable
4
4
  module JSON
5
5
  module ObjectBinding
6
- # TODO: provide a base ObjectBinding for XML/JSON/MP.
7
- include Binding::Extend # provides #serialize/#deserialize with extend.
6
+ include Binding::Object
8
7
 
9
- def serialize(object)
10
- super(object).to_hash(:wrap => false)
8
+ def serialize_method
9
+ :to_hash
11
10
  end
12
11
 
13
- def deserialize(hash)
14
- super(create_object).from_hash(hash)
15
- end
16
-
17
- def create_object
18
- definition.sought_type.new
12
+ def deserialize_method
13
+ :from_hash
19
14
  end
20
15
  end
21
16
 
@@ -3,15 +3,14 @@ require 'representable/binding'
3
3
  module Representable
4
4
  module XML
5
5
  module ObjectBinding
6
- # TODO: provide a base ObjectBinding for XML/JSON/MP.
7
- include Binding::Extend # provides #serialize/#deserialize with extend.
6
+ include Binding::Object
8
7
 
9
- def serialize(object)
10
- super(object).to_node(:wrap => false)
8
+ def serialize_method
9
+ :to_node
11
10
  end
12
11
 
13
- def deserialize(hash)
14
- super(create_object).from_node(hash)
12
+ def deserialize_method
13
+ :from_node
15
14
  end
16
15
 
17
16
  def deserialize_node(node)
@@ -21,10 +20,6 @@ module Representable
21
20
  def serialize_node(node, value)
22
21
  serialize(value)
23
22
  end
24
-
25
- def create_object
26
- definition.sought_type.new
27
- end
28
23
  end
29
24
 
30
25
 
@@ -35,11 +30,20 @@ module Representable
35
30
  end
36
31
 
37
32
  def write(parent, value)
38
- parent << serialize_for(value, parent)
33
+ wrap_node = parent
34
+
35
+ if wrap = definition.options[:wrap]
36
+ parent << wrap_node = node_for(parent, wrap)
37
+ end
38
+
39
+ wrap_node << serialize_for(value, parent)
39
40
  end
40
41
 
41
42
  def read(node)
42
- nodes = node.search("./#{xpath}")
43
+ selector = "./#{xpath}"
44
+ selector = "./#{definition.options[:wrap]}/#{xpath}" if definition.options[:wrap]
45
+ nodes = node.search(selector)
46
+
43
47
  return FragmentNotFound if nodes.size == 0 # TODO: write dedicated test!
44
48
 
45
49
  deserialize_from(nodes)
@@ -48,7 +52,7 @@ module Representable
48
52
  # Creates wrapped node for the property.
49
53
  def serialize_for(value, parent)
50
54
  #def serialize_for(value, parent, tag_name=definition.from)
51
- node = Nokogiri::XML::Node.new(definition.from, parent.document)
55
+ node = node_for(parent, definition.from)
52
56
  serialize_node(node, value)
53
57
  end
54
58
 
@@ -70,19 +74,16 @@ module Representable
70
74
  def xpath
71
75
  definition.from
72
76
  end
77
+
78
+ def node_for(parent, name)
79
+ Nokogiri::XML::Node.new(name.to_s, parent.document)
80
+ end
73
81
  end
74
82
 
75
83
  class CollectionBinding < PropertyBinding
76
- def write(parent, value)
77
- serialize_items(value, parent).each do |node|
78
- parent << node
79
- end
80
- end
81
-
82
- def serialize_items(value, parent)
83
- value.collect do |obj|
84
- serialize_for(obj, parent)
85
- end
84
+ def serialize_for(value, parent)
85
+ # return NodeSet so << works.
86
+ set_for(parent, value.collect { |item| super(item, parent) })
86
87
  end
87
88
 
88
89
  def deserialize_from(nodes)
@@ -90,15 +91,20 @@ module Representable
90
91
  deserialize_node(item)
91
92
  end
92
93
  end
94
+
95
+ private
96
+ def set_for(parent, nodes)
97
+ Nokogiri::XML::NodeSet.new(parent.document, nodes)
98
+ end
93
99
  end
94
100
 
95
101
 
96
102
  class HashBinding < CollectionBinding
97
- def serialize_items(value, parent)
98
- value.collect do |k, v|
99
- node = Nokogiri::XML::Node.new(k, parent.document)
103
+ def serialize_for(value, parent)
104
+ set_for(parent, value.collect do |k, v|
105
+ node = node_for(parent, k)
100
106
  serialize_node(node, v)
101
- end
107
+ end)
102
108
  end
103
109
 
104
110
  def deserialize_from(nodes)
@@ -4,24 +4,24 @@ module Representable::JSON
4
4
  module Hash
5
5
  include Representable::JSON
6
6
  include HashMethods
7
-
7
+
8
8
  def self.included(base)
9
9
  base.class_eval do
10
10
  include Representable
11
11
  extend ClassMethods
12
12
  end
13
13
  end
14
-
15
-
14
+
15
+
16
16
  module ClassMethods
17
17
  def values(options)
18
18
  hash :_self, options
19
19
  end
20
20
  end
21
-
22
-
21
+
22
+
23
23
  def definition_opts
24
- [:_self, :hash => true, :use_attributes => true]
24
+ [:_self, {:hash => true, :use_attributes => true}]
25
25
  end
26
26
  end
27
27
  end
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "1.2.3"
2
+ VERSION = "1.2.4"
3
3
  end
@@ -4,48 +4,48 @@ module Representable::XML
4
4
  module AttributeHash
5
5
  include Representable::XML
6
6
  include Representable::HashMethods
7
-
7
+
8
8
  def self.included(base)
9
9
  base.class_eval do
10
10
  include Representable
11
11
  extend ClassMethods
12
12
  end
13
13
  end
14
-
15
-
14
+
15
+
16
16
  module ClassMethods
17
17
  def values(options)
18
18
  hash :_self, options.merge!(:use_attributes => true)
19
19
  end
20
20
  end
21
-
22
-
21
+
22
+
23
23
  def definition_opts
24
- [:_self, :hash => true, :use_attributes => true]
24
+ [:_self, {:hash => true, :use_attributes => true}]
25
25
  end
26
26
  end
27
-
27
+
28
28
  module Hash
29
29
  include Representable::XML
30
30
  include HashMethods
31
-
31
+
32
32
  def self.included(base)
33
33
  base.class_eval do
34
34
  include Representable
35
35
  extend ClassMethods
36
36
  end
37
37
  end
38
-
39
-
38
+
39
+
40
40
  module ClassMethods
41
41
  def values(options)
42
42
  hash :_self, options
43
43
  end
44
44
  end
45
-
46
-
45
+
46
+
47
47
  def definition_opts
48
- [:_self, :hash => true]
48
+ [:_self, {:hash => true}]
49
49
  end
50
50
  end
51
51
  end
@@ -4,7 +4,7 @@ module JsonTest
4
4
  class APITest < MiniTest::Spec
5
5
  Json = Representable::JSON
6
6
  Def = Representable::Definition
7
-
7
+
8
8
  describe "JSON module" do
9
9
  before do
10
10
  @Band = Class.new do
@@ -12,23 +12,23 @@ module JsonTest
12
12
  property :name
13
13
  property :label
14
14
  attr_accessor :name, :label
15
-
15
+
16
16
  def initialize(name=nil)
17
17
  self.name = name if name
18
18
  end
19
19
  end
20
-
20
+
21
21
  @band = @Band.new
22
22
  end
23
-
24
-
23
+
24
+
25
25
  describe ".from_json" do
26
26
  it "is delegated to #from_json" do
27
27
  block = lambda {|*args|}
28
28
  @Band.any_instance.expects(:from_json).with("{document}", "options") # FIXME: how to NOT expect block?
29
29
  @Band.from_json("{document}", "options", &block)
30
30
  end
31
-
31
+
32
32
  it "yields new object and options to block" do
33
33
  @Band.class_eval { attr_accessor :new_name }
34
34
  @band = @Band.from_json("{}", :new_name => "Diesel Boy") do |band, options|
@@ -37,113 +37,113 @@ module JsonTest
37
37
  assert_equal "Diesel Boy", @band.new_name
38
38
  end
39
39
  end
40
-
41
-
40
+
41
+
42
42
  describe ".from_hash" do
43
43
  it "is delegated to #from_hash not passing the block" do
44
44
  block = lambda {|*args|}
45
45
  @Band.any_instance.expects(:from_hash).with("{document}", "options") # FIXME: how to NOT expect block?
46
46
  @Band.from_hash("{document}", "options", &block)
47
47
  end
48
-
48
+
49
49
  it "yields new object and options to block" do
50
50
  @Band.class_eval { attr_accessor :new_name }
51
51
  @band = @Band.from_hash({}, :new_name => "Diesel Boy") do |band, options|
52
52
  band.new_name= options[:new_name]
53
53
  end
54
-
54
+
55
55
  assert_equal "Diesel Boy", @band.new_name
56
56
  end
57
57
  end
58
-
59
-
58
+
59
+
60
60
  describe "#from_json" do
61
61
  before do
62
62
  @band = @Band.new
63
63
  @json = {:name => "Nofx", :label => "NOFX"}.to_json
64
64
  end
65
-
65
+
66
66
  it "parses JSON and assigns properties" do
67
67
  @band.from_json(@json)
68
68
  assert_equal ["Nofx", "NOFX"], [@band.name, @band.label]
69
69
  end
70
70
  end
71
-
72
-
71
+
72
+
73
73
  describe "#from_hash" do
74
74
  before do
75
75
  @band = @Band.new
76
76
  @hash = {"name" => "Nofx", "label" => "NOFX"}
77
77
  end
78
-
78
+
79
79
  it "receives hash and assigns properties" do
80
80
  @band.from_hash(@hash)
81
81
  assert_equal ["Nofx", "NOFX"], [@band.name, @band.label]
82
82
  end
83
-
83
+
84
84
  it "respects :wrap option" do
85
85
  @band.from_hash({"band" => {"name" => "This Is A Standoff"}}, :wrap => :band)
86
86
  assert_equal "This Is A Standoff", @band.name
87
87
  end
88
-
88
+
89
89
  it "respects :wrap option over representation_wrap" do
90
90
  @Band.class_eval do
91
- self.representation_wrap = :group
91
+ self.representation_wrap = :group
92
92
  end
93
93
  @band.from_hash({"band" => {"name" => "This Is A Standoff"}}, :wrap => :band)
94
94
  assert_equal "This Is A Standoff", @band.name
95
95
  end
96
96
  end
97
-
98
-
97
+
98
+
99
99
  describe "#to_json" do
100
100
  it "delegates to #to_hash and returns string" do
101
- assert_equal "{\"name\":\"Rise Against\"}", @Band.new("Rise Against").to_json
101
+ assert_json "{\"name\":\"Rise Against\"}", @Band.new("Rise Against").to_json
102
102
  end
103
103
  end
104
-
105
-
104
+
105
+
106
106
  describe "#to_hash" do
107
107
  it "returns unwrapped hash" do
108
108
  hash = @Band.new("Rise Against").to_hash
109
109
  assert_equal({"name"=>"Rise Against"}, hash)
110
110
  end
111
-
111
+
112
112
  it "respects #representation_wrap=" do
113
113
  @Band.representation_wrap = :group
114
114
  assert_equal({:group=>{"name"=>"Rise Against"}}, @Band.new("Rise Against").to_hash)
115
115
  end
116
-
116
+
117
117
  it "respects :wrap option" do
118
118
  assert_equal({:band=>{"name"=>"NOFX"}}, @Band.new("NOFX").to_hash(:wrap => :band))
119
119
  end
120
-
120
+
121
121
  it "respects :wrap option over representation_wrap" do
122
122
  @Band.class_eval do
123
- self.representation_wrap = :group
123
+ self.representation_wrap = :group
124
124
  end
125
125
  assert_equal({:band=>{"name"=>"Rise Against"}}, @Band.new("Rise Against").to_hash(:wrap => :band))
126
126
  end
127
127
  end
128
-
128
+
129
129
  describe "#binding_for_definition" do
130
130
  it "returns ObjectBinding" do
131
131
  assert_kind_of Json::ObjectBinding, Json.binding_for_definition(Def.new(:band, :class => Hash))
132
132
  end
133
-
133
+
134
134
  it "returns TextBinding" do
135
135
  assert_kind_of Json::PropertyBinding, Json.binding_for_definition(Def.new(:band))
136
136
  end
137
-
137
+
138
138
  it "returns HashBinding" do
139
139
  assert_kind_of Json::HashBinding, Json.binding_for_definition(Def.new(:band, :hash => true))
140
140
  end
141
-
141
+
142
142
  it "returns CollectionBinding" do
143
143
  assert_kind_of Json::CollectionBinding, Json.binding_for_definition(Def.new(:band, :collection => true))
144
144
  end
145
145
  end
146
-
146
+
147
147
  describe "#representable_bindings" do
148
148
  it "returns bindings for each property" do
149
149
  assert_equal 2, @band.send(:representable_bindings_for, Json).size
@@ -151,27 +151,27 @@ module JsonTest
151
151
  end
152
152
  end
153
153
  end
154
-
155
-
154
+
155
+
156
156
  describe "DCI" do
157
157
  module SongRepresenter
158
158
  include Representable::JSON
159
159
  property :name
160
160
  end
161
-
161
+
162
162
  module AlbumRepresenter
163
163
  include Representable::JSON
164
164
  property :best_song, :class => Song, :extend => SongRepresenter
165
165
  collection :songs, :class => Song, :extend => [SongRepresenter]
166
166
  end
167
-
168
-
167
+
168
+
169
169
  it "allows adding the representer by using #extend" do
170
170
  module BandRepresenter
171
171
  include Representable::JSON
172
172
  property :name
173
173
  end
174
-
174
+
175
175
  civ = Object.new
176
176
  civ.instance_eval do
177
177
  def name; "CIV"; end
@@ -179,30 +179,30 @@ module JsonTest
179
179
  @name = v
180
180
  end
181
181
  end
182
-
182
+
183
183
  civ.extend(BandRepresenter)
184
- assert_equal "{\"name\":\"CIV\"}", civ.to_json
184
+ assert_json "{\"name\":\"CIV\"}", civ.to_json
185
185
  end
186
-
186
+
187
187
  it "extends contained models when serializing" do
188
188
  @album = Album.new(Song.new("I Hate My Brain"), Song.new("Mr. Charisma"))
189
189
  @album.extend(AlbumRepresenter)
190
-
191
- assert_equal "{\"best_song\":{\"name\":\"Mr. Charisma\"},\"songs\":[{\"name\":\"I Hate My Brain\"},{\"name\":\"Mr. Charisma\"}]}", @album.to_json
190
+
191
+ assert_json "{\"best_song\":{\"name\":\"Mr. Charisma\"},\"songs\":[{\"name\":\"I Hate My Brain\"},{\"name\":\"Mr. Charisma\"}]}", @album.to_json
192
192
  end
193
-
193
+
194
194
  it "extends contained models when deserializing" do
195
195
  #@album = Album.new(Song.new("I Hate My Brain"), Song.new("Mr. Charisma"))
196
196
  @album = Album.new
197
197
  @album.extend(AlbumRepresenter)
198
-
198
+
199
199
  @album.from_json("{\"best_song\":{\"name\":\"Mr. Charisma\"},\"songs\":[{\"name\":\"I Hate My Brain\"},{\"name\":\"Mr. Charisma\"}]}")
200
200
  assert_equal "Mr. Charisma", @album.best_song.name
201
201
  end
202
202
  end
203
203
  end
204
-
205
-
204
+
205
+
206
206
  class PropertyTest < MiniTest::Spec
207
207
  describe "property :name" do
208
208
  class Band
@@ -210,45 +210,45 @@ module JsonTest
210
210
  property :name
211
211
  attr_accessor :name
212
212
  end
213
-
213
+
214
214
  it "#from_json creates correct accessors" do
215
215
  band = Band.from_json({:name => "Bombshell Rocks"}.to_json)
216
216
  assert_equal "Bombshell Rocks", band.name
217
217
  end
218
-
218
+
219
219
  it "#to_json serializes correctly" do
220
220
  band = Band.new
221
221
  band.name = "Cigar"
222
-
223
- assert_equal '{"name":"Cigar"}', band.to_json
222
+
223
+ assert_json '{"name":"Cigar"}', band.to_json
224
224
  end
225
225
  end
226
-
226
+
227
227
  describe ":class => Item" do
228
228
  class Label
229
229
  include Representable::JSON
230
230
  property :name
231
231
  attr_accessor :name
232
232
  end
233
-
233
+
234
234
  class Album
235
235
  include Representable::JSON
236
236
  property :label, :class => Label
237
237
  attr_accessor :label
238
238
  end
239
-
239
+
240
240
  it "#from_json creates one Item instance" do
241
241
  album = Album.from_json('{"label":{"name":"Fat Wreck"}}')
242
242
  assert_equal "Fat Wreck", album.label.name
243
243
  end
244
-
244
+
245
245
  it "#to_json serializes" do
246
246
  label = Label.new; label.name = "Fat Wreck"
247
247
  album = Album.new; album.label = label
248
-
249
- assert_equal '{"label":{"name":"Fat Wreck"}}', album.to_json
248
+
249
+ assert_json '{"label":{"name":"Fat Wreck"}}', album.to_json
250
250
  end
251
-
251
+
252
252
  describe ":different_name, :class => Label" do
253
253
  before do
254
254
  @Album = Class.new do
@@ -257,34 +257,34 @@ module JsonTest
257
257
  attr_accessor :seller
258
258
  end
259
259
  end
260
-
260
+
261
261
  it "#to_xml respects the different name" do
262
262
  label = Label.new; label.name = "Fat Wreck"
263
263
  album = @Album.new; album.seller = label
264
-
265
- assert_equal "{\"seller\":{\"name\":\"Fat Wreck\"}}", album.to_json(:wrap => false)
264
+
265
+ assert_json "{\"seller\":{\"name\":\"Fat Wreck\"}}", album.to_json(:wrap => false)
266
266
  end
267
267
  end
268
268
  end
269
-
269
+
270
270
  describe ":from => :songName" do
271
271
  class Song
272
272
  include Representable::JSON
273
273
  property :name, :from => :songName
274
274
  attr_accessor :name
275
275
  end
276
-
276
+
277
277
  it "respects :from in #from_json" do
278
278
  song = Song.from_json({:songName => "Run To The Hills"}.to_json)
279
279
  assert_equal "Run To The Hills", song.name
280
280
  end
281
-
281
+
282
282
  it "respects :from in #to_json" do
283
283
  song = Song.new; song.name = "Run To The Hills"
284
- assert_equal '{"songName":"Run To The Hills"}', song.to_json
284
+ assert_json '{"songName":"Run To The Hills"}', song.to_json
285
285
  end
286
286
  end
287
-
287
+
288
288
  describe ":default => :value" do
289
289
  before do
290
290
  @Album = Class.new do
@@ -293,39 +293,39 @@ module JsonTest
293
293
  attr_accessor :name
294
294
  end
295
295
  end
296
-
296
+
297
297
  describe "#from_json" do
298
298
  it "uses default when property nil in doc" do
299
299
  album = @Album.from_json({}.to_json)
300
300
  assert_equal "30 Years Live", album.name
301
301
  end
302
-
302
+
303
303
  it "uses value from doc when present" do
304
304
  album = @Album.from_json({:name => "Live At The Wireless"}.to_json)
305
305
  assert_equal "Live At The Wireless", album.name
306
306
  end
307
-
307
+
308
308
  it "uses value from doc when empty string" do
309
309
  album = @Album.from_json({:name => ""}.to_json)
310
310
  assert_equal "", album.name
311
311
  end
312
312
  end
313
-
313
+
314
314
  describe "#to_json" do
315
315
  it "uses default when not available in object" do
316
- assert_equal "{\"name\":\"30 Years Live\"}", @Album.new.to_json
316
+ assert_json "{\"name\":\"30 Years Live\"}", @Album.new.to_json
317
317
  end
318
-
318
+
319
319
  it "uses value from represented object when present" do
320
320
  album = @Album.new
321
321
  album.name = "Live At The Wireless"
322
- assert_equal "{\"name\":\"Live At The Wireless\"}", album.to_json
322
+ assert_json "{\"name\":\"Live At The Wireless\"}", album.to_json
323
323
  end
324
-
324
+
325
325
  it "uses value from represented object when emtpy string" do
326
326
  album = @Album.new
327
327
  album.name = ""
328
- assert_equal "{\"name\":\"\"}", album.to_json
328
+ assert_json "{\"name\":\"\"}", album.to_json
329
329
  end
330
330
  end
331
331
  end
@@ -339,37 +339,37 @@ end
339
339
  collection :songs
340
340
  attr_accessor :songs
341
341
  end
342
-
342
+
343
343
  it "#from_json creates correct accessors" do
344
344
  cd = CD.from_json({:songs => ["Out in the cold", "Microphone"]}.to_json)
345
345
  assert_equal ["Out in the cold", "Microphone"], cd.songs
346
346
  end
347
-
347
+
348
348
  it "#to_json serializes correctly" do
349
349
  cd = CD.new
350
350
  cd.songs = ["Out in the cold", "Microphone"]
351
-
352
- assert_equal '{"songs":["Out in the cold","Microphone"]}', cd.to_json
351
+
352
+ assert_json '{"songs":["Out in the cold","Microphone"]}', cd.to_json
353
353
  end
354
354
  end
355
-
355
+
356
356
  describe "collection :name, :class => Band" do
357
357
  class Band
358
358
  include Representable::JSON
359
359
  property :name
360
360
  attr_accessor :name
361
-
361
+
362
362
  def initialize(name="")
363
363
  self.name = name
364
364
  end
365
365
  end
366
-
366
+
367
367
  class Compilation
368
368
  include Representable::JSON
369
369
  collection :bands, :class => Band
370
370
  attr_accessor :bands
371
371
  end
372
-
372
+
373
373
  describe "#from_json" do
374
374
  it "pushes collection items to array" do
375
375
  cd = Compilation.from_json({:bands => [
@@ -377,43 +377,43 @@ end
377
377
  {:name => "Diesel Boy"}]}.to_json)
378
378
  assert_equal ["Cobra Skulls", "Diesel Boy"], cd.bands.map(&:name).sort
379
379
  end
380
-
380
+
381
381
  it "creates emtpy array from default if configured" do
382
382
  cd = Compilation.from_json({}.to_json)
383
383
  assert_equal [], cd.bands
384
384
  end
385
385
  end
386
-
386
+
387
387
  it "responds to #to_json" do
388
388
  cd = Compilation.new
389
389
  cd.bands = [Band.new("Diesel Boy"), Band.new("Bad Religion")]
390
-
391
- assert_equal '{"bands":[{"name":"Diesel Boy"},{"name":"Bad Religion"}]}', cd.to_json
390
+
391
+ assert_json '{"bands":[{"name":"Diesel Boy"},{"name":"Bad Religion"}]}', cd.to_json
392
392
  end
393
393
  end
394
-
395
-
394
+
395
+
396
396
  describe ":from => :songList" do
397
397
  class Songs
398
398
  include Representable::JSON
399
399
  collection :tracks, :from => :songList
400
400
  attr_accessor :tracks
401
401
  end
402
-
402
+
403
403
  it "respects :from in #from_json" do
404
404
  songs = Songs.from_json({:songList => ["Out in the cold", "Microphone"]}.to_json)
405
405
  assert_equal ["Out in the cold", "Microphone"], songs.tracks
406
406
  end
407
-
407
+
408
408
  it "respects option in #to_json" do
409
409
  songs = Songs.new
410
410
  songs.tracks = ["Out in the cold", "Microphone"]
411
-
412
- assert_equal '{"songList":["Out in the cold","Microphone"]}', songs.to_json
411
+
412
+ assert_json '{"songList":["Out in the cold","Microphone"]}', songs.to_json
413
413
  end
414
414
  end
415
415
  end
416
-
416
+
417
417
  class HashTest < MiniTest::Spec
418
418
  describe "hash :songs" do
419
419
  before do
@@ -421,34 +421,34 @@ end
421
421
  include Representable::JSON
422
422
  hash :songs
423
423
  end
424
-
424
+
425
425
  class SongList
426
426
  attr_accessor :songs
427
427
  end
428
-
428
+
429
429
  @list = SongList.new.extend(representer)
430
430
  end
431
-
431
+
432
432
  it "renders with #to_json" do
433
433
  @list.songs = {:one => "65", :two => "Emo Boy"}
434
- assert_equal "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", @list.to_json
434
+ assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", @list.to_json
435
435
  end
436
-
436
+
437
437
  it "parses with #from_json" do
438
438
  assert_equal({"one" => "65", "two" => ["Emo Boy"]}, @list.from_json("{\"songs\":{\"one\":\"65\",\"two\":[\"Emo Boy\"]}}").songs)
439
439
  end
440
440
  end
441
-
441
+
442
442
  end
443
-
444
-
443
+
444
+
445
445
  require 'representable/json/collection'
446
446
  class CollectionRepresenterTest < MiniTest::Spec
447
447
  module SongRepresenter
448
448
  include Representable::JSON
449
449
  property :name
450
450
  end
451
-
451
+
452
452
  describe "JSON::Collection" do
453
453
  describe "with contained objects" do
454
454
  before do
@@ -457,42 +457,42 @@ end
457
457
  items :class => Song, :extend => SongRepresenter
458
458
  end
459
459
  end
460
-
460
+
461
461
  it "renders objects with #to_json" do
462
- assert_equal "[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]", [Song.new("Days Go By"), Song.new("Can't Take Them All")].extend(@songs_representer).to_json
462
+ assert_json "[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]", [Song.new("Days Go By"), Song.new("Can't Take Them All")].extend(@songs_representer).to_json
463
463
  end
464
-
464
+
465
465
  it "returns objects array from #from_json" do
466
466
  assert_equal [Song.new("Days Go By"), Song.new("Can't Take Them All")], [].extend(@songs_representer).from_json("[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]")
467
467
  end
468
468
  end
469
-
469
+
470
470
  describe "with contained text" do
471
471
  before do
472
472
  @songs_representer = Module.new do
473
473
  include Representable::JSON::Collection
474
474
  end
475
475
  end
476
-
476
+
477
477
  it "renders contained items #to_json" do
478
- assert_equal "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
478
+ assert_json "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
479
479
  end
480
-
480
+
481
481
  it "returns objects array from #from_json" do
482
482
  assert_equal ["Days Go By", "Can't Take Them All"], [].extend(@songs_representer).from_json("[\"Days Go By\",\"Can't Take Them All\"]")
483
483
  end
484
484
  end
485
485
  end
486
486
  end
487
-
488
-
487
+
488
+
489
489
  require 'representable/json/hash'
490
490
  class HashRepresenterTest < MiniTest::Spec
491
491
  module SongRepresenter
492
492
  include Representable::JSON
493
493
  property :name
494
494
  end
495
-
495
+
496
496
  describe "JSON::Hash" do # TODO: move to HashTest.
497
497
  describe "with contained objects" do
498
498
  before do
@@ -501,47 +501,47 @@ end
501
501
  values :class => Song, :extend => SongRepresenter
502
502
  end
503
503
  end
504
-
504
+
505
505
  describe "#to_json" do
506
506
  it "renders objects" do
507
- assert_equal "{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(@songs_representer).to_json
507
+ assert_json "{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(@songs_representer).to_json
508
508
  end
509
-
509
+
510
510
  it "respects :exclude" do
511
- assert_equal "{\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(@songs_representer).to_json(:exclude => [:one])
511
+ assert_json "{\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(@songs_representer).to_json(:exclude => [:one])
512
512
  end
513
-
513
+
514
514
  it "respects :include" do
515
- assert_equal "{\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(@songs_representer).to_json(:include => [:two])
515
+ assert_json "{\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(@songs_representer).to_json(:include => [:two])
516
516
  end
517
517
  end
518
-
518
+
519
519
  describe "#from_json" do
520
520
  it "returns objects array" do
521
521
  assert_equal({"one" => Song.new("Days Go By"), "two" => Song.new("Can't Take Them All")}, {}.extend(@songs_representer).from_json("{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}"))
522
522
  end
523
-
523
+
524
524
  it "respects :exclude" do
525
525
  assert_equal({"two" => Song.new("Can't Take Them All")}, {}.extend(@songs_representer).from_json("{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}", :exclude => [:one]))
526
526
  end
527
-
527
+
528
528
  it "respects :include" do
529
529
  assert_equal({"one" => Song.new("Days Go By")}, {}.extend(@songs_representer).from_json("{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}", :include => [:one]))
530
530
  end
531
531
  end
532
532
  end
533
-
533
+
534
534
  describe "with contained text" do
535
535
  before do
536
536
  @songs_representer = Module.new do
537
537
  include Representable::JSON::Collection
538
538
  end
539
539
  end
540
-
540
+
541
541
  it "renders contained items #to_json" do
542
- assert_equal "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
542
+ assert_json "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
543
543
  end
544
-
544
+
545
545
  it "returns objects array from #from_json" do
546
546
  assert_equal ["Days Go By", "Can't Take Them All"], [].extend(@songs_representer).from_json("[\"Days Go By\",\"Can't Take Them All\"]")
547
547
  end
@@ -63,7 +63,7 @@ class RepresentableTest < MiniTest::Spec
63
63
  end.new
64
64
  vd.name = "Vention Dention"
65
65
  vd.street_cred = 1
66
- assert_equal "{\"name\":\"Vention Dention\",\"street_cred\":1}", vd.to_json
66
+ assert_json "{\"name\":\"Vention Dention\",\"street_cred\":1}", vd.to_json
67
67
  end
68
68
 
69
69
  #it "allows including the concrete representer module only" do
@@ -113,7 +113,7 @@ class RepresentableTest < MiniTest::Spec
113
113
  band = Bodyjar.new
114
114
  band.name = "Bodyjar"
115
115
 
116
- assert_equal "{\"band\":{\"name\":\"Bodyjar\"}}", band.to_json
116
+ assert_json "{\"band\":{\"name\":\"Bodyjar\"}}", band.to_json
117
117
  assert_xml_equal "<band><name>Bodyjar</name></band>", band.to_xml
118
118
  end
119
119
 
@@ -130,7 +130,7 @@ class RepresentableTest < MiniTest::Spec
130
130
 
131
131
  @song = Song.new("Days Go By")
132
132
  assert_xml_equal "<song name=\"Days Go By\"/>", @song.extend(SongXmlRepresenter).to_xml
133
- assert_equal "{\"name\":\"Days Go By\"}", @song.extend(SongJsonRepresenter).to_json
133
+ assert_json "{\"name\":\"Days Go By\"}", @song.extend(SongJsonRepresenter).to_json
134
134
  end
135
135
  end
136
136
 
@@ -310,17 +310,32 @@ class RepresentableTest < MiniTest::Spec
310
310
  assert_equal({"name"=>"No One's Choice","groupies"=>false}, @band.send(:create_representation_with, {}, {}, Representable::JSON))
311
311
  end
312
312
 
313
- it "includes nil attribute when :render_nil is true" do
314
- mod = Module.new do
315
- include Representable::JSON
316
- property :name
317
- property :groupies, :render_nil => true
313
+ describe "when :render_nil is true" do
314
+ it "includes nil attribute" do
315
+ mod = Module.new do
316
+ include Representable::JSON
317
+ property :name
318
+ property :groupies, :render_nil => true
319
+ end
320
+
321
+ @band.extend(mod) # FIXME: use clean object.
322
+ @band.groupies = nil
323
+ hash = @band.send(:create_representation_with, {}, {}, Representable::JSON)
324
+ assert_equal({"name"=>"No One's Choice", "groupies" => nil}, hash)
318
325
  end
319
326
 
320
- @band.extend(mod) # FIXME: use clean object.
321
- @band.groupies = nil
322
- hash = @band.send(:create_representation_with, {}, {}, Representable::JSON)
323
- assert_equal({"name"=>"No One's Choice", "groupies" => nil}, hash)
327
+ it "includes nil attribute without extending" do
328
+ mod = Module.new do
329
+ include Representable::JSON
330
+ property :name
331
+ property :groupies, :render_nil => true, :extend => BandRepresentation
332
+ end
333
+
334
+ @band.extend(mod) # FIXME: use clean object.
335
+ @band.groupies = nil
336
+ hash = @band.send(:create_representation_with, {}, {}, Representable::JSON)
337
+ assert_equal({"name"=>"No One's Choice", "groupies" => nil}, hash)
338
+ end
324
339
  end
325
340
  end
326
341
 
@@ -24,7 +24,7 @@ class Song
24
24
  def initialize(name=nil)
25
25
  @name = name
26
26
  end
27
-
27
+
28
28
  def ==(other)
29
29
  name == other.name
30
30
  end
@@ -36,6 +36,16 @@ module XmlHelper
36
36
  end
37
37
  end
38
38
 
39
+ module AssertJson
40
+ module Assertions
41
+ def assert_json(expected, actual, msg=nil)
42
+ msg = message(msg, "") { diff expected, actual }
43
+ assert(expected.split("").sort == actual.split("").sort, msg)
44
+ end
45
+ end
46
+ end
47
+
39
48
  MiniTest::Spec.class_eval do
49
+ include AssertJson::Assertions
40
50
  include XmlHelper
41
51
  end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class TestHelperTest < MiniTest::Spec
4
+ describe "#assert_json" do
5
+ it "tests for equality" do
6
+ assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}"
7
+ end
8
+
9
+ it "allows different key orders" do
10
+ assert_json "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}"
11
+ end
12
+
13
+ it "complains when expected hash is subset" do
14
+ assert_raises MiniTest::Assertion do
15
+ assert_json "{\"songs\":{\"one\":\"65\"}}", "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}"
16
+ end
17
+ end
18
+
19
+ it "complains when source hash is subset" do
20
+ assert_raises MiniTest::Assertion do
21
+ assert_json "{\"songs\":{\"two\":\"Emo Boy\",\"one\":\"65\"}}", "{\"songs\":{\"one\":\"65\"}}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -11,7 +11,9 @@ class Band
11
11
  end
12
12
  end
13
13
 
14
-
14
+ class Album
15
+ attr_accessor :songs
16
+ end
15
17
 
16
18
 
17
19
  class XmlTest < MiniTest::Spec
@@ -319,14 +321,14 @@ class CollectionTest < MiniTest::Spec
319
321
 
320
322
 
321
323
  describe ":from" do
322
- class Album
323
- include Representable::XML
324
- collection :songs, :from => :song
325
- attr_accessor :songs
326
- end
324
+ let(:xml) {
325
+ Module.new do
326
+ include Representable::XML
327
+ collection :songs, :from => :song
328
+ end }
327
329
 
328
330
  it "collects untyped items" do
329
- album = Album.from_xml(%{
331
+ album = Album.new.extend(xml).from_xml(%{
330
332
  <album>
331
333
  <song>Two Kevins</song>
332
334
  <song>Wright and Rong</song>
@@ -336,6 +338,46 @@ class CollectionTest < MiniTest::Spec
336
338
  assert_equal ["Laundry Basket", "Two Kevins", "Wright and Rong"].sort, album.songs.sort
337
339
  end
338
340
  end
341
+
342
+
343
+ describe ":wrap" do
344
+ let (:album) { Album.new.extend(xml) }
345
+ let (:xml) {
346
+ Module.new do
347
+ include Representable::XML
348
+ collection :songs, :from => :song, :wrap => :songs
349
+ end }
350
+
351
+ describe "#from_xml" do
352
+ it "finds items in wrapped collection" do
353
+ album.from_xml(%{
354
+ <album>
355
+ <songs>
356
+ <song>Two Kevins</song>
357
+ <song>Wright and Rong</song>
358
+ <song>Laundry Basket</song>
359
+ </songs>
360
+ </album>
361
+ })
362
+ assert_equal ["Laundry Basket", "Two Kevins", "Wright and Rong"].sort, album.songs.sort
363
+ end
364
+ end
365
+
366
+ describe "#to_xml" do
367
+ it "wraps items" do
368
+ album.songs = ["Laundry Basket", "Two Kevins", "Wright and Rong"]
369
+ assert_xml_equal %{
370
+ <album>
371
+ <songs>
372
+ <song>Laundry Basket</song>
373
+ <song>Two Kevins</song>
374
+ <song>Wright and Rong</song>
375
+ </songs>
376
+ </album>
377
+ }, album.to_xml
378
+ end
379
+ end
380
+ end
339
381
 
340
382
  require 'representable/xml/hash'
341
383
  describe "XML::AttributeHash" do # TODO: move to HashTest.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: representable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-09 00:00:00.000000000 Z
12
+ date: 2012-08-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -155,6 +155,7 @@ files:
155
155
  - LICENSE
156
156
  - README.rdoc
157
157
  - Rakefile
158
+ - gemfiles/Gemfile.mongoid-2.4
158
159
  - lib/representable.rb
159
160
  - lib/representable/binding.rb
160
161
  - lib/representable/bindings/json_bindings.rb
@@ -179,6 +180,7 @@ files:
179
180
  - test/polymorphic_test.rb
180
181
  - test/representable_test.rb
181
182
  - test/test_helper.rb
183
+ - test/test_helper_test.rb
182
184
  - test/xml_bindings_test.rb
183
185
  - test/xml_test.rb
184
186
  homepage: http://representable.apotomo.de