draper 1.0.0 → 1.1.0

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 (90) hide show
  1. data/CHANGELOG.md +3 -0
  2. data/CONTRIBUTING.md +5 -1
  3. data/Gemfile +23 -9
  4. data/README.md +144 -52
  5. data/Rakefile +1 -0
  6. data/draper.gemspec +1 -1
  7. data/lib/draper.rb +9 -6
  8. data/lib/draper/decoratable.rb +3 -7
  9. data/lib/draper/decoratable/equality.rb +14 -0
  10. data/lib/draper/decorator.rb +4 -7
  11. data/lib/draper/helper_proxy.rb +22 -3
  12. data/lib/draper/test/devise_helper.rb +18 -22
  13. data/lib/draper/test/rspec_integration.rb +4 -0
  14. data/lib/draper/test_case.rb +20 -0
  15. data/lib/draper/version.rb +1 -1
  16. data/lib/draper/view_context.rb +75 -13
  17. data/lib/draper/view_context/build_strategy.rb +48 -0
  18. data/lib/draper/view_helpers.rb +2 -2
  19. data/spec/draper/collection_decorator_spec.rb +169 -196
  20. data/spec/draper/decoratable/equality_spec.rb +10 -0
  21. data/spec/draper/decoratable_spec.rb +107 -132
  22. data/spec/draper/decorated_association_spec.rb +99 -96
  23. data/spec/draper/decorator_spec.rb +408 -434
  24. data/spec/draper/finders_spec.rb +160 -126
  25. data/spec/draper/helper_proxy_spec.rb +38 -8
  26. data/spec/draper/view_context/build_strategy_spec.rb +116 -0
  27. data/spec/draper/view_context_spec.rb +154 -0
  28. data/spec/draper/view_helpers_spec.rb +4 -37
  29. data/spec/dummy/app/controllers/posts_controller.rb +7 -0
  30. data/spec/dummy/app/decorators/post_decorator.rb +26 -2
  31. data/spec/dummy/app/helpers/application_helper.rb +3 -0
  32. data/spec/dummy/app/mailers/post_mailer.rb +10 -0
  33. data/spec/dummy/app/models/admin.rb +5 -0
  34. data/spec/dummy/app/models/mongoid_post.rb +5 -0
  35. data/spec/dummy/app/models/user.rb +5 -0
  36. data/spec/dummy/app/views/posts/_post.html.erb +15 -0
  37. data/spec/dummy/bin/rails +4 -0
  38. data/spec/dummy/config/application.rb +9 -3
  39. data/spec/dummy/config/boot.rb +2 -7
  40. data/spec/dummy/config/environments/development.rb +2 -3
  41. data/spec/dummy/config/environments/production.rb +2 -0
  42. data/spec/dummy/config/environments/test.rb +3 -4
  43. data/spec/dummy/config/initializers/secret_token.rb +1 -0
  44. data/spec/dummy/config/mongoid.yml +80 -0
  45. data/spec/dummy/config/routes.rb +2 -0
  46. data/spec/dummy/fast_spec/post_decorator_spec.rb +38 -0
  47. data/spec/dummy/lib/tasks/test.rake +11 -5
  48. data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
  49. data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
  50. data/spec/dummy/spec/decorators/post_decorator_spec.rb +26 -6
  51. data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
  52. data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
  53. data/spec/dummy/spec/mailers/post_mailer_spec.rb +10 -6
  54. data/spec/dummy/spec/models/mongoid_post_spec.rb +10 -0
  55. data/spec/dummy/spec/models/post_spec.rb +5 -5
  56. data/spec/dummy/spec/spec_helper.rb +1 -0
  57. data/spec/dummy/test/decorators/minitest/devise_test.rb +64 -0
  58. data/spec/dummy/test/decorators/minitest/helpers_test.rb +21 -0
  59. data/spec/dummy/{mini_test/mini_test_integration_test.rb → test/decorators/minitest/spec_type_test.rb} +9 -3
  60. data/spec/dummy/test/decorators/minitest/view_context_test.rb +24 -0
  61. data/spec/dummy/test/decorators/test_unit/devise_test.rb +64 -0
  62. data/spec/dummy/test/decorators/test_unit/helpers_test.rb +21 -0
  63. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +24 -0
  64. data/spec/dummy/test/minitest_helper.rb +4 -0
  65. data/spec/dummy/test/test_helper.rb +3 -0
  66. data/spec/generators/decorator/decorator_generator_spec.rb +1 -0
  67. data/spec/integration/integration_spec.rb +31 -6
  68. data/spec/spec_helper.rb +32 -25
  69. data/spec/support/shared_examples/decoratable_equality.rb +40 -0
  70. data/spec/support/shared_examples/view_helpers.rb +39 -0
  71. metadata +56 -44
  72. data/spec/dummy/README.rdoc +0 -261
  73. data/spec/dummy/spec/decorators/rspec_integration_spec.rb +0 -19
  74. data/spec/support/action_controller.rb +0 -12
  75. data/spec/support/active_model.rb +0 -7
  76. data/spec/support/active_record.rb +0 -9
  77. data/spec/support/decorators/decorator_with_application_helper.rb +0 -25
  78. data/spec/support/decorators/namespaced_product_decorator.rb +0 -5
  79. data/spec/support/decorators/non_active_model_product_decorator.rb +0 -2
  80. data/spec/support/decorators/product_decorator.rb +0 -23
  81. data/spec/support/decorators/products_decorator.rb +0 -10
  82. data/spec/support/decorators/some_thing_decorator.rb +0 -2
  83. data/spec/support/decorators/specific_product_decorator.rb +0 -2
  84. data/spec/support/decorators/widget_decorator.rb +0 -2
  85. data/spec/support/models/namespaced_product.rb +0 -49
  86. data/spec/support/models/non_active_model_product.rb +0 -3
  87. data/spec/support/models/product.rb +0 -95
  88. data/spec/support/models/some_thing.rb +0 -5
  89. data/spec/support/models/uninferrable_decorator_model.rb +0 -3
  90. data/spec/support/models/widget.rb +0 -2
@@ -1,132 +1,166 @@
1
1
  require 'spec_helper'
2
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)
3
+ module Draper
4
+ describe Finders do
5
+ protect_class ProductDecorator
6
+ before { ProductDecorator.decorates_finders }
7
+
8
+ describe ".find" do
9
+ it "proxies to the model class" do
10
+ Product.should_receive(:find).with(1)
11
+ ProductDecorator.find(1)
12
+ end
13
+
14
+ it "decorates the result" do
15
+ found = Product.new
16
+ Product.stub(:find).and_return(found)
17
+ decorator = ProductDecorator.find(1)
18
+ expect(decorator).to be_a ProductDecorator
19
+ expect(decorator.source).to be found
20
+ end
21
+
22
+ it "passes context to the decorator" do
23
+ Product.stub(:find)
24
+ context = {some: "context"}
25
+ decorator = ProductDecorator.find(1, context: context)
26
+
27
+ expect(decorator.context).to be context
28
+ end
29
+ end
30
+
31
+ describe ".find_by_(x)" do
32
+ it "proxies to the model class" do
33
+ Product.should_receive(:find_by_name).with("apples")
34
+ ProductDecorator.find_by_name("apples")
35
+ end
36
+
37
+ it "decorates the result" do
38
+ found = Product.new
39
+ Product.stub(:find_by_name).and_return(found)
40
+ decorator = ProductDecorator.find_by_name("apples")
41
+ expect(decorator).to be_a ProductDecorator
42
+ expect(decorator.source).to be found
43
+ end
44
+
45
+ it "proxies complex ProductDecorators" do
46
+ Product.should_receive(:find_by_name_and_size).with("apples", "large")
47
+ ProductDecorator.find_by_name_and_size("apples", "large")
48
+ end
49
+
50
+ it "proxies find_last_by_(x) ProductDecorators" do
51
+ Product.should_receive(:find_last_by_name_and_size).with("apples", "large")
52
+ ProductDecorator.find_last_by_name_and_size("apples", "large")
53
+ end
54
+
55
+ it "proxies find_or_initialize_by_(x) ProductDecorators" do
56
+ Product.should_receive(:find_or_initialize_by_name_and_size).with("apples", "large")
57
+ ProductDecorator.find_or_initialize_by_name_and_size("apples", "large")
58
+ end
59
+
60
+ it "proxies find_or_create_by_(x) ProductDecorators" do
61
+ Product.should_receive(:find_or_create_by_name_and_size).with("apples", "large")
62
+ ProductDecorator.find_or_create_by_name_and_size("apples", "large")
63
+ end
64
+
65
+ it "passes context to the decorator" do
66
+ Product.stub(:find_by_name_and_size)
67
+ context = {some: "context"}
68
+ decorator = ProductDecorator.find_by_name_and_size("apples", "large", context: context)
69
+
70
+ expect(decorator.context).to be context
71
+ end
72
+ end
73
+
74
+ describe ".find_all_by_" do
75
+ it "proxies to the model class" do
76
+ Product.should_receive(:find_all_by_name_and_size).with("apples", "large").and_return([])
77
+ ProductDecorator.find_all_by_name_and_size("apples", "large")
78
+ end
79
+
80
+ it "decorates the result" do
81
+ found = [Product.new, Product.new]
82
+ Product.stub(:find_all_by_name).and_return(found)
83
+ decorator = ProductDecorator.find_all_by_name("apples")
84
+
85
+ expect(decorator).to be_a Draper::CollectionDecorator
86
+ expect(decorator.decorator_class).to be ProductDecorator
87
+ expect(decorator).to eq found
88
+ end
89
+
90
+ it "passes context to the decorator" do
91
+ Product.stub(:find_all_by_name)
92
+ context = {some: "context"}
93
+ decorator = ProductDecorator.find_all_by_name("apples", context: context)
94
+
95
+ expect(decorator.context).to be context
96
+ end
97
+ end
98
+
99
+ describe ".all" do
100
+ it "returns a decorated collection" do
101
+ found = [Product.new, Product.new]
102
+ Product.stub all: found
103
+ decorator = ProductDecorator.all
104
+
105
+ expect(decorator).to be_a Draper::CollectionDecorator
106
+ expect(decorator.decorator_class).to be ProductDecorator
107
+ expect(decorator).to eq found
108
+ end
109
+
110
+ it "passes context to the decorator" do
111
+ Product.stub(:all)
112
+ context = {some: "context"}
113
+ decorator = ProductDecorator.all(context: context)
114
+
115
+ expect(decorator.context).to be context
116
+ end
117
+ end
118
+
119
+ describe ".first" do
120
+ it "proxies to the model class" do
121
+ Product.should_receive(:first)
122
+ ProductDecorator.first
123
+ end
124
+
125
+ it "decorates the result" do
126
+ first = Product.new
127
+ Product.stub(:first).and_return(first)
128
+ decorator = ProductDecorator.first
129
+ expect(decorator).to be_a ProductDecorator
130
+ expect(decorator.source).to be first
131
+ end
132
+
133
+ it "passes context to the decorator" do
134
+ Product.stub(:first)
135
+ context = {some: "context"}
136
+ decorator = ProductDecorator.first(context: context)
137
+
138
+ expect(decorator.context).to be context
139
+ end
140
+ end
141
+
142
+ describe ".last" do
143
+ it "proxies to the model class" do
144
+ Product.should_receive(:last)
145
+ ProductDecorator.last
146
+ end
147
+
148
+ it "decorates the result" do
149
+ last = Product.new
150
+ Product.stub(:last).and_return(last)
151
+ decorator = ProductDecorator.last
152
+ expect(decorator).to be_a ProductDecorator
153
+ expect(decorator.source).to be last
154
+ end
155
+
156
+ it "passes context to the decorator" do
157
+ Product.stub(:last)
158
+ context = {some: "context"}
159
+ decorator = ProductDecorator.last(context: context)
160
+
161
+ expect(decorator.context).to be context
162
+ end
8
163
  end
9
164
 
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 context to the decorator" do
19
- decorator = ProductDecorator.find(1, context: {some: 'context'})
20
- decorator.context.should == {some: 'context'}
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 context to the decorator" do
59
- Product.should_receive(:find_by_name_and_size).with("apples", "large", context: {some: 'context'})
60
- decorator = ProductDecorator.find_by_name_and_size("apples", "large", context: {some: 'context'})
61
- decorator.context.should == {some: 'context'}
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").and_return([])
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.should == 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 context to the collection decorator" do
88
- collection = ProductDecorator.all(context: {some: 'context'})
89
- collection.context.should == {some: 'context'}
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 context to the decorator" do
108
- decorator = ProductDecorator.first(context: {some: 'context'})
109
- decorator.context.should == {some: 'context'}
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 context to the decorator" do
128
- decorator = ProductDecorator.last(context: {some: 'context'})
129
- decorator.context.should == {some: 'context'}
130
- end
131
165
  end
132
166
  end
@@ -1,12 +1,42 @@
1
1
  require 'spec_helper'
2
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")
3
+ module Draper
4
+ describe HelperProxy do
5
+ describe "#initialize" do
6
+ it "sets the view context" do
7
+ view_context = double
8
+ helper_proxy = HelperProxy.new(view_context)
9
+
10
+ expect(helper_proxy.send(:view_context)).to be view_context
11
+ end
12
+ end
13
+
14
+ describe "#method_missing" do
15
+ protect_class HelperProxy
16
+
17
+ it "proxies methods to the view context" do
18
+ view_context = double
19
+ helper_proxy = HelperProxy.new(view_context)
20
+
21
+ view_context.stub(:foo).and_return{|arg| arg}
22
+ expect(helper_proxy.foo(:passed)).to be :passed
23
+ end
24
+
25
+ it "passes blocks" do
26
+ view_context = double
27
+ helper_proxy = HelperProxy.new(view_context)
28
+
29
+ view_context.stub(:foo).and_return{|&block| block.call}
30
+ expect(helper_proxy.foo{:yielded}).to be :yielded
31
+ end
32
+
33
+ it "defines the method for better performance" do
34
+ helper_proxy = HelperProxy.new(double(foo: "bar"))
35
+
36
+ expect(HelperProxy.instance_methods).not_to include :foo
37
+ helper_proxy.foo
38
+ expect(HelperProxy.instance_methods).to include :foo
39
+ end
40
+ end
11
41
  end
12
42
  end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ def fake_view_context
4
+ double("ViewContext")
5
+ end
6
+
7
+ def fake_controller(view_context = fake_view_context)
8
+ double("Controller", view_context: view_context, request: double("Request"))
9
+ end
10
+
11
+ module Draper
12
+ describe ViewContext::BuildStrategy::Full do
13
+ describe "#call" do
14
+ context "when a current controller is set" do
15
+ it "returns the controller's view context" do
16
+ view_context = fake_view_context
17
+ ViewContext.stub controller: fake_controller(view_context)
18
+ strategy = ViewContext::BuildStrategy::Full.new
19
+
20
+ expect(strategy.call).to be view_context
21
+ end
22
+ end
23
+
24
+ context "when a current controller is not set" do
25
+ it "uses ApplicationController" do
26
+ view_context = fake_view_context
27
+ stub_const "ApplicationController", double(new: fake_controller(view_context))
28
+ strategy = ViewContext::BuildStrategy::Full.new
29
+
30
+ expect(strategy.call).to be view_context
31
+ end
32
+ end
33
+
34
+ it "adds a request if one is not defined" do
35
+ controller = Class.new(ActionController::Base).new
36
+ ViewContext.stub controller: controller
37
+ strategy = ViewContext::BuildStrategy::Full.new
38
+
39
+ expect(controller.request).to be_nil
40
+ strategy.call
41
+ expect(controller.request).to be_an ActionController::TestRequest
42
+ expect(controller.params).to eq({})
43
+
44
+ # sanity checks
45
+ expect(controller.view_context.request).to be controller.request
46
+ expect(controller.view_context.params).to be controller.params
47
+ end
48
+
49
+ it "adds methods to the view context from the constructor block" do
50
+ ViewContext.stub controller: fake_controller
51
+ strategy = ViewContext::BuildStrategy::Full.new do
52
+ def a_helper_method; end
53
+ end
54
+
55
+ expect(strategy.call).to respond_to :a_helper_method
56
+ end
57
+
58
+ it "includes modules into the view context from the constructor block" do
59
+ view_context = Object.new
60
+ ViewContext.stub controller: fake_controller(view_context)
61
+ helpers = Module.new do
62
+ def a_helper_method; end
63
+ end
64
+ strategy = ViewContext::BuildStrategy::Full.new do
65
+ include helpers
66
+ end
67
+
68
+ expect(strategy.call).to respond_to :a_helper_method
69
+ end
70
+ end
71
+ end
72
+
73
+ describe ViewContext::BuildStrategy::Fast do
74
+ describe "#call" do
75
+ it "returns an instance of a subclass of ActionView::Base" do
76
+ strategy = ViewContext::BuildStrategy::Fast.new
77
+
78
+ returned = strategy.call
79
+
80
+ expect(returned).to be_an ActionView::Base
81
+ expect(returned.class).not_to be ActionView::Base
82
+ end
83
+
84
+ it "returns different instances each time" do
85
+ strategy = ViewContext::BuildStrategy::Fast.new
86
+
87
+ expect(strategy.call).not_to be strategy.call
88
+ end
89
+
90
+ it "returns the same subclass each time" do
91
+ strategy = ViewContext::BuildStrategy::Fast.new
92
+
93
+ expect(strategy.call.class).to be strategy.call.class
94
+ end
95
+
96
+ it "adds methods to the view context from the constructor block" do
97
+ strategy = ViewContext::BuildStrategy::Fast.new do
98
+ def a_helper_method; end
99
+ end
100
+
101
+ expect(strategy.call).to respond_to :a_helper_method
102
+ end
103
+
104
+ it "includes modules into the view context from the constructor block" do
105
+ helpers = Module.new do
106
+ def a_helper_method; end
107
+ end
108
+ strategy = ViewContext::BuildStrategy::Fast.new do
109
+ include helpers
110
+ end
111
+
112
+ expect(strategy.call).to respond_to :a_helper_method
113
+ end
114
+ end
115
+ end
116
+ end