draper 0.17.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.
Files changed (154) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +5 -0
  3. data/CHANGELOG.markdown +14 -0
  4. data/Gemfile +4 -0
  5. data/Rakefile +50 -31
  6. data/Readme.markdown +63 -92
  7. data/draper.gemspec +4 -2
  8. data/lib/draper/collection_decorator.rb +88 -0
  9. data/lib/draper/decoratable.rb +44 -0
  10. data/lib/draper/decorated_association.rb +55 -0
  11. data/lib/draper/decorator.rb +208 -0
  12. data/lib/draper/finders.rb +44 -0
  13. data/lib/draper/helper_proxy.rb +16 -0
  14. data/lib/draper/railtie.rb +17 -21
  15. data/lib/draper/security.rb +48 -0
  16. data/lib/draper/tasks/tu.rake +5 -0
  17. data/lib/draper/test/minitest_integration.rb +5 -24
  18. data/lib/draper/test/rspec_integration.rb +0 -6
  19. data/lib/draper/test/test_unit_integration.rb +9 -0
  20. data/lib/draper/version.rb +1 -1
  21. data/lib/draper/view_context.rb +24 -6
  22. data/lib/draper/view_helpers.rb +36 -0
  23. data/lib/draper.rb +42 -7
  24. data/lib/generators/decorator/decorator_generator.rb +1 -1
  25. data/lib/generators/decorator/templates/decorator.rb +0 -1
  26. data/lib/generators/rspec/decorator_generator.rb +1 -1
  27. data/lib/generators/test_unit/decorator_generator.rb +1 -1
  28. data/lib/generators/test_unit/templates/decorator_test.rb +0 -3
  29. data/spec/draper/collection_decorator_spec.rb +240 -0
  30. data/spec/draper/decoratable_spec.rb +164 -0
  31. data/spec/draper/decorated_association_spec.rb +130 -0
  32. data/spec/draper/decorator_spec.rb +497 -0
  33. data/spec/draper/finders_spec.rb +156 -0
  34. data/spec/draper/helper_proxy_spec.rb +12 -0
  35. data/spec/draper/security_spec.rb +158 -0
  36. data/spec/draper/view_helpers_spec.rb +41 -0
  37. data/spec/dummy/.rspec +2 -0
  38. data/spec/dummy/README.rdoc +261 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  41. data/spec/dummy/app/controllers/localized_urls.rb +5 -0
  42. data/spec/dummy/app/controllers/posts_controller.rb +17 -0
  43. data/spec/dummy/app/decorators/post_decorator.rb +25 -0
  44. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy/app/mailers/application_mailer.rb +3 -0
  46. data/spec/dummy/app/mailers/post_mailer.rb +9 -0
  47. data/spec/dummy/app/models/post.rb +3 -0
  48. data/spec/dummy/app/views/layouts/application.html.erb +11 -0
  49. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
  50. data/spec/dummy/app/views/posts/_post.html.erb +19 -0
  51. data/spec/dummy/app/views/posts/show.html.erb +1 -0
  52. data/spec/dummy/config/application.rb +64 -0
  53. data/spec/dummy/config/boot.rb +10 -0
  54. data/spec/dummy/config/database.yml +25 -0
  55. data/spec/dummy/config/environment.rb +5 -0
  56. data/spec/dummy/config/environments/development.rb +34 -0
  57. data/spec/dummy/config/environments/production.rb +55 -0
  58. data/spec/dummy/config/environments/test.rb +32 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/inflections.rb +15 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  63. data/spec/dummy/config/initializers/session_store.rb +8 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/spec/dummy/config/locales/en.yml +5 -0
  66. data/spec/dummy/config/routes.rb +7 -0
  67. data/spec/dummy/config.ru +4 -0
  68. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
  69. data/spec/dummy/db/schema.rb +21 -0
  70. data/spec/dummy/db/seeds.rb +2 -0
  71. data/spec/dummy/lib/tasks/spec.rake +5 -0
  72. data/spec/dummy/log/.gitkeep +0 -0
  73. data/spec/dummy/public/404.html +26 -0
  74. data/spec/dummy/public/422.html +26 -0
  75. data/spec/dummy/public/500.html +25 -0
  76. data/spec/dummy/public/favicon.ico +0 -0
  77. data/spec/dummy/script/rails +6 -0
  78. data/spec/dummy/spec/decorators/post_decorator_spec.rb +23 -0
  79. data/spec/dummy/spec/mailers/post_mailer_spec.rb +29 -0
  80. data/spec/dummy/spec/spec_helper.rb +9 -0
  81. data/spec/generators/decorator/decorator_generator_spec.rb +24 -5
  82. data/spec/integration/integration_spec.rb +33 -0
  83. data/spec/minitest-rails/spec_type_spec.rb +63 -0
  84. data/{performance → spec/performance}/decorators.rb +2 -4
  85. data/spec/spec_helper.rb +23 -26
  86. data/spec/support/action_controller.rb +12 -0
  87. data/spec/support/active_model.rb +7 -0
  88. data/spec/support/{samples/active_record.rb → active_record.rb} +5 -0
  89. data/spec/support/{samples → decorators}/decorator_with_application_helper.rb +1 -1
  90. data/spec/support/decorators/namespaced_product_decorator.rb +5 -0
  91. data/spec/support/decorators/non_active_model_product_decorator.rb +2 -0
  92. data/spec/support/decorators/product_decorator.rb +19 -0
  93. data/spec/support/decorators/products_decorator.rb +10 -0
  94. data/spec/support/decorators/some_thing_decorator.rb +2 -0
  95. data/spec/support/{samples → decorators}/specific_product_decorator.rb +0 -2
  96. data/spec/support/dummy_app.rb +84 -0
  97. data/spec/support/matchers/have_text.rb +50 -0
  98. data/spec/support/{samples → models}/namespaced_product.rb +1 -3
  99. data/spec/support/{samples → models}/non_active_model_product.rb +1 -0
  100. data/spec/support/{samples → models}/product.rb +13 -2
  101. data/spec/support/models/some_thing.rb +5 -0
  102. data/spec/support/models/uninferrable_decorator_model.rb +3 -0
  103. metadata +207 -98
  104. data/doc/ApplicationDecorator.html +0 -147
  105. data/doc/Draper/AllHelpers.html +0 -256
  106. data/doc/Draper/Base.html +0 -1222
  107. data/doc/Draper/DecoratorGenerator.html +0 -216
  108. data/doc/Draper/LazyHelpers.html +0 -174
  109. data/doc/Draper/ModelSupport.html +0 -164
  110. data/doc/Draper/System.html +0 -179
  111. data/doc/Draper.html +0 -123
  112. data/doc/_index.html +0 -172
  113. data/doc/class_list.html +0 -47
  114. data/doc/css/common.css +0 -1
  115. data/doc/css/full_list.css +0 -53
  116. data/doc/css/style.css +0 -320
  117. data/doc/file_list.html +0 -46
  118. data/doc/frames.html +0 -13
  119. data/doc/index.html +0 -172
  120. data/doc/js/app.js +0 -205
  121. data/doc/js/full_list.js +0 -150
  122. data/doc/js/jquery.js +0 -16
  123. data/doc/method_list.html +0 -174
  124. data/doc/top-level-namespace.html +0 -103
  125. data/lib/draper/active_model_support.rb +0 -27
  126. data/lib/draper/base.rb +0 -312
  127. data/lib/draper/decorated_enumerable_proxy.rb +0 -57
  128. data/lib/draper/model_support.rb +0 -17
  129. data/lib/draper/rspec_integration.rb +0 -2
  130. data/lib/draper/system.rb +0 -10
  131. data/lib/draper/test/view_context.rb +0 -12
  132. data/spec/draper/base_spec.rb +0 -863
  133. data/spec/draper/helper_support_spec.rb +0 -18
  134. data/spec/draper/model_support_spec.rb +0 -48
  135. data/spec/draper/view_context_spec.rb +0 -30
  136. data/spec/support/samples/active_model.rb +0 -9
  137. data/spec/support/samples/application_controller.rb +0 -42
  138. data/spec/support/samples/application_helper.rb +0 -8
  139. data/spec/support/samples/decorator.rb +0 -5
  140. data/spec/support/samples/decorator_with_allows.rb +0 -3
  141. data/spec/support/samples/decorator_with_denies.rb +0 -3
  142. data/spec/support/samples/decorator_with_denies_all.rb +0 -3
  143. data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
  144. data/spec/support/samples/decorator_with_special_methods.rb +0 -13
  145. data/spec/support/samples/namespaced_product_decorator.rb +0 -7
  146. data/spec/support/samples/product_decorator.rb +0 -7
  147. data/spec/support/samples/sequel_product.rb +0 -13
  148. data/spec/support/samples/some_thing.rb +0 -2
  149. data/spec/support/samples/some_thing_decorator.rb +0 -3
  150. /data/{performance → spec/performance}/active_record.rb +0 -0
  151. /data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
  152. /data/{performance → spec/performance}/models.rb +0 -0
  153. /data/spec/support/{samples → decorators}/widget_decorator.rb +0 -0
  154. /data/spec/support/{samples → models}/widget.rb +0 -0
@@ -0,0 +1,497 @@
1
+ require 'spec_helper'
2
+
3
+ describe Draper::Decorator do
4
+ before { ApplicationController.new.view_context }
5
+ subject { decorator_class.new(source) }
6
+ let(:decorator_class) { Draper::Decorator }
7
+ let(:source) { Product.new }
8
+
9
+ describe "#initialize" do
10
+ it "sets the source" do
11
+ subject.source.should be source
12
+ end
13
+
14
+ it "stores options" do
15
+ decorator = decorator_class.new(source, some: "options")
16
+ decorator.options.should == {some: "options"}
17
+ end
18
+
19
+ context "when decorating an instance of itself" do
20
+ it "does not redecorate" do
21
+ decorator = ProductDecorator.new(source)
22
+ ProductDecorator.new(decorator).source.should be source
23
+ end
24
+
25
+ context "when options are supplied" do
26
+ it "overwrites existing options" do
27
+ decorator = ProductDecorator.new(source, role: :admin)
28
+ ProductDecorator.new(decorator, role: :user).options.should == {role: :user}
29
+ end
30
+ end
31
+
32
+ context "when no options are supplied" do
33
+ it "preserves existing options" do
34
+ decorator = ProductDecorator.new(source, role: :admin)
35
+ ProductDecorator.new(decorator).options.should == {role: :admin}
36
+ end
37
+ end
38
+ end
39
+
40
+ it "decorates other decorators" do
41
+ decorator = ProductDecorator.new(source)
42
+ SpecificProductDecorator.new(decorator).source.should be decorator
43
+ end
44
+
45
+ it "warns if target is already decorated with the same decorator class" do
46
+ warning_message = nil
47
+ Object.any_instance.stub(:warn) { |message| warning_message = message }
48
+
49
+ deep_decorator = SpecificProductDecorator.new(ProductDecorator.new(Product.new))
50
+ expect {
51
+ ProductDecorator.new(deep_decorator)
52
+ }.to change { warning_message }
53
+ warning_message.should =~ /ProductDecorator/
54
+ warning_message.should include caller(1).first
55
+ end
56
+ end
57
+
58
+ describe ".decorate_collection" do
59
+ subject { ProductDecorator.decorate_collection(source) }
60
+ let(:source) { [Product.new, Widget.new] }
61
+
62
+ it "returns a collection decorator" do
63
+ subject.should be_a Draper::CollectionDecorator
64
+ subject.source.should be source
65
+ end
66
+
67
+ it "uses itself as the item decorator by default" do
68
+ subject.each {|item| item.should be_a ProductDecorator}
69
+ end
70
+
71
+ context "when given :with => :infer" do
72
+ subject { ProductDecorator.decorate_collection(source, with: :infer) }
73
+
74
+ it "infers the item decorators" do
75
+ subject.first.should be_a ProductDecorator
76
+ subject.last.should be_a WidgetDecorator
77
+ end
78
+ end
79
+
80
+ context "with options" do
81
+ subject { ProductDecorator.decorate_collection(source, with: :infer, some: "options") }
82
+
83
+ it "passes the options to the collection decorator" do
84
+ subject.options.should == {some: "options"}
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "#helpers" do
90
+ it "returns a HelperProxy" do
91
+ subject.helpers.should be_a Draper::HelperProxy
92
+ end
93
+
94
+ it "is aliased to #h" do
95
+ subject.h.should be subject.helpers
96
+ end
97
+
98
+ it "initializes the wrapper only once" do
99
+ helper_proxy = subject.helpers
100
+ helper_proxy.stub(:test_method) { "test_method" }
101
+ subject.helpers.test_method.should == "test_method"
102
+ subject.helpers.test_method.should == "test_method"
103
+ end
104
+ end
105
+
106
+ describe "#localize" do
107
+ before { subject.helpers.should_receive(:localize).with(:an_object, {some: "options"}) }
108
+
109
+ it "delegates to #helpers" do
110
+ subject.localize(:an_object, some: "options")
111
+ end
112
+
113
+ it "is aliased to #l" do
114
+ subject.l(:an_object, some: "options")
115
+ end
116
+ end
117
+
118
+ describe ".helpers" do
119
+ it "returns a HelperProxy" do
120
+ subject.class.helpers.should be_a Draper::HelperProxy
121
+ end
122
+
123
+ it "is aliased to .h" do
124
+ subject.class.h.should be subject.class.helpers
125
+ end
126
+ end
127
+
128
+ describe ".decorates_association" do
129
+ let(:decorator_class) { Class.new(ProductDecorator) }
130
+ before { decorator_class.decorates_association :similar_products, with: ProductDecorator }
131
+
132
+ describe "overridden association method" do
133
+ let(:decorated_association) { ->{} }
134
+
135
+ it "creates a DecoratedAssociation" do
136
+ Draper::DecoratedAssociation.should_receive(:new).with(source, :similar_products, {with: ProductDecorator}).and_return(decorated_association)
137
+ subject.similar_products
138
+ end
139
+
140
+ it "memoizes the DecoratedAssociation" do
141
+ Draper::DecoratedAssociation.should_receive(:new).once.and_return(decorated_association)
142
+ subject.similar_products
143
+ subject.similar_products
144
+ end
145
+
146
+ it "calls the DecoratedAssociation" do
147
+ Draper::DecoratedAssociation.stub(:new).and_return(decorated_association)
148
+ decorated_association.should_receive(:call).and_return(:decorated)
149
+ subject.similar_products.should be :decorated
150
+ end
151
+ end
152
+ end
153
+
154
+ describe ".decorates_associations" do
155
+ subject { decorator_class }
156
+
157
+ it "decorates each of the associations" do
158
+ subject.should_receive(:decorates_association).with(:similar_products, {})
159
+ subject.should_receive(:decorates_association).with(:previous_version, {})
160
+
161
+ subject.decorates_associations :similar_products, :previous_version
162
+ end
163
+
164
+ it "dispatches options" do
165
+ subject.should_receive(:decorates_association).with(:similar_products, {with: ProductDecorator})
166
+ subject.should_receive(:decorates_association).with(:previous_version, {with: ProductDecorator})
167
+
168
+ subject.decorates_associations :similar_products, :previous_version, with: ProductDecorator
169
+ end
170
+ end
171
+
172
+ describe "#applied_decorators" do
173
+ it "returns a list of decorators applied to a model" do
174
+ decorator = ProductDecorator.new(SpecificProductDecorator.new(Product.new))
175
+ decorator.applied_decorators.should == [SpecificProductDecorator, ProductDecorator]
176
+ end
177
+ end
178
+
179
+ describe "#decorated_with?" do
180
+ it "checks if a decorator has been applied to a model" do
181
+ decorator = ProductDecorator.new(SpecificProductDecorator.new(Product.new))
182
+ decorator.should be_decorated_with ProductDecorator
183
+ decorator.should be_decorated_with SpecificProductDecorator
184
+ decorator.should_not be_decorated_with WidgetDecorator
185
+ end
186
+ end
187
+
188
+ describe "#decorated?" do
189
+ it "returns true" do
190
+ subject.should be_decorated
191
+ end
192
+ end
193
+
194
+ describe "#source" do
195
+ it "returns the wrapped object" do
196
+ subject.source.should be source
197
+ end
198
+
199
+ it "is aliased to #to_source" do
200
+ subject.to_source.should be source
201
+ end
202
+
203
+ it "is aliased to #model" do
204
+ subject.model.should be source
205
+ end
206
+ end
207
+
208
+ describe "#to_model" do
209
+ it "returns the decorator" do
210
+ subject.to_model.should be subject
211
+ end
212
+ end
213
+
214
+ describe "#to_param" do
215
+ it "proxies to the source" do
216
+ source.stub(:to_param).and_return(42)
217
+ subject.to_param.should == 42
218
+ end
219
+ end
220
+
221
+ describe "#==" do
222
+ context "with itself" do
223
+ it "returns true" do
224
+ (subject == subject).should be_true
225
+ end
226
+ end
227
+
228
+ context "with another decorator having the same source" do
229
+ it "returns true" do
230
+ (subject == ProductDecorator.new(source)).should be_true
231
+ end
232
+ end
233
+
234
+ context "with another decorator having a different source" do
235
+ it "returns false" do
236
+ (subject == ProductDecorator.new(Object.new)).should be_false
237
+ end
238
+ end
239
+
240
+ context "with the source object" do
241
+ it "returns true" do
242
+ (subject == source).should be_true
243
+ end
244
+ end
245
+
246
+ context "with another object" do
247
+ it "returns false" do
248
+ (subject == Object.new).should be_false
249
+ end
250
+ end
251
+ end
252
+
253
+ describe "#===" do
254
+ context "with itself" do
255
+ it "returns true" do
256
+ (subject === subject).should be_true
257
+ end
258
+ end
259
+
260
+ context "with another decorator having the same source" do
261
+ it "returns true" do
262
+ (subject === ProductDecorator.new(source)).should be_true
263
+ end
264
+ end
265
+
266
+ context "with another decorator having a different source" do
267
+ it "returns false" do
268
+ (subject === ProductDecorator.new(Object.new)).should be_false
269
+ end
270
+ end
271
+
272
+ context "with the source object" do
273
+ it "returns true" do
274
+ (subject === source).should be_true
275
+ end
276
+ end
277
+
278
+ context "with another object" do
279
+ it "returns false" do
280
+ (subject === Object.new).should be_false
281
+ end
282
+ end
283
+ end
284
+
285
+ describe "#respond_to?" do
286
+ let(:decorator_class) { Class.new(ProductDecorator) }
287
+
288
+ it "returns true for its own methods" do
289
+ subject.should respond_to :awesome_title
290
+ end
291
+
292
+ it "returns true for the source's methods" do
293
+ subject.should respond_to :title
294
+ end
295
+
296
+ context "with include_private" do
297
+ it "returns true for its own private methods" do
298
+ subject.respond_to?(:awesome_private_title, true).should be_true
299
+ end
300
+
301
+ it "returns true for the source's private methods" do
302
+ subject.respond_to?(:private_title, true).should be_true
303
+ end
304
+ end
305
+
306
+ context "with method security" do
307
+ it "respects allows" do
308
+ subject.class.allows :hello_world
309
+
310
+ subject.should respond_to :hello_world
311
+ subject.should_not respond_to :goodnight_moon
312
+ end
313
+
314
+ it "respects denies" do
315
+ subject.class.denies :goodnight_moon
316
+
317
+ subject.should respond_to :hello_world
318
+ subject.should_not respond_to :goodnight_moon
319
+ end
320
+
321
+ it "respects denies_all" do
322
+ subject.class.denies_all
323
+
324
+ subject.should_not respond_to :hello_world
325
+ subject.should_not respond_to :goodnight_moon
326
+ end
327
+ end
328
+ end
329
+
330
+ describe "method proxying" do
331
+ let(:decorator_class) { Class.new(ProductDecorator) }
332
+
333
+ it "does not proxy methods that are defined on the decorator" do
334
+ subject.overridable.should be :overridden
335
+ end
336
+
337
+ it "does not proxy methods inherited from Object" do
338
+ subject.inspect.should_not be source.inspect
339
+ end
340
+
341
+ it "proxies missing methods that exist on the source" do
342
+ source.stub(:hello_world).and_return(:proxied)
343
+ subject.hello_world.should be :proxied
344
+ end
345
+
346
+ it "adds proxied methods to the decorator when they are used" do
347
+ subject.methods.should_not include :hello_world
348
+ subject.hello_world
349
+ subject.methods.should include :hello_world
350
+ end
351
+
352
+ it "passes blocks to proxied methods" do
353
+ subject.block{"marker"}.should == "marker"
354
+ end
355
+
356
+ it "does not confuse Kernel#Array" do
357
+ Array(subject).should be_a Array
358
+ end
359
+
360
+ it "proxies delegated methods" do
361
+ subject.delegated_method.should == "Yay, delegation"
362
+ end
363
+
364
+ context "with method security" do
365
+ it "respects allows" do
366
+ source.stub(:hello_world, :goodnight_moon).and_return(:proxied)
367
+ subject.class.allows :hello_world
368
+
369
+ subject.hello_world.should be :proxied
370
+ expect{subject.goodnight_moon}.to raise_error NameError
371
+ end
372
+
373
+ it "respects denies" do
374
+ source.stub(:hello_world, :goodnight_moon).and_return(:proxied)
375
+ subject.class.denies :goodnight_moon
376
+
377
+ subject.hello_world.should be :proxied
378
+ expect{subject.goodnight_moon}.to raise_error NameError
379
+ end
380
+
381
+ it "respects denies_all" do
382
+ source.stub(:hello_world, :goodnight_moon).and_return(:proxied)
383
+ subject.class.denies_all
384
+
385
+ expect{subject.hello_world}.to raise_error NameError
386
+ expect{subject.goodnight_moon}.to raise_error NameError
387
+ end
388
+ end
389
+ end
390
+
391
+ describe "method security" do
392
+ subject(:decorator_class) { Draper::Decorator }
393
+ let(:security) { stub }
394
+ before { decorator_class.stub(:security).and_return(security) }
395
+
396
+ it "delegates .denies to Draper::Security" do
397
+ security.should_receive(:denies).with(:foo, :bar)
398
+ decorator_class.denies :foo, :bar
399
+ end
400
+
401
+ it "delegates .denies_all to Draper::Security" do
402
+ security.should_receive(:denies_all)
403
+ decorator_class.denies_all
404
+ end
405
+
406
+ it "delegates .allows to Draper::Security" do
407
+ security.should_receive(:allows).with(:foo, :bar)
408
+ decorator_class.allows :foo, :bar
409
+ end
410
+ end
411
+
412
+ context "in a Rails application" do
413
+ let(:decorator_class) { DecoratorWithApplicationHelper }
414
+
415
+ it "has access to ApplicationHelper helpers" do
416
+ subject.uses_hello_world.should == "Hello, World!"
417
+ end
418
+
419
+ it "is able to use the content_tag helper" do
420
+ subject.sample_content.to_s.should == "<span>Hello, World!</span>"
421
+ end
422
+
423
+ it "is able to use the link_to helper" do
424
+ subject.sample_link.should == "<a href=\"/World\">Hello</a>"
425
+ end
426
+
427
+ it "is able to use the truncate helper" do
428
+ subject.sample_truncate.should == "Once..."
429
+ end
430
+
431
+ it "is able to access html_escape, a private method" do
432
+ subject.sample_html_escaped_text.should == '&lt;script&gt;danger&lt;/script&gt;'
433
+ end
434
+ end
435
+
436
+ it "pretends to be the source class" do
437
+ subject.kind_of?(source.class).should be_true
438
+ subject.is_a?(source.class).should be_true
439
+ end
440
+
441
+ it "is still its own class" do
442
+ subject.kind_of?(subject.class).should be_true
443
+ subject.is_a?(subject.class).should be_true
444
+ end
445
+
446
+ describe ".has_finders" do
447
+ it "extends the Finders module" do
448
+ ProductDecorator.should be_a_kind_of Draper::Finders
449
+ end
450
+
451
+ context "with no options" do
452
+ it "infers the finder class" do
453
+ ProductDecorator.finder_class.should be Product
454
+ end
455
+
456
+ context "for a namespaced model" do
457
+ it "infers the finder class" do
458
+ Namespace::ProductDecorator.finder_class.should be Namespace::Product
459
+ end
460
+ end
461
+ end
462
+
463
+ context "with :for option" do
464
+ subject { Class.new(Draper::Decorator) }
465
+
466
+ context "with a symbol" do
467
+ it "sets the finder class" do
468
+ subject.has_finders for: :product
469
+ subject.finder_class.should be Product
470
+ end
471
+ end
472
+
473
+ context "with a string" do
474
+ it "sets the finder class" do
475
+ subject.has_finders for: "some_thing"
476
+ subject.finder_class.should be SomeThing
477
+ end
478
+ end
479
+
480
+ context "with a class" do
481
+ it "sets the finder_class" do
482
+ subject.has_finders for: Namespace::Product
483
+ subject.finder_class.should be Namespace::Product
484
+ end
485
+ end
486
+ end
487
+ end
488
+
489
+ describe "#serializable_hash" do
490
+ let(:decorator_class) { ProductDecorator }
491
+
492
+ it "serializes overridden attributes" do
493
+ subject.serializable_hash[:overridable].should be :overridden
494
+ end
495
+ end
496
+
497
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ describe Draper::Finders do
4
+ describe ".find" do
5
+ it "proxies to the model class" do
6
+ Product.should_receive(:find).with(1)
7
+ ProductDecorator.find(1)
8
+ end
9
+
10
+ it "decorates the result" do
11
+ found = Product.new
12
+ Product.stub(:find).and_return(found)
13
+ decorator = ProductDecorator.find(1)
14
+ decorator.should be_a ProductDecorator
15
+ decorator.source.should be found
16
+ end
17
+
18
+ it "passes options to the decorator" do
19
+ decorator = ProductDecorator.find(1, some: "options")
20
+ decorator.options.should == {some: "options"}
21
+ end
22
+ end
23
+
24
+ describe ".find_by_(x)" do
25
+ it "proxies to the model class" do
26
+ Product.should_receive(:find_by_name).with("apples")
27
+ ProductDecorator.find_by_name("apples")
28
+ end
29
+
30
+ it "decorates the result" do
31
+ found = Product.new
32
+ Product.stub(:find_by_name).and_return(found)
33
+ decorator = ProductDecorator.find_by_name("apples")
34
+ decorator.should be_a ProductDecorator
35
+ decorator.source.should be found
36
+ end
37
+
38
+ it "proxies complex finders" do
39
+ Product.should_receive(:find_by_name_and_size).with("apples", "large")
40
+ ProductDecorator.find_by_name_and_size("apples", "large")
41
+ end
42
+
43
+ it "proxies find_last_by_(x) finders" do
44
+ Product.should_receive(:find_last_by_name_and_size).with("apples", "large")
45
+ ProductDecorator.find_last_by_name_and_size("apples", "large")
46
+ end
47
+
48
+ it "proxies find_or_initialize_by_(x) finders" do
49
+ Product.should_receive(:find_or_initialize_by_name_and_size).with("apples", "large")
50
+ ProductDecorator.find_or_initialize_by_name_and_size("apples", "large")
51
+ end
52
+
53
+ it "proxies find_or_create_by_(x) finders" do
54
+ Product.should_receive(:find_or_create_by_name_and_size).with("apples", "large")
55
+ ProductDecorator.find_or_create_by_name_and_size("apples", "large")
56
+ end
57
+
58
+ it "passes options to the decorator" do
59
+ Product.should_receive(:find_by_name_and_size).with("apples", "large", {some: "options"})
60
+ decorator = ProductDecorator.find_by_name_and_size("apples", "large", some: "options")
61
+ decorator.options.should == {some: "options"}
62
+ end
63
+ end
64
+
65
+ describe ".find_all_by_" do
66
+ it "proxies to the model class" do
67
+ Product.should_receive(:find_all_by_name_and_size).with("apples", "large")
68
+ ProductDecorator.find_all_by_name_and_size("apples", "large")
69
+ end
70
+
71
+ it "decorates the result" do
72
+ found = [Product.new, Product.new]
73
+ Product.stub(:find_all_by_name).and_return(found)
74
+ decorator = ProductDecorator.find_all_by_name("apples")
75
+ decorator.should be_a Draper::CollectionDecorator
76
+ decorator.source.should be found
77
+ end
78
+ end
79
+
80
+ describe ".all" do
81
+ it "returns a decorated collection" do
82
+ collection = ProductDecorator.all
83
+ collection.should be_a Draper::CollectionDecorator
84
+ collection.first.should be_a ProductDecorator
85
+ end
86
+
87
+ it "passes options to the collection decorator" do
88
+ collection = ProductDecorator.all(some: "options")
89
+ collection.options.should == {some: "options"}
90
+ end
91
+ end
92
+
93
+ describe ".first" do
94
+ it "proxies to the model class" do
95
+ Product.should_receive(:first)
96
+ ProductDecorator.first
97
+ end
98
+
99
+ it "decorates the result" do
100
+ first = Product.new
101
+ Product.stub(:first).and_return(first)
102
+ decorator = ProductDecorator.first
103
+ decorator.should be_a ProductDecorator
104
+ decorator.source.should be first
105
+ end
106
+
107
+ it "passes options to the decorator" do
108
+ decorator = ProductDecorator.first(some: "options")
109
+ decorator.options.should == {some: "options"}
110
+ end
111
+ end
112
+
113
+ describe ".last" do
114
+ it "proxies to the model class" do
115
+ Product.should_receive(:last)
116
+ ProductDecorator.last
117
+ end
118
+
119
+ it "decorates the result" do
120
+ last = Product.new
121
+ Product.stub(:last).and_return(last)
122
+ decorator = ProductDecorator.last
123
+ decorator.should be_a ProductDecorator
124
+ decorator.source.should be last
125
+ end
126
+
127
+ it "passes options to the decorator" do
128
+ decorator = ProductDecorator.last(some: "options")
129
+ decorator.options.should == {some: "options"}
130
+ end
131
+ end
132
+
133
+ describe "scopes" do
134
+ it "proxies to the model class" do
135
+ Product.should_receive(:where).with({name: "apples"})
136
+ ProductDecorator.where(name: "apples")
137
+ end
138
+
139
+ it "doesn't decorate the result" do
140
+ found = [Product.new]
141
+ Product.stub(:where).and_return(found)
142
+ ProductDecorator.where(name: "apples").should be found
143
+ end
144
+ end
145
+
146
+ describe ".respond_to?" do
147
+ it "responds to the model's class methods" do
148
+ ProductDecorator.should respond_to :sample_class_method
149
+ end
150
+
151
+ it "responds to its own methods" do
152
+ ProductDecorator.should respond_to :my_class_method
153
+ end
154
+ end
155
+
156
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Draper::HelperProxy do
4
+ subject(:helper_proxy) { Draper::HelperProxy.new }
5
+ let(:view_context) { Object.new }
6
+ before { helper_proxy.stub(:view_context).and_return(view_context) }
7
+
8
+ it "proxies methods to the view context" do
9
+ view_context.should_receive(:foo).with("bar")
10
+ helper_proxy.foo("bar")
11
+ end
12
+ end