draper 0.18.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.
- data/.gitignore +3 -0
- data/.travis.yml +11 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +164 -0
- data/CONTRIBUTING.md +15 -0
- data/Gemfile +34 -0
- data/LICENSE +7 -0
- data/README.md +416 -0
- data/Rakefile +53 -31
- data/draper.gemspec +11 -9
- data/lib/draper/automatic_delegation.rb +50 -0
- data/lib/draper/collection_decorator.rb +107 -0
- data/lib/draper/decoratable/equality.rb +14 -0
- data/lib/draper/decoratable.rb +79 -0
- data/lib/draper/decorated_association.rb +74 -0
- data/lib/draper/decorator.rb +235 -0
- data/lib/draper/delegation.rb +13 -0
- data/lib/draper/finders.rb +37 -0
- data/lib/draper/helper_proxy.rb +36 -0
- data/lib/draper/lazy_helpers.rb +10 -6
- data/lib/draper/railtie.rb +27 -21
- data/lib/draper/tasks/test.rake +22 -0
- data/lib/draper/test/devise_helper.rb +30 -0
- data/lib/draper/test/minitest_integration.rb +2 -3
- data/lib/draper/test/rspec_integration.rb +7 -13
- data/lib/draper/test_case.rb +53 -0
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context/build_strategy.rb +48 -0
- data/lib/draper/view_context.rb +81 -24
- data/lib/draper/view_helpers.rb +37 -0
- data/lib/draper.rb +50 -8
- data/lib/generators/decorator/decorator_generator.rb +10 -2
- data/lib/generators/decorator/templates/decorator.rb +12 -27
- 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/test_unit/templates/decorator_test.rb +1 -1
- data/spec/draper/collection_decorator_spec.rb +259 -0
- data/spec/draper/decoratable/equality_spec.rb +10 -0
- data/spec/draper/decoratable_spec.rb +167 -0
- data/spec/draper/decorated_association_spec.rb +145 -0
- data/spec/draper/decorator_spec.rb +598 -0
- data/spec/draper/finders_spec.rb +166 -0
- data/spec/draper/helper_proxy_spec.rb +42 -0
- data/spec/draper/view_context/build_strategy_spec.rb +116 -0
- data/spec/draper/view_context_spec.rb +154 -0
- data/spec/draper/view_helpers_spec.rb +8 -0
- data/spec/dummy/.rspec +2 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/localized_urls.rb +5 -0
- data/spec/dummy/app/controllers/posts_controller.rb +18 -0
- data/spec/dummy/app/decorators/post_decorator.rb +56 -0
- data/spec/dummy/app/helpers/application_helper.rb +5 -0
- data/spec/dummy/app/mailers/application_mailer.rb +3 -0
- data/spec/dummy/app/mailers/post_mailer.rb +19 -0
- data/spec/dummy/app/models/admin.rb +5 -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 +11 -0
- data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
- data/spec/dummy/app/views/posts/_post.html.erb +34 -0
- data/spec/dummy/app/views/posts/show.html.erb +1 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/config/application.rb +70 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +33 -0
- data/spec/dummy/config/environments/production.rb +57 -0
- data/spec/dummy/config/environments/test.rb +31 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/mongoid.yml +80 -0
- data/spec/dummy/config/routes.rb +9 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
- data/spec/dummy/db/schema.rb +21 -0
- data/spec/dummy/db/seeds.rb +2 -0
- data/spec/dummy/fast_spec/post_decorator_spec.rb +38 -0
- data/spec/dummy/lib/tasks/test.rake +16 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
- data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +46 -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 +10 -0
- data/spec/dummy/spec/models/post_spec.rb +14 -0
- data/spec/dummy/spec/spec_helper.rb +9 -0
- data/spec/dummy/test/decorators/minitest/devise_test.rb +64 -0
- data/spec/dummy/test/decorators/minitest/helpers_test.rb +21 -0
- data/spec/dummy/test/decorators/minitest/spec_type_test.rb +52 -0
- data/spec/dummy/test/decorators/minitest/view_context_test.rb +24 -0
- data/spec/dummy/test/decorators/test_unit/devise_test.rb +64 -0
- data/spec/dummy/test/decorators/test_unit/helpers_test.rb +21 -0
- data/spec/dummy/test/decorators/test_unit/view_context_test.rb +24 -0
- data/spec/dummy/test/minitest_helper.rb +4 -0
- data/spec/dummy/test/test_helper.rb +3 -0
- data/spec/generators/decorator/decorator_generator_spec.rb +48 -7
- data/spec/integration/integration_spec.rb +58 -0
- data/{performance → spec/performance}/decorators.rb +2 -4
- data/spec/spec_helper.rb +25 -43
- data/spec/support/dummy_app.rb +85 -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 +253 -87
- data/CHANGELOG.markdown +0 -57
- data/Readme.markdown +0 -387
- data/lib/draper/active_model_support.rb +0 -27
- data/lib/draper/base.rb +0 -312
- data/lib/draper/decorated_enumerable_proxy.rb +0 -90
- data/lib/draper/model_support.rb +0 -25
- data/lib/draper/rspec_integration.rb +0 -2
- data/lib/draper/system.rb +0 -18
- data/spec/draper/base_spec.rb +0 -873
- data/spec/draper/decorated_enumerable_proxy_spec.rb +0 -45
- data/spec/draper/model_support_spec.rb +0 -48
- data/spec/minitest-rails/spec_type_spec.rb +0 -63
- data/spec/support/samples/active_record.rb +0 -17
- data/spec/support/samples/decorator.rb +0 -5
- data/spec/support/samples/decorator_with_allows.rb +0 -3
- data/spec/support/samples/decorator_with_application_helper.rb +0 -25
- data/spec/support/samples/decorator_with_denies.rb +0 -3
- data/spec/support/samples/decorator_with_denies_all.rb +0 -3
- data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
- data/spec/support/samples/decorator_with_special_methods.rb +0 -13
- data/spec/support/samples/enumerable_proxy.rb +0 -3
- data/spec/support/samples/namespaced_product.rb +0 -51
- data/spec/support/samples/namespaced_product_decorator.rb +0 -7
- data/spec/support/samples/non_active_model_product.rb +0 -2
- data/spec/support/samples/product.rb +0 -80
- data/spec/support/samples/product_decorator.rb +0 -7
- data/spec/support/samples/products_decorator.rb +0 -10
- data/spec/support/samples/sequel_product.rb +0 -13
- data/spec/support/samples/some_thing.rb +0 -2
- data/spec/support/samples/some_thing_decorator.rb +0 -3
- data/spec/support/samples/specific_product_decorator.rb +0 -4
- data/spec/support/samples/widget.rb +0 -2
- data/spec/support/samples/widget_decorator.rb +0 -2
- /data/{performance → spec/performance}/active_record.rb +0 -0
- /data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
- /data/{performance → spec/performance}/models.rb +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Draper
|
|
2
|
+
module Delegation
|
|
3
|
+
# @overload delegate(*methods, options = {})
|
|
4
|
+
# Overrides {http://api.rubyonrails.org/classes/Module.html#method-i-delegate Module.delegate}
|
|
5
|
+
# to make `:source` the default delegation target.
|
|
6
|
+
#
|
|
7
|
+
# @return [void]
|
|
8
|
+
def delegate(*methods)
|
|
9
|
+
options = methods.extract_options!
|
|
10
|
+
super *methods, options.reverse_merge(to: :source)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Draper
|
|
2
|
+
# Provides automatically-decorated finder methods for your decorators. You
|
|
3
|
+
# do not have to extend this module directly; it is extended by
|
|
4
|
+
# {Decorator.decorates_finders}.
|
|
5
|
+
module Finders
|
|
6
|
+
|
|
7
|
+
def find(id, options = {})
|
|
8
|
+
decorate(source_class.find(id), options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def all(options = {})
|
|
12
|
+
decorate_collection(source_class.all, options)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def first(options = {})
|
|
16
|
+
decorate(source_class.first, options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def last(options = {})
|
|
20
|
+
decorate(source_class.last, options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Decorates dynamic finder methods (`find_all_by_` and friends).
|
|
24
|
+
def method_missing(method, *args, &block)
|
|
25
|
+
return super unless method =~ /^find_(all_|last_|or_(initialize_|create_))?by_/
|
|
26
|
+
|
|
27
|
+
result = source_class.send(method, *args, &block)
|
|
28
|
+
options = args.extract_options!
|
|
29
|
+
|
|
30
|
+
if method =~ /^find_all/
|
|
31
|
+
decorate_collection(result, options)
|
|
32
|
+
else
|
|
33
|
+
decorate(result, options)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Draper
|
|
2
|
+
# Provides access to helper methods - both Rails built-in helpers, and those
|
|
3
|
+
# defined in your application.
|
|
4
|
+
class HelperProxy
|
|
5
|
+
|
|
6
|
+
# @overload initialize(view_context)
|
|
7
|
+
def initialize(view_context = nil)
|
|
8
|
+
view_context ||= current_view_context # backwards compatibility
|
|
9
|
+
|
|
10
|
+
@view_context = view_context
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Sends helper methods to the view context.
|
|
14
|
+
def method_missing(method, *args, &block)
|
|
15
|
+
self.class.define_proxy method
|
|
16
|
+
send(method, *args, &block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
attr_reader :view_context
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def self.define_proxy(name)
|
|
26
|
+
define_method name do |*args, &block|
|
|
27
|
+
view_context.send(name, *args, &block)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def current_view_context
|
|
32
|
+
ActiveSupport::Deprecation.warn("wrong number of arguments (0 for 1) passed to Draper::HelperProxy.new", caller[1..-1])
|
|
33
|
+
Draper::ViewContext.current.view_context
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/draper/lazy_helpers.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
module Draper
|
|
2
|
+
# Include this module in your decorators to get direct access to the helpers
|
|
3
|
+
# so that you can stop typing `h.` everywhere, at the cost of mixing in a
|
|
4
|
+
# bazillion methods.
|
|
2
5
|
module LazyHelpers
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
# Sends missing methods to the {HelperProxy}.
|
|
8
|
+
def method_missing(method, *args, &block)
|
|
9
|
+
helpers.send(method, *args, &block)
|
|
10
|
+
rescue NoMethodError
|
|
11
|
+
super
|
|
9
12
|
end
|
|
13
|
+
|
|
10
14
|
end
|
|
11
15
|
end
|
data/lib/draper/railtie.rb
CHANGED
|
@@ -3,8 +3,10 @@ require 'rails/railtie'
|
|
|
3
3
|
module ActiveModel
|
|
4
4
|
class Railtie < Rails::Railtie
|
|
5
5
|
generators do |app|
|
|
6
|
-
Rails
|
|
7
|
-
|
|
6
|
+
app ||= Rails.application # Rails 3.0.x does not yield `app`
|
|
7
|
+
|
|
8
|
+
Rails::Generators.configure! app.config.generators
|
|
9
|
+
require 'generators/resource_override'
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -12,40 +14,44 @@ end
|
|
|
12
14
|
module Draper
|
|
13
15
|
class Railtie < Rails::Railtie
|
|
14
16
|
|
|
15
|
-
##
|
|
16
|
-
# The `app/decorators` path is eager loaded
|
|
17
|
-
#
|
|
18
|
-
# This is the standard "Rails Way" to add paths from which constants
|
|
19
|
-
# can be loaded.
|
|
20
|
-
#
|
|
21
17
|
config.after_initialize do |app|
|
|
22
|
-
app.config.paths.add 'app/decorators', :
|
|
18
|
+
app.config.paths.add 'app/decorators', eager_load: true
|
|
19
|
+
|
|
20
|
+
unless Rails.env.production?
|
|
21
|
+
require 'draper/test_case'
|
|
22
|
+
require 'draper/test/rspec_integration' if defined?(RSpec) and RSpec.respond_to?(:configure)
|
|
23
|
+
require 'draper/test/minitest_integration' if defined?(MiniTest::Rails)
|
|
24
|
+
end
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
initializer "draper.
|
|
26
|
-
ActiveSupport.on_load
|
|
27
|
-
Draper
|
|
27
|
+
initializer "draper.setup_action_controller" do |app|
|
|
28
|
+
ActiveSupport.on_load :action_controller do
|
|
29
|
+
Draper.setup_action_controller self
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
|
|
31
|
-
initializer "draper.
|
|
32
|
-
ActiveSupport.on_load
|
|
33
|
-
Draper
|
|
33
|
+
initializer "draper.setup_action_mailer" do |app|
|
|
34
|
+
ActiveSupport.on_load :action_mailer do
|
|
35
|
+
Draper.setup_action_mailer self
|
|
34
36
|
end
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
initializer "draper.
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
initializer "draper.setup_orm" do |app|
|
|
40
|
+
[:active_record, :mongoid].each do |orm|
|
|
41
|
+
ActiveSupport.on_load orm do
|
|
42
|
+
Draper.setup_orm self
|
|
43
|
+
end
|
|
40
44
|
end
|
|
41
45
|
end
|
|
42
46
|
|
|
43
47
|
console do
|
|
44
48
|
require 'action_controller/test_case'
|
|
45
49
|
ApplicationController.new.view_context
|
|
46
|
-
Draper::ViewContext.
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
Draper::ViewContext.build_view_context
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
rake_tasks do
|
|
54
|
+
Dir[File.join(File.dirname(__FILE__),'tasks/*.rake')].each { |f| load f }
|
|
49
55
|
end
|
|
50
56
|
end
|
|
51
57
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
|
|
3
|
+
test_task = if Rails.version.to_f < 3.2
|
|
4
|
+
require 'rails/test_unit/railtie'
|
|
5
|
+
Rake::TestTask
|
|
6
|
+
else
|
|
7
|
+
require 'rails/test_unit/sub_test_task'
|
|
8
|
+
Rails::SubTestTask
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
namespace :test do
|
|
12
|
+
test_task.new(:decorators => "test:prepare") do |t|
|
|
13
|
+
t.libs << "test"
|
|
14
|
+
t.pattern = "test/decorators/**/*_test.rb"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if Rake::Task.task_defined?('test:run')
|
|
19
|
+
Rake::Task['test:run'].enhance do
|
|
20
|
+
Rake::Task['test:decorators'].invoke
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Draper
|
|
2
|
+
module DeviseHelper
|
|
3
|
+
def sign_in(resource_or_scope, resource = nil)
|
|
4
|
+
scope = begin
|
|
5
|
+
Devise::Mapping.find_scope!(resource_or_scope)
|
|
6
|
+
rescue RuntimeError => e
|
|
7
|
+
# Draper 1.0 didn't require the mapping to exist
|
|
8
|
+
ActiveSupport::Deprecation.warn("#{e.message}.\nUse `sign_in :user, mock_user` instead.", caller)
|
|
9
|
+
:user
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
_stub_current_scope scope, resource || resource_or_scope
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def sign_out(resource_or_scope)
|
|
16
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
|
17
|
+
_stub_current_scope scope, nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def _stub_current_scope(scope, resource)
|
|
23
|
+
Draper::ViewContext.current.controller.singleton_class.class_eval do
|
|
24
|
+
define_method "current_#{scope}" do
|
|
25
|
+
resource
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
class
|
|
2
|
-
# Use AS::TestCase for the base class when describing a decorator
|
|
1
|
+
class Draper::TestCase
|
|
3
2
|
register_spec_type(self) do |desc|
|
|
4
|
-
desc < Draper::
|
|
3
|
+
desc < Draper::Decorator || desc < Draper::CollectionDecorator if desc.is_a?(Class)
|
|
5
4
|
end
|
|
6
5
|
register_spec_type(/Decorator( ?Test)?\z/i, self)
|
|
7
6
|
end
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
module Draper
|
|
2
2
|
module DecoratorExampleGroup
|
|
3
|
+
include Draper::TestCase::Behavior
|
|
3
4
|
extend ActiveSupport::Concern
|
|
5
|
+
|
|
4
6
|
included { metadata[:type] = :decorator }
|
|
5
7
|
end
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
RSpec.configure do |config|
|
|
9
|
-
# Automatically tag specs in specs/decorators as type: :decorator
|
|
10
|
-
config.include Draper::DecoratorExampleGroup, :type => :decorator, :example_group => {
|
|
11
|
-
:file_path => /spec[\\\/]decorators/
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
if defined?(Capybara)
|
|
17
|
-
require 'capybara/rspec/matchers'
|
|
18
8
|
|
|
19
9
|
RSpec.configure do |config|
|
|
20
|
-
config.include
|
|
10
|
+
config.include DecoratorExampleGroup, example_group: {file_path: %r{spec/decorators}}, type: :decorator
|
|
11
|
+
|
|
12
|
+
[:decorator, :controller, :mailer].each do |type|
|
|
13
|
+
config.after(:each, type: type) { Draper::ViewContext.clear! }
|
|
14
|
+
end
|
|
21
15
|
end
|
|
22
16
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Draper
|
|
2
|
+
begin
|
|
3
|
+
require 'minitest/rails'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
active_support_test_case = begin
|
|
8
|
+
require 'minitest/rails/active_support' # minitest-rails < 0.5
|
|
9
|
+
::MiniTest::Rails::ActiveSupport::TestCase
|
|
10
|
+
rescue LoadError
|
|
11
|
+
require 'active_support/test_case'
|
|
12
|
+
::ActiveSupport::TestCase
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class TestCase < active_support_test_case
|
|
16
|
+
module ViewContextTeardown
|
|
17
|
+
def teardown
|
|
18
|
+
super
|
|
19
|
+
Draper::ViewContext.clear!
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module Behavior
|
|
24
|
+
if defined?(::Devise)
|
|
25
|
+
require 'draper/test/devise_helper'
|
|
26
|
+
include Draper::DeviseHelper
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if defined?(::Capybara) && (defined?(::RSpec) || defined?(::MiniTest::Matchers))
|
|
30
|
+
require 'capybara/rspec/matchers'
|
|
31
|
+
include ::Capybara::RSpecMatchers
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
include Draper::ViewHelpers::ClassMethods
|
|
35
|
+
alias_method :helper, :helpers
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
include Behavior
|
|
39
|
+
include ViewContextTeardown
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if defined?(ActionController::TestCase)
|
|
44
|
+
class ActionController::TestCase
|
|
45
|
+
include Draper::TestCase::ViewContextTeardown
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if defined?(ActionMailer::TestCase)
|
|
50
|
+
class ActionMailer::TestCase
|
|
51
|
+
include Draper::TestCase::ViewContextTeardown
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/draper/version.rb
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Draper
|
|
2
|
+
module ViewContext
|
|
3
|
+
# @private
|
|
4
|
+
module BuildStrategy
|
|
5
|
+
|
|
6
|
+
def self.new(name, &block)
|
|
7
|
+
const_get(name.to_s.camelize).new(&block)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Fast
|
|
11
|
+
def initialize(&block)
|
|
12
|
+
@view_context_class = Class.new(ActionView::Base, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
view_context_class.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :view_context_class
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Full
|
|
25
|
+
def initialize(&block)
|
|
26
|
+
@block = block
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call
|
|
30
|
+
controller.view_context.tap do |context|
|
|
31
|
+
context.singleton_class.class_eval(&block) if block
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
attr_reader :block
|
|
38
|
+
|
|
39
|
+
def controller
|
|
40
|
+
(Draper::ViewContext.controller || ApplicationController.new).tap do |controller|
|
|
41
|
+
controller.request ||= ActionController::TestRequest.new if defined?(ActionController::TestRequest)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/draper/view_context.rb
CHANGED
|
@@ -1,42 +1,99 @@
|
|
|
1
|
+
require 'draper/view_context/build_strategy'
|
|
2
|
+
require 'request_store'
|
|
3
|
+
|
|
1
4
|
module Draper
|
|
2
5
|
module ViewContext
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
# Hooks into a controller or mailer to save the view context in {current}.
|
|
7
|
+
def view_context
|
|
8
|
+
super.tap do |context|
|
|
9
|
+
Draper::ViewContext.current = context
|
|
10
|
+
end
|
|
5
11
|
end
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
# Returns the current controller.
|
|
14
|
+
def self.controller
|
|
15
|
+
RequestStore.store[:current_controller]
|
|
9
16
|
end
|
|
10
17
|
|
|
18
|
+
# Sets the current controller.
|
|
19
|
+
def self.controller=(controller)
|
|
20
|
+
RequestStore.store[:current_controller] = controller
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the current view context, or builds one if none is saved.
|
|
24
|
+
#
|
|
25
|
+
# @return [HelperProxy]
|
|
11
26
|
def self.current
|
|
12
|
-
|
|
27
|
+
RequestStore.store.fetch(:current_view_context) { build! }
|
|
13
28
|
end
|
|
14
29
|
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
# Sets the current view context.
|
|
31
|
+
def self.current=(view_context)
|
|
32
|
+
RequestStore.store[:current_view_context] = Draper::HelperProxy.new(view_context)
|
|
17
33
|
end
|
|
18
34
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
# Clears the saved controller and view context.
|
|
36
|
+
def self.clear!
|
|
37
|
+
RequestStore.store.delete :current_controller
|
|
38
|
+
RequestStore.store.delete :current_view_context
|
|
23
39
|
end
|
|
24
40
|
|
|
25
|
-
|
|
41
|
+
# Builds a new view context for usage in tests. See {test_strategy} for
|
|
42
|
+
# details of how the view context is built.
|
|
43
|
+
def self.build
|
|
44
|
+
build_strategy.call
|
|
45
|
+
end
|
|
26
46
|
|
|
47
|
+
# Builds a new view context and sets it as the current view context.
|
|
48
|
+
#
|
|
49
|
+
# @return [HelperProxy]
|
|
50
|
+
def self.build!
|
|
51
|
+
# send because we want to return the HelperProxy returned from #current=
|
|
52
|
+
send :current=, build
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Configures the strategy used to build view contexts in tests, which
|
|
56
|
+
# defaults to `:full` if `test_strategy` has not been called. Evaluates
|
|
57
|
+
# the block, if given, in the context of the view context's class.
|
|
58
|
+
#
|
|
59
|
+
# @example Pass a block to add helper methods to the view context:
|
|
60
|
+
# Draper::ViewContext.test_strategy :fast do
|
|
61
|
+
# include ApplicationHelper
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# @param [:full, :fast] name
|
|
65
|
+
# the strategy to use:
|
|
66
|
+
#
|
|
67
|
+
# `:full` - build a fully-working view context. Your Rails environment
|
|
68
|
+
# must be loaded, including your `ApplicationController`.
|
|
69
|
+
#
|
|
70
|
+
# `:fast` - build a minimal view context in tests, with no dependencies
|
|
71
|
+
# on other components of your application.
|
|
72
|
+
def self.test_strategy(name, &block)
|
|
73
|
+
@build_strategy = Draper::ViewContext::BuildStrategy.new(name, &block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @private
|
|
77
|
+
def self.build_strategy
|
|
78
|
+
@build_strategy ||= Draper::ViewContext::BuildStrategy.new(:full)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @deprecated Use {controller} instead.
|
|
82
|
+
def self.current_controller
|
|
83
|
+
ActiveSupport::Deprecation.warn("Draper::ViewContext.current_controller is deprecated (use controller instead)", caller)
|
|
84
|
+
self.controller || ApplicationController.new
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @deprecated Use {controller=} instead.
|
|
88
|
+
def self.current_controller=(controller)
|
|
89
|
+
ActiveSupport::Deprecation.warn("Draper::ViewContext.current_controller= is deprecated (use controller instead)", caller)
|
|
90
|
+
self.controller = controller
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @deprecated Use {build} instead.
|
|
27
94
|
def self.build_view_context
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def url_options
|
|
31
|
-
ActionMailer::Base.default_url_options
|
|
32
|
-
end
|
|
33
|
-
end unless context.request
|
|
34
|
-
if defined?(ActionController::TestRequest)
|
|
35
|
-
context.controller.request ||= ActionController::TestRequest.new
|
|
36
|
-
context.request ||= context.controller.request
|
|
37
|
-
context.params ||= {}
|
|
38
|
-
end
|
|
39
|
-
end
|
|
95
|
+
ActiveSupport::Deprecation.warn("Draper::ViewContext.build_view_context is deprecated (use build instead)", caller)
|
|
96
|
+
build
|
|
40
97
|
end
|
|
41
98
|
end
|
|
42
99
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Draper
|
|
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
|
+
|
|
9
|
+
# Access the helpers proxy to call built-in and user-defined
|
|
10
|
+
# Rails helpers from a class context.
|
|
11
|
+
#
|
|
12
|
+
# @return [HelperProxy] the helpers proxy
|
|
13
|
+
def helpers
|
|
14
|
+
Draper::ViewContext.current
|
|
15
|
+
end
|
|
16
|
+
alias_method :h, :helpers
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Access the helpers proxy to call built-in and user-defined
|
|
21
|
+
# Rails helpers. Aliased to `h` for convenience.
|
|
22
|
+
#
|
|
23
|
+
# @return [HelperProxy] the helpers proxy
|
|
24
|
+
def helpers
|
|
25
|
+
Draper::ViewContext.current
|
|
26
|
+
end
|
|
27
|
+
alias_method :h, :helpers
|
|
28
|
+
|
|
29
|
+
# Alias for `helpers.localize`, since localize is something that's used
|
|
30
|
+
# quite often. Further aliased to `l` for convenience.
|
|
31
|
+
def localize(*args)
|
|
32
|
+
helpers.localize(*args)
|
|
33
|
+
end
|
|
34
|
+
alias_method :l, :localize
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/draper.rb
CHANGED
|
@@ -1,16 +1,58 @@
|
|
|
1
1
|
require 'action_view'
|
|
2
|
+
require 'active_model/serialization'
|
|
3
|
+
require 'active_support/inflector'
|
|
4
|
+
require 'active_support/core_ext/hash/keys'
|
|
5
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
|
2
6
|
|
|
3
7
|
require 'draper/version'
|
|
4
|
-
require 'draper/
|
|
5
|
-
require 'draper/
|
|
6
|
-
require 'draper/
|
|
8
|
+
require 'draper/view_helpers'
|
|
9
|
+
require 'draper/delegation'
|
|
10
|
+
require 'draper/automatic_delegation'
|
|
11
|
+
require 'draper/finders'
|
|
12
|
+
require 'draper/decorator'
|
|
13
|
+
require 'draper/helper_proxy'
|
|
7
14
|
require 'draper/lazy_helpers'
|
|
8
|
-
require 'draper/
|
|
15
|
+
require 'draper/decoratable'
|
|
16
|
+
require 'draper/decorated_association'
|
|
9
17
|
require 'draper/helper_support'
|
|
10
18
|
require 'draper/view_context'
|
|
11
|
-
require 'draper/
|
|
19
|
+
require 'draper/collection_decorator'
|
|
12
20
|
require 'draper/railtie' if defined?(Rails)
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
module Draper
|
|
23
|
+
def self.setup_action_controller(base)
|
|
24
|
+
base.class_eval do
|
|
25
|
+
include Draper::ViewContext
|
|
26
|
+
extend Draper::HelperSupport
|
|
27
|
+
|
|
28
|
+
before_filter do |controller|
|
|
29
|
+
Draper::ViewContext.clear!
|
|
30
|
+
Draper::ViewContext.controller = controller
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.setup_action_mailer(base)
|
|
36
|
+
base.class_eval do
|
|
37
|
+
include Draper::ViewContext
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.setup_orm(base)
|
|
42
|
+
base.class_eval do
|
|
43
|
+
include Draper::Decoratable
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class UninferrableDecoratorError < NameError
|
|
48
|
+
def initialize(klass)
|
|
49
|
+
super("Could not infer a decorator for #{klass}.")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class UninferrableSourceError < NameError
|
|
54
|
+
def initialize(klass)
|
|
55
|
+
super("Could not infer a source for #{klass}.")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -20,9 +20,17 @@ module Rails
|
|
|
20
20
|
elsif defined?(ApplicationDecorator)
|
|
21
21
|
"ApplicationDecorator"
|
|
22
22
|
else
|
|
23
|
-
"Draper::
|
|
23
|
+
"Draper::Decorator"
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
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(&block)
|
|
31
|
+
yield if block
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
27
35
|
end
|
|
28
36
|
end
|