representable 2.0.4 → 2.1.0

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.
@@ -28,7 +28,7 @@ class LonelyRepresenterTest < MiniTest::Spec
28
28
  assert_json json, songs.extend(representer).to_json
29
29
  end
30
30
 
31
- it "renders array with decorator" do
31
+ it "renders array with decorator xxx" do
32
32
  assert_json json, decorator.new(songs).to_json
33
33
  end
34
34
 
@@ -0,0 +1,83 @@
1
+ require 'test_helper'
2
+ require 'benchmark'
3
+
4
+ SONG_PROPERTIES = 50.times.collect do |i|
5
+ "property_#{i}"
6
+ end
7
+
8
+
9
+ module SongRepresenter
10
+ include Representable::JSON
11
+
12
+ SONG_PROPERTIES.each { |p| property p }
13
+ end
14
+
15
+ class SongDecorator < Representable::Decorator
16
+ include Representable::JSON
17
+
18
+ SONG_PROPERTIES.each { |p| property p }
19
+ end
20
+
21
+ module AlbumRepresenter
22
+ include Representable::JSON
23
+
24
+ # collection :songs, extend: SongRepresenter
25
+ collection :songs, extend: SongDecorator
26
+ end
27
+
28
+ def random_song
29
+ attrs = Hash[SONG_PROPERTIES.collect { |n| [n,n] }]
30
+ OpenStruct.new(attrs)
31
+ end
32
+
33
+ times = []
34
+
35
+ 3.times.each do
36
+ album = OpenStruct.new(songs: 50.times.collect { random_song })
37
+
38
+ times << Benchmark.measure do
39
+ puts "================ next!"
40
+ album.extend(AlbumRepresenter).to_json
41
+ end
42
+ end
43
+
44
+ puts times.join("")
45
+
46
+ # 100 songs, 100 attrs
47
+ # 0.050000 0.000000 0.050000 ( 0.093157)
48
+
49
+ ## 100 songs, 1000 attrs
50
+ # 0.470000 0.010000 0.480000 ( 0.483708)
51
+
52
+
53
+ ### without binding cache:
54
+ # 2.790000 0.030000 2.820000 ( 2.820190)
55
+
56
+
57
+
58
+ ### with extend: on Song, with binding cache>
59
+ # 2.490000 0.030000 2.520000 ( 2.517433) 2.4-3.0
60
+ ### without skip?
61
+ # 2.030000 0.020000 2.050000 ( 2.050796) 2.1-2.3
62
+
63
+ ### without :writer
64
+ # 2.270000 0.010000 2.280000 ( 2.284530 1.9-2.2
65
+ ### without :render_filter
66
+ # 2.020000 0.000000 2.020000 ( 2.030234) 1.5-2.0
67
+ ###without default_for and skipable?
68
+ # 1.730000 0.010000 1.740000 ( 1.735597 1.4-1.7
69
+ ### without :serialize
70
+ # 1.780000 0.010000 1.790000 ( 1.786791) 1.4-1.7
71
+ ### using decorator
72
+ # 1.400000 0.030000 1.430000 ( 1.434206) 1.4-1.6
73
+ ### with prepare AFTER representable?
74
+ # 1.330000 0.010000 1.340000 ( 1.335900) 1.1-1.3
75
+
76
+
77
+ # representable 2.0
78
+ # 3.000000 0.020000 3.020000 ( 3.013031) 2.7-3.0
79
+
80
+ # no method missing
81
+ # 2.280000 0.030000 2.310000 ( 2.313522) 2.2-2.5
82
+ # no def_delegator in Definition
83
+ # 2.130000 0.010000 2.140000 ( 2.136115) 1.7-2.1
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class SkipTest < MiniTest::Spec
4
+ representer! do
5
+ property :title
6
+ property :band,
7
+ skip_parse: lambda { |fragment, opts| opts[:skip?] and fragment["name"].nil? }, class: OpenStruct do
8
+ property :name
9
+ end
10
+
11
+ collection :airplays,
12
+ skip_parse: lambda { |fragment, opts| puts fragment.inspect; opts[:skip?] and fragment["station"].nil? }, class: OpenStruct do
13
+ property :station
14
+ end
15
+ end
16
+
17
+ let (:song) { OpenStruct.new.extend(representer) }
18
+
19
+ # do parse.
20
+ it { song.from_hash({"band" => {"name" => "Mute 98"}}, skip?: true).band.name.must_equal "Mute 98" }
21
+ it { song.from_hash({"airplays" => [{"station" => "JJJ"}]}, skip?: true).airplays[0].station.must_equal "JJJ" }
22
+
23
+ # skip parsing.
24
+ it { song.from_hash({"band" => {}}, skip?: true).band.must_equal nil }
25
+ # skip_parse is _per item_.
26
+ let (:airplay) { OpenStruct.new(station: "JJJ") }
27
+ it { song.from_hash({"airplays" => [{"station" => "JJJ"}, {}]}, skip?: true).airplays.must_equal [airplay] }
28
+ end
@@ -23,120 +23,13 @@ class XMLBindingTest < MiniTest::Spec
23
23
  @song = SongWithRepresenter.new("Thinning the Herd")
24
24
  end
25
25
 
26
- describe "PropertyBinding" do
27
- describe "with plain text" do
28
- before do
29
- @property = Representable::XML::PropertyBinding.new(Representable::Definition.new(:song), nil, nil, {:doc => @doc})
30
- end
31
-
32
- it "extracts with #read" do
33
- assert_equal "Thinning the Herd", @property.read(Nokogiri::XML("<song>Thinning the Herd</song>"))
34
- end
35
-
36
- it "inserts with #write" do
37
- @property.write(@doc, "Thinning the Herd")
38
- assert_xml_equal "<song>Thinning the Herd</song>", @doc.to_s
39
- end
40
- end
41
-
42
- describe "with an object" do
43
- before do
44
- @property = Representable::XML::PropertyBinding.new(Representable::Definition.new(:song, :class => SongWithRepresenter), nil, nil, {:doc => @doc})
45
- end
46
-
47
- it "extracts with #read" do
48
- assert_equal @song, @property.read(Nokogiri::XML("<song><name>Thinning the Herd</name></song>"))
49
- end
50
-
51
- it "inserts with #write" do
52
- @property.write(@doc, @song)
53
- assert_xml_equal("<song><name>Thinning the Herd</name></song>", @doc.to_s)
54
- end
55
- end
56
-
57
- describe "with an object and :extend" do
58
- before do
59
- @property = Representable::XML::PropertyBinding.new(Representable::Definition.new(:song, :class => Song, :extend => SongRepresenter), nil, nil, {:doc => @doc})
60
- end
61
-
62
- it "extracts with #read" do
63
- assert_equal @song, @property.read(Nokogiri::XML("<song><name>Thinning the Herd</name></song>"))
64
- end
65
-
66
- it "inserts with #write" do
67
- @property.write(@doc, @song)
68
- assert_xml_equal("<song><name>Thinning the Herd</name></song>", @doc.to_s)
69
- end
70
- end
71
- end
72
-
73
-
74
- describe "CollectionBinding" do
75
- describe "with plain text items" do
76
- before do
77
- @property = Representable::XML::CollectionBinding.new(Representable::Definition.new(:song, :collection => true), Struct.new(:song).new, nil)
78
- end
79
26
 
80
- it "extracts with #read" do
81
- assert_equal ["The Gargoyle", "Bronx"], @property.read(Nokogiri::XML("<doc><song>The Gargoyle</song><song>Bronx</song></doc>").root)
82
- end
83
-
84
- it "inserts with #write" do
85
- parent = Nokogiri::XML::Node.new("parent", @doc)
86
- @property.write(parent, ["The Gargoyle", "Bronx"])
87
- assert_xml_equal("<songs><song>The Gargoyle</song><song>Bronx</song></songs>", parent.to_s)
88
- end
89
- end
90
-
91
- describe "with objects" do
92
- before do
93
- @property = Representable::XML::PropertyBinding.new(Representable::Definition.new(:song, :collection => true, :class => SongWithRepresenter), nil, nil, {:doc => @doc})
94
- end
95
-
96
- it "extracts with #read" do
97
- assert_equal @song, @property.read(Nokogiri::XML("<song><name>Thinning the Herd</name></song>"))
98
- end
99
-
100
- it "inserts with #write" do
101
- @property.write(@doc, @song)
102
- assert_xml_equal("<song><name>Thinning the Herd</name></song>", @doc.to_s)
103
- assert_kind_of Nokogiri::XML::Node, @doc.children.first
104
- assert_equal "song", @doc.children.first.name
105
- assert_equal "name", @doc.children.first.children.first.name
106
- end
107
- end
108
- end
109
-
110
-
111
- describe "HashBinding" do
112
- describe "with plain text items" do
113
- before do
114
- @property = Representable::XML::HashBinding.new(Representable::Definition.new(:songs, :hash => true), nil, nil)
115
- end
116
-
117
- it "extracts with #read" do
118
- assert_equal({"first" => "The Gargoyle", "second" => "Bronx"} , @property.read(Nokogiri::XML("<songs><first>The Gargoyle</first><second>Bronx</second></songs>")))
119
- end
120
-
121
- it "inserts with #write" do
122
- parent = Nokogiri::XML::Node.new("parent", @doc)
123
- @property.write(parent, {"first" => "The Gargoyle", "second" => "Bronx"})
124
- assert_xml_equal("<songs><first>The Gargoyle</first><second>Bronx</second></songs>", parent.to_s)
125
- end
126
- end
127
-
128
- describe "with objects" do
129
- before do
130
- @property = Representable::XML::HashBinding.new(Representable::Definition.new(:songs, :hash => true, :class => Song, :extend => SongRepresenter), nil)
131
- end
132
- end
133
- end
134
27
 
135
28
 
136
29
  describe "AttributeBinding" do
137
30
  describe "with plain text items" do
138
31
  before do
139
- @property = Representable::XML::AttributeBinding.new(Representable::Definition.new(:name, :attribute => true), nil, nil)
32
+ @property = Representable::XML::Binding::Attribute.new(Representable::Definition.new(:name, :attribute => true), nil, nil)
140
33
  end
141
34
 
142
35
  it "extracts with #read" do
@@ -153,7 +46,7 @@ class XMLBindingTest < MiniTest::Spec
153
46
 
154
47
  describe "ContentBinding" do
155
48
  before do
156
- @property = Representable::XML::ContentBinding.new(Representable::Definition.new(:name, :content => true), nil, nil)
49
+ @property = Representable::XML::Binding::Content.new(Representable::Definition.new(:name, :content => true), nil, nil)
157
50
  end
158
51
 
159
52
  it "extracts with #read" do
@@ -104,20 +104,20 @@ class XmlTest < MiniTest::Spec
104
104
 
105
105
  describe "XML::Binding#build_for" do
106
106
  it "returns AttributeBinding" do
107
- assert_kind_of XML::AttributeBinding, XML::PropertyBinding.build_for(Def.new(:band, :as => "band", :attribute => true), nil, nil)
107
+ assert_kind_of XML::Binding::Attribute, XML::Binding.build_for(Def.new(:band, :as => "band", :attribute => true), nil, nil)
108
108
  end
109
109
 
110
- it "returns PropertyBinding" do
111
- assert_kind_of XML::PropertyBinding, XML::PropertyBinding.build_for(Def.new(:band, :class => Hash), nil, nil)
112
- assert_kind_of XML::PropertyBinding, XML::PropertyBinding.build_for(Def.new(:band, :as => :content), nil, nil)
110
+ it "returns Binding" do
111
+ assert_kind_of XML::Binding, XML::Binding.build_for(Def.new(:band, :class => Hash), nil, nil)
112
+ assert_kind_of XML::Binding, XML::Binding.build_for(Def.new(:band, :as => :content), nil, nil)
113
113
  end
114
114
 
115
115
  it "returns CollectionBinding" do
116
- assert_kind_of XML::CollectionBinding, XML::PropertyBinding.build_for(Def.new(:band, :collection => :true), nil, nil)
116
+ assert_kind_of XML::Binding::Collection, XML::Binding.build_for(Def.new(:band, :collection => :true), nil, nil)
117
117
  end
118
118
 
119
119
  it "returns HashBinding" do
120
- assert_kind_of XML::HashBinding, XML::PropertyBinding.build_for(Def.new(:band, :hash => :true), nil, nil)
120
+ assert_kind_of XML::Binding::Hash, XML::Binding.build_for(Def.new(:band, :hash => :true), nil, nil)
121
121
  end
122
122
  end
123
123
 
@@ -206,7 +206,7 @@ end
206
206
 
207
207
 
208
208
  class CDataBand
209
- class CData < Representable::XML::PropertyBinding
209
+ class CData < Representable::XML::Binding
210
210
  def serialize_node(parent, value)
211
211
  parent << Nokogiri::XML::CDATA.new(parent, represented.name)
212
212
  end
@@ -320,14 +320,14 @@ class CollectionTest < MiniTest::Spec
320
320
 
321
321
 
322
322
  describe ":as" do
323
- let(:xml) {
323
+ let(:xml_doc) {
324
324
  Module.new do
325
325
  include Representable::XML
326
326
  collection :songs, :as => :song
327
327
  end }
328
328
 
329
329
  it "collects untyped items" do
330
- album = Album.new.extend(xml).from_xml(%{
330
+ album = Album.new.extend(xml_doc).from_xml(%{
331
331
  <album>
332
332
  <song>Two Kevins</song>
333
333
  <song>Wright and Rong</song>
@@ -340,8 +340,8 @@ class CollectionTest < MiniTest::Spec
340
340
 
341
341
 
342
342
  describe ":wrap" do
343
- let (:album) { Album.new.extend(xml) }
344
- let (:xml) {
343
+ let (:album) { Album.new.extend(xml_doc) }
344
+ let (:xml_doc) {
345
345
  Module.new do
346
346
  include Representable::XML
347
347
  collection :songs, :as => :song, :wrap => :songs
@@ -397,22 +397,22 @@ class CollectionTest < MiniTest::Spec
397
397
  end
398
398
 
399
399
  let (:songs) { [Song.new("Days Go By"), Song.new("Can't Take Them All")] }
400
- let (:xml) { "<songs><song><name>Days Go By</name></song><song><name>Can't Take Them All</name></song></songs>" }
400
+ let (:xml_doc) { "<songs><song><name>Days Go By</name></song><song><name>Can't Take Them All</name></song></songs>" }
401
401
 
402
402
  it "renders array" do
403
- songs.extend(representer).to_xml.must_equal_xml xml
403
+ songs.extend(representer).to_xml.must_equal_xml xml_doc
404
404
  end
405
405
 
406
406
  it "renders array with decorator" do
407
- decorator.new(songs).to_xml.must_equal_xml xml
407
+ decorator.new(songs).to_xml.must_equal_xml xml_doc
408
408
  end
409
409
 
410
410
  it "parses array" do
411
- [].extend(representer).from_xml(xml).must_equal songs
411
+ [].extend(representer).from_xml(xml_doc).must_equal songs
412
412
  end
413
413
 
414
414
  it "parses array with decorator" do
415
- decorator.new([]).from_xml(xml).must_equal songs
415
+ decorator.new([]).from_xml(xml_doc).must_equal songs
416
416
  end
417
417
  end
418
418
  end
@@ -423,11 +423,11 @@ class CollectionTest < MiniTest::Spec
423
423
  end
424
424
 
425
425
  let (:songs) { {"one" => "Graveyards", "two" => "Can't Take Them All"} }
426
- let (:xml) { "<favs one=\"Graveyards\" two=\"Can't Take Them All\" />" }
426
+ let (:xml_doc) { "<favs one=\"Graveyards\" two=\"Can't Take Them All\" />" }
427
427
 
428
428
  describe "#to_xml" do
429
429
  it "renders hash" do
430
- songs.extend(representer).to_xml.must_equal_xml xml
430
+ songs.extend(representer).to_xml.must_equal_xml xml_doc
431
431
  end
432
432
 
433
433
  it "respects :exclude" do
@@ -439,27 +439,65 @@ class CollectionTest < MiniTest::Spec
439
439
  end
440
440
 
441
441
  it "renders hash with decorator" do
442
- decorator.new(songs).to_xml.must_equal_xml xml
442
+ decorator.new(songs).to_xml.must_equal_xml xml_doc
443
443
  end
444
444
  end
445
445
 
446
446
  describe "#from_json" do
447
447
  it "returns hash" do
448
- {}.extend(representer).from_xml(xml).must_equal songs
448
+ {}.extend(representer).from_xml(xml_doc).must_equal songs
449
449
  end
450
450
 
451
451
  it "respects :exclude" do
452
- assert_equal({"two" => "Can't Take Them All"}, {}.extend(representer).from_xml(xml, :exclude => [:one]))
452
+ assert_equal({"two" => "Can't Take Them All"}, {}.extend(representer).from_xml(xml_doc, :exclude => [:one]))
453
453
  end
454
454
 
455
455
  it "respects :include" do
456
- assert_equal({"one" => "Graveyards"}, {}.extend(representer).from_xml(xml, :include => [:one]))
456
+ assert_equal({"one" => "Graveyards"}, {}.extend(representer).from_xml(xml_doc, :include => [:one]))
457
457
  end
458
458
 
459
459
  it "parses hash with decorator" do
460
- decorator.new({}).from_xml(xml).must_equal songs
460
+ decorator.new({}).from_xml(xml_doc).must_equal songs
461
461
  end
462
462
  end
463
463
  end
464
464
  end
465
465
  end
466
+
467
+ class XmlHashTest < MiniTest::Spec
468
+ # scalar, no object
469
+ describe "plain text" do
470
+ representer!(module: Representable::XML) do
471
+ hash :songs
472
+ end
473
+
474
+ let (:doc) { "<open_struct><first>The Gargoyle</first><second>Bronx</second></open_struct>" }
475
+
476
+ # to_xml
477
+ it { OpenStruct.new(songs: {"first" => "The Gargoyle", "second" => "Bronx"}).extend(representer).to_xml.must_equal_xml(doc) }
478
+ # FIXME: this NEVER worked!
479
+ # it { OpenStruct.new.extend(representer).from_xml(doc).songs.must_equal({"first" => "The Gargoyle", "second" => "Bronx"}) }
480
+ end
481
+
482
+ describe "with objects" do
483
+ representer!(module: Representable::XML) do
484
+ hash :songs, class: OpenStruct do
485
+ property :title
486
+ end
487
+ end
488
+
489
+ let (:doc) { "<open_struct>
490
+ <open_struct>
491
+ <title>The Gargoyle</title>
492
+ </open_struct>
493
+ <open_struct>
494
+ <title>Bronx</title>
495
+ </open_struct>
496
+ </open_struct>" }
497
+
498
+ # to_xml
499
+ it { OpenStruct.new(songs: {"first" => OpenStruct.new(title: "The Gargoyle"), "second" => OpenStruct.new(title: "Bronx")}).extend(representer).to_xml.must_equal_xml(doc) }
500
+ # FIXME: this NEVER worked!
501
+ # it { OpenStruct.new.extend(representer).from_xml(doc).songs.must_equal({"first" => "The Gargoyle", "second" => "Bronx"}) }
502
+ end
503
+ end
@@ -124,18 +124,15 @@ songs: [Off Key Melody, Sinking]").must_equal Album.new(["Off Key Melody", "Sink
124
124
 
125
125
 
126
126
  describe "with :class and :extend" do
127
- yaml_song = yaml_representer do
128
- property :name
129
- property :track
130
- end
131
127
  let (:yaml_album) { Module.new do
132
128
  include Representable::YAML
133
- collection :songs, :extend => yaml_song, :class => Song
129
+ collection :songs, :class => Song do
130
+ property :name
131
+ property :track
132
+ end
134
133
  end }
135
134
 
136
- let (:album) { Album.new.tap do |album|
137
- album.songs = [Song.new("Liar", 1), Song.new("What I Know", 2)]
138
- end }
135
+ let (:album) { Album.new([Song.new("Liar", 1), Song.new("What I Know", 2)]) }
139
136
 
140
137
 
141
138
  describe "#to_yaml" do