drape 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 (181) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +27 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +1159 -0
  6. data/.travis.yml +14 -0
  7. data/.yardopts +1 -0
  8. data/CHANGELOG.md +230 -0
  9. data/CONTRIBUTING.md +20 -0
  10. data/Gemfile +16 -0
  11. data/Guardfile +26 -0
  12. data/LICENSE +7 -0
  13. data/README.md +592 -0
  14. data/Rakefile +76 -0
  15. data/drape.gemspec +31 -0
  16. data/gemfiles/5.0.gemfile +8 -0
  17. data/lib/drape.rb +63 -0
  18. data/lib/drape/automatic_delegation.rb +55 -0
  19. data/lib/drape/collection_decorator.rb +102 -0
  20. data/lib/drape/decoratable.rb +93 -0
  21. data/lib/drape/decoratable/equality.rb +26 -0
  22. data/lib/drape/decorated_association.rb +33 -0
  23. data/lib/drape/decorates_assigned.rb +44 -0
  24. data/lib/drape/decorator.rb +282 -0
  25. data/lib/drape/delegation.rb +13 -0
  26. data/lib/drape/factory.rb +91 -0
  27. data/lib/drape/finders.rb +36 -0
  28. data/lib/drape/helper_proxy.rb +43 -0
  29. data/lib/drape/helper_support.rb +5 -0
  30. data/lib/drape/lazy_helpers.rb +13 -0
  31. data/lib/drape/railtie.rb +69 -0
  32. data/lib/drape/tasks/test.rake +9 -0
  33. data/lib/drape/test/devise_helper.rb +30 -0
  34. data/lib/drape/test/minitest_integration.rb +6 -0
  35. data/lib/drape/test/rspec_integration.rb +20 -0
  36. data/lib/drape/test_case.rb +42 -0
  37. data/lib/drape/undecorate.rb +9 -0
  38. data/lib/drape/version.rb +3 -0
  39. data/lib/drape/view_context.rb +104 -0
  40. data/lib/drape/view_context/build_strategy.rb +46 -0
  41. data/lib/drape/view_helpers.rb +34 -0
  42. data/lib/generators/controller_override.rb +17 -0
  43. data/lib/generators/mini_test/decorator_generator.rb +20 -0
  44. data/lib/generators/mini_test/templates/decorator_spec.rb +4 -0
  45. data/lib/generators/mini_test/templates/decorator_test.rb +4 -0
  46. data/lib/generators/rails/decorator_generator.rb +36 -0
  47. data/lib/generators/rails/templates/decorator.rb +19 -0
  48. data/lib/generators/rspec/decorator_generator.rb +9 -0
  49. data/lib/generators/rspec/templates/decorator_spec.rb +4 -0
  50. data/lib/generators/test_unit/decorator_generator.rb +9 -0
  51. data/lib/generators/test_unit/templates/decorator_test.rb +4 -0
  52. data/spec/draper/collection_decorator_spec.rb +305 -0
  53. data/spec/draper/decoratable/equality_spec.rb +10 -0
  54. data/spec/draper/decoratable_spec.rb +203 -0
  55. data/spec/draper/decorated_association_spec.rb +85 -0
  56. data/spec/draper/decorates_assigned_spec.rb +70 -0
  57. data/spec/draper/decorator_spec.rb +828 -0
  58. data/spec/draper/factory_spec.rb +250 -0
  59. data/spec/draper/finders_spec.rb +165 -0
  60. data/spec/draper/helper_proxy_spec.rb +61 -0
  61. data/spec/draper/lazy_helpers_spec.rb +21 -0
  62. data/spec/draper/undecorate_spec.rb +19 -0
  63. data/spec/draper/view_context/build_strategy_spec.rb +116 -0
  64. data/spec/draper/view_context_spec.rb +160 -0
  65. data/spec/draper/view_helpers_spec.rb +8 -0
  66. data/spec/dummy/.gitignore +21 -0
  67. data/spec/dummy/Rakefile +6 -0
  68. data/spec/dummy/app/assets/config/manifest.js +3 -0
  69. data/spec/dummy/app/assets/images/.keep +0 -0
  70. data/spec/dummy/app/assets/javascripts/application.js +16 -0
  71. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  72. data/spec/dummy/app/assets/javascripts/channels/.keep +0 -0
  73. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  74. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  75. data/spec/dummy/app/channels/application_cable/connection.rb +5 -0
  76. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  77. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  78. data/spec/dummy/app/controllers/posts_controller.rb +21 -0
  79. data/spec/dummy/app/decorators/mongoid_post_decorator.rb +4 -0
  80. data/spec/dummy/app/decorators/post_decorator.rb +59 -0
  81. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  82. data/spec/dummy/app/jobs/application_job.rb +2 -0
  83. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  84. data/spec/dummy/app/mailers/post_mailer.rb +18 -0
  85. data/spec/dummy/app/models/admin.rb +5 -0
  86. data/spec/dummy/app/models/application_record.rb +3 -0
  87. data/spec/dummy/app/models/concerns/.keep +0 -0
  88. data/spec/dummy/app/models/mongoid_post.rb +5 -0
  89. data/spec/dummy/app/models/post.rb +3 -0
  90. data/spec/dummy/app/models/user.rb +5 -0
  91. data/spec/dummy/app/views/layouts/application.html.erb +9 -0
  92. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  93. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  94. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +31 -0
  95. data/spec/dummy/app/views/posts/_post.html.erb +40 -0
  96. data/spec/dummy/app/views/posts/show.html.erb +1 -0
  97. data/spec/dummy/bin/bundle +3 -0
  98. data/spec/dummy/bin/rails +9 -0
  99. data/spec/dummy/bin/rake +9 -0
  100. data/spec/dummy/bin/setup +34 -0
  101. data/spec/dummy/bin/spring +15 -0
  102. data/spec/dummy/bin/update +29 -0
  103. data/spec/dummy/config.ru +5 -0
  104. data/spec/dummy/config/application.rb +21 -0
  105. data/spec/dummy/config/boot.rb +2 -0
  106. data/spec/dummy/config/cable.yml +10 -0
  107. data/spec/dummy/config/database.yml +25 -0
  108. data/spec/dummy/config/environment.rb +5 -0
  109. data/spec/dummy/config/environments/development.rb +51 -0
  110. data/spec/dummy/config/environments/production.rb +91 -0
  111. data/spec/dummy/config/environments/test.rb +42 -0
  112. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
  113. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  114. data/spec/dummy/config/initializers/assets.rb +11 -0
  115. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  116. data/spec/dummy/config/initializers/callback_terminator.rb +6 -0
  117. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  118. data/spec/dummy/config/initializers/devise.rb +3 -0
  119. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  120. data/spec/dummy/config/initializers/inflections.rb +16 -0
  121. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  122. data/spec/dummy/config/initializers/per_form_csrf_tokens.rb +4 -0
  123. data/spec/dummy/config/initializers/request_forgery_protection.rb +4 -0
  124. data/spec/dummy/config/initializers/session_store.rb +3 -0
  125. data/spec/dummy/config/initializers/ssl_options.rb +4 -0
  126. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  127. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  128. data/spec/dummy/config/locales/en.yml +23 -0
  129. data/spec/dummy/config/mongoid.yml +16 -0
  130. data/spec/dummy/config/puma.rb +47 -0
  131. data/spec/dummy/config/routes.rb +8 -0
  132. data/spec/dummy/config/secrets.yml +22 -0
  133. data/spec/dummy/config/spring.rb +6 -0
  134. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +7 -0
  135. data/spec/dummy/db/schema.rb +19 -0
  136. data/spec/dummy/db/seeds.rb +2 -0
  137. data/spec/dummy/lib/assets/.keep +0 -0
  138. data/spec/dummy/lib/tasks/.keep +0 -0
  139. data/spec/dummy/lib/tasks/test.rake +16 -0
  140. data/spec/dummy/log/.keep +0 -0
  141. data/spec/dummy/public/404.html +67 -0
  142. data/spec/dummy/public/422.html +67 -0
  143. data/spec/dummy/public/500.html +66 -0
  144. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  145. data/spec/dummy/public/apple-touch-icon.png +0 -0
  146. data/spec/dummy/public/favicon.ico +0 -0
  147. data/spec/dummy/public/robots.txt +5 -0
  148. data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +12 -0
  149. data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
  150. data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
  151. data/spec/dummy/spec/decorators/post_decorator_spec.rb +66 -0
  152. data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
  153. data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
  154. data/spec/dummy/spec/mailers/post_mailer_spec.rb +33 -0
  155. data/spec/dummy/spec/models/mongoid_post_spec.rb +8 -0
  156. data/spec/dummy/spec/models/post_spec.rb +6 -0
  157. data/spec/dummy/spec/shared_examples/decoratable.rb +26 -0
  158. data/spec/dummy/spec/spec_helper.rb +8 -0
  159. data/spec/dummy/test/controllers/.keep +0 -0
  160. data/spec/dummy/test/fixtures/.keep +0 -0
  161. data/spec/dummy/test/fixtures/files/.keep +0 -0
  162. data/spec/dummy/test/helpers/.keep +0 -0
  163. data/spec/dummy/test/integration/.keep +0 -0
  164. data/spec/dummy/test/mailers/.keep +0 -0
  165. data/spec/dummy/test/models/.keep +0 -0
  166. data/spec/dummy/test/test_helper.rb +10 -0
  167. data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
  168. data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
  169. data/spec/generators/controller/controller_generator_spec.rb +24 -0
  170. data/spec/generators/decorator/decorator_generator_spec.rb +94 -0
  171. data/spec/integration/integration_spec.rb +68 -0
  172. data/spec/performance/active_record.rb +4 -0
  173. data/spec/performance/benchmark.rb +57 -0
  174. data/spec/performance/decorators.rb +41 -0
  175. data/spec/performance/models.rb +20 -0
  176. data/spec/spec_helper.rb +41 -0
  177. data/spec/support/dummy_app.rb +88 -0
  178. data/spec/support/matchers/have_text.rb +50 -0
  179. data/spec/support/shared_examples/decoratable_equality.rb +40 -0
  180. data/spec/support/shared_examples/view_helpers.rb +39 -0
  181. metadata +497 -0
@@ -0,0 +1,34 @@
1
+ module Drape
2
+ # Provides the {#helpers} method used in {Decorator} and {CollectionDecorator}
3
+ # to call the Rails helpers.
4
+ module ViewHelpers
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ # Access the helpers proxy to call built-in and user-defined
9
+ # Rails helpers from a class context.
10
+ #
11
+ # @return [HelperProxy] the helpers proxy
12
+ def helpers
13
+ Drape::ViewContext.current
14
+ end
15
+ alias h helpers
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
+ Drape::ViewContext.current
24
+ end
25
+ alias h helpers
26
+
27
+ # Alias for `helpers.localize`, since localize is something that's used
28
+ # quite often. Further aliased to `l` for convenience.
29
+ def localize(*args)
30
+ helpers.localize(*args)
31
+ end
32
+ alias l localize
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/controller/controller_generator'
3
+ require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
4
+
5
+ module Rails
6
+ module Generators
7
+ class ControllerGenerator
8
+ hook_for :decorator, default: true do |generator|
9
+ invoke generator, [name.singularize]
10
+ end
11
+ end
12
+
13
+ class ScaffoldControllerGenerator
14
+ hook_for :decorator, default: true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'generators/mini_test'
2
+
3
+ module MiniTest
4
+ module Generators
5
+ class DecoratorGenerator < Base
6
+ def self.source_root
7
+ File.expand_path('../templates', __FILE__)
8
+ end
9
+
10
+ class_option :spec, type: :boolean, default: false, desc: 'Use MiniTest::Spec DSL'
11
+
12
+ check_class_collision suffix: 'DecoratorTest'
13
+
14
+ def create_test_file
15
+ template_type = options[:spec] ? 'spec' : 'test'
16
+ template "decorator_#{template_type}.rb", File.join('test/decorators', class_path, "#{singular_name}_decorator_test.rb")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ describe <%= class_name %>Decorator do
4
+ end
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ class <%= class_name %>DecoratorTest < Drape::TestCase
4
+ end
@@ -0,0 +1,36 @@
1
+ module Rails
2
+ module Generators
3
+ class DecoratorGenerator < NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ check_class_collision suffix: 'Decorator'
6
+
7
+ class_option :parent, type: :string, desc: 'The parent class for the generated decorator'
8
+
9
+ def create_decorator_file
10
+ template 'decorator.rb', File.join('app/decorators', class_path, "#{file_name}_decorator.rb")
11
+ end
12
+
13
+ hook_for :test_framework
14
+
15
+ private
16
+
17
+ def parent_class_name
18
+ options.fetch('parent') do
19
+ begin
20
+ require 'application_decorator'
21
+ ApplicationDecorator
22
+ rescue LoadError
23
+ 'Drape::Decorator'
24
+ end
25
+ end
26
+ end
27
+
28
+ # Rails 3.0.X compatibility, stolen from https://github.com/jnunemaker/mongomapper/pull/385/files#L1R32
29
+ unless methods.include?(:module_namespacing)
30
+ def module_namespacing
31
+ yield if block_given?
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ <%- module_namespacing do -%>
2
+ <%- if parent_class_name.present? -%>
3
+ class <%= class_name %>Decorator < <%= parent_class_name %>
4
+ <%- else -%>
5
+ class <%= class_name %>
6
+ <%- end -%>
7
+ delegate_all
8
+
9
+ # Define presentation-specific methods here. Helpers are accessed through
10
+ # `helpers` (aka `h`). You can override attributes, for example:
11
+ #
12
+ # def created_at
13
+ # helpers.content_tag :span, class: 'time' do
14
+ # object.created_at.strftime("%a %m/%d/%y")
15
+ # end
16
+ # end
17
+
18
+ end
19
+ <% end -%>
@@ -0,0 +1,9 @@
1
+ module Rspec
2
+ class DecoratorGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def create_spec_file
6
+ template 'decorator_spec.rb', File.join('spec/decorators', class_path, "#{singular_name}_decorator_spec.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= class_name %>Decorator do
4
+ end
@@ -0,0 +1,9 @@
1
+ module TestUnit
2
+ class DecoratorGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def create_test_file
6
+ template 'decorator_test.rb', File.join('test/decorators', class_path, "#{singular_name}_decorator_test.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ class <%= class_name %>DecoratorTest < Drape::TestCase
4
+ end
@@ -0,0 +1,305 @@
1
+ require 'spec_helper'
2
+ require 'support/shared_examples/view_helpers'
3
+
4
+ module Drape
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
+ decorator.should_not_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
+ Object.should_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
+ Object.should_receive(:delegate).with(:foo, :bar, to: :baz)
118
+ ProductsDecorator.delegate :foo, :bar, to: :baz
119
+ end
120
+ end
121
+
122
+ describe '#find' do
123
+ context 'with a block' do
124
+ it 'decorates Enumerable#find' do
125
+ decorator = CollectionDecorator.new([])
126
+
127
+ decorator.decorated_collection.should_receive(:find).and_return(:delegated)
128
+ expect(decorator.find { |p| p.title == 'title' }).to be :delegated
129
+ end
130
+ end
131
+
132
+ context 'without a block' do
133
+ it 'decorates object.find' do
134
+ object = []
135
+ found = double(decorate: :decorated)
136
+ decorator = CollectionDecorator.new(object)
137
+
138
+ object.should_receive(:find).and_return(found)
139
+ ActiveSupport::Deprecation.silence do
140
+ expect(decorator.find(1)).to be :decorated
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ describe '#to_ary' do
147
+ # required for `render @collection` in Rails
148
+ it 'delegates to the decorated collection' do
149
+ decorator = CollectionDecorator.new([])
150
+
151
+ decorator.decorated_collection.should_receive(:to_ary).and_return(:delegated)
152
+ expect(decorator.to_ary).to be :delegated
153
+ end
154
+ end
155
+
156
+ it 'delegates array methods to the decorated collection' do
157
+ decorator = CollectionDecorator.new([])
158
+
159
+ decorator.decorated_collection.should_receive(:[]).with(42).and_return(:delegated)
160
+ expect(decorator[42]).to be :delegated
161
+ end
162
+
163
+ describe '#==' do
164
+ context 'when comparing to a collection decorator with the same object' do
165
+ it 'returns true' do
166
+ object = [Product.new, Product.new]
167
+ decorator = CollectionDecorator.new(object)
168
+ other = ProductsDecorator.new(object)
169
+
170
+ expect(decorator == other).to be_truthy
171
+ end
172
+ end
173
+
174
+ context 'when comparing to a collection decorator with a different object' do
175
+ it 'returns false' do
176
+ decorator = CollectionDecorator.new([Product.new, Product.new])
177
+ other = ProductsDecorator.new([Product.new, Product.new])
178
+
179
+ expect(decorator == other).to be_falsey
180
+ end
181
+ end
182
+
183
+ context 'when comparing to a collection of the same items' do
184
+ it 'returns true' do
185
+ object = [Product.new, Product.new]
186
+ decorator = CollectionDecorator.new(object)
187
+ other = object.dup
188
+
189
+ expect(decorator == other).to be_truthy
190
+ end
191
+ end
192
+
193
+ context 'when comparing to a collection of different items' do
194
+ it 'returns false' do
195
+ decorator = CollectionDecorator.new([Product.new, Product.new])
196
+ other = [Product.new, Product.new]
197
+
198
+ expect(decorator == other).to be_falsey
199
+ end
200
+ end
201
+
202
+ context 'when the decorated collection has been modified' do
203
+ it 'is no longer equal to the object' do
204
+ object = [Product.new, Product.new]
205
+ decorator = CollectionDecorator.new(object)
206
+ other = object.dup
207
+
208
+ decorator << Product.new.decorate
209
+ expect(decorator == other).to be_falsey
210
+ end
211
+ end
212
+ end
213
+
214
+ describe '#to_s' do
215
+ context 'when :with option was given' do
216
+ it 'returns a string representation of the collection decorator' do
217
+ decorator = CollectionDecorator.new(['a', 'b', 'c'], with: ProductDecorator)
218
+
219
+ expect(decorator.to_s).to eq '#<Drape::CollectionDecorator of ProductDecorator for ["a", "b", "c"]>'
220
+ end
221
+ end
222
+
223
+ context 'when :with option was not given' do
224
+ it 'returns a string representation of the collection decorator' do
225
+ decorator = CollectionDecorator.new(['a', 'b', 'c'])
226
+
227
+ expect(decorator.to_s).to eq '#<Drape::CollectionDecorator of inferred decorators for ["a", "b", "c"]>'
228
+ end
229
+ end
230
+
231
+ context 'for a custom subclass' do
232
+ it 'uses the custom class name' do
233
+ decorator = ProductsDecorator.new([])
234
+
235
+ expect(decorator.to_s).to include('ProductsDecorator')
236
+ end
237
+ end
238
+ end
239
+
240
+ describe '#object' do
241
+ it 'returns the underlying collection' do
242
+ collection = [Product.new]
243
+ decorator = ProductsDecorator.new(collection)
244
+
245
+ expect(decorator.object).to eq collection
246
+ end
247
+ end
248
+
249
+ describe '#decorated?' do
250
+ it 'returns true' do
251
+ decorator = ProductsDecorator.new([Product.new])
252
+
253
+ expect(decorator).to be_decorated
254
+ end
255
+ end
256
+
257
+ describe '#decorated_with?' do
258
+ it 'checks if a decorator has been applied to a collection' do
259
+ decorator = ProductsDecorator.new([Product.new])
260
+
261
+ expect(decorator).to be_decorated_with ProductsDecorator
262
+ expect(decorator).not_to be_decorated_with OtherDecorator
263
+ end
264
+ end
265
+
266
+ describe '#kind_of?' do
267
+ it 'asks the kind of its decorated collection' do
268
+ decorator = ProductsDecorator.new([])
269
+ decorator.decorated_collection.should_receive(:kind_of?).with(Array).and_return('true')
270
+ expect(decorator.is_a?(Array)).to eq 'true'
271
+ end
272
+
273
+ context 'when asking the underlying collection returns false' do
274
+ it 'asks the CollectionDecorator instance itself' do
275
+ decorator = ProductsDecorator.new([])
276
+ decorator.decorated_collection.stub(:kind_of?).with(::Drape::CollectionDecorator).and_return(false)
277
+ expect(decorator.is_a?(::Drape::CollectionDecorator)).to be true
278
+ end
279
+ end
280
+ end
281
+
282
+ describe '#is_a?' do
283
+ it 'aliases to #kind_of?' do
284
+ decorator = ProductsDecorator.new([])
285
+ expect(decorator.method(:kind_of?)).to eq decorator.method(:is_a?)
286
+ end
287
+ end
288
+
289
+ describe '#replace' do
290
+ it 'replaces the decorated collection' do
291
+ decorator = CollectionDecorator.new([Product.new])
292
+ replacement = [:foo, :bar]
293
+
294
+ decorator.replace replacement
295
+ expect(decorator).to match_array replacement
296
+ end
297
+
298
+ it 'returns itself' do
299
+ decorator = CollectionDecorator.new([Product.new])
300
+
301
+ expect(decorator.replace([:foo, :bar])).to be decorator
302
+ end
303
+ end
304
+ end
305
+ end