representable 2.0.4 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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