draper 0.18.0 → 1.0.0.beta1
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.
- data/.gitignore +3 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.markdown +8 -0
- data/Gemfile +4 -0
- data/Rakefile +50 -31
- data/Readme.markdown +42 -48
- data/draper.gemspec +2 -1
- data/lib/draper.rb +42 -7
- data/lib/draper/collection_decorator.rb +88 -0
- data/lib/draper/decoratable.rb +44 -0
- data/lib/draper/decorated_association.rb +55 -0
- data/lib/draper/decorator.rb +208 -0
- data/lib/draper/finders.rb +44 -0
- data/lib/draper/helper_proxy.rb +16 -0
- data/lib/draper/railtie.rb +17 -21
- data/lib/draper/security.rb +48 -0
- data/lib/draper/tasks/tu.rake +5 -0
- data/lib/draper/test/minitest_integration.rb +1 -1
- data/lib/draper/test/test_unit_integration.rb +9 -0
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context.rb +6 -13
- data/lib/draper/view_helpers.rb +36 -0
- data/lib/generators/decorator/decorator_generator.rb +1 -1
- data/lib/generators/decorator/templates/decorator.rb +0 -1
- data/spec/draper/collection_decorator_spec.rb +240 -0
- data/spec/draper/decoratable_spec.rb +164 -0
- data/spec/draper/decorated_association_spec.rb +130 -0
- data/spec/draper/decorator_spec.rb +497 -0
- data/spec/draper/finders_spec.rb +156 -0
- data/spec/draper/helper_proxy_spec.rb +12 -0
- data/spec/draper/security_spec.rb +158 -0
- data/spec/draper/view_helpers_spec.rb +41 -0
- data/spec/dummy/.rspec +2 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/localized_urls.rb +5 -0
- data/spec/dummy/app/controllers/posts_controller.rb +17 -0
- data/spec/dummy/app/decorators/post_decorator.rb +25 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +3 -0
- data/spec/dummy/app/mailers/post_mailer.rb +9 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +11 -0
- data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
- data/spec/dummy/app/views/posts/_post.html.erb +19 -0
- data/spec/dummy/app/views/posts/show.html.erb +1 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +64 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +34 -0
- data/spec/dummy/config/environments/production.rb +55 -0
- data/spec/dummy/config/environments/test.rb +32 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +7 -0
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
- data/spec/dummy/db/schema.rb +21 -0
- data/spec/dummy/db/seeds.rb +2 -0
- data/spec/dummy/lib/tasks/spec.rake +5 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +23 -0
- data/spec/dummy/spec/mailers/post_mailer_spec.rb +29 -0
- data/spec/dummy/spec/spec_helper.rb +9 -0
- data/spec/generators/decorator/decorator_generator_spec.rb +3 -4
- data/spec/integration/integration_spec.rb +33 -0
- data/{performance → spec/performance}/active_record.rb +0 -0
- data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
- data/{performance → spec/performance}/decorators.rb +2 -4
- data/{performance → spec/performance}/models.rb +0 -0
- data/spec/spec_helper.rb +20 -41
- data/spec/support/action_controller.rb +12 -0
- data/spec/support/active_model.rb +7 -0
- data/spec/support/{samples/active_record.rb → active_record.rb} +5 -0
- data/spec/support/{samples → decorators}/decorator_with_application_helper.rb +1 -1
- data/spec/support/decorators/namespaced_product_decorator.rb +5 -0
- data/spec/support/decorators/non_active_model_product_decorator.rb +2 -0
- data/spec/support/decorators/product_decorator.rb +19 -0
- data/spec/support/{samples → decorators}/products_decorator.rb +1 -1
- data/spec/support/decorators/some_thing_decorator.rb +2 -0
- data/spec/support/{samples → decorators}/specific_product_decorator.rb +0 -2
- data/spec/support/{samples → decorators}/widget_decorator.rb +0 -0
- data/spec/support/dummy_app.rb +84 -0
- data/spec/support/matchers/have_text.rb +50 -0
- data/spec/support/{samples → models}/namespaced_product.rb +1 -3
- data/spec/support/{samples → models}/non_active_model_product.rb +1 -0
- data/spec/support/{samples → models}/product.rb +13 -2
- data/spec/support/models/some_thing.rb +5 -0
- data/spec/support/models/uninferrable_decorator_model.rb +3 -0
- data/spec/support/{samples → models}/widget.rb +0 -0
- metadata +185 -68
- data/lib/draper/active_model_support.rb +0 -27
- data/lib/draper/base.rb +0 -312
- data/lib/draper/decorated_enumerable_proxy.rb +0 -90
- data/lib/draper/model_support.rb +0 -25
- data/lib/draper/rspec_integration.rb +0 -2
- data/lib/draper/system.rb +0 -18
- data/spec/draper/base_spec.rb +0 -873
- data/spec/draper/decorated_enumerable_proxy_spec.rb +0 -45
- data/spec/draper/model_support_spec.rb +0 -48
- data/spec/support/samples/decorator.rb +0 -5
- data/spec/support/samples/decorator_with_allows.rb +0 -3
- data/spec/support/samples/decorator_with_denies.rb +0 -3
- data/spec/support/samples/decorator_with_denies_all.rb +0 -3
- data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
- data/spec/support/samples/decorator_with_special_methods.rb +0 -13
- data/spec/support/samples/enumerable_proxy.rb +0 -3
- data/spec/support/samples/namespaced_product_decorator.rb +0 -7
- data/spec/support/samples/product_decorator.rb +0 -7
- data/spec/support/samples/sequel_product.rb +0 -13
- data/spec/support/samples/some_thing.rb +0 -2
- data/spec/support/samples/some_thing_decorator.rb +0 -3
@@ -1,7 +1,7 @@
|
|
1
1
|
class MiniTest::Rails::ActiveSupport::TestCase
|
2
2
|
# Use AS::TestCase for the base class when describing a decorator
|
3
3
|
register_spec_type(self) do |desc|
|
4
|
-
desc < Draper::
|
4
|
+
desc < Draper::Decorator if desc.is_a?(Class)
|
5
5
|
end
|
6
6
|
register_spec_type(/Decorator( ?Test)?\z/i, self)
|
7
7
|
end
|
data/lib/draper/version.rb
CHANGED
data/lib/draper/view_context.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module Draper
|
2
2
|
module ViewContext
|
3
|
+
def view_context
|
4
|
+
super.tap do |context|
|
5
|
+
Draper::ViewContext.current = context
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
3
9
|
def self.current_controller
|
4
10
|
Thread.current[:current_controller] || ApplicationController.new
|
5
11
|
end
|
@@ -16,21 +22,8 @@ module Draper
|
|
16
22
|
Thread.current[:current_view_context] = context
|
17
23
|
end
|
18
24
|
|
19
|
-
def view_context
|
20
|
-
super.tap do |context|
|
21
|
-
Draper::ViewContext.current = context
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
25
|
def self.build_view_context
|
28
26
|
current_controller.view_context.tap do |context|
|
29
|
-
context.instance_eval do
|
30
|
-
def url_options
|
31
|
-
ActionMailer::Base.default_url_options
|
32
|
-
end
|
33
|
-
end unless context.request
|
34
27
|
if defined?(ActionController::TestRequest)
|
35
28
|
context.controller.request ||= ActionController::TestRequest.new
|
36
29
|
context.request ||= context.controller.request
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Draper
|
2
|
+
module ViewHelpers
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
# Access the helpers proxy to call built-in and user-defined
|
8
|
+
# Rails helpers from a class context.
|
9
|
+
#
|
10
|
+
# @return [HelperProxy] the helpers proxy
|
11
|
+
def helpers
|
12
|
+
@helpers ||= Draper::HelperProxy.new
|
13
|
+
end
|
14
|
+
alias_method :h, :helpers
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# Access the helpers proxy to call built-in and user-defined
|
19
|
+
# Rails helpers. Aliased to `h` for convenience.
|
20
|
+
#
|
21
|
+
# @return [HelperProxy] the helpers proxy
|
22
|
+
def helpers
|
23
|
+
self.class.helpers
|
24
|
+
end
|
25
|
+
alias_method :h, :helpers
|
26
|
+
|
27
|
+
# Localize is something that's used quite often. Even though
|
28
|
+
# it's available through helpers, that's annoying. Aliased
|
29
|
+
# to `l` for convenience.
|
30
|
+
def localize(*args)
|
31
|
+
helpers.localize(*args)
|
32
|
+
end
|
33
|
+
alias_method :l, :localize
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Draper::CollectionDecorator do
|
4
|
+
before { ApplicationController.new.view_context }
|
5
|
+
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator) }
|
6
|
+
let(:source){ [Product.new, Product.new] }
|
7
|
+
let(:non_active_model_source){ NonActiveModelProduct.new }
|
8
|
+
|
9
|
+
it "decorates a collection's items" do
|
10
|
+
subject.each do |item|
|
11
|
+
item.should be_decorated_with ProductDecorator
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sets the decorated items' source models" do
|
16
|
+
subject.map{|item| item.source}.should == source
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with options" do
|
20
|
+
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator, some: "options") }
|
21
|
+
|
22
|
+
its(:options) { should == {some: "options"} }
|
23
|
+
|
24
|
+
it "passes options to the individual decorators" do
|
25
|
+
subject.each do |item|
|
26
|
+
item.options.should == {some: "options"}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#options=" do
|
31
|
+
it "updates the options on the collection decorator" do
|
32
|
+
subject.options = {other: "options"}
|
33
|
+
subject.options.should == {other: "options"}
|
34
|
+
end
|
35
|
+
|
36
|
+
it "updates the options on the individual decorators" do
|
37
|
+
subject.options = {other: "options"}
|
38
|
+
subject.each do |item|
|
39
|
+
item.options.should == {other: "options"}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#initialize" do
|
46
|
+
context "when the :with option is given" do
|
47
|
+
context "and the decorator can't be inferred from the class" do
|
48
|
+
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator) }
|
49
|
+
|
50
|
+
it "uses the :with option" do
|
51
|
+
subject.decorator_class.should be ProductDecorator
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "and the decorator is inferrable from the class" do
|
56
|
+
subject { ProductsDecorator.new(source, with: SpecificProductDecorator) }
|
57
|
+
|
58
|
+
it "uses the :with option" do
|
59
|
+
subject.decorator_class.should be SpecificProductDecorator
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when the :with option is not given" do
|
65
|
+
context "and the decorator can't be inferred from the class" do
|
66
|
+
it "raises an UninferrableDecoratorError" do
|
67
|
+
expect{Draper::CollectionDecorator.new(source)}.to raise_error Draper::UninferrableDecoratorError
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "and the decorator is inferrable from the class" do
|
72
|
+
subject { ProductsDecorator.new(source) }
|
73
|
+
|
74
|
+
it "infers the decorator" do
|
75
|
+
subject.decorator_class.should be ProductDecorator
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#source" do
|
82
|
+
it "returns the source collection" do
|
83
|
+
subject.source.should be source
|
84
|
+
end
|
85
|
+
|
86
|
+
it "is aliased to #to_source" do
|
87
|
+
subject.to_source.should be source
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#find" do
|
92
|
+
context "with a block" do
|
93
|
+
it "decorates Enumerable#find" do
|
94
|
+
subject.decorated_collection.should_receive(:find)
|
95
|
+
subject.find {|p| p.title == "title" }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "without a block" do
|
100
|
+
it "decorates Model.find" do
|
101
|
+
source.should_not_receive(:find)
|
102
|
+
Product.should_receive(:find).with(1).and_return(:product)
|
103
|
+
subject.find(1).should == ProductDecorator.new(:product)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#helpers" do
|
109
|
+
it "returns a HelperProxy" do
|
110
|
+
subject.helpers.should be_a Draper::HelperProxy
|
111
|
+
end
|
112
|
+
|
113
|
+
it "is aliased to #h" do
|
114
|
+
subject.h.should be subject.helpers
|
115
|
+
end
|
116
|
+
|
117
|
+
it "initializes the wrapper only once" do
|
118
|
+
helper_proxy = subject.helpers
|
119
|
+
helper_proxy.stub(:test_method) { "test_method" }
|
120
|
+
subject.helpers.test_method.should == "test_method"
|
121
|
+
subject.helpers.test_method.should == "test_method"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#localize" do
|
126
|
+
before { subject.helpers.should_receive(:localize).with(:an_object, {some: "options"}) }
|
127
|
+
|
128
|
+
it "delegates to helpers" do
|
129
|
+
subject.localize(:an_object, some: "options")
|
130
|
+
end
|
131
|
+
|
132
|
+
it "is aliased to #l" do
|
133
|
+
subject.l(:an_object, some: "options")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe ".helpers" do
|
138
|
+
it "returns a HelperProxy" do
|
139
|
+
subject.class.helpers.should be_a Draper::HelperProxy
|
140
|
+
end
|
141
|
+
|
142
|
+
it "is aliased to .h" do
|
143
|
+
subject.class.h.should be subject.class.helpers
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#to_ary" do
|
148
|
+
# required for `render @collection` in Rails
|
149
|
+
it "delegates to the decorated collection" do
|
150
|
+
subject.decorated_collection.should_receive(:to_ary).and_return(:an_array)
|
151
|
+
subject.to_ary.should == :an_array
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#respond_to?" do
|
156
|
+
it "returns true for its own methods" do
|
157
|
+
subject.should respond_to :decorated_collection
|
158
|
+
end
|
159
|
+
|
160
|
+
it "returns true for the wrapped collection's methods" do
|
161
|
+
source.stub(:respond_to?).with(:whatever, true).and_return(true)
|
162
|
+
subject.respond_to?(:whatever, true).should be_true
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "Array methods" do
|
167
|
+
describe "#include?" do
|
168
|
+
it "delegates to the decorated collection" do
|
169
|
+
subject.decorated_collection.should_receive(:include?).with(:something).and_return(true)
|
170
|
+
subject.should include :something
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#[]" do
|
175
|
+
it "delegates to the decorated collection" do
|
176
|
+
subject.decorated_collection.should_receive(:[]).with(42).and_return(:something)
|
177
|
+
subject[42].should == :something
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "#==" do
|
183
|
+
context "when comparing to a collection decorator with the same source" do
|
184
|
+
it "returns true" do
|
185
|
+
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
|
186
|
+
b = ProductsDecorator.new(source)
|
187
|
+
a.should == b
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "when comparing to a collection decorator with a different source" do
|
192
|
+
it "returns false" do
|
193
|
+
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
|
194
|
+
b = ProductsDecorator.new([Product.new])
|
195
|
+
a.should_not == b
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when comparing to a collection of the same items" do
|
200
|
+
it "returns true" do
|
201
|
+
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
|
202
|
+
b = source.dup
|
203
|
+
a.should == b
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "when comparing to a collection of different items" do
|
208
|
+
it "returns true" do
|
209
|
+
a = Draper::CollectionDecorator.new(source, with: ProductDecorator)
|
210
|
+
b = [Product.new]
|
211
|
+
a.should_not == b
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
it "pretends to be the source class" do
|
217
|
+
subject.kind_of?(source.class).should be_true
|
218
|
+
subject.is_a?(source.class).should be_true
|
219
|
+
end
|
220
|
+
|
221
|
+
it "is still its own class" do
|
222
|
+
subject.kind_of?(subject.class).should be_true
|
223
|
+
subject.is_a?(subject.class).should be_true
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "#method_missing" do
|
227
|
+
before do
|
228
|
+
class << source
|
229
|
+
def page_number
|
230
|
+
42
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
it "proxies unknown methods to the source collection" do
|
236
|
+
subject.page_number.should == 42
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Draper::Decoratable do
|
4
|
+
subject { Product.new }
|
5
|
+
|
6
|
+
describe "#decorate" do
|
7
|
+
it "returns a decorator for self" do
|
8
|
+
subject.decorate.should be_a ProductDecorator
|
9
|
+
subject.decorate.source.should be subject
|
10
|
+
end
|
11
|
+
|
12
|
+
it "accepts options" do
|
13
|
+
decorator = subject.decorate(some: "options")
|
14
|
+
decorator.options.should == {some: "options"}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is not memoized" do
|
18
|
+
subject.decorate.should_not be subject.decorate
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#applied_decorators" do
|
23
|
+
it "returns an empty list" do
|
24
|
+
subject.applied_decorators.should be_empty
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#decorated_with?" do
|
29
|
+
it "returns false" do
|
30
|
+
subject.should_not be_decorated_with ProductDecorator
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#decorated?" do
|
35
|
+
it "returns false" do
|
36
|
+
subject.should_not be_decorated
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#decorator_class" do
|
41
|
+
it "delegates to .decorator_class" do
|
42
|
+
Product.stub(:decorator_class).and_return(WidgetDecorator)
|
43
|
+
product = Product.new
|
44
|
+
product.decorator_class.should be WidgetDecorator
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#===" do
|
49
|
+
context "with itself" do
|
50
|
+
it "returns true" do
|
51
|
+
(subject === subject).should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with another instance" do
|
56
|
+
it "returns false" do
|
57
|
+
(subject === Product.new).should be_false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with a decorated version of itself" do
|
62
|
+
it "returns true" do
|
63
|
+
decorator = double(source: subject)
|
64
|
+
(subject === decorator).should be_true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with a decorated other instance" do
|
69
|
+
it "returns false" do
|
70
|
+
decorator = double(source: Product.new)
|
71
|
+
(subject === decorator).should be_false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe ".====" do
|
77
|
+
context "with an instance" do
|
78
|
+
it "returns true" do
|
79
|
+
(Product === Product.new).should be_true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with a derived instance" do
|
84
|
+
it "returns true" do
|
85
|
+
(Product === Widget.new).should be_true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with an unrelated instance" do
|
90
|
+
it "returns false" do
|
91
|
+
(Product === Object.new).should be_false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "with a decorated instance" do
|
96
|
+
it "returns true" do
|
97
|
+
decorator = double(source: Product.new)
|
98
|
+
(Product === decorator).should be_true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "with a decorated derived instance" do
|
103
|
+
it "returns true" do
|
104
|
+
decorator = double(source: Widget.new)
|
105
|
+
(Product === decorator).should be_true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "with a decorated unrelated instance" do
|
110
|
+
it "returns false" do
|
111
|
+
decorator = double(source: Object.new)
|
112
|
+
(Product === decorator).should be_false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe ".decorate" do
|
118
|
+
it "returns a collection decorator" do
|
119
|
+
Product.stub(:scoped).and_return([Product.new])
|
120
|
+
Product.stub(:decorator_class).and_return(WidgetDecorator)
|
121
|
+
decorator = Product.decorate
|
122
|
+
|
123
|
+
decorator.should be_a Draper::CollectionDecorator
|
124
|
+
decorator.decorator_class.should be WidgetDecorator
|
125
|
+
decorator.source.should be Product.scoped
|
126
|
+
end
|
127
|
+
|
128
|
+
it "accepts options" do
|
129
|
+
decorator = Product.decorate(some: "options")
|
130
|
+
decorator.options.should == {some: "options"}
|
131
|
+
end
|
132
|
+
|
133
|
+
it "is not memoized" do
|
134
|
+
Product.decorate.should_not be Product.decorate
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe ".decorator_class" do
|
139
|
+
context "for non-ActiveModel classes" do
|
140
|
+
it "infers the decorator from the class" do
|
141
|
+
NonActiveModelProduct.decorator_class.should be NonActiveModelProductDecorator
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "for ActiveModel classes" do
|
146
|
+
it "infers the decorator from the model name" do
|
147
|
+
Product.stub(:model_name).and_return("Widget")
|
148
|
+
Product.decorator_class.should be WidgetDecorator
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "for namespaced ActiveModel classes" do
|
153
|
+
it "infers the decorator from the model name" do
|
154
|
+
Namespace::Product.decorator_class.should be Namespace::ProductDecorator
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when the decorator can't be inferred" do
|
159
|
+
it "throws an UninferrableDecoratorError" do
|
160
|
+
expect{UninferrableDecoratorModel.decorator_class}.to raise_error Draper::UninferrableDecoratorError
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|