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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +27 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1159 -0
- data/.travis.yml +14 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +230 -0
- data/CONTRIBUTING.md +20 -0
- data/Gemfile +16 -0
- data/Guardfile +26 -0
- data/LICENSE +7 -0
- data/README.md +592 -0
- data/Rakefile +76 -0
- data/drape.gemspec +31 -0
- data/gemfiles/5.0.gemfile +8 -0
- data/lib/drape.rb +63 -0
- data/lib/drape/automatic_delegation.rb +55 -0
- data/lib/drape/collection_decorator.rb +102 -0
- data/lib/drape/decoratable.rb +93 -0
- data/lib/drape/decoratable/equality.rb +26 -0
- data/lib/drape/decorated_association.rb +33 -0
- data/lib/drape/decorates_assigned.rb +44 -0
- data/lib/drape/decorator.rb +282 -0
- data/lib/drape/delegation.rb +13 -0
- data/lib/drape/factory.rb +91 -0
- data/lib/drape/finders.rb +36 -0
- data/lib/drape/helper_proxy.rb +43 -0
- data/lib/drape/helper_support.rb +5 -0
- data/lib/drape/lazy_helpers.rb +13 -0
- data/lib/drape/railtie.rb +69 -0
- data/lib/drape/tasks/test.rake +9 -0
- data/lib/drape/test/devise_helper.rb +30 -0
- data/lib/drape/test/minitest_integration.rb +6 -0
- data/lib/drape/test/rspec_integration.rb +20 -0
- data/lib/drape/test_case.rb +42 -0
- data/lib/drape/undecorate.rb +9 -0
- data/lib/drape/version.rb +3 -0
- data/lib/drape/view_context.rb +104 -0
- data/lib/drape/view_context/build_strategy.rb +46 -0
- data/lib/drape/view_helpers.rb +34 -0
- data/lib/generators/controller_override.rb +17 -0
- data/lib/generators/mini_test/decorator_generator.rb +20 -0
- data/lib/generators/mini_test/templates/decorator_spec.rb +4 -0
- data/lib/generators/mini_test/templates/decorator_test.rb +4 -0
- data/lib/generators/rails/decorator_generator.rb +36 -0
- data/lib/generators/rails/templates/decorator.rb +19 -0
- data/lib/generators/rspec/decorator_generator.rb +9 -0
- data/lib/generators/rspec/templates/decorator_spec.rb +4 -0
- data/lib/generators/test_unit/decorator_generator.rb +9 -0
- data/lib/generators/test_unit/templates/decorator_test.rb +4 -0
- data/spec/draper/collection_decorator_spec.rb +305 -0
- data/spec/draper/decoratable/equality_spec.rb +10 -0
- data/spec/draper/decoratable_spec.rb +203 -0
- data/spec/draper/decorated_association_spec.rb +85 -0
- data/spec/draper/decorates_assigned_spec.rb +70 -0
- data/spec/draper/decorator_spec.rb +828 -0
- data/spec/draper/factory_spec.rb +250 -0
- data/spec/draper/finders_spec.rb +165 -0
- data/spec/draper/helper_proxy_spec.rb +61 -0
- data/spec/draper/lazy_helpers_spec.rb +21 -0
- data/spec/draper/undecorate_spec.rb +19 -0
- data/spec/draper/view_context/build_strategy_spec.rb +116 -0
- data/spec/draper/view_context_spec.rb +160 -0
- data/spec/draper/view_helpers_spec.rb +8 -0
- data/spec/dummy/.gitignore +21 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/javascripts/channels/.keep +0 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +5 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/posts_controller.rb +21 -0
- data/spec/dummy/app/decorators/mongoid_post_decorator.rb +4 -0
- data/spec/dummy/app/decorators/post_decorator.rb +59 -0
- data/spec/dummy/app/helpers/application_helper.rb +5 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/mailers/post_mailer.rb +18 -0
- data/spec/dummy/app/models/admin.rb +5 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/mongoid_post.rb +5 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/views/layouts/application.html.erb +9 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +31 -0
- data/spec/dummy/app/views/posts/_post.html.erb +40 -0
- data/spec/dummy/app/views/posts/show.html.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +9 -0
- data/spec/dummy/bin/rake +9 -0
- data/spec/dummy/bin/setup +34 -0
- data/spec/dummy/bin/spring +15 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +21 -0
- data/spec/dummy/config/boot.rb +2 -0
- data/spec/dummy/config/cable.yml +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 +51 -0
- data/spec/dummy/config/environments/production.rb +91 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/callback_terminator.rb +6 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/devise.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/per_form_csrf_tokens.rb +4 -0
- data/spec/dummy/config/initializers/request_forgery_protection.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/ssl_options.rb +4 -0
- data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/mongoid.yml +16 -0
- data/spec/dummy/config/puma.rb +47 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +7 -0
- data/spec/dummy/db/schema.rb +19 -0
- data/spec/dummy/db/seeds.rb +2 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/lib/tasks/.keep +0 -0
- data/spec/dummy/lib/tasks/test.rake +16 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +12 -0
- data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
- data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +66 -0
- data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
- data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
- data/spec/dummy/spec/mailers/post_mailer_spec.rb +33 -0
- data/spec/dummy/spec/models/mongoid_post_spec.rb +8 -0
- data/spec/dummy/spec/models/post_spec.rb +6 -0
- data/spec/dummy/spec/shared_examples/decoratable.rb +26 -0
- data/spec/dummy/spec/spec_helper.rb +8 -0
- data/spec/dummy/test/controllers/.keep +0 -0
- data/spec/dummy/test/fixtures/.keep +0 -0
- data/spec/dummy/test/fixtures/files/.keep +0 -0
- data/spec/dummy/test/helpers/.keep +0 -0
- data/spec/dummy/test/integration/.keep +0 -0
- data/spec/dummy/test/mailers/.keep +0 -0
- data/spec/dummy/test/models/.keep +0 -0
- data/spec/dummy/test/test_helper.rb +10 -0
- data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
- data/spec/generators/controller/controller_generator_spec.rb +24 -0
- data/spec/generators/decorator/decorator_generator_spec.rb +94 -0
- data/spec/integration/integration_spec.rb +68 -0
- data/spec/performance/active_record.rb +4 -0
- data/spec/performance/benchmark.rb +57 -0
- data/spec/performance/decorators.rb +41 -0
- data/spec/performance/models.rb +20 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/dummy_app.rb +88 -0
- data/spec/support/matchers/have_text.rb +50 -0
- data/spec/support/shared_examples/decoratable_equality.rb +40 -0
- data/spec/support/shared_examples/view_helpers.rb +39 -0
- 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,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,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,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
|