representable 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,8 +9,9 @@ module Representable
9
9
  # things might work as expected.
10
10
  module JSON
11
11
  def self.binding_for_definition(definition)
12
- return ObjectBinding.new(definition) if definition.typed?
13
- TextBinding.new(definition)
12
+ return CollectionBinding.new(definition) if definition.array?
13
+ return HashBinding.new(definition) if definition.hash?
14
+ PropertyBinding.new(definition)
14
15
  end
15
16
 
16
17
  def self.included(base)
@@ -0,0 +1,38 @@
1
+ module Representable::JSON
2
+ module Collection
3
+ include Representable::JSON
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ include Representable
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+
13
+ module ClassMethods
14
+ def items(options)
15
+ collection :_self, options
16
+ end
17
+ end
18
+
19
+
20
+ def create_representation_with(doc, options, format)
21
+ bin = representable_bindings_for(format).first
22
+ bin.serialize_for(self)
23
+ end
24
+
25
+ def update_properties_from(doc, options, format)
26
+ bin = representable_bindings_for(format).first
27
+ value = bin.deserialize_from(doc)
28
+ replace(value)
29
+ end
30
+
31
+ # FIXME: refactor Definition so we can simply add options in #items to existing definition.
32
+ def representable_attrs
33
+ attrs = super
34
+ attrs << Definition.new(:_self, :collection => true) if attrs.size == 0
35
+ attrs
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module Representable::JSON
2
+ module Hash
3
+ include Representable::JSON
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ include Representable
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+
13
+ module ClassMethods
14
+ def values(options)
15
+ hash :_self, options
16
+ end
17
+ end
18
+
19
+
20
+ def create_representation_with(doc, options, format)
21
+ bin = representable_bindings_for(format).first
22
+ bin.serialize_for(self)
23
+ end
24
+
25
+ def update_properties_from(doc, options, format)
26
+ bin = representable_bindings_for(format).first
27
+ value = bin.deserialize_from(doc)
28
+ replace(value)
29
+ end
30
+
31
+ # FIXME: refactor Definition so we can simply add options in #items to existing definition.
32
+ def representable_attrs
33
+ attrs = super
34
+ attrs << Definition.new(:_self, :hash => true) if attrs.size == 0
35
+ attrs
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -5,9 +5,10 @@ require 'nokogiri'
5
5
  module Representable
6
6
  module XML
7
7
  def self.binding_for_definition(definition)
8
- return ObjectBinding.new(definition) if definition.typed?
9
- return AttributeBinding.new(definition) if definition.attribute
10
- TextBinding.new(definition)
8
+ return CollectionBinding.new(definition) if definition.array?
9
+ return HashBinding.new(definition) if definition.hash?
10
+ return AttributeBinding.new(definition) if definition.attribute
11
+ PropertyBinding.new(definition)
11
12
  end
12
13
 
13
14
  def self.included(base)
@@ -0,0 +1,38 @@
1
+ module Representable::XML
2
+ module Collection
3
+ include Representable::XML
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ include Representable
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+
13
+ module ClassMethods
14
+ def items(options)
15
+ collection :_self, options
16
+ end
17
+ end
18
+
19
+
20
+ def create_representation_with(doc, options, format)
21
+ bin = representable_bindings_for(format).first
22
+ bin.serialize_for(self)
23
+ end
24
+
25
+ def update_properties_from(doc, options, format)
26
+ bin = representable_bindings_for(format).first
27
+ value = bin.deserialize_from(doc)
28
+ replace(value)
29
+ end
30
+
31
+ # FIXME: refactor Definition so we can simply add options in #items to existing definition.
32
+ def representable_attrs
33
+ attrs = super
34
+ attrs << Definition.new(:_self, :collection => true) if attrs.size == 0
35
+ attrs
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module Representable::XML
2
+ module Hash
3
+ include Representable::XML
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ include Representable
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+
13
+ module ClassMethods
14
+ def values(options)
15
+ hash :_self, options
16
+ end
17
+ end
18
+
19
+
20
+ def create_representation_with(doc, options, format)
21
+ bin = representable_bindings_for(format).first
22
+ bin.serialize_for(self)
23
+ end
24
+
25
+ def update_properties_from(doc, options, format)
26
+ bin = representable_bindings_for(format).first
27
+ value = bin.deserialize_from(doc)
28
+ replace(value)
29
+ end
30
+
31
+ # FIXME: refactor Definition so we can simply add options in #items to existing definition.
32
+ def representable_attrs
33
+ attrs = super
34
+ attrs << Definition.new(:_self, :hash => true) if attrs.size == 0
35
+ attrs
36
+ end
37
+ end
38
+ end
@@ -13,9 +13,18 @@ class DefinitionTest < MiniTest::Spec
13
13
  end
14
14
  end
15
15
 
16
- it "responds to #typed?" do
17
- assert ! @def.typed?
18
- assert Representable::Definition.new(:songs, :class => Hash).typed?
16
+ describe "#typed?" do
17
+ it "is false per default" do
18
+ assert ! @def.typed?
19
+ end
20
+
21
+ it "is true when :class is present" do
22
+ assert Representable::Definition.new(:songs, :class => Hash).typed?
23
+ end
24
+
25
+ it "is true when :extend is present, only" do
26
+ assert Representable::Definition.new(:songs, :extend => Hash).typed?
27
+ end
19
28
  end
20
29
 
21
30
  it "responds to #getter and returns string" do
@@ -26,10 +35,6 @@ class DefinitionTest < MiniTest::Spec
26
35
  assert_equal "songs", @def.name
27
36
  end
28
37
 
29
- it "responds to #instance_variable_name" do
30
- assert_equal :"@songs", @def.instance_variable_name
31
- end
32
-
33
38
  it "responds to #setter" do
34
39
  assert_equal :"songs=", @def.setter
35
40
  end
@@ -39,23 +44,6 @@ class DefinitionTest < MiniTest::Spec
39
44
  end
40
45
  end
41
46
 
42
-
43
- describe "#apply" do
44
- it "works with a single item" do
45
- @d = Representable::Definition.new(:song)
46
- assert_equal 2, @d.apply(1) { |v| v+1 }
47
- end
48
-
49
- it "works with collection" do
50
- @d = Representable::Definition.new(:song, :collection => true)
51
- assert_equal [2,3,4], @d.apply([1,2,3]) { |v| v+1 }
52
- end
53
-
54
- it "skips with collection and nil" do
55
- @d = Representable::Definition.new(:song, :collection => true)
56
- assert_equal nil, @d.apply(nil) { |v| v+1 }
57
- end
58
- end
59
47
 
60
48
  describe ":collection => true" do
61
49
  before do
@@ -96,4 +84,15 @@ class DefinitionTest < MiniTest::Spec
96
84
  assert_equal "Atheist Peace", @def.default
97
85
  end
98
86
  end
87
+
88
+ describe ":hash => true" do
89
+ before do
90
+ @def = Representable::Definition.new(:songs, :hash => true)
91
+ end
92
+
93
+ it "responds to #hash?" do
94
+ assert @def.hash?
95
+ assert ! Representable::Definition.new(:songs).hash?
96
+ end
97
+ end
99
98
  end
@@ -0,0 +1,119 @@
1
+ require 'test_helper'
2
+ require 'representable/json'
3
+
4
+ class JSONBindingTest < MiniTest::Spec
5
+ module SongRepresenter
6
+ include Representable::JSON
7
+ property :name
8
+ end
9
+
10
+ class SongWithRepresenter < ::Song
11
+ include Representable
12
+ include SongRepresenter
13
+ end
14
+
15
+
16
+ describe "PropertyBinding" do
17
+ describe "with plain text" do
18
+ before do
19
+ @property = Representable::JSON::PropertyBinding.new(Representable::Definition.new(:song))
20
+ end
21
+
22
+ it "extracts with #read" do
23
+ assert_equal "Thinning the Herd", @property.read("song" => "Thinning the Herd")
24
+ end
25
+
26
+ it "inserts with #write" do
27
+ doc = {}
28
+ assert_equal("Thinning the Herd", @property.write(doc,"Thinning the Herd"))
29
+ assert_equal({"song"=>"Thinning the Herd"}, doc)
30
+ end
31
+ end
32
+
33
+ describe "with an object" do
34
+ before do
35
+ @property = Representable::JSON::PropertyBinding.new(Representable::Definition.new(:song, :class => SongWithRepresenter))
36
+ @doc = {}
37
+ end
38
+
39
+ it "extracts with #read" do
40
+ assert_equal SongWithRepresenter.new("Thinning the Herd"), @property.read("song" => {"name" => "Thinning the Herd"})
41
+ end
42
+
43
+ it "inserts with #write" do
44
+ assert_equal({"name"=>"Thinning the Herd"}, @property.write(@doc, SongWithRepresenter.new("Thinning the Herd")))
45
+ assert_equal({"song" => {"name"=>"Thinning the Herd"}}, @doc)
46
+ end
47
+ end
48
+
49
+ describe "with an object and :extend" do
50
+ before do
51
+ @property = Representable::JSON::PropertyBinding.new(Representable::Definition.new(:song, :class => Song, :extend => SongRepresenter))
52
+ @doc = {}
53
+ end
54
+
55
+ it "extracts with #read" do
56
+ assert_equal Song.new("Thinning the Herd"), @property.read("song" => {"name" => "Thinning the Herd"})
57
+ end
58
+
59
+ it "inserts with #write" do
60
+ assert_equal({"name"=>"Thinning the Herd"}, @property.write(@doc, Song.new("Thinning the Herd")))
61
+ assert_equal({"song" => {"name"=>"Thinning the Herd"}}, @doc)
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ describe "CollectionBinding" do
68
+ describe "with plain text items" do
69
+ before do
70
+ @property = Representable::JSON::CollectionBinding.new(Representable::Definition.new(:songs, :collection => true))
71
+ end
72
+
73
+ it "extracts with #read" do
74
+ assert_equal ["The Gargoyle", "Bronx"], @property.read("songs" => ["The Gargoyle", "Bronx"])
75
+ end
76
+
77
+ it "inserts with #write" do
78
+ doc = {}
79
+ assert_equal(["The Gargoyle", "Bronx"], @property.write(doc, ["The Gargoyle", "Bronx"]))
80
+ assert_equal({"songs"=>["The Gargoyle", "Bronx"]}, doc)
81
+ end
82
+ end
83
+ end
84
+
85
+
86
+
87
+
88
+ describe "HashBinding" do
89
+ describe "with plain text items" do
90
+ before do
91
+ @property = Representable::JSON::HashBinding.new(Representable::Definition.new(:songs, :hash => true))
92
+ end
93
+
94
+ it "extracts with #read" do
95
+ assert_equal({"first" => "The Gargoyle", "second" => "Bronx"} , @property.read("songs" => {"first" => "The Gargoyle", "second" => "Bronx"}))
96
+ end
97
+
98
+ it "inserts with #write" do
99
+ doc = {}
100
+ assert_equal({"first" => "The Gargoyle", "second" => "Bronx"}, @property.write(doc, {"first" => "The Gargoyle", "second" => "Bronx"}))
101
+ assert_equal({"songs"=>{"first" => "The Gargoyle", "second" => "Bronx"}}, doc)
102
+ end
103
+ end
104
+
105
+ describe "with objects" do
106
+ before do
107
+ @property = Representable::JSON::HashBinding.new(Representable::Definition.new(:songs, :hash => true, :class => Song, :extend => SongRepresenter))
108
+ end
109
+
110
+ it "doesn't change the represented hash in #write" do
111
+ song = Song.new("Better Than That")
112
+ hash = {"first" => song}
113
+ @property.write({}, hash)
114
+ assert_equal({"first" => song}, hash)
115
+ end
116
+ end
117
+
118
+ end
119
+ end
@@ -133,7 +133,15 @@ module JsonTest
133
133
  end
134
134
 
135
135
  it "returns TextBinding" do
136
- assert_kind_of Json::TextBinding, Json.binding_for_definition(Def.new(:band))
136
+ assert_kind_of Json::PropertyBinding, Json.binding_for_definition(Def.new(:band))
137
+ end
138
+
139
+ it "returns HashBinding" do
140
+ assert_kind_of Json::HashBinding, Json.binding_for_definition(Def.new(:band, :hash => true))
141
+ end
142
+
143
+ it "returns CollectionBinding" do
144
+ assert_kind_of Json::CollectionBinding, Json.binding_for_definition(Def.new(:band, :collection => true))
137
145
  end
138
146
  end
139
147
 
@@ -155,7 +163,7 @@ module JsonTest
155
163
  module AlbumRepresenter
156
164
  include Representable::JSON
157
165
  property :best_song, :class => Song, :extend => SongRepresenter
158
- collection :songs, :class => Song, :extend => SongRepresenter
166
+ collection :songs, :class => Song, :extend => [SongRepresenter]
159
167
  end
160
168
 
161
169
 
@@ -194,7 +202,8 @@ module JsonTest
194
202
  end
195
203
  end
196
204
  end
197
-
205
+
206
+
198
207
  class PropertyTest < MiniTest::Spec
199
208
  describe "property :name" do
200
209
  class Band
@@ -405,4 +414,119 @@ end
405
414
  end
406
415
  end
407
416
  end
417
+
418
+ class HashTest < MiniTest::Spec
419
+ describe "hash :songs" do
420
+ before do
421
+ representer = Module.new do
422
+ include Representable::JSON
423
+ hash :songs
424
+ end
425
+
426
+ class SongList
427
+ attr_accessor :songs
428
+ end
429
+
430
+ @list = SongList.new.extend(representer)
431
+ end
432
+
433
+ it "renders with #to_json" do
434
+ @list.songs = {:one => "65", :two => "Emo Boy"}
435
+ assert_equal "{\"songs\":{\"one\":\"65\",\"two\":\"Emo Boy\"}}", @list.to_json
436
+ end
437
+
438
+ it "parses with #from_json" do
439
+ assert_equal({"one" => "65", "two" => ["Emo Boy"]}, @list.from_json("{\"songs\":{\"one\":\"65\",\"two\":[\"Emo Boy\"]}}").songs)
440
+ end
441
+ end
442
+
443
+ end
444
+
445
+
446
+ require 'representable/json/collection'
447
+ class CollectionRepresenterTest < MiniTest::Spec
448
+ module SongRepresenter
449
+ include Representable::JSON
450
+ property :name
451
+ end
452
+
453
+ describe "JSON::Collection" do
454
+ describe "with contained objects" do
455
+ before do
456
+ @songs_representer = Module.new do
457
+ include Representable::JSON::Collection
458
+ items :class => Song, :extend => SongRepresenter
459
+ end
460
+ end
461
+
462
+ it "renders objects with #to_json" do
463
+ 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
464
+ end
465
+
466
+ it "returns objects array from #from_json" do
467
+ 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\"}]")
468
+ end
469
+ end
470
+
471
+ describe "with contained text" do
472
+ before do
473
+ @songs_representer = Module.new do
474
+ include Representable::JSON::Collection
475
+ end
476
+ end
477
+
478
+ it "renders contained items #to_json" do
479
+ assert_equal "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
480
+ end
481
+
482
+ it "returns objects array from #from_json" do
483
+ assert_equal ["Days Go By", "Can't Take Them All"], [].extend(@songs_representer).from_json("[\"Days Go By\",\"Can't Take Them All\"]")
484
+ end
485
+ end
486
+ end
487
+ end
488
+
489
+
490
+ require 'representable/json/hash'
491
+ class HashRepresenterTest < MiniTest::Spec
492
+ module SongRepresenter
493
+ include Representable::JSON
494
+ property :name
495
+ end
496
+
497
+ describe "JSON::Hash" do
498
+ describe "with contained objects" do
499
+ before do
500
+ @songs_representer = Module.new do
501
+ include Representable::JSON::Hash
502
+ values :class => Song, :extend => SongRepresenter
503
+ end
504
+ end
505
+
506
+ it "renders objects with #to_json" 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
508
+ end
509
+
510
+ it "returns objects array from #from_json" do
511
+ 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\"}}"))
512
+ end
513
+ end
514
+
515
+ describe "with contained text" do
516
+ before do
517
+ @songs_representer = Module.new do
518
+ include Representable::JSON::Collection
519
+ end
520
+ end
521
+
522
+ it "renders contained items #to_json" do
523
+ assert_equal "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
524
+ end
525
+
526
+ it "returns objects array from #from_json" do
527
+ assert_equal ["Days Go By", "Can't Take Them All"], [].extend(@songs_representer).from_json("[\"Days Go By\",\"Can't Take Them All\"]")
528
+ end
529
+ end
530
+ end
531
+ end
408
532
  end