representable 1.5.0 → 1.5.1

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.
@@ -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