draper 4.0.1 → 4.0.6

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -2
  3. data/CHANGELOG.md +40 -0
  4. data/README.md +26 -7
  5. data/lib/draper/automatic_delegation.rb +16 -6
  6. data/lib/draper/compatibility/broadcastable.rb +24 -0
  7. data/lib/draper/compatibility/global_id.rb +9 -5
  8. data/lib/draper/decoratable/collection_proxy.rb +15 -0
  9. data/lib/draper/decoratable.rb +7 -2
  10. data/lib/draper/helper_proxy.rb +2 -1
  11. data/lib/draper/lazy_helpers.rb +1 -1
  12. data/lib/draper/query_methods.rb +2 -2
  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/view_helpers.rb +1 -1
  17. data/lib/draper.rb +2 -6
  18. metadata +29 -230
  19. data/.github/PULL_REQUEST_TEMPLATE.md +0 -24
  20. data/.gitignore +0 -18
  21. data/.travis.yml +0 -28
  22. data/Gemfile +0 -23
  23. data/draper.gemspec +0 -34
  24. data/spec/draper/collection_decorator_spec.rb +0 -290
  25. data/spec/draper/configuration_spec.rb +0 -49
  26. data/spec/draper/decoratable/equality_spec.rb +0 -10
  27. data/spec/draper/decoratable_spec.rb +0 -235
  28. data/spec/draper/decorated_association_spec.rb +0 -82
  29. data/spec/draper/decorates_assigned_spec.rb +0 -71
  30. data/spec/draper/decorator_spec.rb +0 -872
  31. data/spec/draper/draper_spec.rb +0 -25
  32. data/spec/draper/factory_spec.rb +0 -247
  33. data/spec/draper/finders_spec.rb +0 -166
  34. data/spec/draper/helper_proxy_spec.rb +0 -61
  35. data/spec/draper/lazy_helpers_spec.rb +0 -21
  36. data/spec/draper/query_methods/load_strategy_spec.rb +0 -26
  37. data/spec/draper/query_methods_spec.rb +0 -70
  38. data/spec/draper/undecorate_chain_spec.rb +0 -20
  39. data/spec/draper/undecorate_spec.rb +0 -19
  40. data/spec/draper/view_context/build_strategy_spec.rb +0 -132
  41. data/spec/draper/view_context_spec.rb +0 -182
  42. data/spec/draper/view_helpers_spec.rb +0 -8
  43. data/spec/dummy/.rspec +0 -2
  44. data/spec/dummy/Rakefile +0 -7
  45. data/spec/dummy/app/assets/config/manifest.js +0 -3
  46. data/spec/dummy/app/controllers/application_controller.rb +0 -2
  47. data/spec/dummy/app/controllers/base_controller.rb +0 -4
  48. data/spec/dummy/app/controllers/localized_urls.rb +0 -5
  49. data/spec/dummy/app/controllers/posts_controller.rb +0 -20
  50. data/spec/dummy/app/decorators/mongoid_post_decorator.rb +0 -4
  51. data/spec/dummy/app/decorators/post_decorator.rb +0 -60
  52. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  53. data/spec/dummy/app/jobs/publish_post_job.rb +0 -7
  54. data/spec/dummy/app/mailers/application_mailer.rb +0 -3
  55. data/spec/dummy/app/mailers/post_mailer.rb +0 -19
  56. data/spec/dummy/app/models/admin.rb +0 -5
  57. data/spec/dummy/app/models/application_record.rb +0 -3
  58. data/spec/dummy/app/models/mongoid_post.rb +0 -5
  59. data/spec/dummy/app/models/post.rb +0 -3
  60. data/spec/dummy/app/models/user.rb +0 -5
  61. data/spec/dummy/app/views/layouts/application.html.erb +0 -11
  62. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +0 -1
  63. data/spec/dummy/app/views/posts/_post.html.erb +0 -42
  64. data/spec/dummy/app/views/posts/show.html.erb +0 -1
  65. data/spec/dummy/bin/rails +0 -4
  66. data/spec/dummy/config/application.rb +0 -68
  67. data/spec/dummy/config/boot.rb +0 -5
  68. data/spec/dummy/config/database.yml +0 -25
  69. data/spec/dummy/config/environment.rb +0 -5
  70. data/spec/dummy/config/environments/development.rb +0 -33
  71. data/spec/dummy/config/environments/production.rb +0 -57
  72. data/spec/dummy/config/environments/test.rb +0 -33
  73. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  74. data/spec/dummy/config/initializers/draper.rb +0 -3
  75. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  76. data/spec/dummy/config/initializers/inflections.rb +0 -15
  77. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  78. data/spec/dummy/config/initializers/secret_token.rb +0 -8
  79. data/spec/dummy/config/initializers/session_store.rb +0 -8
  80. data/spec/dummy/config/locales/en.yml +0 -5
  81. data/spec/dummy/config/mongoid.yml +0 -142
  82. data/spec/dummy/config/routes.rb +0 -9
  83. data/spec/dummy/config.ru +0 -4
  84. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +0 -8
  85. data/spec/dummy/db/schema.rb +0 -21
  86. data/spec/dummy/db/seeds.rb +0 -2
  87. data/spec/dummy/fast_spec/post_decorator_spec.rb +0 -37
  88. data/spec/dummy/lib/tasks/test.rake +0 -16
  89. data/spec/dummy/log/.gitkeep +0 -0
  90. data/spec/dummy/public/404.html +0 -26
  91. data/spec/dummy/public/422.html +0 -26
  92. data/spec/dummy/public/500.html +0 -25
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/dummy/script/rails +0 -6
  95. data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +0 -12
  96. data/spec/dummy/spec/decorators/devise_spec.rb +0 -55
  97. data/spec/dummy/spec/decorators/helpers_spec.rb +0 -21
  98. data/spec/dummy/spec/decorators/post_decorator_spec.rb +0 -64
  99. data/spec/dummy/spec/decorators/spec_type_spec.rb +0 -7
  100. data/spec/dummy/spec/decorators/view_context_spec.rb +0 -22
  101. data/spec/dummy/spec/jobs/publish_post_job_spec.rb +0 -9
  102. data/spec/dummy/spec/mailers/post_mailer_spec.rb +0 -25
  103. data/spec/dummy/spec/models/application_spec.rb +0 -7
  104. data/spec/dummy/spec/models/mongoid_post_spec.rb +0 -8
  105. data/spec/dummy/spec/models/post_spec.rb +0 -15
  106. data/spec/dummy/spec/shared_examples/decoratable.rb +0 -22
  107. data/spec/dummy/spec/spec_helper.rb +0 -8
  108. data/spec/dummy/test/decorators/minitest/devise_test.rb +0 -55
  109. data/spec/dummy/test/decorators/minitest/helpers_test.rb +0 -21
  110. data/spec/dummy/test/decorators/minitest/spec_type_test.rb +0 -52
  111. data/spec/dummy/test/decorators/minitest/view_context_test.rb +0 -24
  112. data/spec/dummy/test/decorators/test_unit/devise_test.rb +0 -55
  113. data/spec/dummy/test/decorators/test_unit/helpers_test.rb +0 -21
  114. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +0 -24
  115. data/spec/dummy/test/minitest_helper.rb +0 -2
  116. data/spec/dummy/test/test_helper.rb +0 -3
  117. data/spec/generators/controller/controller_generator_spec.rb +0 -23
  118. data/spec/generators/decorator/decorator_generator_spec.rb +0 -93
  119. data/spec/generators/install/install_generator_spec.rb +0 -19
  120. data/spec/integration/integration_spec.rb +0 -70
  121. data/spec/performance/active_record.rb +0 -4
  122. data/spec/performance/benchmark.rb +0 -55
  123. data/spec/performance/decorators.rb +0 -45
  124. data/spec/performance/models.rb +0 -20
  125. data/spec/spec_helper.rb +0 -50
  126. data/spec/support/dummy_app.rb +0 -85
  127. data/spec/support/matchers/have_text.rb +0 -50
  128. data/spec/support/shared_examples/decoratable_equality.rb +0 -40
  129. data/spec/support/shared_examples/view_helpers.rb +0 -39
@@ -1,290 +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
- decorator = CollectionDecorator.new([])
64
-
65
- expect(decorator).not_to receive(:decorated_collection)
66
- decorator.context = {other: "context"}
67
- end
68
-
69
- it "sets context after decoration is triggered" do
70
- decorator = CollectionDecorator.new([Product.new, Product.new], context: {some: "context"})
71
- new_context = {other: "context"}
72
-
73
- decorator.context = new_context
74
- decorator.each do |item|
75
- expect(item.context).to be new_context
76
- end
77
- end
78
- end
79
- end
80
-
81
- describe "item decoration" do
82
- it "sets decorated items' source models" do
83
- collection = [Product.new, Product.new]
84
- decorator = CollectionDecorator.new(collection)
85
-
86
- decorator.zip collection do |item, object|
87
- expect(item.object).to be object
88
- end
89
- end
90
-
91
- context "when the :with option was given" do
92
- it "uses the :with option" do
93
- decorator = CollectionDecorator.new([Product.new], with: OtherDecorator).first
94
-
95
- expect(decorator).to be_decorated_with OtherDecorator
96
- end
97
- end
98
-
99
- context "when the :with option was not given" do
100
- it "infers the item decorator from each item" do
101
- decorator = CollectionDecorator.new([double(decorate: :inferred_decorator)]).first
102
-
103
- expect(decorator).to be :inferred_decorator
104
- end
105
- end
106
- end
107
-
108
- describe ".delegate" do
109
- protect_class ProductsDecorator
110
-
111
- it "defaults the :to option to :object" do
112
- expect(Object).to receive(:delegate).with(:foo, :bar, to: :object)
113
- ProductsDecorator.delegate :foo, :bar
114
- end
115
-
116
- it "does not overwrite the :to option if supplied" do
117
- expect(Object).to receive(:delegate).with(:foo, :bar, to: :baz)
118
- ProductsDecorator.delegate :foo, :bar, to: :baz
119
- end
120
- end
121
-
122
- describe "#find" do
123
- it "decorates Enumerable#find" do
124
- decorator = CollectionDecorator.new([])
125
-
126
- expect(decorator.decorated_collection).to receive(:find).and_return(:delegated)
127
- expect(decorator.find{|p| p.title == "title"}).to be :delegated
128
- end
129
- end
130
-
131
- describe "#to_ary" do
132
- # required for `render @collection` in Rails
133
- it "delegates to the decorated collection" do
134
- decorator = CollectionDecorator.new([])
135
-
136
- expect(decorator.decorated_collection).to receive(:to_ary).and_return(:delegated)
137
- expect(decorator.to_ary).to be :delegated
138
- end
139
- end
140
-
141
- it "delegates array methods to the decorated collection" do
142
- decorator = CollectionDecorator.new([])
143
-
144
- allow(decorator).to receive_message_chain(:decorated_collection, :[]).with(42).and_return(:delegated)
145
- expect(decorator[42]).to be :delegated
146
- end
147
-
148
- describe "#==" do
149
- context "when comparing to a collection decorator with the same object" do
150
- it "returns true" do
151
- object = [Product.new, Product.new]
152
- decorator = CollectionDecorator.new(object)
153
- other = ProductsDecorator.new(object)
154
-
155
- expect(decorator == other).to be_truthy
156
- end
157
- end
158
-
159
- context "when comparing to a collection decorator with a different object" do
160
- it "returns false" do
161
- decorator = CollectionDecorator.new([Product.new, Product.new])
162
- other = ProductsDecorator.new([Product.new, Product.new])
163
-
164
- expect(decorator == other).to be_falsey
165
- end
166
- end
167
-
168
- context "when comparing to a collection of the same items" do
169
- it "returns true" do
170
- object = [Product.new, Product.new]
171
- decorator = CollectionDecorator.new(object)
172
- other = object.dup
173
-
174
- expect(decorator == other).to be_truthy
175
- end
176
- end
177
-
178
- context "when comparing to a collection of different items" do
179
- it "returns false" do
180
- decorator = CollectionDecorator.new([Product.new, Product.new])
181
- other = [Product.new, Product.new]
182
-
183
- expect(decorator == other).to be_falsey
184
- end
185
- end
186
-
187
- context "when the decorated collection has been modified" do
188
- it "is no longer equal to the object" do
189
- object = [Product.new, Product.new]
190
- decorator = CollectionDecorator.new(object)
191
- other = object.dup
192
-
193
- decorator << Product.new.decorate
194
- expect(decorator == other).to be_falsey
195
- end
196
- end
197
- end
198
-
199
- describe "#to_s" do
200
- context "when :with option was given" do
201
- it "returns a string representation of the collection decorator" do
202
- decorator = CollectionDecorator.new(["a", "b", "c"], with: ProductDecorator)
203
-
204
- expect(decorator.to_s).to eq '#<Draper::CollectionDecorator of ProductDecorator for ["a", "b", "c"]>'
205
- end
206
- end
207
-
208
- context "when :with option was not given" do
209
- it "returns a string representation of the collection decorator" do
210
- decorator = CollectionDecorator.new(["a", "b", "c"])
211
-
212
- expect(decorator.to_s).to eq '#<Draper::CollectionDecorator of inferred decorators for ["a", "b", "c"]>'
213
- end
214
- end
215
-
216
- context "for a custom subclass" do
217
- it "uses the custom class name" do
218
- decorator = ProductsDecorator.new([])
219
-
220
- expect(decorator.to_s).to match /ProductsDecorator/
221
- end
222
- end
223
- end
224
-
225
- describe '#object' do
226
- it 'returns the underlying collection' do
227
- collection = [Product.new]
228
- decorator = ProductsDecorator.new(collection)
229
-
230
- expect(decorator.object).to eq collection
231
- end
232
- end
233
-
234
- describe '#decorated?' do
235
- it 'returns true' do
236
- decorator = ProductsDecorator.new([Product.new])
237
-
238
- expect(decorator).to be_decorated
239
- end
240
- end
241
-
242
- describe '#decorated_with?' do
243
- it "checks if a decorator has been applied to a collection" do
244
- decorator = ProductsDecorator.new([Product.new])
245
-
246
- expect(decorator).to be_decorated_with ProductsDecorator
247
- expect(decorator).not_to be_decorated_with OtherDecorator
248
- end
249
- end
250
-
251
- describe '#kind_of?' do
252
- it 'asks the kind of its decorated collection' do
253
- decorator = ProductsDecorator.new([])
254
- expect(decorator.decorated_collection).to receive(:kind_of?).with(Array).and_return("true")
255
- expect(decorator.kind_of?(Array)).to eq "true"
256
- end
257
-
258
- context 'when asking the underlying collection returns false' do
259
- it 'asks the CollectionDecorator instance itself' do
260
- decorator = ProductsDecorator.new([])
261
- allow(decorator.decorated_collection).to receive(:kind_of?).with(::Draper::CollectionDecorator).and_return(false)
262
- expect(decorator.kind_of?(::Draper::CollectionDecorator)).to be true
263
- end
264
- end
265
- end
266
-
267
- describe '#is_a?' do
268
- it 'aliases to #kind_of?' do
269
- decorator = ProductsDecorator.new([])
270
- expect(decorator.method(:kind_of?)).to eq decorator.method(:is_a?)
271
- end
272
- end
273
-
274
- describe "#replace" do
275
- it "replaces the decorated collection" do
276
- decorator = CollectionDecorator.new([Product.new])
277
- replacement = [:foo, :bar]
278
-
279
- decorator.replace replacement
280
- expect(decorator).to match_array replacement
281
- end
282
-
283
- it "returns itself" do
284
- decorator = CollectionDecorator.new([Product.new])
285
-
286
- expect(decorator.replace([:foo, :bar])).to be decorator
287
- end
288
- end
289
- end
290
- 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