representable 2.4.1 → 3.0.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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -12
  3. data/CHANGES.md +6 -27
  4. data/README.md +28 -1326
  5. data/lib/representable.rb +4 -14
  6. data/lib/representable/binding.rb +3 -7
  7. data/lib/representable/definition.rb +1 -2
  8. data/lib/representable/populator.rb +35 -0
  9. data/lib/representable/version.rb +1 -1
  10. data/test/definition_test.rb +0 -7
  11. data/test/exec_context_test.rb +2 -2
  12. data/test/instance_test.rb +0 -19
  13. data/test/realistic_benchmark.rb +0 -13
  14. data/test/representable_test.rb +0 -16
  15. data/test/skip_test.rb +1 -1
  16. data/test/test_helper.rb +0 -2
  17. metadata +3 -65
  18. data/lib/representable/deprecations.rb +0 -127
  19. data/lib/representable/parse_strategies.rb +0 -93
  20. data/test-with-deprecations/as_test.rb +0 -65
  21. data/test-with-deprecations/benchmarking.rb +0 -83
  22. data/test-with-deprecations/binding_test.rb +0 -46
  23. data/test-with-deprecations/blaaaaaaaa_test.rb +0 -69
  24. data/test-with-deprecations/cached_test.rb +0 -147
  25. data/test-with-deprecations/class_test.rb +0 -119
  26. data/test-with-deprecations/coercion_test.rb +0 -52
  27. data/test-with-deprecations/config/inherit_test.rb +0 -135
  28. data/test-with-deprecations/config_test.rb +0 -122
  29. data/test-with-deprecations/decorator_scope_test.rb +0 -28
  30. data/test-with-deprecations/decorator_test.rb +0 -96
  31. data/test-with-deprecations/default_test.rb +0 -34
  32. data/test-with-deprecations/defaults_options_test.rb +0 -93
  33. data/test-with-deprecations/definition_test.rb +0 -264
  34. data/test-with-deprecations/example.rb +0 -310
  35. data/test-with-deprecations/examples/object.rb +0 -31
  36. data/test-with-deprecations/exec_context_test.rb +0 -93
  37. data/test-with-deprecations/features_test.rb +0 -70
  38. data/test-with-deprecations/filter_test.rb +0 -57
  39. data/test-with-deprecations/for_collection_test.rb +0 -74
  40. data/test-with-deprecations/generic_test.rb +0 -116
  41. data/test-with-deprecations/getter_setter_test.rb +0 -21
  42. data/test-with-deprecations/hash_bindings_test.rb +0 -87
  43. data/test-with-deprecations/hash_test.rb +0 -160
  44. data/test-with-deprecations/heritage_test.rb +0 -62
  45. data/test-with-deprecations/if_test.rb +0 -79
  46. data/test-with-deprecations/include_exclude_test.rb +0 -88
  47. data/test-with-deprecations/inherit_test.rb +0 -159
  48. data/test-with-deprecations/inline_test.rb +0 -272
  49. data/test-with-deprecations/instance_test.rb +0 -266
  50. data/test-with-deprecations/is_representable_test.rb +0 -77
  51. data/test-with-deprecations/json_test.rb +0 -355
  52. data/test-with-deprecations/lonely_test.rb +0 -239
  53. data/test-with-deprecations/mongoid_test.rb +0 -31
  54. data/test-with-deprecations/nested_test.rb +0 -115
  55. data/test-with-deprecations/object_test.rb +0 -60
  56. data/test-with-deprecations/parse_pipeline_test.rb +0 -64
  57. data/test-with-deprecations/parse_strategy_test.rb +0 -279
  58. data/test-with-deprecations/pass_options_test.rb +0 -27
  59. data/test-with-deprecations/pipeline_test.rb +0 -277
  60. data/test-with-deprecations/populator_test.rb +0 -105
  61. data/test-with-deprecations/prepare_test.rb +0 -67
  62. data/test-with-deprecations/private_options_test.rb +0 -18
  63. data/test-with-deprecations/reader_writer_test.rb +0 -19
  64. data/test-with-deprecations/realistic_benchmark.rb +0 -115
  65. data/test-with-deprecations/render_nil_test.rb +0 -21
  66. data/test-with-deprecations/represent_test.rb +0 -88
  67. data/test-with-deprecations/representable_test.rb +0 -511
  68. data/test-with-deprecations/schema_test.rb +0 -148
  69. data/test-with-deprecations/serialize_deserialize_test.rb +0 -33
  70. data/test-with-deprecations/skip_test.rb +0 -81
  71. data/test-with-deprecations/stringify_hash_test.rb +0 -41
  72. data/test-with-deprecations/test_helper.rb +0 -135
  73. data/test-with-deprecations/test_helper_test.rb +0 -25
  74. data/test-with-deprecations/uncategorized_test.rb +0 -67
  75. data/test-with-deprecations/user_options_test.rb +0 -15
  76. data/test-with-deprecations/wrap_test.rb +0 -152
  77. data/test-with-deprecations/xml_bindings_test.rb +0 -62
  78. data/test-with-deprecations/xml_test.rb +0 -503
  79. data/test-with-deprecations/yaml_test.rb +0 -162
  80. data/test/parse_strategy_test.rb +0 -279
@@ -1,239 +0,0 @@
1
- require 'test_helper'
2
-
3
- require 'representable/json/hash'
4
-
5
- class LonelyRepresenterTest < MiniTest::Spec
6
-
7
- # test ::items without arguments, render-only.
8
- for_formats(
9
- :hash => [Representable::Hash::Collection, [{"name"=>"Resist Stance"}, {"name"=>"Suffer"}]],
10
- :json => [Representable::JSON::Collection, "[{\"name\":\"Resist Stance\"},{\"name\":\"Suffer\"}]"],
11
- :xml => [Representable::XML::Collection, "<array><song><name>Resist Stance</name></song><song><name>Suffer</name></song></array>"],
12
- ) do |format, mod, output, input|
13
-
14
- describe "[#{format}] lonely collection, render-only" do # TODO: introduce :representable option?
15
- let (:format) { format }
16
-
17
- representer!(module: mod) do
18
- items do
19
- property :name
20
- end
21
- end
22
-
23
- let (:album) { [Song.new("Resist Stance"), Song.new("Suffer")].extend(representer) }
24
-
25
- it "calls #to_hash on song instances, nothing else" do
26
- render(album).must_equal_document(output)
27
- end
28
- end
29
- end
30
-
31
-
32
-
33
- module SongRepresenter
34
- include Representable::JSON
35
-
36
- property :name
37
- end
38
-
39
- let (:decorator) { rpr = representer; Class.new(Representable::Decorator) { include Representable::Hash; include rpr } }
40
-
41
- describe "JSON::Collection" do
42
- let (:songs) { [Song.new("Days Go By"), Song.new("Can't Take Them All")] }
43
- let (:json) { "[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]" }
44
-
45
- describe "with contained objects" do
46
- let (:representer) {
47
- Module.new do
48
- include Representable::JSON::Collection
49
- items :class => Song, :extend => SongRepresenter
50
- end
51
- }
52
-
53
-
54
- it "renders array" do
55
- assert_json json, songs.extend(representer).to_json
56
- end
57
-
58
- it "renders array with decorator" do
59
- assert_json json, decorator.new(songs).to_json
60
- end
61
-
62
- it "parses array" do
63
- [].extend(representer).from_json(json).must_equal songs
64
- end
65
-
66
- it "parses array with decorator" do
67
- decorator.new([]).from_json(json).must_equal songs
68
- end
69
- end
70
-
71
- describe "with inline representer" do
72
- representer!(:module => Representable::JSON::Collection) do
73
- items :class => Song do
74
- property :name
75
- end
76
- end
77
-
78
- it { songs.extend(representer).to_json.must_equal json }
79
- it { [].extend(representer).from_json(json).must_equal songs }
80
- end
81
-
82
- describe "with contained text" do
83
- let (:representer) {
84
- Module.new do
85
- include Representable::JSON::Collection
86
- end
87
- }
88
- let (:songs) { ["Days Go By", "Can't Take Them All"] }
89
- let (:json) { "[\"Days Go By\",\"Can't Take Them All\"]" }
90
-
91
- it "renders contained items #to_json" do
92
- assert_json json, songs.extend(representer).to_json
93
- end
94
-
95
- it "returns objects array from #from_json" do
96
- [].extend(representer).from_json(json).must_equal songs
97
- end
98
- end
99
- end
100
-
101
- describe "Hash::Collection with dynamic options" do
102
- class One < Representable::Decorator
103
- def to_hash(*); "One: #{represented}"; end
104
- end
105
-
106
- class Two < Representable::Decorator
107
- def to_hash(*); "Two: #{represented}"; end
108
- end
109
-
110
- representer!(module: Representable::Hash::Collection) do
111
- items extend: ->(options) { options[:input] == 1 ? options[:user_options][:one] : options[:user_options][:two] }
112
- end
113
-
114
-
115
- it { [1,2].extend(representer).to_hash(one: One, two: Two).must_equal(["One: 1", "Two: 2"]) }
116
- end
117
-
118
-
119
- describe "JSON::Hash" do # TODO: move to HashTest.
120
- describe "with contained objects" do
121
- let (:representer) {
122
- Module.new do
123
- include Representable::JSON::Hash
124
- values :class => Song, :extend => SongRepresenter
125
- end
126
- }
127
- let (:json) { "{\"one\":{\"name\":\"Days Go By\"},\"two\":{\"name\":\"Can't Take Them All\"}}" }
128
- let (:songs) { {"one" => Song.new("Days Go By"), "two" => Song.new("Can't Take Them All")} }
129
-
130
- describe "#to_json" do
131
- it "renders hash" do
132
- songs.extend(representer).to_json.must_equal json
133
- end
134
-
135
- it "renders hash with decorator" do
136
- decorator.new(songs).to_json.must_equal json
137
- end
138
-
139
- it "respects :exclude" do
140
- 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])
141
- end
142
-
143
- it "respects :include" do
144
- 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])
145
- end
146
- end
147
-
148
- describe "#from_json" do
149
- it "returns objects array" do
150
- {}.extend(representer).from_json(json).must_equal songs
151
- end
152
-
153
- it "parses hash with decorator" do
154
- decorator.new({}).from_json(json).must_equal songs
155
- end
156
-
157
- it "respects :exclude" do
158
- assert_equal({"two" => Song.new("Can't Take Them All")}, {}.extend(representer).from_json(json, :exclude => [:one]))
159
- end
160
-
161
- it "respects :include" do
162
- assert_equal({"one" => Song.new("Days Go By")}, {}.extend(representer).from_json(json, :include => [:one]))
163
- end
164
- end
165
-
166
-
167
- describe "with inline representer" do
168
- representer!(:module => Representable::JSON::Hash) do
169
- values :class => Song do
170
- property :name
171
- end
172
- end
173
-
174
- it { songs.extend(representer).to_json.must_equal json }
175
- it { {}.extend(representer).from_json(json).must_equal songs }
176
- end
177
- end
178
-
179
-
180
- describe "with scalar" do
181
- let (:representer) {
182
- Module.new do
183
- include Representable::JSON::Hash
184
- end
185
- }
186
- let (:json) { %{{"one":1,"two":2}} }
187
- let (:data) { {one: 2, two: 3} }
188
-
189
- describe "#to_json" do
190
- it { data.extend(representer).to_json.must_equal %{{"one":2,"two":3}} }
191
-
192
- # it "respects :exclude" do
193
- # 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])
194
- # end
195
-
196
- # it "respects :include" do
197
- # 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])
198
- # end
199
- end
200
-
201
- describe "#from_json" do # FIXME: what's the point of this?
202
- it { data.extend(representer).from_hash(data).must_equal data }
203
- end
204
- end
205
-
206
-
207
- describe "with contained text" do
208
- before do
209
- @songs_representer = Module.new do
210
- include Representable::JSON::Collection
211
- end
212
- end
213
-
214
- it "renders contained items #to_json" do
215
- assert_json "[\"Days Go By\",\"Can't Take Them All\"]", ["Days Go By", "Can't Take Them All"].extend(@songs_representer).to_json
216
- end
217
-
218
- it "returns objects array from #from_json" do
219
- assert_equal ["Days Go By", "Can't Take Them All"], [].extend(@songs_representer).from_json("[\"Days Go By\",\"Can't Take Them All\"]")
220
- end
221
- end
222
- end
223
- end
224
-
225
-
226
- # describe "Hash::Collection with :include" do
227
- class CollectionWithIncludeTest < MiniTest::Spec
228
- Song = Struct.new(:id, :title)
229
-
230
- representer!(decorator: true, module: Representable::Hash::Collection) do
231
- items do
232
- property :id
233
- property :title
234
- end
235
- end
236
-
237
- it { representer.new([Song.new(1, "ACAB")]).to_hash.must_equal([{"id"=>1, "title"=>"ACAB"}]) }
238
- it { representer.new([Song.new(1, "ACAB")]).to_hash(include: [:title]).must_equal([{"title"=>"ACAB"}]) }
239
- end
@@ -1,31 +0,0 @@
1
- require 'test_helper'
2
- require 'mongoid'
3
- require 'mongoid/document'
4
-
5
- class MongoidTest < MiniTest::Spec
6
- describe "Mongoid compatibility" do
7
- it "allows #to_json" do
8
- class Profile
9
- include Mongoid::Document
10
- field :name
11
- end
12
-
13
- class Dude
14
- include Mongoid::Document
15
- embeds_one :profile, :class_name => "MongoidTest::Profile"
16
- end
17
-
18
- module ProfileRepresenter
19
- include Representable::JSON
20
-
21
- property :name
22
- end
23
-
24
- dude = Dude.new
25
- dude.profile = Profile.new
26
- dude.profile.name = "Kofi"
27
-
28
- assert_equal "{\"name\":\"Kofi\"}", dude.profile.extend(ProfileRepresenter).to_json
29
- end
30
- end
31
- end
@@ -1,115 +0,0 @@
1
- require 'test_helper'
2
-
3
- class NestedTest < MiniTest::Spec
4
- Album = Struct.new(:label, :owner, :amount)
5
-
6
- for_formats(
7
- :hash => [Representable::Hash, {"label" => {"label"=>"Epitaph", "owner"=>"Brett Gurewitz", "releases"=>{"amount"=>19}}}],
8
- # :xml => [Representable::XML, "<open_struct></open_struct>"],
9
- :yaml => [Representable::YAML, "---\nlabel:\n label: Epitaph\n owner: Brett Gurewitz\n releases:\n amount: 19\n"]
10
- ) do |format, mod, output, input|
11
-
12
- [false, true].each do |is_decorator|
13
- describe "::nested with (inline representer|decorator): #{is_decorator}" do
14
- let (:format) { format }
15
-
16
- representer!(:module => mod, :decorator => is_decorator) do
17
- nested :label do
18
- property :label
19
- property :owner
20
-
21
- # self.representation_wrap = nil if format == :xml
22
- nested :releases do
23
- property :amount
24
- end
25
- end
26
-
27
- # self.representation_wrap = :album if format == :xml
28
- end
29
-
30
- let (:album) { Album.new("Epitaph", "Brett Gurewitz", 19) }
31
- let (:decorator) { representer.prepare(album) }
32
-
33
- it "renders nested Album-properties in separate section" do
34
- render(decorator).must_equal_document output
35
-
36
- # do not use extend on the nested object. # FIXME: make this a proper test with two describes instead of this pseudo-meta stuff.
37
- if is_decorator==true
38
- album.wont_be_kind_of(Representable::Hash)
39
- end
40
- end
41
-
42
- it "parses nested properties to Album instance" do
43
- album = parse(representer.prepare(Album.new), output)
44
- album.label.must_equal "Epitaph"
45
- album.owner.must_equal "Brett Gurewitz"
46
- end
47
- end
48
- end
49
-
50
-
51
- describe "Decorator ::nested with extend:" do
52
- let (:format) { format }
53
-
54
- representer!(:name => :label_rpr) do
55
- include mod
56
- property :label
57
- property :owner
58
-
59
- nested :releases do # DISCUSS: do we need to test this?
60
- property :amount
61
- end
62
- end
63
-
64
- representer!(:module => mod, :decorator => true, :inject => :label_rpr) do
65
- nested :label, :extend => label_rpr
66
-
67
- self.representation_wrap = :album if format == :xml
68
- end
69
-
70
- let (:album) { representer.prepare(Album.new("Epitaph", "Brett Gurewitz", 19)) }
71
-
72
- # TODO: shared example with above.
73
- it "renders nested Album-properties in separate section" do
74
- render(album).must_equal_document output
75
- end
76
-
77
- it "parses nested properties to Album instance" do
78
- album = parse(representer.prepare(Album.new), output)
79
- album.label.must_equal "Epitaph"
80
- album.owner.must_equal "Brett Gurewitz"
81
- album.amount.must_equal 19
82
- end
83
- end
84
- end
85
-
86
-
87
- describe "::nested without block but with inherit:" do
88
-
89
- representer!(:name => :parent) do
90
- include Representable::Hash
91
-
92
- nested :label do
93
- property :owner
94
- end
95
- end
96
-
97
- representer!(:module => Representable::Hash, :inject => :parent) do
98
- include parent
99
- nested :label, :inherit => true, :as => "Label"
100
- end
101
-
102
- let (:album) { representer.prepare(Album.new("Epitaph", "Brett Gurewitz", 19)) }
103
-
104
- it "renders nested Album-properties in separate section" do
105
- representer.prepare(album).to_hash.must_equal({"Label"=>{"owner"=>"Brett Gurewitz"}})
106
- end
107
-
108
- # it "parses nested properties to Album instance" do
109
- # album = parse(representer.prepare(Album.new), output)
110
- # album.label.must_equal "Epitaph"
111
- # album.owner.must_equal "Brett Gurewitz"
112
- # album.amount.must_equal 19
113
- # end
114
- end
115
- end
@@ -1,60 +0,0 @@
1
- require "test_helper"
2
- require "representable/object"
3
-
4
- class ObjectTest < MiniTest::Spec
5
- Song = Struct.new(:title, :album)
6
- Album = Struct.new(:name, :songs)
7
-
8
- representer!(module: Representable::Object) do
9
- property :title
10
-
11
- property :album, instance: lambda { |fragment, *| fragment.name.upcase!; fragment } do
12
- property :name
13
-
14
- collection :songs, instance: lambda { |fragment, *| fragment.title.upcase!; fragment } do
15
- property :title
16
- end
17
- end
18
- # TODO: collection
19
- end
20
-
21
- let (:source) { Song.new("The King Is Dead", Album.new("Ruiner", [Song.new("In Vino Veritas II")])) }
22
- let (:target) { Song.new }
23
-
24
- it do
25
- representer.prepare(target).from_object(source)
26
-
27
- target.title.must_equal "The King Is Dead"
28
- target.album.name.must_equal "RUINER"
29
- target.album.songs[0].title.must_equal "IN VINO VERITAS II"
30
- end
31
-
32
- # ignore nested object when nil
33
- it do
34
- representer.prepare(Song.new("The King Is Dead")).from_object(Song.new)
35
-
36
- target.title.must_equal nil # scalar property gets overridden when nil.
37
- target.album.must_equal nil # nested property stays nil.
38
- end
39
-
40
- # to_object
41
- describe "#to_object" do
42
- representer!(module: Representable::Object) do
43
- property :title
44
-
45
- property :album, render_filter: lambda { |object, *| object.name = "Live"; object } do
46
- property :name
47
-
48
- collection :songs, render_filter: lambda { |object, *| object[0].title = 1; object } do
49
- property :title
50
- end
51
- end
52
- end
53
-
54
- it do
55
- representer.prepare(source).to_object
56
- source.album.name.must_equal "Live"
57
- source.album.songs[0].title.must_equal 1
58
- end
59
- end
60
- end
@@ -1,64 +0,0 @@
1
- require "test_helper"
2
-
3
- class ParsePipelineTest < MiniTest::Spec
4
- Album = Struct.new(:id, :artist, :songs)
5
- Artist = Struct.new(:email)
6
- Song = Struct.new(:title)
7
-
8
- describe "transforming nil to [] when parsing" do
9
- representer!(decorator: true) do
10
- collection :songs,
11
- parse_pipeline: ->(*) {
12
- Representable::Pipeline.insert(
13
- parse_functions, # original function list from Binding#parse_functions.
14
- ->(input, options) { input.nil? ? [] : input }, # your new function (can be any callable object)..
15
- replace: Representable::OverwriteOnNil # ..that replaces the original function.
16
- )
17
- },
18
- class: Song do
19
- property :title
20
- end
21
- end
22
-
23
- it do
24
- representer.new(album = Album.new).from_hash("songs"=>nil)
25
- album.songs.must_equal []
26
- end
27
-
28
- it do
29
- representer.new(album = Album.new).from_hash("songs"=>[{"title" => "Business Conduct"}])
30
- album.songs.must_equal [Song.new("Business Conduct")]
31
- end
32
- end
33
-
34
-
35
- # tests [Collect[Instance, Prepare, Deserialize], Setter]
36
- class Representer < Representable::Decorator
37
- include Representable::Hash
38
-
39
- # property :artist, populator: Uber::Options::Value.new(ArtistPopulator.new), pass_options:true do
40
- # property :email
41
- # end
42
- # DISCUSS: rename to populator_pipeline ?
43
- collection :songs, parse_pipeline: ->(*) { [Collect[Instance, Prepare, Deserialize], Setter] }, instance: :instance!, exec_context: :decorator, pass_options: true do
44
- property :title
45
- end
46
-
47
- def instance!(*options)
48
- puts "@@@@@ #{options.inspect}"
49
- Song.new
50
- end
51
-
52
- def songs=(array)
53
- represented.songs=array
54
- end
55
- end
56
-
57
- it do
58
- skip "TODO: implement :parse_pipeline and :render_pipeline, and before/after/replace semantics"
59
- album = Album.new
60
- Representer.new(album).from_hash({"artist"=>{"email"=>"yo"}, "songs"=>[{"title"=>"Affliction"}, {"title"=>"Dream Beater"}]})
61
- album.songs.must_equal([Song.new("Affliction"), Song.new("Dream Beater")])
62
- puts album.inspect
63
- end
64
- end