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.
Files changed (155) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +11 -0
  3. data/.yardopts +1 -1
  4. data/CHANGELOG.md +164 -0
  5. data/CONTRIBUTING.md +15 -0
  6. data/Gemfile +34 -0
  7. data/LICENSE +7 -0
  8. data/README.md +416 -0
  9. data/Rakefile +53 -31
  10. data/draper.gemspec +11 -9
  11. data/lib/draper/automatic_delegation.rb +50 -0
  12. data/lib/draper/collection_decorator.rb +107 -0
  13. data/lib/draper/decoratable/equality.rb +14 -0
  14. data/lib/draper/decoratable.rb +79 -0
  15. data/lib/draper/decorated_association.rb +74 -0
  16. data/lib/draper/decorator.rb +235 -0
  17. data/lib/draper/delegation.rb +13 -0
  18. data/lib/draper/finders.rb +37 -0
  19. data/lib/draper/helper_proxy.rb +36 -0
  20. data/lib/draper/lazy_helpers.rb +10 -6
  21. data/lib/draper/railtie.rb +27 -21
  22. data/lib/draper/tasks/test.rake +22 -0
  23. data/lib/draper/test/devise_helper.rb +30 -0
  24. data/lib/draper/test/minitest_integration.rb +2 -3
  25. data/lib/draper/test/rspec_integration.rb +7 -13
  26. data/lib/draper/test_case.rb +53 -0
  27. data/lib/draper/version.rb +1 -1
  28. data/lib/draper/view_context/build_strategy.rb +48 -0
  29. data/lib/draper/view_context.rb +81 -24
  30. data/lib/draper/view_helpers.rb +37 -0
  31. data/lib/draper.rb +50 -8
  32. data/lib/generators/decorator/decorator_generator.rb +10 -2
  33. data/lib/generators/decorator/templates/decorator.rb +12 -27
  34. data/lib/generators/mini_test/decorator_generator.rb +20 -0
  35. data/lib/generators/mini_test/templates/decorator_spec.rb +4 -0
  36. data/lib/generators/mini_test/templates/decorator_test.rb +4 -0
  37. data/lib/generators/test_unit/templates/decorator_test.rb +1 -1
  38. data/spec/draper/collection_decorator_spec.rb +259 -0
  39. data/spec/draper/decoratable/equality_spec.rb +10 -0
  40. data/spec/draper/decoratable_spec.rb +167 -0
  41. data/spec/draper/decorated_association_spec.rb +145 -0
  42. data/spec/draper/decorator_spec.rb +598 -0
  43. data/spec/draper/finders_spec.rb +166 -0
  44. data/spec/draper/helper_proxy_spec.rb +42 -0
  45. data/spec/draper/view_context/build_strategy_spec.rb +116 -0
  46. data/spec/draper/view_context_spec.rb +154 -0
  47. data/spec/draper/view_helpers_spec.rb +8 -0
  48. data/spec/dummy/.rspec +2 -0
  49. data/spec/dummy/Rakefile +7 -0
  50. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  51. data/spec/dummy/app/controllers/localized_urls.rb +5 -0
  52. data/spec/dummy/app/controllers/posts_controller.rb +18 -0
  53. data/spec/dummy/app/decorators/post_decorator.rb +56 -0
  54. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  55. data/spec/dummy/app/mailers/application_mailer.rb +3 -0
  56. data/spec/dummy/app/mailers/post_mailer.rb +19 -0
  57. data/spec/dummy/app/models/admin.rb +5 -0
  58. data/spec/dummy/app/models/mongoid_post.rb +5 -0
  59. data/spec/dummy/app/models/post.rb +3 -0
  60. data/spec/dummy/app/models/user.rb +5 -0
  61. data/spec/dummy/app/views/layouts/application.html.erb +11 -0
  62. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
  63. data/spec/dummy/app/views/posts/_post.html.erb +34 -0
  64. data/spec/dummy/app/views/posts/show.html.erb +1 -0
  65. data/spec/dummy/bin/rails +4 -0
  66. data/spec/dummy/config/application.rb +70 -0
  67. data/spec/dummy/config/boot.rb +5 -0
  68. data/spec/dummy/config/database.yml +25 -0
  69. data/spec/dummy/config/environment.rb +5 -0
  70. data/spec/dummy/config/environments/development.rb +33 -0
  71. data/spec/dummy/config/environments/production.rb +57 -0
  72. data/spec/dummy/config/environments/test.rb +31 -0
  73. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/spec/dummy/config/initializers/inflections.rb +15 -0
  75. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  76. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  77. data/spec/dummy/config/initializers/session_store.rb +8 -0
  78. data/spec/dummy/config/locales/en.yml +5 -0
  79. data/spec/dummy/config/mongoid.yml +80 -0
  80. data/spec/dummy/config/routes.rb +9 -0
  81. data/spec/dummy/config.ru +4 -0
  82. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
  83. data/spec/dummy/db/schema.rb +21 -0
  84. data/spec/dummy/db/seeds.rb +2 -0
  85. data/spec/dummy/fast_spec/post_decorator_spec.rb +38 -0
  86. data/spec/dummy/lib/tasks/test.rake +16 -0
  87. data/spec/dummy/log/.gitkeep +0 -0
  88. data/spec/dummy/public/404.html +26 -0
  89. data/spec/dummy/public/422.html +26 -0
  90. data/spec/dummy/public/500.html +25 -0
  91. data/spec/dummy/public/favicon.ico +0 -0
  92. data/spec/dummy/script/rails +6 -0
  93. data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
  94. data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
  95. data/spec/dummy/spec/decorators/post_decorator_spec.rb +46 -0
  96. data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
  97. data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
  98. data/spec/dummy/spec/mailers/post_mailer_spec.rb +33 -0
  99. data/spec/dummy/spec/models/mongoid_post_spec.rb +10 -0
  100. data/spec/dummy/spec/models/post_spec.rb +14 -0
  101. data/spec/dummy/spec/spec_helper.rb +9 -0
  102. data/spec/dummy/test/decorators/minitest/devise_test.rb +64 -0
  103. data/spec/dummy/test/decorators/minitest/helpers_test.rb +21 -0
  104. data/spec/dummy/test/decorators/minitest/spec_type_test.rb +52 -0
  105. data/spec/dummy/test/decorators/minitest/view_context_test.rb +24 -0
  106. data/spec/dummy/test/decorators/test_unit/devise_test.rb +64 -0
  107. data/spec/dummy/test/decorators/test_unit/helpers_test.rb +21 -0
  108. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +24 -0
  109. data/spec/dummy/test/minitest_helper.rb +4 -0
  110. data/spec/dummy/test/test_helper.rb +3 -0
  111. data/spec/generators/decorator/decorator_generator_spec.rb +48 -7
  112. data/spec/integration/integration_spec.rb +58 -0
  113. data/{performance → spec/performance}/decorators.rb +2 -4
  114. data/spec/spec_helper.rb +25 -43
  115. data/spec/support/dummy_app.rb +85 -0
  116. data/spec/support/matchers/have_text.rb +50 -0
  117. data/spec/support/shared_examples/decoratable_equality.rb +40 -0
  118. data/spec/support/shared_examples/view_helpers.rb +39 -0
  119. metadata +253 -87
  120. data/CHANGELOG.markdown +0 -57
  121. data/Readme.markdown +0 -387
  122. data/lib/draper/active_model_support.rb +0 -27
  123. data/lib/draper/base.rb +0 -312
  124. data/lib/draper/decorated_enumerable_proxy.rb +0 -90
  125. data/lib/draper/model_support.rb +0 -25
  126. data/lib/draper/rspec_integration.rb +0 -2
  127. data/lib/draper/system.rb +0 -18
  128. data/spec/draper/base_spec.rb +0 -873
  129. data/spec/draper/decorated_enumerable_proxy_spec.rb +0 -45
  130. data/spec/draper/model_support_spec.rb +0 -48
  131. data/spec/minitest-rails/spec_type_spec.rb +0 -63
  132. data/spec/support/samples/active_record.rb +0 -17
  133. data/spec/support/samples/decorator.rb +0 -5
  134. data/spec/support/samples/decorator_with_allows.rb +0 -3
  135. data/spec/support/samples/decorator_with_application_helper.rb +0 -25
  136. data/spec/support/samples/decorator_with_denies.rb +0 -3
  137. data/spec/support/samples/decorator_with_denies_all.rb +0 -3
  138. data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
  139. data/spec/support/samples/decorator_with_special_methods.rb +0 -13
  140. data/spec/support/samples/enumerable_proxy.rb +0 -3
  141. data/spec/support/samples/namespaced_product.rb +0 -51
  142. data/spec/support/samples/namespaced_product_decorator.rb +0 -7
  143. data/spec/support/samples/non_active_model_product.rb +0 -2
  144. data/spec/support/samples/product.rb +0 -80
  145. data/spec/support/samples/product_decorator.rb +0 -7
  146. data/spec/support/samples/products_decorator.rb +0 -10
  147. data/spec/support/samples/sequel_product.rb +0 -13
  148. data/spec/support/samples/some_thing.rb +0 -2
  149. data/spec/support/samples/some_thing_decorator.rb +0 -3
  150. data/spec/support/samples/specific_product_decorator.rb +0 -4
  151. data/spec/support/samples/widget.rb +0 -2
  152. data/spec/support/samples/widget_decorator.rb +0 -2
  153. /data/{performance → spec/performance}/active_record.rb +0 -0
  154. /data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
  155. /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
@@ -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
- def method_missing(method_name, *args, &block)
4
- begin
5
- helpers.send method_name, *args, &block
6
- rescue NoMethodError
7
- super
8
- end
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
@@ -3,8 +3,10 @@ require 'rails/railtie'
3
3
  module ActiveModel
4
4
  class Railtie < Rails::Railtie
5
5
  generators do |app|
6
- Rails::Generators.configure!(app.config.generators)
7
- require "generators/resource_override"
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', :eager_load => true
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.extend_action_controller_base" do |app|
26
- ActiveSupport.on_load(:action_controller) do
27
- Draper::System.setup_action_controller(self)
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.extend_action_mailer_base" do |app|
32
- ActiveSupport.on_load(:action_mailer) do
33
- Draper::System.setup_action_mailer(self)
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.extend_active_record_base" do |app|
38
- ActiveSupport.on_load(:active_record) do
39
- self.send(:include, Draper::ModelSupport)
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.current.controller.request ||= ActionController::TestRequest.new
47
- Draper::ViewContext.current.request ||= Draper::ViewContext.current.controller.request
48
- Draper::ViewContext.current.params ||= {}
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 MiniTest::Rails::ActiveSupport::TestCase
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::Base if desc.is_a?(Class)
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 Capybara::RSpecMatchers, :type => :decorator
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
@@ -1,3 +1,3 @@
1
1
  module Draper
2
- VERSION = "0.18.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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
@@ -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
- def self.current_controller
4
- Thread.current[:current_controller] || ApplicationController.new
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
- def self.current_controller=(controller)
8
- Thread.current[:current_controller] = controller
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
- Thread.current[:current_view_context] ||= build_view_context
27
+ RequestStore.store.fetch(:current_view_context) { build! }
13
28
  end
14
29
 
15
- def self.current=(context)
16
- Thread.current[:current_view_context] = context
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
- def view_context
20
- super.tap do |context|
21
- Draper::ViewContext.current = context
22
- end
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
- private
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
- current_controller.view_context.tap do |context|
29
- context.instance_eval do
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/system'
5
- require 'draper/active_model_support'
6
- require 'draper/base'
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/model_support'
15
+ require 'draper/decoratable'
16
+ require 'draper/decorated_association'
9
17
  require 'draper/helper_support'
10
18
  require 'draper/view_context'
11
- require 'draper/decorated_enumerable_proxy'
19
+ require 'draper/collection_decorator'
12
20
  require 'draper/railtie' if defined?(Rails)
13
21
 
14
- # Test Support
15
- require 'draper/test/rspec_integration' if defined?(RSpec) and RSpec.respond_to?(:configure)
16
- require 'draper/test/minitest_integration' if defined?(MiniTest::Rails)
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::Base"
23
+ "Draper::Decorator"
24
24
  end
25
25
  end
26
- end
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