Skip to content

Commit c028da1

Browse files
Ivan DenisovAlexander-Senko
Ivan Denisov
authored andcommitted
use current module's namespace for decorates_association
1 parent 9daf3ac commit c028da1

8 files changed

+69
-39
lines changed

lib/draper/decoratable.rb

+8-6
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ module Decoratable
1515
# @param [Hash] options
1616
# see {Decorator#initialize}
1717
def decorate(options = {})
18-
decorator_class.decorate(self, options)
18+
decorator_class(namespace: options.delete(:namespace)).decorate(self, options)
1919
end
2020

2121
# (see ClassMethods#decorator_class)
22-
def decorator_class
23-
self.class.decorator_class
22+
def decorator_class(namespace: nil)
23+
self.class.decorator_class(namespace: namespace)
2424
end
2525

2626
def decorator_class?
@@ -55,7 +55,7 @@ module ClassMethods
5555
# @param [Hash] options
5656
# see {Decorator.decorate_collection}.
5757
def decorate(options = {})
58-
decorator_class.decorate_collection(all, options.reverse_merge(with: nil))
58+
decorator_class(namespace: options[:namespace]).decorate_collection(all, options.reverse_merge(with: nil))
5959
end
6060

6161
def decorator_class?
@@ -68,9 +68,11 @@ def decorator_class?
6868
# `Product` maps to `ProductDecorator`).
6969
#
7070
# @return [Class] the inferred decorator class.
71-
def decorator_class(called_on = self)
71+
def decorator_class(called_on = self, namespace: nil)
7272
prefix = respond_to?(:model_name) ? model_name : name
73-
decorator_name = "#{prefix}Decorator"
73+
namespace = "#{namespace}::" if namespace.present?
74+
75+
decorator_name = "#{namespace}#{prefix}Decorator"
7476
decorator_name_constant = decorator_name.safe_constantize
7577
return decorator_name_constant unless decorator_name_constant.nil?
7678

lib/draper/decorated_association.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def initialize(owner, association, options)
1111

1212
decorator_class = options[:with]
1313
context = options.fetch(:context, ->(context){ context })
14-
@factory = Draper::Factory.new(with: decorator_class, context: context)
14+
@factory = Draper::Factory.new(with: decorator_class, context: context, namespace: owner.namespace)
1515
end
1616

1717
def call

lib/draper/decorator.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ def self.decorates_associations(*associations)
139139
# extra data to be stored in the collection decorator.
140140
def self.decorate_collection(object, options = {})
141141
options.assert_valid_keys(:with, :context)
142-
collection_decorator_class.new(object, options.reverse_merge(with: self))
142+
options[:with] ||= self
143+
collection_decorator_class.new(object, options)
143144
end
144145

145146
# @return [Array<Class>] the list of decorators that have been applied to
@@ -218,6 +219,10 @@ def attributes
218219
object.attributes.select {|attribute, _| respond_to?(attribute) }
219220
end
220221

222+
def namespace
223+
self.class.to_s.deconstantize.presence
224+
end
225+
221226
# ActiveModel compatibility
222227
delegate :to_param, :to_partial_path
223228

lib/draper/factory.rb

+7-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ class Factory
1010
# will be called each time {#decorate} is called and its return value
1111
# will be used as the context.
1212
def initialize(options = {})
13-
options.assert_valid_keys(:with, :context)
13+
options.assert_valid_keys(:with, :context, :namespace)
1414
@decorator_class = options.delete(:with)
15+
@namespace = options.delete(:namespace)
1516
@default_options = options
1617
end
1718

@@ -28,7 +29,7 @@ def initialize(options = {})
2829
# @return [Decorator, CollectionDecorator] the decorated object.
2930
def decorate(object, options = {})
3031
return nil if object.nil?
31-
Worker.new(decorator_class, object).call(options.reverse_merge(default_options))
32+
Worker.new(decorator_class, object, @namespace).call(options.reverse_merge(default_options))
3233
end
3334

3435
private
@@ -37,9 +38,10 @@ def decorate(object, options = {})
3738

3839
# @private
3940
class Worker
40-
def initialize(decorator_class, object)
41+
def initialize(decorator_class, object, namespace)
4142
@decorator_class = decorator_class
4243
@object = object
44+
@namespace = namespace
4345
end
4446

4547
def call(options)
@@ -60,9 +62,9 @@ def decorator
6062

6163
def object_decorator
6264
if collection?
63-
->(object, options) { object.decorator_class.decorate_collection(object, options.reverse_merge(with: nil))}
65+
->(object, options) { object.decorator_class(namespace: @namespace).decorate_collection(object, options.reverse_merge(with: nil))}
6466
else
65-
->(object, options) { object.decorate(options) }
67+
->(object, options) { object.decorate(options.merge(namespace: @namespace)) }
6668
end
6769
end
6870

spec/draper/decoratable_spec.rb

+6
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ module Draper
197197
end
198198
end
199199

200+
context "when namespace is passed explicitly" do
201+
it "returns namespaced decorator class" do
202+
expect(Product.decorator_class(namespace: Namespaced)).to be Namespaced::ProductDecorator
203+
end
204+
end
205+
200206
context "when the decorator contains name error" do
201207
it "throws an NameError" do
202208
# We imitate ActiveSupport::Autoload behavior here in order to cause lazy NameError exception raising

spec/draper/decorated_association_spec.rb

+8-8
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ module Draper
1515
it "creates a factory" do
1616
options = {with: Decorator, context: {foo: "bar"}}
1717

18-
expect(Factory).to receive(:new).with(options)
19-
DecoratedAssociation.new(double, :association, options)
18+
expect(Factory).to receive(:new).with(options.merge(namespace: nil))
19+
DecoratedAssociation.new(double(namespace: nil), :association, options)
2020
end
2121

2222
describe ":with option" do
2323
it "defaults to nil" do
24-
expect(Factory).to receive(:new).with(with: nil, context: anything())
25-
DecoratedAssociation.new(double, :association, {})
24+
expect(Factory).to receive(:new).with(with: nil, context: anything(), namespace: nil)
25+
DecoratedAssociation.new(double(namespace: nil), :association, {})
2626
end
2727
end
2828

@@ -31,7 +31,7 @@ module Draper
3131
expect(Factory).to receive(:new) do |options|
3232
options[:context].call(:anything) == :anything
3333
end
34-
DecoratedAssociation.new(double, :association, {})
34+
DecoratedAssociation.new(double(namespace: nil), :association, {})
3535
end
3636
end
3737
end
@@ -43,7 +43,7 @@ module Draper
4343
associated = double
4444
owner_context = {foo: "bar"}
4545
object = double(association: associated)
46-
owner = double(object: object, context: owner_context)
46+
owner = double(object: object, context: owner_context, namespace: nil)
4747
decorated_association = DecoratedAssociation.new(owner, :association, {})
4848
decorated = double
4949

@@ -54,7 +54,7 @@ module Draper
5454
it "memoizes" do
5555
factory = double
5656
allow(Factory).to receive_messages(new: factory)
57-
owner = double(object: double(association: double), context: {})
57+
owner = double(object: double(association: double), context: {}, namespace: nil)
5858
decorated_association = DecoratedAssociation.new(owner, :association, {})
5959
decorated = double
6060

@@ -69,7 +69,7 @@ module Draper
6969
allow(Factory).to receive_messages(new: factory)
7070
scoped = double
7171
object = double(association: double(applied_scope: scoped))
72-
owner = double(object: object, context: {})
72+
owner = double(object: object, context: {}, namespace: nil)
7373
decorated_association = DecoratedAssociation.new(owner, :association, scope: :applied_scope)
7474
decorated = double
7575

spec/draper/decorator_spec.rb

+15
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,21 @@ module Draper
471471
end
472472
end
473473

474+
describe "#namespace" do
475+
it "returns own module nesting" do
476+
decorator = Namespaced::ProductDecorator.new(double)
477+
expect(decorator.namespace).to eq("Namespaced")
478+
end
479+
480+
context "when class has no nesting" do
481+
it "returns nil" do
482+
::TopLevelDecorator = Class.new(Draper::Decorator)
483+
decorator = TopLevelDecorator.new(double)
484+
expect(decorator.namespace).to eq(nil)
485+
end
486+
end
487+
end
488+
474489
describe ".model_name" do
475490
it "delegates to the object class" do
476491
allow(Decorator).to receive(:object_class).and_return(double(model_name: :delegated))

spec/draper/factory_spec.rb

+18-18
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ module Draper
3434
factory = Factory.new
3535
object = double
3636

37-
expect(Factory::Worker).to receive(:new).with(anything(), object).and_return(->(*){})
37+
expect(Factory::Worker).to receive(:new).with(anything(), object, anything()).and_return(->(*){})
3838
factory.decorate(object)
3939
end
4040

@@ -43,7 +43,7 @@ module Draper
4343
decorator_class = double
4444
factory = Factory.new(with: decorator_class)
4545

46-
expect(Factory::Worker).to receive(:new).with(decorator_class, anything()).and_return(->(*){})
46+
expect(Factory::Worker).to receive(:new).with(decorator_class, anything(), anything()).and_return(->(*){})
4747
factory.decorate(double)
4848
end
4949
end
@@ -52,7 +52,7 @@ module Draper
5252
it "passes nil to the worker" do
5353
factory = Factory.new
5454

55-
expect(Factory::Worker).to receive(:new).with(nil, anything()).and_return(->(*){})
55+
expect(Factory::Worker).to receive(:new).with(nil, anything(), anything()).and_return(->(*){})
5656
factory.decorate(double)
5757
end
5858
end
@@ -94,7 +94,7 @@ module Draper
9494
it "calls the decorator method" do
9595
object = double
9696
options = {foo: "bar"}
97-
worker = Factory::Worker.new(double, object)
97+
worker = Factory::Worker.new(double, object, nil)
9898
decorator = ->(*){}
9999
allow(worker).to receive(:decorator){ decorator }
100100

@@ -104,7 +104,7 @@ module Draper
104104

105105
context "when the :context option is callable" do
106106
it "calls it" do
107-
worker = Factory::Worker.new(double, double)
107+
worker = Factory::Worker.new(double, double, nil)
108108
decorator = ->(*){}
109109
allow(worker).to receive_messages decorator: decorator
110110
context = {foo: "bar"}
@@ -114,7 +114,7 @@ module Draper
114114
end
115115

116116
it "receives arguments from the :context_args option" do
117-
worker = Factory::Worker.new(double, double)
117+
worker = Factory::Worker.new(double, double, nil)
118118
allow(worker).to receive_messages decorator: ->(*){}
119119
context = ->{}
120120

@@ -123,7 +123,7 @@ module Draper
123123
end
124124

125125
it "wraps non-arrays passed to :context_args" do
126-
worker = Factory::Worker.new(double, double)
126+
worker = Factory::Worker.new(double, double, nil)
127127
allow(worker).to receive_messages decorator: ->(*){}
128128
context = ->{}
129129
hash = {foo: "bar"}
@@ -135,7 +135,7 @@ module Draper
135135

136136
context "when the :context option is not callable" do
137137
it "doesn't call it" do
138-
worker = Factory::Worker.new(double, double)
138+
worker = Factory::Worker.new(double, double, nil)
139139
decorator = ->(*){}
140140
allow(worker).to receive_messages decorator: decorator
141141
context = {foo: "bar"}
@@ -146,7 +146,7 @@ module Draper
146146
end
147147

148148
it "does not pass the :context_args option to the decorator" do
149-
worker = Factory::Worker.new(double, double)
149+
worker = Factory::Worker.new(double, double, nil)
150150
decorator = ->(*){}
151151
allow(worker).to receive_messages decorator: decorator
152152

@@ -160,7 +160,7 @@ module Draper
160160
context "when decorator_class is specified" do
161161
it "returns the .decorate method from the decorator" do
162162
decorator_class = Class.new(Decorator)
163-
worker = Factory::Worker.new(decorator_class, double)
163+
worker = Factory::Worker.new(decorator_class, double, nil)
164164

165165
expect(worker.decorator).to eq decorator_class.method(:decorate)
166166
end
@@ -171,17 +171,17 @@ module Draper
171171
it "returns the object's #decorate method" do
172172
object = double
173173
options = {foo: "bar"}
174-
worker = Factory::Worker.new(nil, object)
174+
worker = Factory::Worker.new(nil, object, nil)
175175

176-
expect(object).to receive(:decorate).with(options).and_return(:decorated)
176+
expect(object).to receive(:decorate).with(options.merge(namespace: nil)).and_return(:decorated)
177177
expect(worker.decorator.call(object, options)).to be :decorated
178178
end
179179
end
180180

181181
context "and the object is not decoratable" do
182182
it "raises an error" do
183183
object = double
184-
worker = Factory::Worker.new(nil, object)
184+
worker = Factory::Worker.new(nil, object, nil)
185185

186186
expect{worker.decorator}.to raise_error UninferrableDecoratorError
187187
end
@@ -193,7 +193,7 @@ module Draper
193193
object = Struct.new(:stuff).new("things")
194194

195195
decorator_class = Class.new(Decorator)
196-
worker = Factory::Worker.new(decorator_class, object)
196+
worker = Factory::Worker.new(decorator_class, object, nil)
197197

198198
expect(worker.decorator).to eq decorator_class.method(:decorate)
199199
end
@@ -204,7 +204,7 @@ module Draper
204204
context "when decorator_class is a CollectionDecorator" do
205205
it "returns the .decorate method from the collection decorator" do
206206
decorator_class = Class.new(CollectionDecorator)
207-
worker = Factory::Worker.new(decorator_class, [])
207+
worker = Factory::Worker.new(decorator_class, [], nil)
208208

209209
expect(worker.decorator).to eq decorator_class.method(:decorate)
210210
end
@@ -213,7 +213,7 @@ module Draper
213213
context "when decorator_class is a Decorator" do
214214
it "returns the .decorate_collection method from the decorator" do
215215
decorator_class = Class.new(Decorator)
216-
worker = Factory::Worker.new(decorator_class, [])
216+
worker = Factory::Worker.new(decorator_class, [], nil)
217217

218218
expect(worker.decorator).to eq decorator_class.method(:decorate_collection)
219219
end
@@ -226,7 +226,7 @@ module Draper
226226
decorator_class = Class.new(Decorator)
227227
allow(object).to receive(:decorator_class){ decorator_class }
228228
allow(object).to receive(:decorate){ nil }
229-
worker = Factory::Worker.new(nil, object)
229+
worker = Factory::Worker.new(nil, object, nil)
230230

231231
expect(decorator_class).to receive(:decorate_collection).with(object, {foo: "bar", with: nil}).and_return(:decorated)
232232
expect(worker.decorator.call(object, foo: "bar")).to be :decorated
@@ -235,7 +235,7 @@ module Draper
235235

236236
context "and the object is not decoratable" do
237237
it "returns the .decorate method from CollectionDecorator" do
238-
worker = Factory::Worker.new(nil, [])
238+
worker = Factory::Worker.new(nil, [], nil)
239239

240240
expect(worker.decorator).to eq CollectionDecorator.method(:decorate)
241241
end

0 commit comments

Comments
 (0)