draper 4.0.4 → 4.0.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +3 -6
- data/lib/draper/collection_decorator.rb +0 -6
- data/lib/draper/compatibility/broadcastable.rb +24 -0
- data/lib/draper/compatibility/global_id.rb +9 -5
- data/lib/draper/decoratable.rb +5 -0
- data/lib/draper/decorator.rb +2 -18
- data/lib/draper/railtie.rb +6 -1
- data/lib/draper/version.rb +1 -1
- metadata +4 -232
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -24
- data/.github/workflows/ci.yml +0 -71
- data/.gitignore +0 -18
- data/Gemfile +0 -46
- data/bin/bundle +0 -114
- data/bin/rake +0 -29
- data/draper.gemspec +0 -34
- data/spec/draper/collection_decorator_spec.rb +0 -291
- data/spec/draper/configuration_spec.rb +0 -49
- data/spec/draper/decoratable/equality_spec.rb +0 -10
- data/spec/draper/decoratable_spec.rb +0 -235
- data/spec/draper/decorated_association_spec.rb +0 -82
- data/spec/draper/decorates_assigned_spec.rb +0 -71
- data/spec/draper/decorator_spec.rb +0 -872
- data/spec/draper/draper_spec.rb +0 -25
- data/spec/draper/factory_spec.rb +0 -247
- data/spec/draper/finders_spec.rb +0 -166
- data/spec/draper/helper_proxy_spec.rb +0 -61
- data/spec/draper/lazy_helpers_spec.rb +0 -21
- data/spec/draper/query_methods/load_strategy_spec.rb +0 -26
- data/spec/draper/query_methods_spec.rb +0 -80
- data/spec/draper/undecorate_chain_spec.rb +0 -20
- data/spec/draper/undecorate_spec.rb +0 -19
- data/spec/draper/view_context/build_strategy_spec.rb +0 -115
- data/spec/draper/view_context_spec.rb +0 -182
- data/spec/draper/view_helpers_spec.rb +0 -8
- data/spec/dummy/.rspec +0 -1
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/assets/config/manifest.js +0 -3
- data/spec/dummy/app/controllers/application_controller.rb +0 -2
- data/spec/dummy/app/controllers/base_controller.rb +0 -4
- data/spec/dummy/app/controllers/localized_urls.rb +0 -5
- data/spec/dummy/app/controllers/posts_controller.rb +0 -20
- data/spec/dummy/app/decorators/comment_decorator.rb +0 -13
- data/spec/dummy/app/decorators/mongoid_post_decorator.rb +0 -2
- data/spec/dummy/app/decorators/post_decorator.rb +0 -60
- data/spec/dummy/app/helpers/application_helper.rb +0 -5
- data/spec/dummy/app/jobs/publish_post_job.rb +0 -7
- data/spec/dummy/app/mailers/application_mailer.rb +0 -3
- data/spec/dummy/app/mailers/post_mailer.rb +0 -19
- data/spec/dummy/app/models/admin.rb +0 -3
- data/spec/dummy/app/models/application_record.rb +0 -3
- data/spec/dummy/app/models/comment.rb +0 -3
- data/spec/dummy/app/models/mongoid_post.rb +0 -3
- data/spec/dummy/app/models/post.rb +0 -7
- data/spec/dummy/app/models/user.rb +0 -3
- data/spec/dummy/app/views/layouts/application.html.erb +0 -11
- data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +0 -1
- data/spec/dummy/app/views/posts/_post.html.erb +0 -42
- data/spec/dummy/app/views/posts/show.html.erb +0 -1
- data/spec/dummy/bin/rails +0 -4
- data/spec/dummy/config/application.rb +0 -39
- data/spec/dummy/config/boot.rb +0 -5
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -78
- data/spec/dummy/config/environments/production.rb +0 -102
- data/spec/dummy/config/environments/test.rb +0 -69
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/draper.rb +0 -5
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
- data/spec/dummy/config/initializers/inflections.rb +0 -15
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/secret_token.rb +0 -8
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/mongoid.yml +0 -142
- data/spec/dummy/config/routes.rb +0 -9
- data/spec/dummy/config/storage.yml +0 -7
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +0 -8
- data/spec/dummy/db/migrate/20240907041839_create_comments.rb +0 -9
- data/spec/dummy/db/schema.rb +0 -28
- data/spec/dummy/db/seeds.rb +0 -2
- data/spec/dummy/fast_spec/post_decorator_spec.rb +0 -37
- data/spec/dummy/lib/tasks/test.rake +0 -16
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -25
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -6
- data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +0 -12
- data/spec/dummy/spec/decorators/devise_spec.rb +0 -55
- data/spec/dummy/spec/decorators/helpers_spec.rb +0 -21
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +0 -64
- data/spec/dummy/spec/decorators/spec_type_spec.rb +0 -7
- data/spec/dummy/spec/decorators/view_context_spec.rb +0 -22
- data/spec/dummy/spec/jobs/publish_post_job_spec.rb +0 -11
- data/spec/dummy/spec/mailers/post_mailer_spec.rb +0 -25
- data/spec/dummy/spec/models/application_spec.rb +0 -7
- data/spec/dummy/spec/models/mongoid_post_spec.rb +0 -8
- data/spec/dummy/spec/models/post_spec.rb +0 -51
- data/spec/dummy/spec/rails_helper.rb +0 -69
- data/spec/dummy/spec/shared_examples/decoratable.rb +0 -22
- data/spec/dummy/spec/spec_helper.rb +0 -93
- data/spec/dummy/test/decorators/minitest/devise_test.rb +0 -55
- data/spec/dummy/test/decorators/minitest/helpers_test.rb +0 -21
- data/spec/dummy/test/decorators/minitest/spec_type_test.rb +0 -52
- data/spec/dummy/test/decorators/minitest/view_context_test.rb +0 -24
- data/spec/dummy/test/decorators/test_unit/devise_test.rb +0 -55
- data/spec/dummy/test/decorators/test_unit/helpers_test.rb +0 -21
- data/spec/dummy/test/decorators/test_unit/view_context_test.rb +0 -24
- data/spec/dummy/test/minitest_helper.rb +0 -2
- data/spec/dummy/test/test_helper.rb +0 -3
- data/spec/generators/controller/controller_generator_spec.rb +0 -23
- data/spec/generators/decorator/decorator_generator_spec.rb +0 -93
- data/spec/generators/install/install_generator_spec.rb +0 -19
- data/spec/integration/integration_spec.rb +0 -70
- data/spec/performance/active_record.rb +0 -4
- data/spec/performance/benchmark.rb +0 -55
- data/spec/performance/decorators.rb +0 -45
- data/spec/performance/models.rb +0 -20
- data/spec/spec_helper.rb +0 -50
- data/spec/support/dummy_app.rb +0 -85
- data/spec/support/matchers/have_text.rb +0 -50
- data/spec/support/shared_examples/decoratable_equality.rb +0 -40
- data/spec/support/shared_examples/view_helpers.rb +0 -39
|
@@ -1,872 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'support/shared_examples/view_helpers'
|
|
3
|
-
|
|
4
|
-
module Draper
|
|
5
|
-
describe Decorator do
|
|
6
|
-
it_behaves_like "view helpers", Decorator.new(Model.new)
|
|
7
|
-
|
|
8
|
-
describe "#initialize" do
|
|
9
|
-
describe "options validation" do
|
|
10
|
-
it "does not raise error on valid options" do
|
|
11
|
-
valid_options = {context: {}}
|
|
12
|
-
expect{Decorator.new(Model.new, valid_options)}.not_to raise_error
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "raises error on invalid options" do
|
|
16
|
-
expect{Decorator.new(Model.new, foo: "bar")}.to raise_error ArgumentError, /Unknown key/
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it "sets the object" do
|
|
21
|
-
object = Model.new
|
|
22
|
-
decorator = Decorator.new(object)
|
|
23
|
-
|
|
24
|
-
expect(decorator.object).to be object
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it "stores context" do
|
|
28
|
-
context = {some: "context"}
|
|
29
|
-
decorator = Decorator.new(Model.new, context: context)
|
|
30
|
-
|
|
31
|
-
expect(decorator.context).to be context
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
context "when decorating an instance of itself" do
|
|
35
|
-
it "applies to the object instead" do
|
|
36
|
-
object = Model.new
|
|
37
|
-
decorated = Decorator.new(object)
|
|
38
|
-
redecorated = Decorator.new(decorated)
|
|
39
|
-
|
|
40
|
-
expect(redecorated.object).to be object
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
context "with context" do
|
|
44
|
-
it "overwrites existing context" do
|
|
45
|
-
decorated = Decorator.new(Model.new, context: {some: "context"})
|
|
46
|
-
new_context = {other: "context"}
|
|
47
|
-
redecorated = Decorator.new(decorated, context: new_context)
|
|
48
|
-
|
|
49
|
-
expect(redecorated.context).to be new_context
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
context "without context" do
|
|
54
|
-
it "preserves existing context" do
|
|
55
|
-
old_context = {some: "context"}
|
|
56
|
-
decorated = Decorator.new(Model.new, context: old_context)
|
|
57
|
-
redecorated = Decorator.new(decorated)
|
|
58
|
-
|
|
59
|
-
expect(redecorated.context).to be old_context
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it "decorates other decorators" do
|
|
65
|
-
decorated = OtherDecorator.new(Model.new)
|
|
66
|
-
redecorated = Decorator.new(decorated)
|
|
67
|
-
|
|
68
|
-
expect(redecorated.object).to be decorated
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
context "when it has been applied previously" do
|
|
72
|
-
it "warns" do
|
|
73
|
-
decorated = OtherDecorator.new(Decorator.new(Model.new))
|
|
74
|
-
|
|
75
|
-
warning_message = nil
|
|
76
|
-
allow_any_instance_of(Object).to receive(:warn) { |instance, message| warning_message = message }
|
|
77
|
-
|
|
78
|
-
expect{Decorator.new(decorated)}.to change{warning_message}
|
|
79
|
-
expect(warning_message).to start_with "Reapplying Draper::Decorator"
|
|
80
|
-
expect(warning_message).to include caller(1).first
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "decorates anyway" do
|
|
84
|
-
decorated = OtherDecorator.new(Decorator.new(Model.new))
|
|
85
|
-
allow_any_instance_of(Object).to receive(:warn)
|
|
86
|
-
redecorated = Decorator.decorate(decorated)
|
|
87
|
-
|
|
88
|
-
expect(redecorated.object).to be decorated
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
describe "#context=" do
|
|
94
|
-
it "modifies the context" do
|
|
95
|
-
decorator = Decorator.new(Model.new, context: {some: "context"})
|
|
96
|
-
new_context = {other: "context"}
|
|
97
|
-
|
|
98
|
-
decorator.context = new_context
|
|
99
|
-
expect(decorator.context).to be new_context
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
describe ".decorate_collection" do
|
|
104
|
-
describe "options validation" do
|
|
105
|
-
before { allow(CollectionDecorator).to receive(:new) }
|
|
106
|
-
|
|
107
|
-
it "does not raise error on valid options" do
|
|
108
|
-
valid_options = {with: OtherDecorator, context: {}}
|
|
109
|
-
expect{Decorator.decorate_collection([], valid_options)}.not_to raise_error
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it "raises error on invalid options" do
|
|
113
|
-
expect{Decorator.decorate_collection([], foo: "bar")}.to raise_error ArgumentError, /Unknown key/
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
context "without a custom collection decorator" do
|
|
118
|
-
it "creates a CollectionDecorator using itself for each item" do
|
|
119
|
-
object = [Model.new]
|
|
120
|
-
|
|
121
|
-
expect(CollectionDecorator).to receive(:new).with(object, {with: Decorator})
|
|
122
|
-
Decorator.decorate_collection(object)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it "passes options to the collection decorator" do
|
|
126
|
-
options = {with: OtherDecorator, context: {some: "context"}}
|
|
127
|
-
|
|
128
|
-
expect(CollectionDecorator).to receive(:new).with([], options)
|
|
129
|
-
Decorator.decorate_collection([], options)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
context "with a custom collection decorator" do
|
|
134
|
-
it "creates a custom collection decorator using itself for each item" do
|
|
135
|
-
object = [Model.new]
|
|
136
|
-
|
|
137
|
-
expect(ProductsDecorator).to receive(:new).with(object, {with: ProductDecorator})
|
|
138
|
-
ProductDecorator.decorate_collection(object)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
it "passes options to the collection decorator" do
|
|
142
|
-
options = {with: OtherDecorator, context: {some: "context"}}
|
|
143
|
-
|
|
144
|
-
expect(ProductsDecorator).to receive(:new).with([], options)
|
|
145
|
-
ProductDecorator.decorate_collection([], options)
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
describe ".decorates" do
|
|
151
|
-
protect_class Decorator
|
|
152
|
-
|
|
153
|
-
it "sets .object_class with a symbol" do
|
|
154
|
-
Decorator.decorates :product
|
|
155
|
-
|
|
156
|
-
expect(Decorator.object_class).to be Product
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
it "sets .object_class with a string" do
|
|
160
|
-
Decorator.decorates "product"
|
|
161
|
-
|
|
162
|
-
expect(Decorator.object_class).to be Product
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
it "sets .object_class with a class" do
|
|
166
|
-
Decorator.decorates Product
|
|
167
|
-
|
|
168
|
-
expect(Decorator.object_class).to be Product
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
describe ".object_class" do
|
|
173
|
-
protect_class ProductDecorator
|
|
174
|
-
protect_class Namespaced::ProductDecorator
|
|
175
|
-
|
|
176
|
-
context "when not set by .decorates" do
|
|
177
|
-
it "raises an UninferrableObjectError for a so-named 'Decorator'" do
|
|
178
|
-
expect{Decorator.object_class}.to raise_error UninferrableObjectError
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
it "raises an UninferrableObjectError for anonymous decorators" do
|
|
182
|
-
expect{Class.new(Decorator).object_class}.to raise_error UninferrableObjectError
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
it "raises an UninferrableObjectError for a decorator without a model" do
|
|
186
|
-
SomeDecorator = Class.new(Draper::Decorator)
|
|
187
|
-
expect{SomeDecorator.object_class}.to raise_error UninferrableObjectError
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
it "raises an UninferrableObjectError for other naming conventions" do
|
|
191
|
-
ProductPresenter = Class.new(Draper::Decorator)
|
|
192
|
-
expect{ProductPresenter.object_class}.to raise_error UninferrableObjectError
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
it "infers the object class for '<Model>Decorator'" do
|
|
196
|
-
expect(ProductDecorator.object_class).to be Product
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
it "infers the object class for namespaced decorators" do
|
|
200
|
-
expect(Namespaced::ProductDecorator.object_class).to be Namespaced::Product
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
context "when an unrelated NameError is thrown" do
|
|
204
|
-
it "re-raises that error" do
|
|
205
|
-
# Not related to safe_constantize behavior, we just want to raise a NameError inside the function
|
|
206
|
-
allow_any_instance_of(String).to receive(:safe_constantize) { SomethingThatDoesntExist }
|
|
207
|
-
expect{ProductDecorator.object_class}.to raise_error NameError, /SomethingThatDoesntExist/
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
describe ".object_class?" do
|
|
214
|
-
it "returns truthy when .object_class is set" do
|
|
215
|
-
allow(Decorator).to receive(:object_class).and_return(Model)
|
|
216
|
-
|
|
217
|
-
expect(Decorator.object_class?).to be_truthy
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
it "returns false when .object_class is not inferrable" do
|
|
221
|
-
allow(Decorator).to receive(:object_class).and_raise(UninferrableObjectError.new(Decorator))
|
|
222
|
-
|
|
223
|
-
expect(Decorator.object_class?).to be_falsey
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
describe '.collection_decorator_class' do
|
|
228
|
-
it 'defaults to CollectionDecorator' do
|
|
229
|
-
allow_any_instance_of(String).to receive(:safe_constantize) { nil }
|
|
230
|
-
expect(ProductDecorator.collection_decorator_class).to be Draper::CollectionDecorator
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
it 'infers collection decorator based on name' do
|
|
234
|
-
expect(ProductDecorator.collection_decorator_class).to be ProductsDecorator
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it 'infers collection decorator base on name for namespeced model' do
|
|
238
|
-
expect(Namespaced::ProductDecorator.collection_decorator_class).to be Namespaced::ProductsDecorator
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
describe ".decorates_association" do
|
|
243
|
-
protect_class Decorator
|
|
244
|
-
|
|
245
|
-
describe "options validation" do
|
|
246
|
-
before { allow(DecoratedAssociation).to receive(:new).and_return(->{}) }
|
|
247
|
-
|
|
248
|
-
it "does not raise error on valid options" do
|
|
249
|
-
valid_options = {with: Class, scope: :sorted, context: {}}
|
|
250
|
-
expect{Decorator.decorates_association(:children, valid_options)}.not_to raise_error
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
it "raises error on invalid options" do
|
|
254
|
-
expect{Decorator.decorates_association(:children, foo: "bar")}.to raise_error ArgumentError, /Unknown key/
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
describe "defines an association method" do
|
|
259
|
-
it "creates a DecoratedAssociation" do
|
|
260
|
-
options = {with: Class.new, scope: :foo, context: {}}
|
|
261
|
-
Decorator.decorates_association :children, options
|
|
262
|
-
decorator = Decorator.new(Model.new)
|
|
263
|
-
|
|
264
|
-
expect(DecoratedAssociation).to receive(:new).with(decorator, :children, options).and_return(->{})
|
|
265
|
-
decorator.children
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
it "memoizes the DecoratedAssociation" do
|
|
269
|
-
Decorator.decorates_association :children
|
|
270
|
-
decorator = Decorator.new(Model.new)
|
|
271
|
-
|
|
272
|
-
expect(DecoratedAssociation).to receive(:new).once.and_return(->{})
|
|
273
|
-
decorator.children
|
|
274
|
-
decorator.children
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
it "calls the DecoratedAssociation" do
|
|
278
|
-
Decorator.decorates_association :children
|
|
279
|
-
decorator = Decorator.new(Model.new)
|
|
280
|
-
decorated_association = ->{}
|
|
281
|
-
allow(DecoratedAssociation).to receive(:new).and_return(decorated_association)
|
|
282
|
-
|
|
283
|
-
expect(decorated_association).to receive(:call).and_return(:decorated)
|
|
284
|
-
expect(decorator.children).to be :decorated
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
describe ".decorates_associations" do
|
|
290
|
-
protect_class Decorator
|
|
291
|
-
|
|
292
|
-
it "decorates each of the associations" do
|
|
293
|
-
expect(Decorator).to receive(:decorates_association).with(:friends, {})
|
|
294
|
-
expect(Decorator).to receive(:decorates_association).with(:enemies, {})
|
|
295
|
-
Decorator.decorates_associations :friends, :enemies
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
it "dispatches options" do
|
|
299
|
-
options = {with: Class.new, scope: :foo, context: {}}
|
|
300
|
-
|
|
301
|
-
expect(Decorator).to receive(:decorates_association).with(:friends, options)
|
|
302
|
-
expect(Decorator).to receive(:decorates_association).with(:enemies, options)
|
|
303
|
-
Decorator.decorates_associations :friends, :enemies, options
|
|
304
|
-
end
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
describe "#applied_decorators" do
|
|
308
|
-
it "returns a list of decorators applied to a model" do
|
|
309
|
-
decorator = ProductDecorator.new(OtherDecorator.new(Decorator.new(Model.new)))
|
|
310
|
-
|
|
311
|
-
expect(decorator.applied_decorators).to eq [Decorator, OtherDecorator, ProductDecorator]
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
describe "#decorated_with?" do
|
|
316
|
-
it "checks if a decorator has been applied to a model" do
|
|
317
|
-
decorator = ProductDecorator.new(Decorator.new(Model.new))
|
|
318
|
-
|
|
319
|
-
expect(decorator).to be_decorated_with Decorator
|
|
320
|
-
expect(decorator).to be_decorated_with ProductDecorator
|
|
321
|
-
expect(decorator).not_to be_decorated_with OtherDecorator
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
describe "#decorated?" do
|
|
326
|
-
it "returns true" do
|
|
327
|
-
decorator = Decorator.new(Model.new)
|
|
328
|
-
|
|
329
|
-
expect(decorator).to be_decorated
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
describe "#object" do
|
|
334
|
-
it "returns the wrapped object" do
|
|
335
|
-
object = Model.new
|
|
336
|
-
decorator = Decorator.new(object)
|
|
337
|
-
|
|
338
|
-
expect(decorator.object).to be object
|
|
339
|
-
expect(decorator.model).to be object
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
it "is aliased to #model" do
|
|
343
|
-
object = Model.new
|
|
344
|
-
decorator = Decorator.new(object)
|
|
345
|
-
|
|
346
|
-
expect(decorator.model).to be object
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
describe "aliasing object to object class name" do
|
|
351
|
-
context "when object_class is inferrable from the decorator name" do
|
|
352
|
-
it "aliases object to the object class name" do
|
|
353
|
-
object = double
|
|
354
|
-
decorator = ProductDecorator.new(object)
|
|
355
|
-
|
|
356
|
-
expect(decorator.product).to be object
|
|
357
|
-
end
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
context "when object_class is set by decorates" do
|
|
361
|
-
it "aliases object to the object class name" do
|
|
362
|
-
decorator_class = Class.new(Decorator) { decorates Product }
|
|
363
|
-
object = double
|
|
364
|
-
decorator = decorator_class.new(object)
|
|
365
|
-
|
|
366
|
-
expect(decorator.product).to be object
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
context "when object_class's name is several words long" do
|
|
371
|
-
it "underscores the method name" do
|
|
372
|
-
stub_const "LongWindedModel", Class.new
|
|
373
|
-
decorator_class = Class.new(Decorator) { decorates LongWindedModel }
|
|
374
|
-
object = double
|
|
375
|
-
decorator = decorator_class.new(object)
|
|
376
|
-
|
|
377
|
-
expect(decorator.long_winded_model).to be object
|
|
378
|
-
end
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
context "when object_class is not set" do
|
|
382
|
-
it "does not alias object" do
|
|
383
|
-
decorator_class = Class.new(Decorator)
|
|
384
|
-
|
|
385
|
-
expect(decorator_class.instance_methods).to eq Decorator.instance_methods
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
describe "#to_model" do
|
|
391
|
-
it "returns the decorator" do
|
|
392
|
-
decorator = Decorator.new(Model.new)
|
|
393
|
-
|
|
394
|
-
expect(decorator.to_model).to be decorator
|
|
395
|
-
end
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
describe "#to_param" do
|
|
399
|
-
it "delegates to the object" do
|
|
400
|
-
decorator = Decorator.new(double(to_param: :delegated))
|
|
401
|
-
|
|
402
|
-
expect(decorator.to_param).to be :delegated
|
|
403
|
-
end
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
describe "#present?" do
|
|
407
|
-
it "delegates to the object" do
|
|
408
|
-
decorator = Decorator.new(double(present?: :delegated))
|
|
409
|
-
|
|
410
|
-
expect(decorator.present?).to be :delegated
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
describe "#blank?" do
|
|
415
|
-
it "delegates to the object" do
|
|
416
|
-
decorator = Decorator.new(double(blank?: :delegated))
|
|
417
|
-
|
|
418
|
-
expect(decorator.blank?).to be :delegated
|
|
419
|
-
end
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
describe "#to_partial_path" do
|
|
423
|
-
it "delegates to the object" do
|
|
424
|
-
decorator = Decorator.new(double(to_partial_path: :delegated))
|
|
425
|
-
|
|
426
|
-
expect(decorator.to_partial_path).to be :delegated
|
|
427
|
-
end
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
describe "#to_s" do
|
|
431
|
-
it "delegates to the object" do
|
|
432
|
-
decorator = Decorator.new(double(to_s: :delegated))
|
|
433
|
-
|
|
434
|
-
expect(decorator.to_s).to be :delegated
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
|
-
|
|
438
|
-
describe "#inspect" do
|
|
439
|
-
it "returns a detailed description of the decorator" do
|
|
440
|
-
decorator = ProductDecorator.new(double)
|
|
441
|
-
|
|
442
|
-
expect(decorator.inspect).to match(/#<ProductDecorator:0x\h+ .+>/)
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
it "includes the object" do
|
|
446
|
-
decorator = Decorator.new(double(inspect: "#<the object>"))
|
|
447
|
-
|
|
448
|
-
expect(decorator.inspect).to include "@object=#<the object>"
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
it "includes the context" do
|
|
452
|
-
decorator = Decorator.new(double, context: {foo: "bar"})
|
|
453
|
-
|
|
454
|
-
expect(decorator.inspect).to include '@context={:foo=>"bar"}'
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
it "includes other instance variables" do
|
|
458
|
-
decorator = Decorator.new(double)
|
|
459
|
-
decorator.instance_variable_set :@foo, "bar"
|
|
460
|
-
|
|
461
|
-
expect(decorator.inspect).to include '@foo="bar"'
|
|
462
|
-
end
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
describe "#attributes" do
|
|
466
|
-
it "returns only the object's attributes that are implemented by the decorator" do
|
|
467
|
-
decorator = Decorator.new(double(attributes: {foo: "bar", baz: "qux"}))
|
|
468
|
-
allow(decorator).to receive(:foo)
|
|
469
|
-
|
|
470
|
-
expect(decorator.attributes).to eq({foo: "bar"})
|
|
471
|
-
end
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
describe ".model_name" do
|
|
475
|
-
it "delegates to the object class" do
|
|
476
|
-
allow(Decorator).to receive(:object_class).and_return(double(model_name: :delegated))
|
|
477
|
-
|
|
478
|
-
expect(Decorator.model_name).to be :delegated
|
|
479
|
-
end
|
|
480
|
-
end
|
|
481
|
-
|
|
482
|
-
describe "#==" do
|
|
483
|
-
it "works for a object that does not include Decoratable" do
|
|
484
|
-
object = Object.new
|
|
485
|
-
decorator = Decorator.new(object)
|
|
486
|
-
|
|
487
|
-
expect(decorator).to eq Decorator.new(object)
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
it "works for a multiply-decorated object that does not include Decoratable" do
|
|
491
|
-
object = Object.new
|
|
492
|
-
decorator = Decorator.new(object)
|
|
493
|
-
|
|
494
|
-
expect(decorator).to eq ProductDecorator.new(Decorator.new(object))
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
it "is true when object #== is true" do
|
|
498
|
-
object = Model.new
|
|
499
|
-
decorator = Decorator.new(object)
|
|
500
|
-
other = double(object: Model.new)
|
|
501
|
-
|
|
502
|
-
expect(object).to receive(:==).with(other).and_return(true)
|
|
503
|
-
expect(decorator == other).to be_truthy
|
|
504
|
-
end
|
|
505
|
-
|
|
506
|
-
it "is false when object #== is false" do
|
|
507
|
-
object = Model.new
|
|
508
|
-
decorator = Decorator.new(object)
|
|
509
|
-
other = double(object: Model.new)
|
|
510
|
-
|
|
511
|
-
expect(object).to receive(:==).with(other).and_return(false)
|
|
512
|
-
expect(decorator == other).to be_falsey
|
|
513
|
-
end
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
describe "#===" do
|
|
517
|
-
it "is true when #== is true" do
|
|
518
|
-
decorator = Decorator.new(Model.new)
|
|
519
|
-
allow(decorator).to receive(:==) { true }
|
|
520
|
-
|
|
521
|
-
expect(decorator === :anything).to be_truthy
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
it "is false when #== is false" do
|
|
525
|
-
decorator = Decorator.new(Model.new)
|
|
526
|
-
allow(decorator).to receive(:==).with(:anything).and_return(false)
|
|
527
|
-
|
|
528
|
-
expect(decorator === :anything).to be_falsey
|
|
529
|
-
end
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
describe "#eql?" do
|
|
533
|
-
it "is true when #eql? is true" do
|
|
534
|
-
first = Decorator.new('foo')
|
|
535
|
-
second = Decorator.new('foo')
|
|
536
|
-
|
|
537
|
-
expect(first.eql? second).to be
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
it "is false when #eql? is false" do
|
|
541
|
-
first = Decorator.new('foo')
|
|
542
|
-
second = Decorator.new('bar')
|
|
543
|
-
|
|
544
|
-
expect(first.eql? second).to_not be
|
|
545
|
-
end
|
|
546
|
-
end
|
|
547
|
-
|
|
548
|
-
describe "#hash" do
|
|
549
|
-
it "is consistent for equal objects" do
|
|
550
|
-
object = Model.new
|
|
551
|
-
first = Decorator.new(object)
|
|
552
|
-
second = Decorator.new(object)
|
|
553
|
-
|
|
554
|
-
expect(first.hash == second.hash).to be
|
|
555
|
-
end
|
|
556
|
-
end
|
|
557
|
-
|
|
558
|
-
describe ".delegate" do
|
|
559
|
-
protect_class Decorator
|
|
560
|
-
|
|
561
|
-
it "defaults the :to option to :object" do
|
|
562
|
-
expect(Object).to receive(:delegate).with(:foo, :bar, to: :object)
|
|
563
|
-
Decorator.delegate :foo, :bar
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
it "does not overwrite the :to option if supplied" do
|
|
567
|
-
expect(Object).to receive(:delegate).with(:foo, :bar, to: :baz)
|
|
568
|
-
Decorator.delegate :foo, :bar, to: :baz
|
|
569
|
-
end
|
|
570
|
-
end
|
|
571
|
-
|
|
572
|
-
context "with .delegate_all" do
|
|
573
|
-
protect_class Decorator
|
|
574
|
-
|
|
575
|
-
before { Decorator.delegate_all }
|
|
576
|
-
|
|
577
|
-
describe "#method_missing" do
|
|
578
|
-
it "delegates missing methods that exist on the object" do
|
|
579
|
-
decorator = Decorator.new(double(hello_world: :delegated))
|
|
580
|
-
|
|
581
|
-
expect(decorator.hello_world).to be :delegated
|
|
582
|
-
end
|
|
583
|
-
|
|
584
|
-
it 'delegates `super` to parent class first' do
|
|
585
|
-
parent_decorator_class = Class.new(Decorator) do
|
|
586
|
-
def hello_world
|
|
587
|
-
"parent#hello_world"
|
|
588
|
-
end
|
|
589
|
-
end
|
|
590
|
-
|
|
591
|
-
child_decorator_class = Class.new(parent_decorator_class) do
|
|
592
|
-
def hello_world
|
|
593
|
-
super
|
|
594
|
-
end
|
|
595
|
-
end
|
|
596
|
-
|
|
597
|
-
decorator = child_decorator_class.new(double(hello_world: 'object#hello_world'))
|
|
598
|
-
expect(decorator.hello_world).to eq 'parent#hello_world'
|
|
599
|
-
end
|
|
600
|
-
|
|
601
|
-
it 'delegates `super` to object if method does not exist on parent class' do
|
|
602
|
-
decorator_class = Class.new(Decorator) do
|
|
603
|
-
def hello_world
|
|
604
|
-
super
|
|
605
|
-
end
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
decorator = decorator_class.new(double(hello_world: 'object#hello_world'))
|
|
609
|
-
expect(decorator.hello_world).to eq 'object#hello_world'
|
|
610
|
-
end
|
|
611
|
-
|
|
612
|
-
it 'raises `NoMethodError` when `super` is called on for method that does not exist' do
|
|
613
|
-
decorator_class = Class.new(Decorator) do
|
|
614
|
-
def hello_world
|
|
615
|
-
super
|
|
616
|
-
end
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
decorator = decorator_class.new(double)
|
|
620
|
-
expect{decorator.hello_world}.to raise_error NoMethodError
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
it "allows decorator to decorate different classes of objects" do
|
|
624
|
-
decorator_1 = Decorator.new(double)
|
|
625
|
-
decorator_2 = Decorator.new(double(hello_world: :delegated))
|
|
626
|
-
|
|
627
|
-
decorator_2.hello_world
|
|
628
|
-
expect(decorator_1.methods).not_to include :hello_world
|
|
629
|
-
end
|
|
630
|
-
|
|
631
|
-
it "passes blocks to delegated methods" do
|
|
632
|
-
object = Model.new
|
|
633
|
-
allow(object).to receive(:hello_world) { |*args, &block| block.call }
|
|
634
|
-
decorator = Decorator.new(object)
|
|
635
|
-
|
|
636
|
-
expect(decorator.hello_world{:yielded}).to be :yielded
|
|
637
|
-
end
|
|
638
|
-
|
|
639
|
-
it "does not confuse Kernel#Array" do
|
|
640
|
-
decorator = Decorator.new(Model.new)
|
|
641
|
-
|
|
642
|
-
expect(Array(decorator)).to be_an Array
|
|
643
|
-
end
|
|
644
|
-
|
|
645
|
-
it "delegates already-delegated methods" do
|
|
646
|
-
object = Class.new{ delegate :bar, to: :foo }.new
|
|
647
|
-
allow(object).to receive_messages foo: double(bar: :delegated)
|
|
648
|
-
decorator = Decorator.new(object)
|
|
649
|
-
|
|
650
|
-
expect(decorator.bar).to be :delegated
|
|
651
|
-
end
|
|
652
|
-
|
|
653
|
-
it "does not delegate private methods" do
|
|
654
|
-
object = Class.new{ private; def hello_world; end }.new
|
|
655
|
-
decorator = Decorator.new(object)
|
|
656
|
-
|
|
657
|
-
expect{decorator.hello_world}.to raise_error NoMethodError
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
it "does not delegate methods that do not exist on the object" do
|
|
661
|
-
decorator = Decorator.new(Model.new)
|
|
662
|
-
|
|
663
|
-
expect(decorator.methods).not_to include :hello_world
|
|
664
|
-
expect{decorator.hello_world}.to raise_error NoMethodError
|
|
665
|
-
expect(decorator.methods).not_to include :hello_world
|
|
666
|
-
end
|
|
667
|
-
|
|
668
|
-
context 'when decorator overrides a public method defined on the object with a private' do
|
|
669
|
-
let(:decorator_class) do
|
|
670
|
-
Class.new(Decorator) do
|
|
671
|
-
private
|
|
672
|
-
|
|
673
|
-
def hello_world
|
|
674
|
-
'hello world'
|
|
675
|
-
end
|
|
676
|
-
end
|
|
677
|
-
end
|
|
678
|
-
|
|
679
|
-
let(:object) { Class.new { def hello_world; end }.new }
|
|
680
|
-
|
|
681
|
-
it 'does not delegate the public method defined on the object' do
|
|
682
|
-
decorator = decorator_class.new(object)
|
|
683
|
-
|
|
684
|
-
expect{ decorator.hello_world }.to raise_error NoMethodError
|
|
685
|
-
end
|
|
686
|
-
end
|
|
687
|
-
|
|
688
|
-
context 'when delegated method has the same name as private method defined on another object' do
|
|
689
|
-
let(:decorator_class) { Class.new(Decorator) }
|
|
690
|
-
let(:object) { Class.new { def print; end }.new }
|
|
691
|
-
|
|
692
|
-
it 'delegates the public method defined on the object' do
|
|
693
|
-
decorator = decorator_class.new(object)
|
|
694
|
-
|
|
695
|
-
# `print` private method is defined on `Object`
|
|
696
|
-
expect{ decorator.print }.not_to raise_error
|
|
697
|
-
end
|
|
698
|
-
end
|
|
699
|
-
end
|
|
700
|
-
|
|
701
|
-
context ".method_missing" do
|
|
702
|
-
context "without an object class" do
|
|
703
|
-
it "raises a NoMethodError on missing methods" do
|
|
704
|
-
expect{Decorator.hello_world}.to raise_error NoMethodError
|
|
705
|
-
end
|
|
706
|
-
end
|
|
707
|
-
|
|
708
|
-
context "with an object class" do
|
|
709
|
-
it "delegates methods that exist on the object class" do
|
|
710
|
-
object_class = Class.new
|
|
711
|
-
allow(object_class).to receive_messages hello_world: :delegated
|
|
712
|
-
allow(Decorator).to receive_messages object_class: object_class
|
|
713
|
-
|
|
714
|
-
expect(Decorator.hello_world).to be :delegated
|
|
715
|
-
end
|
|
716
|
-
|
|
717
|
-
it "does not delegate methods that do not exist on the object class" do
|
|
718
|
-
allow(Decorator).to receive_messages object_class: Class.new
|
|
719
|
-
|
|
720
|
-
expect{Decorator.hello_world}.to raise_error NoMethodError
|
|
721
|
-
end
|
|
722
|
-
end
|
|
723
|
-
end
|
|
724
|
-
|
|
725
|
-
describe "#respond_to?" do
|
|
726
|
-
it "returns true for its own methods" do
|
|
727
|
-
Decorator.class_eval{def hello_world; end}
|
|
728
|
-
decorator = Decorator.new(Model.new)
|
|
729
|
-
|
|
730
|
-
expect(decorator).to respond_to :hello_world
|
|
731
|
-
end
|
|
732
|
-
|
|
733
|
-
it "returns true for the object's methods" do
|
|
734
|
-
decorator = Decorator.new(double(hello_world: :delegated))
|
|
735
|
-
|
|
736
|
-
expect(decorator).to respond_to :hello_world
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
context "with include_private" do
|
|
740
|
-
it "returns true for its own private methods" do
|
|
741
|
-
Decorator.class_eval{private; def hello_world; end}
|
|
742
|
-
decorator = Decorator.new(Model.new)
|
|
743
|
-
|
|
744
|
-
expect(decorator.respond_to?(:hello_world, true)).to be_truthy
|
|
745
|
-
end
|
|
746
|
-
|
|
747
|
-
it "returns false for the object's private methods" do
|
|
748
|
-
object = Class.new{private; def hello_world; end}.new
|
|
749
|
-
decorator = Decorator.new(object)
|
|
750
|
-
|
|
751
|
-
expect(decorator.respond_to?(:hello_world, true)).to be_falsey
|
|
752
|
-
end
|
|
753
|
-
end
|
|
754
|
-
end
|
|
755
|
-
|
|
756
|
-
describe ".respond_to?" do
|
|
757
|
-
context "without a object class" do
|
|
758
|
-
it "returns true for its own class methods" do
|
|
759
|
-
Decorator.class_eval{def self.hello_world; end}
|
|
760
|
-
|
|
761
|
-
expect(Decorator).to respond_to :hello_world
|
|
762
|
-
end
|
|
763
|
-
|
|
764
|
-
it "returns false for other class methods" do
|
|
765
|
-
expect(Decorator).not_to respond_to :goodnight_moon
|
|
766
|
-
end
|
|
767
|
-
end
|
|
768
|
-
|
|
769
|
-
context "with a object class" do
|
|
770
|
-
it "returns true for its own class methods" do
|
|
771
|
-
Decorator.class_eval{def self.hello_world; end}
|
|
772
|
-
allow(Decorator).to receive_messages object_class: Class.new
|
|
773
|
-
|
|
774
|
-
expect(Decorator).to respond_to :hello_world
|
|
775
|
-
end
|
|
776
|
-
|
|
777
|
-
it "returns true for the object's class methods" do
|
|
778
|
-
allow(Decorator).to receive_messages object_class: double(hello_world: :delegated)
|
|
779
|
-
|
|
780
|
-
expect(Decorator).to respond_to :hello_world
|
|
781
|
-
end
|
|
782
|
-
end
|
|
783
|
-
end
|
|
784
|
-
|
|
785
|
-
describe "#respond_to_missing?" do
|
|
786
|
-
it "allows #method to be called on delegated methods" do
|
|
787
|
-
object = Class.new{def hello_world; end}.new
|
|
788
|
-
decorator = Decorator.new(object)
|
|
789
|
-
|
|
790
|
-
expect(decorator.method(:hello_world)).not_to be_nil
|
|
791
|
-
end
|
|
792
|
-
end
|
|
793
|
-
|
|
794
|
-
describe ".respond_to_missing?" do
|
|
795
|
-
it "allows .method to be called on delegated class methods" do
|
|
796
|
-
allow(Decorator).to receive_messages object_class: double(hello_world: :delegated)
|
|
797
|
-
|
|
798
|
-
expect(Decorator.method(:hello_world)).not_to be_nil
|
|
799
|
-
end
|
|
800
|
-
end
|
|
801
|
-
end
|
|
802
|
-
|
|
803
|
-
describe "class spoofing" do
|
|
804
|
-
it "pretends to be a kind of the object class" do
|
|
805
|
-
decorator = Decorator.new(Model.new)
|
|
806
|
-
|
|
807
|
-
expect(decorator.kind_of?(Model)).to be_truthy
|
|
808
|
-
expect(decorator.is_a?(Model)).to be_truthy
|
|
809
|
-
end
|
|
810
|
-
|
|
811
|
-
it "is still a kind of its own class" do
|
|
812
|
-
decorator = Decorator.new(Model.new)
|
|
813
|
-
|
|
814
|
-
expect(decorator.kind_of?(Decorator)).to be_truthy
|
|
815
|
-
expect(decorator.is_a?(Decorator)).to be_truthy
|
|
816
|
-
end
|
|
817
|
-
|
|
818
|
-
it "pretends to be an instance of the object class" do
|
|
819
|
-
decorator = Decorator.new(Model.new)
|
|
820
|
-
|
|
821
|
-
expect(decorator.instance_of?(Model)).to be_truthy
|
|
822
|
-
end
|
|
823
|
-
|
|
824
|
-
it "is still an instance of its own class" do
|
|
825
|
-
decorator = Decorator.new(Model.new)
|
|
826
|
-
|
|
827
|
-
expect(decorator.instance_of?(Decorator)).to be_truthy
|
|
828
|
-
end
|
|
829
|
-
end
|
|
830
|
-
|
|
831
|
-
describe ".decorates_finders" do
|
|
832
|
-
protect_class Decorator
|
|
833
|
-
|
|
834
|
-
it "extends the Finders module" do
|
|
835
|
-
expect(Decorator).not_to be_a_kind_of Finders
|
|
836
|
-
Decorator.decorates_finders
|
|
837
|
-
expect(Decorator).to be_a_kind_of Finders
|
|
838
|
-
end
|
|
839
|
-
end
|
|
840
|
-
|
|
841
|
-
describe "Enumerable hash and equality functionality" do
|
|
842
|
-
describe "#uniq" do
|
|
843
|
-
it "removes duplicate objects with same decorator" do
|
|
844
|
-
object = Model.new
|
|
845
|
-
array = [Decorator.new(object), Decorator.new(object)]
|
|
846
|
-
|
|
847
|
-
expect(array.uniq.count).to eq(1)
|
|
848
|
-
end
|
|
849
|
-
|
|
850
|
-
it "separates different objects with identical decorators" do
|
|
851
|
-
array = [Decorator.new('foo'), Decorator.new('bar')]
|
|
852
|
-
|
|
853
|
-
expect(array.uniq.count).to eq(2)
|
|
854
|
-
end
|
|
855
|
-
|
|
856
|
-
it "separates identical objects with different decorators" do
|
|
857
|
-
object = Model.new
|
|
858
|
-
array = [Decorator.new(object), OtherDecorator.new(object)]
|
|
859
|
-
|
|
860
|
-
expect(array.uniq.count).to eq(2)
|
|
861
|
-
end
|
|
862
|
-
|
|
863
|
-
it "distinguishes between an objects and its decorated version" do
|
|
864
|
-
object = Model.new
|
|
865
|
-
array = [Decorator.new(object), object]
|
|
866
|
-
|
|
867
|
-
expect(array.uniq.count).to eq(2)
|
|
868
|
-
end
|
|
869
|
-
end
|
|
870
|
-
end
|
|
871
|
-
end
|
|
872
|
-
end
|