representable 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,7 @@
1
+ h2. 1.5.1
2
+
3
+ * Make lonely collections and hashes work with decorators.
4
+
1
5
  h2. 1.5.0
2
6
 
3
7
  * All lambdas now receive user options, too. Note that this might break your existing lambdas (especially with `:extend` or `:class`) raising an `ArgumentError: wrong number of arguments (2 for 1)`. Fix this by declaring your block params correctly, e.g. `lambda { |name, *|`. Internally, this happens by running all lambdas through the new `Binding#represented_exec_for`.
data/README.md CHANGED
@@ -64,7 +64,7 @@ song = Song.new.extend(SongRepresenter).from_json(%{ {"title":"Roxanne"} })
64
64
 
65
65
  ## Extend vs. Decorator
66
66
 
67
- If you don't want representer modules to be mixed into your objects (using `#extend`) you can use the `Decorator` strategy [described below](https://github.com/apotonick/representable#decorator-vs-extend). Decorating instead of extending was introduced in 1.4.
67
+ If you don't want representer modules to be mixed into your objects (using `#extend`) you can use the `Decorator` strategy [described below](#decorator-vs-extend). Decorating instead of extending was introduced in 1.4.
68
68
 
69
69
 
70
70
  ## Aliasing
@@ -205,6 +205,29 @@ class AlbumRepresentation < Representable::Decorator
205
205
  end
206
206
  ```
207
207
 
208
+ ### Helpers In Decorators
209
+
210
+ In module representers you can add methods for properties.
211
+
212
+ ```ruby
213
+ module SongRepresenter
214
+ property :title
215
+
216
+ def title
217
+ @name
218
+ end
219
+ ```
220
+
221
+ That works as the method is mixed into the represented object. Of course, this doesn't work with decorators.
222
+
223
+ Use `:getter` or `:setter` to dynamically add a method for the represented object.
224
+
225
+ ```ruby
226
+ class SongRepresenter < Representable::Decorator
227
+ property :title, getter: lambda { |*| @name }
228
+ ```
229
+ As always, the block is executed in the represented object's context.
230
+
208
231
  ## XML Support
209
232
 
210
233
  While representable does a great job with JSON, it also features support for XML, YAML and pure ruby hashes.
data/TODO CHANGED
@@ -25,4 +25,7 @@ module ReaderWriter
25
25
  end
26
26
  => do that for all "features" (what parts would that be?: getter/setter, reader/writer, readable/writeable )?
27
27
 
28
- * make lambda options optional (arity == 0)
28
+ * make lambda options optional (arity == 0)
29
+
30
+ * use `representer_exec` not only for lambdas, but also for methods
31
+ property :title # => calls decorator.title
@@ -12,10 +12,6 @@ module Representable
12
12
  build_for(definition, *args)
13
13
  end
14
14
 
15
- def definition # TODO: remove in 1.4.
16
- raise "Binding#definition is no longer supported as all Definition methods are now delegated automatically."
17
- end
18
-
19
15
  def initialize(definition, represented, user_options={}, lambda_context=represented) # TODO: remove default arg for user options. # DISCUSS: make lambda_context an options hash?
20
16
  super(definition)
21
17
  @represented = represented
@@ -1,6 +1,7 @@
1
1
  module Representable
2
2
  class Decorator
3
3
  attr_reader :represented
4
+ alias_method :decorated, :represented
4
5
 
5
6
  def self.prepare(represented)
6
7
  new(represented) # was: PrepareStrategy::Decorate.
@@ -1,6 +1,5 @@
1
1
  require 'representable'
2
2
  require 'representable/bindings/hash_bindings'
3
- require 'json'
4
3
 
5
4
  module Representable
6
5
  # The generic representer. Brings #to_hash and #from_hash to your object.
@@ -13,28 +12,28 @@ module Representable
13
12
  extend ClassMethods # DISCUSS: do that only for classes?
14
13
  end
15
14
  end
16
-
17
-
15
+
16
+
18
17
  module ClassMethods
19
18
  def from_hash(*args, &block)
20
19
  create_represented(*args, &block).from_hash(*args)
21
20
  end
22
21
  end
23
-
24
-
22
+
23
+
25
24
  def from_hash(data, options={}, binding_builder=PropertyBinding)
26
25
  if wrap = options[:wrap] || representation_wrap
27
26
  data = data[wrap.to_s]
28
27
  end
29
-
28
+
30
29
  update_properties_from(data, options, binding_builder)
31
30
  end
32
-
31
+
33
32
  def to_hash(options={}, binding_builder=PropertyBinding)
34
33
  hash = create_representation_with({}, options, binding_builder)
35
-
34
+
36
35
  return hash unless wrap = options[:wrap] || representation_wrap
37
-
36
+
38
37
  {wrap => hash}
39
38
  end
40
39
  end
@@ -6,21 +6,20 @@ module Representable
6
6
  attrs << Definition.new(*definition_opts) if attrs.size == 0
7
7
  attrs
8
8
  end
9
-
9
+
10
10
  def create_representation_with(doc, options, format)
11
11
  bin = representable_bindings_for(format, options).first
12
- hash = filter_keys_for(self, options)
12
+ hash = filter_keys_for(represented, options)
13
13
  bin.write(doc, hash)
14
14
  end
15
-
15
+
16
16
  def update_properties_from(doc, options, format)
17
17
  bin = representable_bindings_for(format, options).first
18
18
  hash = filter_keys_for(doc, options)
19
19
  value = bin.deserialize_from(hash)
20
- replace(value)
21
- self
20
+ represented.replace(value)
22
21
  end
23
-
22
+
24
23
  private
25
24
  def filter_keys_for(hash, options)
26
25
  return hash unless props = options[:exclude] || options[:include]
@@ -1,33 +1,33 @@
1
1
  module Representable::JSON
2
2
  module Collection
3
3
  include Representable::JSON
4
-
4
+
5
5
  def self.included(base)
6
6
  base.class_eval do
7
7
  include Representable
8
8
  extend ClassMethods
9
9
  end
10
10
  end
11
-
12
-
11
+
12
+
13
13
  module ClassMethods
14
14
  def items(options)
15
15
  collection :_self, options
16
16
  end
17
17
  end
18
-
19
-
18
+
19
+
20
20
  def create_representation_with(doc, options, format)
21
21
  bin = representable_bindings_for(format, options).first
22
- bin.serialize_for(self)
22
+ bin.serialize_for(represented)
23
23
  end
24
-
24
+
25
25
  def update_properties_from(doc, options, format)
26
26
  bin = representable_bindings_for(format, options).first
27
27
  value = bin.deserialize_from(doc)
28
- replace(value)
28
+ represented.replace(value)
29
29
  end
30
-
30
+
31
31
  # FIXME: refactor Definition so we can simply add options in #items to existing definition.
32
32
  def representable_attrs
33
33
  attrs = super
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "1.5.0"
2
+ VERSION = "1.5.1"
3
3
  end
@@ -1,33 +1,33 @@
1
1
  module Representable::XML
2
2
  module Collection
3
3
  include Representable::XML
4
-
4
+
5
5
  def self.included(base)
6
6
  base.class_eval do
7
7
  include Representable
8
8
  extend ClassMethods
9
9
  end
10
10
  end
11
-
12
-
11
+
12
+
13
13
  module ClassMethods
14
14
  def items(options)
15
15
  collection :_self, options
16
16
  end
17
17
  end
18
-
19
-
18
+
19
+
20
20
  def create_representation_with(doc, options, format)
21
21
  bin = representable_bindings_for(format, options).first
22
- bin.write(doc, self)
22
+ bin.write(doc, represented)
23
23
  end
24
-
24
+
25
25
  def update_properties_from(doc, options, format)
26
26
  bin = representable_bindings_for(format, options).first
27
27
  value = bin.deserialize_from(doc.search("./*")) # FIXME: use Binding#read.
28
- replace(value)
28
+ represented.replace(value)
29
29
  end
30
-
30
+
31
31
  # FIXME: refactor Definition so we can simply add options in #items to existing definition.
32
32
  def representable_attrs
33
33
  attrs = super
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency "multi_json"
24
24
 
25
25
  s.add_development_dependency "rake"
26
- s.add_development_dependency "test_xml"
27
- s.add_development_dependency "minitest", ">= 2.8.1"
26
+ s.add_development_dependency "test_xml", ">= 0.1.6"
27
+ s.add_development_dependency "minitest", "~> 5.0.0"
28
28
  s.add_development_dependency "mocha", ">= 0.13.0"
29
29
  s.add_development_dependency "mongoid"
30
30
  s.add_development_dependency "virtus", "~> 0.5.0"
@@ -478,90 +478,107 @@ end
478
478
 
479
479
 
480
480
  require 'representable/json/collection'
481
- class CollectionRepresenterTest < MiniTest::Spec
481
+ require 'representable/json/hash'
482
+ class LonelyRepresenterTest < MiniTest::Spec
482
483
  module SongRepresenter
483
484
  include Representable::JSON
484
485
  property :name
485
486
  end
486
487
 
488
+ let (:decorator) { rpr = representer; Class.new(Representable::Decorator) { include rpr } }
489
+
487
490
  describe "JSON::Collection" do
488
491
  describe "with contained objects" do
489
- before do
490
- @songs_representer = Module.new do
492
+ let (:representer) {
493
+ Module.new do
491
494
  include Representable::JSON::Collection
492
495
  items :class => Song, :extend => SongRepresenter
493
496
  end
497
+ }
498
+ let (:songs) { [Song.new("Days Go By"), Song.new("Can't Take Them All")] }
499
+ let (:json) { "[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]" }
500
+
501
+ it "renders array" do
502
+ assert_json json, songs.extend(representer).to_json
494
503
  end
495
504
 
496
- it "renders objects with #to_json" do
497
- 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
505
+ it "renders array with decorator" do
506
+ assert_json json, decorator.new(songs).to_json
498
507
  end
499
508
 
500
- it "returns objects array from #from_json" do
501
- 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\"}]")
509
+ it "parses array" do
510
+ [].extend(representer).from_json(json).must_equal songs
511
+ end
512
+
513
+ it "parses array with decorator" do
514
+ decorator.new([]).from_json(json).must_equal songs
502
515
  end
503
516
  end
504
517
 
505
518
  describe "with contained text" do
506
- before do
507
- @songs_representer = Module.new do
519
+ let (:representer) {
520
+ Module.new do
508
521
  include Representable::JSON::Collection
509
522
  end
510
- end
523
+ }
524
+ let (:songs) { ["Days Go By", "Can't Take Them All"] }
525
+ let (:json) { "[\"Days Go By\",\"Can't Take Them All\"]" }
511
526
 
512
527
  it "renders contained items #to_json" do
513
- assert_json "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
528
+ assert_json json, songs.extend(representer).to_json
514
529
  end
515
530
 
516
531
  it "returns objects array from #from_json" do
517
- assert_equal ["Days Go By", "Can't Take Them All"], [].extend(@songs_representer).from_json("[\"Days Go By\",\"Can't Take Them All\"]")
532
+ [].extend(representer).from_json(json).must_equal songs
518
533
  end
519
534
  end
520
535
  end
521
- end
522
536
 
523
537
 
524
- require 'representable/json/hash'
525
- class HashRepresenterTest < MiniTest::Spec
526
- module SongRepresenter
527
- include Representable::JSON
528
- property :name
529
- end
530
-
531
538
  describe "JSON::Hash" do # TODO: move to HashTest.
532
539
  describe "with contained objects" do
533
- before do
534
- @songs_representer = Module.new do
540
+ let (:representer) {
541
+ Module.new do
535
542
  include Representable::JSON::Hash
536
543
  values :class => Song, :extend => SongRepresenter
537
544
  end
538
- end
545
+ }
546
+ let (:json) { "{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}" }
547
+ let (:songs) { {"one" => Song.new("Days Go By"), "two" => Song.new("Can't Take Them All")} }
539
548
 
540
549
  describe "#to_json" do
541
- it "renders objects" do
542
- 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
550
+ it "renders hash" do
551
+ songs.extend(representer).to_json.must_equal json
552
+ end
553
+
554
+ it "renders hash with decorator" do
555
+ decorator.new(songs).to_json.must_equal json
543
556
  end
544
557
 
545
558
  it "respects :exclude" do
546
- 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])
559
+ assert_json "{\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(representer).to_json(:exclude => [:one])
547
560
  end
548
561
 
549
562
  it "respects :include" do
550
- 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])
563
+ assert_json "{\"two\":{\"name\":\"Can't Take Them All\"}}", {:one => Song.new("Days Go By"), :two => Song.new("Can't Take Them All")}.extend(representer).to_json(:include => [:two])
551
564
  end
552
565
  end
553
566
 
554
567
  describe "#from_json" do
555
568
  it "returns objects array" do
556
- 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\"}}"))
569
+ {}.extend(representer).from_json(json).must_equal songs
570
+ end
571
+
572
+ it "parses hash with decorator" do
573
+ decorator.new({}).from_json(json).must_equal songs
557
574
  end
558
575
 
559
576
  it "respects :exclude" do
560
- 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]))
577
+ assert_equal({"two" => Song.new("Can't Take Them All")}, {}.extend(representer).from_json(json, :exclude => [:one]))
561
578
  end
562
579
 
563
580
  it "respects :include" do
564
- 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]))
581
+ assert_equal({"one" => Song.new("Days Go By")}, {}.extend(representer).from_json(json, :include => [:one]))
565
582
  end
566
583
  end
567
584
  end
@@ -752,6 +752,12 @@ class RepresentableTest < MiniTest::Spec
752
752
  album.wont_respond_to :to_hash
753
753
  song.wont_respond_to :to_hash # DISCUSS: weak test, how to assert blank slate?
754
754
  end
755
+
756
+ describe "#decorated" do
757
+ it "is aliased to #represented" do
758
+ AlbumRepresentation.prepare(album).decorated.must_equal album
759
+ end
760
+ end
755
761
  end
756
762
 
757
763
  describe "::prepare" do
@@ -1,8 +1,6 @@
1
1
  require 'representable'
2
2
  require 'representable/json'
3
3
  require 'representable/xml'
4
- require 'test/unit'
5
- require 'minitest/spec'
6
4
  require 'minitest/autorun'
7
5
  require 'test_xml/mini_test'
8
6
  require 'mocha/setup'
@@ -5,7 +5,7 @@ class Band
5
5
  include Representable::XML
6
6
  property :name
7
7
  attr_accessor :name
8
-
8
+
9
9
  def initialize(name=nil)
10
10
  name and self.name = name
11
11
  end
@@ -14,12 +14,12 @@ end
14
14
  class Album
15
15
  attr_accessor :songs
16
16
  end
17
-
18
-
17
+
18
+
19
19
  class XmlTest < MiniTest::Spec
20
20
  XML = Representable::XML
21
21
  Def = Representable::Definition
22
-
22
+
23
23
  describe "Xml module" do
24
24
  before do
25
25
  @Band = Class.new do
@@ -29,18 +29,18 @@ class XmlTest < MiniTest::Spec
29
29
  property :label
30
30
  attr_accessor :name, :label
31
31
  end
32
-
32
+
33
33
  @band = @Band.new
34
34
  end
35
-
36
-
35
+
36
+
37
37
  describe ".from_xml" do
38
38
  it "is delegated to #from_xml" do
39
39
  block = lambda {|*args|}
40
40
  @Band.any_instance.expects(:from_xml).with("<document>", "options") # FIXME: how to NOT expect block?
41
41
  @Band.from_xml("<document>", "options", &block)
42
42
  end
43
-
43
+
44
44
  it "yields new object and options to block" do
45
45
  @Band.class_eval { attr_accessor :new_name }
46
46
  @band = @Band.from_xml("<band/>", :new_name => "Diesel Boy") do |band, options|
@@ -49,15 +49,15 @@ class XmlTest < MiniTest::Spec
49
49
  assert_equal "Diesel Boy", @band.new_name
50
50
  end
51
51
  end
52
-
53
-
52
+
53
+
54
54
  describe ".from_node" do
55
55
  it "is delegated to #from_node" do
56
56
  block = lambda {|*args|}
57
57
  @Band.any_instance.expects(:from_node).with("<document>", "options") # FIXME: how to expect block?
58
58
  @Band.from_node("<document>", "options", &block)
59
59
  end
60
-
60
+
61
61
  it "yields new object and options to block" do
62
62
  @Band.class_eval { attr_accessor :new_name }
63
63
  @band = @Band.from_node(Nokogiri::XML("<band/>"), :new_name => "Diesel Boy") do |band, options|
@@ -66,105 +66,105 @@ class XmlTest < MiniTest::Spec
66
66
  assert_equal "Diesel Boy", @band.new_name
67
67
  end
68
68
  end
69
-
70
-
69
+
70
+
71
71
  describe "#from_xml" do
72
72
  before do
73
73
  @band = @Band.new
74
74
  @xml = %{<band><name>Nofx</name><label>NOFX</label></band>}
75
75
  end
76
-
76
+
77
77
  it "parses XML and assigns properties" do
78
78
  @band.from_xml(@xml)
79
79
  assert_equal ["Nofx", "NOFX"], [@band.name, @band.label]
80
80
  end
81
81
  end
82
-
83
-
82
+
83
+
84
84
  describe "#from_node" do
85
85
  before do
86
86
  @band = @Band.new
87
87
  @xml = Nokogiri::XML(%{<band><name>Nofx</name><label>NOFX</label></band>}).root
88
88
  end
89
-
89
+
90
90
  it "receives Nokogiri node and assigns properties" do
91
91
  @band.from_node(@xml)
92
92
  assert_equal ["Nofx", "NOFX"], [@band.name, @band.label]
93
93
  end
94
94
  end
95
-
96
-
95
+
96
+
97
97
  describe "#to_xml" do
98
98
  it "delegates to #to_node and returns string" do
99
99
  assert_xml_equal "<band><name>Rise Against</name></band>", Band.new("Rise Against").to_xml
100
100
  end
101
101
  end
102
-
103
-
102
+
103
+
104
104
  describe "#to_node" do
105
105
  it "returns Nokogiri node" do
106
106
  node = Band.new("Rise Against").to_node
107
107
  assert_kind_of Nokogiri::XML::Element, node
108
108
  end
109
-
109
+
110
110
  it "wraps with infered class name per default" do
111
111
  node = Band.new("Rise Against").to_node
112
- assert_xml_equal "<band><name>Rise Against</name></band>", node.to_s
112
+ assert_xml_equal "<band><name>Rise Against</name></band>", node.to_s
113
113
  end
114
-
114
+
115
115
  it "respects #representation_wrap=" do
116
116
  klass = Class.new(Band) do
117
117
  include Representable
118
118
  property :name
119
119
  end
120
-
120
+
121
121
  klass.representation_wrap = :group
122
122
  assert_xml_equal "<group><name>Rise Against</name></group>", klass.new("Rise Against").to_node.to_s
123
123
  end
124
124
  end
125
-
126
-
125
+
126
+
127
127
  describe "XML::Binding#build_for" do
128
128
  it "returns AttributeBinding" do
129
129
  assert_kind_of XML::AttributeBinding, XML::PropertyBinding.build_for(Def.new(:band, :from => "band", :attribute => true), nil)
130
130
  end
131
-
131
+
132
132
  it "returns PropertyBinding" do
133
133
  assert_kind_of XML::PropertyBinding, XML::PropertyBinding.build_for(Def.new(:band, :class => Hash), nil)
134
134
  assert_kind_of XML::PropertyBinding, XML::PropertyBinding.build_for(Def.new(:band, :from => :content), nil)
135
135
  end
136
-
136
+
137
137
  it "returns CollectionBinding" do
138
138
  assert_kind_of XML::CollectionBinding, XML::PropertyBinding.build_for(Def.new(:band, :collection => :true), nil)
139
139
  end
140
-
140
+
141
141
  it "returns HashBinding" do
142
142
  assert_kind_of XML::HashBinding, XML::PropertyBinding.build_for(Def.new(:band, :hash => :true), nil)
143
143
  end
144
144
  end
145
-
146
-
145
+
146
+
147
147
  describe "DCI" do
148
148
  module SongRepresenter
149
149
  include Representable::XML
150
150
  property :name
151
151
  representation_wrap = :song
152
152
  end
153
-
153
+
154
154
  module AlbumRepresenter
155
155
  include Representable::XML
156
156
  property :best_song, :class => Song, :extend => SongRepresenter
157
157
  collection :songs, :class => Song, :from => :song, :extend => SongRepresenter
158
158
  representation_wrap = :album
159
159
  end
160
-
161
-
160
+
161
+
162
162
  it "allows adding the representer by using #extend" do
163
163
  module BandRepresenter
164
164
  include Representable::XML
165
165
  property :name
166
166
  end
167
-
167
+
168
168
  civ = Object.new
169
169
  civ.instance_eval do
170
170
  def name; "CIV"; end
@@ -172,26 +172,26 @@ class XmlTest < MiniTest::Spec
172
172
  @name = v
173
173
  end
174
174
  end
175
-
175
+
176
176
  civ.extend(BandRepresenter)
177
177
  assert_xml_equal "<object><name>CIV</name></object>", civ.to_xml
178
178
  end
179
-
179
+
180
180
  it "extends contained models when serializing" do
181
181
  @album = Album.new([Song.new("I Hate My Brain"), mr=Song.new("Mr. Charisma")], mr)
182
182
  @album.extend(AlbumRepresenter)
183
-
183
+
184
184
  assert_xml_equal "<album>
185
185
  <song><name>Mr. Charisma</name></song>
186
186
  <song><name>I Hate My Brain</name></song>
187
187
  <song><name>Mr. Charisma</name></song>
188
188
  </album>", @album.to_xml
189
189
  end
190
-
190
+
191
191
  it "extends contained models when deserializing" do
192
192
  @album = Album.new
193
193
  @album.extend(AlbumRepresenter)
194
-
194
+
195
195
  @album.from_xml("<album><best_song><name>Mr. Charisma</name></best_song><song><name>I Hate My Brain</name></song><song><name>Mr. Charisma</name></song></album>")
196
196
  assert_equal "Mr. Charisma", @album.best_song.name
197
197
  end
@@ -208,7 +208,7 @@ class AttributesTest < MiniTest::Spec
208
208
  property :title, :from => "title", :attribute => true
209
209
  attr_accessor :href, :title
210
210
  end
211
-
211
+
212
212
  it "#from_xml creates correct accessors" do
213
213
  link = Link.from_xml(%{
214
214
  <a href="http://apotomo.de" title="Home, sweet home" />
@@ -216,11 +216,11 @@ class AttributesTest < MiniTest::Spec
216
216
  assert_equal "http://apotomo.de", link.href
217
217
  assert_equal "Home, sweet home", link.title
218
218
  end
219
-
219
+
220
220
  it "#to_xml serializes correctly" do
221
221
  link = Link.new
222
222
  link.href = "http://apotomo.de/"
223
-
223
+
224
224
  assert_xml_equal %{<link href="http://apotomo.de/">}, link.to_xml
225
225
  end
226
226
  end
@@ -231,15 +231,15 @@ class TypedPropertyTest < MiniTest::Spec
231
231
  include Representable::XML
232
232
  property :band, :class => Band
233
233
  end
234
-
235
-
234
+
235
+
236
236
  class Album
237
237
  attr_accessor :band
238
238
  def initialize(band=nil)
239
239
  @band = band
240
240
  end
241
241
  end
242
-
242
+
243
243
  # TODO:property :group, :class => Band
244
244
  # :class
245
245
  # where to mixin DCI?
@@ -252,19 +252,19 @@ class TypedPropertyTest < MiniTest::Spec
252
252
  })
253
253
  assert_equal "Bad Religion", album.band.name
254
254
  end
255
-
255
+
256
256
  describe "#to_xml" do
257
257
  it "doesn't escape xml from Band#to_xml" do
258
258
  band = Band.new("Bad Religion")
259
259
  album = Album.new(band).extend(AlbumRepresenter)
260
-
260
+
261
261
  assert_xml_equal %{<album>
262
262
  <band>
263
263
  <name>Bad Religion</name>
264
264
  </band>
265
265
  </album>}, album.to_xml
266
266
  end
267
-
267
+
268
268
  it "doesn't escape and wrap string from Band#to_node" do
269
269
  band = Band.new("Bad Religion")
270
270
  band.instance_eval do
@@ -272,7 +272,7 @@ class TypedPropertyTest < MiniTest::Spec
272
272
  "<band>Baaaad Religion</band>"
273
273
  end
274
274
  end
275
-
275
+
276
276
  assert_xml_equal %{<album><band>Baaaad Religion</band></album>}, Album.new(band).extend(AlbumRepresenter).to_xml
277
277
  end
278
278
  end
@@ -287,7 +287,7 @@ class CollectionTest < MiniTest::Spec
287
287
  collection :bands, :class => Band, :from => :band
288
288
  attr_accessor :bands
289
289
  end
290
-
290
+
291
291
  describe "#from_xml" do
292
292
  it "pushes collection items to array" do
293
293
  cd = Compilation.from_xml(%{
@@ -298,7 +298,7 @@ class CollectionTest < MiniTest::Spec
298
298
  })
299
299
  assert_equal ["Cobra Skulls", "Diesel Boy"], cd.bands.map(&:name).sort
300
300
  end
301
-
301
+
302
302
  it "collections can be empty when default set" do
303
303
  cd = Compilation.from_xml(%{
304
304
  <compilation>
@@ -307,21 +307,21 @@ class CollectionTest < MiniTest::Spec
307
307
  assert_equal [], cd.bands
308
308
  end
309
309
  end
310
-
310
+
311
311
  it "responds to #to_xml" do
312
312
  cd = Compilation.new
313
313
  cd.bands = [Band.new("Diesel Boy"), Band.new("Bad Religion")]
314
-
314
+
315
315
  assert_xml_equal %{<compilation>
316
316
  <band><name>Diesel Boy</name></band>
317
317
  <band><name>Bad Religion</name></band>
318
318
  </compilation>}, cd.to_xml
319
319
  end
320
320
  end
321
-
322
-
321
+
322
+
323
323
  describe ":from" do
324
- let(:xml) {
324
+ let(:xml) {
325
325
  Module.new do
326
326
  include Representable::XML
327
327
  collection :songs, :from => :song
@@ -362,7 +362,7 @@ class CollectionTest < MiniTest::Spec
362
362
  assert_equal ["Laundry Basket", "Two Kevins", "Wright and Rong"].sort, album.songs.sort
363
363
  end
364
364
  end
365
-
365
+
366
366
  describe "#to_xml" do
367
367
  it "wraps items" do
368
368
  album.songs = ["Laundry Basket", "Two Kevins", "Wright and Rong"]
@@ -380,12 +380,16 @@ class CollectionTest < MiniTest::Spec
380
380
  end
381
381
 
382
382
  require 'representable/xml/collection'
383
- class CollectionRepresenterTest < MiniTest::Spec
383
+ require 'representable/xml/hash'
384
+ class LonelyRepresenterTest < MiniTest::Spec
385
+ # TODO: where is the XML::Hash test?
384
386
  module SongRepresenter
385
387
  include Representable::XML
386
388
  property :name
387
389
  end
388
390
 
391
+ let (:decorator) { rpr = representer; Class.new(Representable::Decorator) { include rpr; self.representation_wrap= :songs } } # FIXME: why isn't representation wrap inherited properly?
392
+
389
393
  describe "XML::Collection" do
390
394
  describe "with contained objects" do
391
395
  representer!(Representable::XML::Collection) do
@@ -393,48 +397,69 @@ class CollectionTest < MiniTest::Spec
393
397
  self.representation_wrap= :songs
394
398
  end
395
399
 
396
- it "renders objects with #to_xml" do
397
- assert_xml_equal "<songs><song><name>Days Go By</name></song><song><name>Can't Take Them All</name></song></songs>", [Song.new("Days Go By"), Song.new("Can't Take Them All")].extend(representer).to_xml
400
+ let (:songs) { [Song.new("Days Go By"), Song.new("Can't Take Them All")] }
401
+ let (:xml) { "<songs><song><name>Days Go By</name></song><song><name>Can't Take Them All</name></song></songs>" }
402
+
403
+ it "renders array" do
404
+ songs.extend(representer).to_xml.must_equal_xml xml
398
405
  end
399
406
 
400
- it "returns objects array from #from_xml" do
401
- assert_equal [Song.new("Days Go By"), Song.new("Can't Take Them All")], [].extend(representer).from_xml("<songs><song><name>Days Go By</name></song><song><name>Can't Take Them All</name></song></songs>")
407
+ it "renders array with decorator" do
408
+ decorator.new(songs).to_xml.must_equal_xml xml
409
+ end
410
+
411
+ it "parses array" do
412
+ [].extend(representer).from_xml(xml).must_equal songs
413
+ end
414
+
415
+ it "parses array with decorator" do
416
+ decorator.new([]).from_xml(xml).must_equal songs
402
417
  end
403
418
  end
404
419
  end
405
- end
406
420
 
407
- require 'representable/xml/hash'
408
- describe "XML::AttributeHash" do # TODO: move to HashTest.
409
- representer!(Representable::XML::AttributeHash) do
410
- self.representation_wrap= :favs
411
- end
412
-
413
- describe "#to_xml" do
414
- it "renders values into attributes converting values to strings" do
415
- assert_xml_equal "<favs one=\"Graveyards\" two=\"Can't Take Them All\" />", {:one => :Graveyards, :two => "Can't Take Them All"}.extend(representer).to_xml
416
- end
417
-
418
- it "respects :exclude" do
419
- assert_xml_equal "<favs two=\"Can't Take Them All\" />", {:one => :Graveyards, :two => "Can't Take Them All"}.extend(representer).to_xml(:exclude => [:one])
421
+ describe "XML::AttributeHash" do # TODO: move to HashTest.
422
+ representer!(Representable::XML::AttributeHash) do
423
+ self.representation_wrap= :songs
420
424
  end
421
-
422
- it "respects :include" do
423
- assert_xml_equal "<favs two=\"Can't Take Them All\" />", {:one => :Graveyards, :two => "Can't Take Them All"}.extend(representer).to_xml(:include => [:two])
425
+
426
+ let (:songs) { {"one" => "Graveyards", "two" => "Can't Take Them All"} }
427
+ let (:xml) { "<favs one=\"Graveyards\" two=\"Can't Take Them All\" />" }
428
+
429
+ describe "#to_xml" do
430
+ it "renders hash" do
431
+ songs.extend(representer).to_xml.must_equal_xml xml
432
+ end
433
+
434
+ it "respects :exclude" do
435
+ assert_xml_equal "<favs two=\"Can't Take Them All\" />", songs.extend(representer).to_xml(:exclude => [:one])
436
+ end
437
+
438
+ it "respects :include" do
439
+ assert_xml_equal "<favs two=\"Can't Take Them All\" />", songs.extend(representer).to_xml(:include => [:two])
440
+ end
441
+
442
+ it "renders hash with decorator" do
443
+ decorator.new(songs).to_xml.must_equal_xml xml
444
+ end
424
445
  end
425
- end
426
-
427
- describe "#from_json" do
428
- it "returns hash" do
429
- assert_equal({"one" => "Graveyards", "two" => "Can't Take Them All"}, {}.extend(representer).from_xml("<favs one=\"Graveyards\" two=\"Can't Take Them All\" />"))
430
- end
431
-
432
- it "respects :exclude" do
433
- assert_equal({"two" => "Can't Take Them All"}, {}.extend(representer).from_xml("<favs one=\"Graveyards\" two=\"Can't Take Them All\" />", :exclude => [:one]))
434
- end
435
-
436
- it "respects :include" do
437
- assert_equal({"one" => "Graveyards"}, {}.extend(representer).from_xml("<favs one=\"Graveyards\" two=\"Can't Take Them All\" />", :include => [:one]))
446
+
447
+ describe "#from_json" do
448
+ it "returns hash" do
449
+ {}.extend(representer).from_xml(xml).must_equal songs
450
+ end
451
+
452
+ it "respects :exclude" do
453
+ assert_equal({"two" => "Can't Take Them All"}, {}.extend(representer).from_xml(xml, :exclude => [:one]))
454
+ end
455
+
456
+ it "respects :include" do
457
+ assert_equal({"one" => "Graveyards"}, {}.extend(representer).from_xml(xml, :include => [:one]))
458
+ end
459
+
460
+ it "parses hash with decorator" do
461
+ decorator.new({}).from_xml(xml).must_equal songs
462
+ end
438
463
  end
439
464
  end
440
465
  end
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.5.0
4
+ version: 1.5.1
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: 2013-05-04 00:00:00.000000000 Z
12
+ date: 2013-05-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ! '>='
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: 0.1.6
70
70
  type: :development
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,23 +74,23 @@ dependencies:
74
74
  requirements:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
- version: '0'
77
+ version: 0.1.6
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: minitest
80
80
  requirement: !ruby/object:Gem::Requirement
81
81
  none: false
82
82
  requirements:
83
- - - ! '>='
83
+ - - ~>
84
84
  - !ruby/object:Gem::Version
85
- version: 2.8.1
85
+ version: 5.0.0
86
86
  type: :development
87
87
  prerelease: false
88
88
  version_requirements: !ruby/object:Gem::Requirement
89
89
  none: false
90
90
  requirements:
91
- - - ! '>='
91
+ - - ~>
92
92
  - !ruby/object:Gem::Version
93
- version: 2.8.1
93
+ version: 5.0.0
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: mocha
96
96
  requirement: !ruby/object:Gem::Requirement