draper 4.0.2 → 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.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -2
  3. data/CHANGELOG.md +24 -0
  4. data/README.md +26 -7
  5. data/lib/draper/automatic_delegation.rb +14 -4
  6. data/lib/draper/collection_decorator.rb +0 -6
  7. data/lib/draper/compatibility/broadcastable.rb +24 -0
  8. data/lib/draper/compatibility/global_id.rb +9 -5
  9. data/lib/draper/decoratable/collection_proxy.rb +15 -0
  10. data/lib/draper/decoratable.rb +7 -2
  11. data/lib/draper/decorator.rb +2 -18
  12. data/lib/draper/query_methods.rb +1 -1
  13. data/lib/draper/railtie.rb +14 -5
  14. data/lib/draper/version.rb +1 -1
  15. data/lib/draper/view_context/build_strategy.rb +1 -9
  16. data/lib/draper.rb +0 -6
  17. metadata +16 -235
  18. data/.github/PULL_REQUEST_TEMPLATE.md +0 -24
  19. data/.github/workflows/ci.yml +0 -55
  20. data/.gitignore +0 -18
  21. data/Gemfile +0 -24
  22. data/bin/bundle +0 -114
  23. data/bin/rake +0 -29
  24. data/draper.gemspec +0 -34
  25. data/spec/draper/collection_decorator_spec.rb +0 -291
  26. data/spec/draper/configuration_spec.rb +0 -49
  27. data/spec/draper/decoratable/equality_spec.rb +0 -10
  28. data/spec/draper/decoratable_spec.rb +0 -235
  29. data/spec/draper/decorated_association_spec.rb +0 -82
  30. data/spec/draper/decorates_assigned_spec.rb +0 -71
  31. data/spec/draper/decorator_spec.rb +0 -872
  32. data/spec/draper/draper_spec.rb +0 -25
  33. data/spec/draper/factory_spec.rb +0 -247
  34. data/spec/draper/finders_spec.rb +0 -166
  35. data/spec/draper/helper_proxy_spec.rb +0 -61
  36. data/spec/draper/lazy_helpers_spec.rb +0 -21
  37. data/spec/draper/query_methods/load_strategy_spec.rb +0 -26
  38. data/spec/draper/query_methods_spec.rb +0 -70
  39. data/spec/draper/undecorate_chain_spec.rb +0 -20
  40. data/spec/draper/undecorate_spec.rb +0 -19
  41. data/spec/draper/view_context/build_strategy_spec.rb +0 -132
  42. data/spec/draper/view_context_spec.rb +0 -182
  43. data/spec/draper/view_helpers_spec.rb +0 -8
  44. data/spec/dummy/.rspec +0 -2
  45. data/spec/dummy/Rakefile +0 -7
  46. data/spec/dummy/app/assets/config/manifest.js +0 -3
  47. data/spec/dummy/app/controllers/application_controller.rb +0 -2
  48. data/spec/dummy/app/controllers/base_controller.rb +0 -4
  49. data/spec/dummy/app/controllers/localized_urls.rb +0 -5
  50. data/spec/dummy/app/controllers/posts_controller.rb +0 -20
  51. data/spec/dummy/app/decorators/mongoid_post_decorator.rb +0 -4
  52. data/spec/dummy/app/decorators/post_decorator.rb +0 -60
  53. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  54. data/spec/dummy/app/jobs/publish_post_job.rb +0 -7
  55. data/spec/dummy/app/mailers/application_mailer.rb +0 -3
  56. data/spec/dummy/app/mailers/post_mailer.rb +0 -19
  57. data/spec/dummy/app/models/admin.rb +0 -5
  58. data/spec/dummy/app/models/application_record.rb +0 -3
  59. data/spec/dummy/app/models/mongoid_post.rb +0 -5
  60. data/spec/dummy/app/models/post.rb +0 -3
  61. data/spec/dummy/app/models/user.rb +0 -5
  62. data/spec/dummy/app/views/layouts/application.html.erb +0 -11
  63. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +0 -1
  64. data/spec/dummy/app/views/posts/_post.html.erb +0 -42
  65. data/spec/dummy/app/views/posts/show.html.erb +0 -1
  66. data/spec/dummy/bin/rails +0 -4
  67. data/spec/dummy/config/application.rb +0 -68
  68. data/spec/dummy/config/boot.rb +0 -5
  69. data/spec/dummy/config/database.yml +0 -25
  70. data/spec/dummy/config/environment.rb +0 -5
  71. data/spec/dummy/config/environments/development.rb +0 -35
  72. data/spec/dummy/config/environments/production.rb +0 -59
  73. data/spec/dummy/config/environments/test.rb +0 -35
  74. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  75. data/spec/dummy/config/initializers/draper.rb +0 -3
  76. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  77. data/spec/dummy/config/initializers/inflections.rb +0 -15
  78. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  79. data/spec/dummy/config/initializers/secret_token.rb +0 -8
  80. data/spec/dummy/config/initializers/session_store.rb +0 -8
  81. data/spec/dummy/config/locales/en.yml +0 -5
  82. data/spec/dummy/config/mongoid.yml +0 -142
  83. data/spec/dummy/config/routes.rb +0 -9
  84. data/spec/dummy/config/storage.yml +0 -7
  85. data/spec/dummy/config.ru +0 -4
  86. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +0 -8
  87. data/spec/dummy/db/schema.rb +0 -21
  88. data/spec/dummy/db/seeds.rb +0 -2
  89. data/spec/dummy/fast_spec/post_decorator_spec.rb +0 -37
  90. data/spec/dummy/lib/tasks/test.rake +0 -16
  91. data/spec/dummy/log/.gitkeep +0 -0
  92. data/spec/dummy/public/404.html +0 -26
  93. data/spec/dummy/public/422.html +0 -26
  94. data/spec/dummy/public/500.html +0 -25
  95. data/spec/dummy/public/favicon.ico +0 -0
  96. data/spec/dummy/script/rails +0 -6
  97. data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +0 -12
  98. data/spec/dummy/spec/decorators/devise_spec.rb +0 -55
  99. data/spec/dummy/spec/decorators/helpers_spec.rb +0 -21
  100. data/spec/dummy/spec/decorators/post_decorator_spec.rb +0 -64
  101. data/spec/dummy/spec/decorators/spec_type_spec.rb +0 -7
  102. data/spec/dummy/spec/decorators/view_context_spec.rb +0 -22
  103. data/spec/dummy/spec/jobs/publish_post_job_spec.rb +0 -9
  104. data/spec/dummy/spec/mailers/post_mailer_spec.rb +0 -25
  105. data/spec/dummy/spec/models/application_spec.rb +0 -7
  106. data/spec/dummy/spec/models/mongoid_post_spec.rb +0 -8
  107. data/spec/dummy/spec/models/post_spec.rb +0 -15
  108. data/spec/dummy/spec/shared_examples/decoratable.rb +0 -22
  109. data/spec/dummy/spec/spec_helper.rb +0 -8
  110. data/spec/dummy/test/decorators/minitest/devise_test.rb +0 -55
  111. data/spec/dummy/test/decorators/minitest/helpers_test.rb +0 -21
  112. data/spec/dummy/test/decorators/minitest/spec_type_test.rb +0 -52
  113. data/spec/dummy/test/decorators/minitest/view_context_test.rb +0 -24
  114. data/spec/dummy/test/decorators/test_unit/devise_test.rb +0 -55
  115. data/spec/dummy/test/decorators/test_unit/helpers_test.rb +0 -21
  116. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +0 -24
  117. data/spec/dummy/test/minitest_helper.rb +0 -2
  118. data/spec/dummy/test/test_helper.rb +0 -3
  119. data/spec/generators/controller/controller_generator_spec.rb +0 -23
  120. data/spec/generators/decorator/decorator_generator_spec.rb +0 -93
  121. data/spec/generators/install/install_generator_spec.rb +0 -19
  122. data/spec/integration/integration_spec.rb +0 -70
  123. data/spec/performance/active_record.rb +0 -4
  124. data/spec/performance/benchmark.rb +0 -55
  125. data/spec/performance/decorators.rb +0 -45
  126. data/spec/performance/models.rb +0 -20
  127. data/spec/spec_helper.rb +0 -50
  128. data/spec/support/dummy_app.rb +0 -85
  129. data/spec/support/matchers/have_text.rb +0 -50
  130. data/spec/support/shared_examples/decoratable_equality.rb +0 -40
  131. data/spec/support/shared_examples/view_helpers.rb +0 -39
@@ -1,291 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/shared_examples/view_helpers'
3
-
4
- module Draper
5
- describe CollectionDecorator do
6
- it_behaves_like "view helpers", CollectionDecorator.new([])
7
-
8
- describe "#initialize" do
9
- describe "options validation" do
10
- it "does not raise error on valid options" do
11
- valid_options = {with: Decorator, context: {}}
12
- expect{CollectionDecorator.new([], valid_options)}.not_to raise_error
13
- end
14
-
15
- it "raises error on invalid options" do
16
- expect{CollectionDecorator.new([], foo: "bar")}.to raise_error ArgumentError, /Unknown key/
17
- end
18
- end
19
- end
20
-
21
- context "with context" do
22
- it "stores the context itself" do
23
- context = {some: "context"}
24
- decorator = CollectionDecorator.new([], context: context)
25
-
26
- expect(decorator.context).to be context
27
- end
28
-
29
- it "passes context to the individual decorators" do
30
- context = {some: "context"}
31
- decorator = CollectionDecorator.new([Product.new, Product.new], context: context)
32
-
33
- decorator.each do |item|
34
- expect(item.context).to be context
35
- end
36
- end
37
- end
38
-
39
- describe "#context=" do
40
- it "updates the stored context" do
41
- decorator = CollectionDecorator.new([], context: {some: "context"})
42
- new_context = {other: "context"}
43
-
44
- decorator.context = new_context
45
- expect(decorator.context).to be new_context
46
- end
47
-
48
- context "when the collection is already decorated" do
49
- it "updates the items' context" do
50
- decorator = CollectionDecorator.new([Product.new, Product.new], context: {some: "context"})
51
- decorator.decorated_collection # trigger decoration
52
- new_context = {other: "context"}
53
-
54
- decorator.context = new_context
55
- decorator.each do |item|
56
- expect(item.context).to be new_context
57
- end
58
- end
59
- end
60
-
61
- context "when the collection has not yet been decorated" do
62
- it "does not trigger decoration" do
63
- decorated = CollectionDecorator.new([]).tap(&:to_a)
64
- undecorated = CollectionDecorator.new([])
65
-
66
- expect(decorated.instance_variable_defined?(:@decorated_collection)).to be_truthy
67
- expect(undecorated.instance_variable_defined?(:@decorated_collection)).to be_falsy
68
- end
69
-
70
- it "sets context after decoration is triggered" do
71
- decorator = CollectionDecorator.new([Product.new, Product.new], context: {some: "context"})
72
- new_context = {other: "context"}
73
-
74
- decorator.context = new_context
75
- decorator.each do |item|
76
- expect(item.context).to be new_context
77
- end
78
- end
79
- end
80
- end
81
-
82
- describe "item decoration" do
83
- it "sets decorated items' source models" do
84
- collection = [Product.new, Product.new]
85
- decorator = CollectionDecorator.new(collection)
86
-
87
- decorator.zip collection do |item, object|
88
- expect(item.object).to be object
89
- end
90
- end
91
-
92
- context "when the :with option was given" do
93
- it "uses the :with option" do
94
- decorator = CollectionDecorator.new([Product.new], with: OtherDecorator).first
95
-
96
- expect(decorator).to be_decorated_with OtherDecorator
97
- end
98
- end
99
-
100
- context "when the :with option was not given" do
101
- it "infers the item decorator from each item" do
102
- decorator = CollectionDecorator.new([double(decorate: :inferred_decorator)]).first
103
-
104
- expect(decorator).to be :inferred_decorator
105
- end
106
- end
107
- end
108
-
109
- describe ".delegate" do
110
- protect_class ProductsDecorator
111
-
112
- it "defaults the :to option to :object" do
113
- expect(Object).to receive(:delegate).with(:foo, :bar, to: :object)
114
- ProductsDecorator.delegate :foo, :bar
115
- end
116
-
117
- it "does not overwrite the :to option if supplied" do
118
- expect(Object).to receive(:delegate).with(:foo, :bar, to: :baz)
119
- ProductsDecorator.delegate :foo, :bar, to: :baz
120
- end
121
- end
122
-
123
- describe "#find" do
124
- it "decorates Enumerable#find" do
125
- decorator = CollectionDecorator.new([])
126
-
127
- expect(decorator.decorated_collection).to receive(:find).and_return(:delegated)
128
- expect(decorator.find{|p| p.title == "title"}).to be :delegated
129
- end
130
- end
131
-
132
- describe "#to_ary" do
133
- # required for `render @collection` in Rails
134
- it "delegates to the decorated collection" do
135
- decorator = CollectionDecorator.new([])
136
-
137
- expect(decorator.decorated_collection).to receive(:to_ary).and_return(:delegated)
138
- expect(decorator.to_ary).to be :delegated
139
- end
140
- end
141
-
142
- it "delegates array methods to the decorated collection" do
143
- decorator = CollectionDecorator.new([])
144
-
145
- allow(decorator).to receive_message_chain(:decorated_collection, :[]).with(42).and_return(:delegated)
146
- expect(decorator[42]).to be :delegated
147
- end
148
-
149
- describe "#==" do
150
- context "when comparing to a collection decorator with the same object" do
151
- it "returns true" do
152
- object = [Product.new, Product.new]
153
- decorator = CollectionDecorator.new(object)
154
- other = ProductsDecorator.new(object)
155
-
156
- expect(decorator == other).to be_truthy
157
- end
158
- end
159
-
160
- context "when comparing to a collection decorator with a different object" do
161
- it "returns false" do
162
- decorator = CollectionDecorator.new([Product.new, Product.new])
163
- other = ProductsDecorator.new([Product.new, Product.new])
164
-
165
- expect(decorator == other).to be_falsey
166
- end
167
- end
168
-
169
- context "when comparing to a collection of the same items" do
170
- it "returns true" do
171
- object = [Product.new, Product.new]
172
- decorator = CollectionDecorator.new(object)
173
- other = object.dup
174
-
175
- expect(decorator == other).to be_truthy
176
- end
177
- end
178
-
179
- context "when comparing to a collection of different items" do
180
- it "returns false" do
181
- decorator = CollectionDecorator.new([Product.new, Product.new])
182
- other = [Product.new, Product.new]
183
-
184
- expect(decorator == other).to be_falsey
185
- end
186
- end
187
-
188
- context "when the decorated collection has been modified" do
189
- it "is no longer equal to the object" do
190
- object = [Product.new, Product.new]
191
- decorator = CollectionDecorator.new(object)
192
- other = object.dup
193
-
194
- decorator << Product.new.decorate
195
- expect(decorator == other).to be_falsey
196
- end
197
- end
198
- end
199
-
200
- describe "#to_s" do
201
- context "when :with option was given" do
202
- it "returns a string representation of the collection decorator" do
203
- decorator = CollectionDecorator.new(["a", "b", "c"], with: ProductDecorator)
204
-
205
- expect(decorator.to_s).to eq '#<Draper::CollectionDecorator of ProductDecorator for ["a", "b", "c"]>'
206
- end
207
- end
208
-
209
- context "when :with option was not given" do
210
- it "returns a string representation of the collection decorator" do
211
- decorator = CollectionDecorator.new(["a", "b", "c"])
212
-
213
- expect(decorator.to_s).to eq '#<Draper::CollectionDecorator of inferred decorators for ["a", "b", "c"]>'
214
- end
215
- end
216
-
217
- context "for a custom subclass" do
218
- it "uses the custom class name" do
219
- decorator = ProductsDecorator.new([])
220
-
221
- expect(decorator.to_s).to match(/ProductsDecorator/)
222
- end
223
- end
224
- end
225
-
226
- describe '#object' do
227
- it 'returns the underlying collection' do
228
- collection = [Product.new]
229
- decorator = ProductsDecorator.new(collection)
230
-
231
- expect(decorator.object).to eq collection
232
- end
233
- end
234
-
235
- describe '#decorated?' do
236
- it 'returns true' do
237
- decorator = ProductsDecorator.new([Product.new])
238
-
239
- expect(decorator).to be_decorated
240
- end
241
- end
242
-
243
- describe '#decorated_with?' do
244
- it "checks if a decorator has been applied to a collection" do
245
- decorator = ProductsDecorator.new([Product.new])
246
-
247
- expect(decorator).to be_decorated_with ProductsDecorator
248
- expect(decorator).not_to be_decorated_with OtherDecorator
249
- end
250
- end
251
-
252
- describe '#kind_of?' do
253
- it 'asks the kind of its decorated collection' do
254
- decorator = ProductsDecorator.new([])
255
- expect(decorator.decorated_collection).to receive(:kind_of?).with(Array).and_return("true")
256
- expect(decorator.kind_of?(Array)).to eq "true"
257
- end
258
-
259
- context 'when asking the underlying collection returns false' do
260
- it 'asks the CollectionDecorator instance itself' do
261
- decorator = ProductsDecorator.new([])
262
- allow(decorator.decorated_collection).to receive(:kind_of?).with(::Draper::CollectionDecorator).and_return(false)
263
- expect(decorator.kind_of?(::Draper::CollectionDecorator)).to be true
264
- end
265
- end
266
- end
267
-
268
- describe '#is_a?' do
269
- it 'aliases to #kind_of?' do
270
- decorator = ProductsDecorator.new([])
271
- expect(decorator.method(:kind_of?)).to eq decorator.method(:is_a?)
272
- end
273
- end
274
-
275
- describe "#replace" do
276
- it "replaces the decorated collection" do
277
- decorator = CollectionDecorator.new([Product.new])
278
- replacement = [:foo, :bar]
279
-
280
- decorator.replace replacement
281
- expect(decorator).to match_array replacement
282
- end
283
-
284
- it "returns itself" do
285
- decorator = CollectionDecorator.new([Product.new])
286
-
287
- expect(decorator.replace([:foo, :bar])).to be decorator
288
- end
289
- end
290
- end
291
- end
@@ -1,49 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Draper
4
- RSpec.describe Configuration do
5
- it 'yields Draper on configure' do
6
- Draper.configure { |config| expect(config).to be Draper }
7
- end
8
-
9
- describe '#default_controller' do
10
- it 'defaults default_controller to ApplicationController' do
11
- expect(Draper.default_controller).to be ApplicationController
12
- end
13
-
14
- it 'allows customizing default_controller through configure' do
15
- default = Draper.default_controller
16
-
17
- Draper.configure do |config|
18
- config.default_controller = CustomController
19
- end
20
-
21
- expect(Draper.default_controller).to be CustomController
22
-
23
- Draper.default_controller = default
24
- end
25
- end
26
-
27
- describe '#default_query_methods_strategy' do
28
- let!(:default) { Draper.default_query_methods_strategy }
29
-
30
- subject { Draper.default_query_methods_strategy }
31
-
32
- context 'when there is no custom strategy' do
33
- it { is_expected.to eq(:active_record) }
34
- end
35
-
36
- context 'when using a custom strategy' do
37
- before do
38
- Draper.configure do |config|
39
- config.default_query_methods_strategy = :mongoid
40
- end
41
- end
42
-
43
- after { Draper.default_query_methods_strategy = default }
44
-
45
- it { is_expected.to eq(:mongoid) }
46
- end
47
- end
48
- end
49
- end
@@ -1,10 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/shared_examples/decoratable_equality'
3
-
4
- module Draper
5
- describe Decoratable::Equality do
6
- describe "#==" do
7
- it_behaves_like "decoration-aware #==", Object.new.extend(Decoratable::Equality)
8
- end
9
- end
10
- end
@@ -1,235 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/shared_examples/decoratable_equality'
3
-
4
- module Draper
5
- describe Decoratable do
6
- describe "#decorate" do
7
- it "returns a decorator for self" do
8
- product = Product.new
9
- decorator = product.decorate
10
-
11
- expect(decorator).to be_a ProductDecorator
12
- expect(decorator.object).to be product
13
- end
14
-
15
- it "accepts context" do
16
- context = {some: "context"}
17
- decorator = Product.new.decorate(context: context)
18
-
19
- expect(decorator.context).to be context
20
- end
21
-
22
- it "uses the #decorator_class" do
23
- product = Product.new
24
- allow(product).to receive_messages decorator_class: OtherDecorator
25
-
26
- expect(product.decorate).to be_an_instance_of OtherDecorator
27
- end
28
- end
29
-
30
- describe "#applied_decorators" do
31
- it "returns an empty list" do
32
- expect(Product.new.applied_decorators).to eq []
33
- end
34
- end
35
-
36
- describe "#decorated_with?" do
37
- it "returns false" do
38
- expect(Product.new).not_to be_decorated_with Decorator
39
- end
40
- end
41
-
42
- describe "#decorated?" do
43
- it "returns false" do
44
- expect(Product.new).not_to be_decorated
45
- end
46
- end
47
-
48
- describe "#decorator_class?" do
49
- it "returns true for decoratable model" do
50
- expect(Product.new.decorator_class?).to be_truthy
51
- end
52
-
53
- it "returns false for non-decoratable model" do
54
- expect(Model.new.decorator_class?).to be_falsey
55
- end
56
- end
57
-
58
- describe ".decorator_class?" do
59
- it "returns true for decoratable model" do
60
- expect(Product.decorator_class?).to be_truthy
61
- end
62
-
63
- it "returns false for non-decoratable model" do
64
- expect(Model.decorator_class?).to be_falsey
65
- end
66
- end
67
-
68
- describe "#decorator_class" do
69
- it "delegates to .decorator_class" do
70
- product = Product.new
71
-
72
- expect(Product).to receive(:decorator_class).and_return(:some_decorator)
73
- expect(product.decorator_class).to be :some_decorator
74
- end
75
-
76
- it "specifies the class that #decorator_class was first called on (superclass)" do
77
- person = Person.new
78
- expect { person.decorator_class }.to raise_error(Draper::UninferrableDecoratorError, 'Could not infer a decorator for Person.')
79
- end
80
-
81
- it "specifies the class that #decorator_class was first called on (subclass)" do
82
- child = Child.new
83
- expect { child.decorator_class }.to raise_error(Draper::UninferrableDecoratorError, 'Could not infer a decorator for Child.')
84
- end
85
- end
86
-
87
- describe "#==" do
88
- it_behaves_like "decoration-aware #==", Product.new
89
- end
90
-
91
- describe "#===" do
92
- it "is true when #== is true" do
93
- product = Product.new
94
-
95
- expect(product).to receive(:==).and_return(true)
96
- expect(product === :anything).to be_truthy
97
- end
98
-
99
- it "is false when #== is false" do
100
- product = Product.new
101
-
102
- expect(product).to receive(:==).and_return(false)
103
- expect(product === :anything).to be_falsey
104
- end
105
- end
106
-
107
- describe ".====" do
108
- it "is true for an instance" do
109
- expect(Product === Product.new).to be_truthy
110
- end
111
-
112
- it "is true for a derived instance" do
113
- expect(Product === Class.new(Product).new).to be_truthy
114
- end
115
-
116
- it "is false for an unrelated instance" do
117
- expect(Product === Model.new).to be_falsey
118
- end
119
-
120
- it "is true for a decorated instance" do
121
- decorator = Product.new.decorate
122
-
123
- expect(Product === decorator).to be_truthy
124
- end
125
-
126
- it "is true for a decorated derived instance" do
127
- decorator = Class.new(Product).new.decorate
128
-
129
- expect(Product === decorator).to be_truthy
130
- end
131
-
132
- it "is false for a decorated unrelated instance" do
133
- decorator = Other.new.decorate
134
-
135
- expect(Product === decorator).to be_falsey
136
- end
137
-
138
- it "is false for a non-decorator which happens to respond to object" do
139
- decorator = double(object: Product.new)
140
-
141
- expect(Product === decorator).to be_falsey
142
- end
143
- end
144
-
145
- describe ".decorate" do
146
- it "calls #decorate_collection on .decorator_class" do
147
- scoped = [Product.new]
148
- allow(Product).to receive(:all).and_return(scoped)
149
-
150
- expect(Product.decorator_class).to receive(:decorate_collection).with(scoped, with: nil).and_return(:decorated_collection)
151
- expect(Product.decorate).to be :decorated_collection
152
- end
153
-
154
- it "accepts options" do
155
- options = {with: ProductDecorator, context: {some: "context"}}
156
- allow(Product).to receive(:all).and_return([])
157
-
158
- expect(Product.decorator_class).to receive(:decorate_collection).with([], options)
159
- Product.decorate(options)
160
- end
161
- end
162
-
163
- describe ".decorator_class" do
164
- context "for classes" do
165
- it "infers the decorator from the class" do
166
- expect(Product.decorator_class).to be ProductDecorator
167
- end
168
-
169
- context "without a decorator on its own" do
170
- it "infers the decorator from a superclass" do
171
- expect(SpecialProduct.decorator_class).to be ProductDecorator
172
- end
173
- end
174
- end
175
-
176
- context "for ActiveModel classes" do
177
- it "infers the decorator from the model name" do
178
- allow(Product).to receive(:model_name){"Other"}
179
-
180
- expect(Product.decorator_class).to be OtherDecorator
181
- end
182
- end
183
-
184
- context "in a namespace" do
185
- context "for classes" do
186
- it "infers the decorator from the class" do
187
- expect(Namespaced::Product.decorator_class).to be Namespaced::ProductDecorator
188
- end
189
- end
190
-
191
- context "for ActiveModel classes" do
192
- it "infers the decorator from the model name" do
193
- allow(Namespaced::Product).to receive(:model_name).and_return("Namespaced::Other")
194
-
195
- expect(Namespaced::Product.decorator_class).to be Namespaced::OtherDecorator
196
- end
197
- end
198
- end
199
-
200
- context "when the decorator contains name error" do
201
- it "throws an NameError" do
202
- # We imitate ActiveSupport::Autoload behavior here in order to cause lazy NameError exception raising
203
- allow_any_instance_of(Module).to receive(:const_missing) { Class.new { any_nonexisting_method_name } }
204
-
205
- expect{Model.decorator_class}.to raise_error { |error| expect(error).to be_an_instance_of(NameError) }
206
- end
207
- end
208
-
209
- context "when the decorator can't be inferred" do
210
- it "throws an UninferrableDecoratorError" do
211
- expect{Model.decorator_class}.to raise_error UninferrableDecoratorError
212
- end
213
- end
214
-
215
- context "when an unrelated NameError is thrown" do
216
- it "re-raises that error" do
217
- # Not related to safe_constantize behavior, we just want to raise a NameError inside the function
218
- allow_any_instance_of(String).to receive(:safe_constantize) { Draper::Base }
219
- expect{Product.decorator_class}.to raise_error NameError, /Draper::Base/
220
- end
221
- end
222
-
223
- context "when an anonymous class is given" do
224
- it "infers the decorator from a superclass" do
225
- anonymous_class = Class.new(Product) do
226
- def self.name
227
- to_s
228
- end
229
- end
230
- expect(anonymous_class.decorator_class).to be ProductDecorator
231
- end
232
- end
233
- end
234
- end
235
- end
@@ -1,82 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Draper
4
- describe DecoratedAssociation do
5
- describe "#initialize" do
6
- it "accepts valid options" do
7
- valid_options = {with: Decorator, scope: :foo, context: {}}
8
- expect{DecoratedAssociation.new(Decorator.new(Model.new), :association, valid_options)}.not_to raise_error
9
- end
10
-
11
- it "rejects invalid options" do
12
- expect{DecoratedAssociation.new(Decorator.new(Model.new), :association, foo: "bar")}.to raise_error ArgumentError, /Unknown key/
13
- end
14
-
15
- it "creates a factory" do
16
- options = {with: Decorator, context: {foo: "bar"}}
17
-
18
- expect(Factory).to receive(:new).with(options)
19
- DecoratedAssociation.new(double, :association, options)
20
- end
21
-
22
- describe ":with option" do
23
- it "defaults to nil" do
24
- expect(Factory).to receive(:new).with(with: nil, context: anything())
25
- DecoratedAssociation.new(double, :association, {})
26
- end
27
- end
28
-
29
- describe ":context option" do
30
- it "defaults to the identity function" do
31
- expect(Factory).to receive(:new) do |options|
32
- options[:context].call(:anything) == :anything
33
- end
34
- DecoratedAssociation.new(double, :association, {})
35
- end
36
- end
37
- end
38
-
39
- describe "#call" do
40
- it "calls the factory" do
41
- factory = double
42
- allow(Factory).to receive_messages(new: factory)
43
- associated = double
44
- owner_context = {foo: "bar"}
45
- object = double(association: associated)
46
- owner = double(object: object, context: owner_context)
47
- decorated_association = DecoratedAssociation.new(owner, :association, {})
48
- decorated = double
49
-
50
- expect(factory).to receive(:decorate).with(associated, context_args: owner_context).and_return(decorated)
51
- expect(decorated_association.call).to be decorated
52
- end
53
-
54
- it "memoizes" do
55
- factory = double
56
- allow(Factory).to receive_messages(new: factory)
57
- owner = double(object: double(association: double), context: {})
58
- decorated_association = DecoratedAssociation.new(owner, :association, {})
59
- decorated = double
60
-
61
- expect(factory).to receive(:decorate).once.and_return(decorated)
62
- expect(decorated_association.call).to be decorated
63
- expect(decorated_association.call).to be decorated
64
- end
65
-
66
- context "when the :scope option was given" do
67
- it "applies the scope before decoration" do
68
- factory = double
69
- allow(Factory).to receive_messages(new: factory)
70
- scoped = double
71
- object = double(association: double(applied_scope: scoped))
72
- owner = double(object: object, context: {})
73
- decorated_association = DecoratedAssociation.new(owner, :association, scope: :applied_scope)
74
- decorated = double
75
-
76
- expect(factory).to receive(:decorate).with(scoped, anything()).and_return(decorated)
77
- expect(decorated_association.call).to be decorated
78
- end
79
- end
80
- end
81
- end
82
- end