1
0
Fork 0
mirror of https://github.com/drapergem/draper synced 2023-03-27 23:21:17 -04:00

Store helper proxies instead of raw view contexts

Closes #436.
This commit is contained in:
Andrew Haines 2013-01-24 00:23:39 +00:00
parent 6ca2897278
commit 50a3435acb
9 changed files with 123 additions and 36 deletions

View file

@ -3,15 +3,27 @@ module Draper
# defined in your application.
class HelperProxy
# @overload initialize(view_context)
def initialize(view_context = nil)
view_context ||= current_view_context # backwards compatibility
@view_context = view_context
end
# Sends helper methods to the view context.
def method_missing(method, *args, &block)
view_context.send(method, *args, &block)
end
protected
attr_reader :view_context
private
def view_context
Draper::ViewContext.current
def current_view_context
ActiveSupport::Deprecation.warn("wrong number of arguments (0 for 1) passed to Draper::HelperProxy.new", caller[1..-1])
Draper::ViewContext.current.view_context
end
end
end

View file

@ -21,19 +21,21 @@ module Draper
end
# Returns the current view context, or builds one if none is saved.
#
# @return [HelperProxy]
def self.current
RequestStore.store[:current_view_context] ||= build
RequestStore.store.fetch(:current_view_context) { build! }
end
# Sets the current view context.
def self.current=(view_context)
RequestStore.store[:current_view_context] = view_context
RequestStore.store[:current_view_context] = Draper::HelperProxy.new(view_context)
end
# Clears the saved controller and view context.
def self.clear!
self.controller = nil
self.current = nil
RequestStore.store.delete :current_controller
RequestStore.store.delete :current_view_context
end
# Builds a new view context for usage in tests. See {test_strategy} for
@ -42,6 +44,14 @@ module Draper
build_strategy.call
end
# Builds a new view context and sets it as the current view context.
#
# @return [HelperProxy]
def self.build!
# send because we want to return the HelperProxy returned from #current=
send :current=, build
end
# Configures the strategy used to build view contexts in tests, which
# defaults to `:full` if `test_strategy` has not been called. Evaluates
# the block, if given, in the context of the view context's class.

View file

@ -11,7 +11,7 @@ module Draper
#
# @return [HelperProxy] the helpers proxy
def helpers
@helpers ||= Draper::HelperProxy.new
Draper::ViewContext.current
end
alias_method :h, :helpers
@ -22,7 +22,7 @@ module Draper
#
# @return [HelperProxy] the helpers proxy
def helpers
self.class.helpers
Draper::ViewContext.current
end
alias_method :h, :helpers

View file

@ -2,13 +2,23 @@ require 'spec_helper'
module Draper
describe HelperProxy do
it "proxies methods to the view context" do
view_context = double
ViewContext.stub(current: view_context)
helper_proxy = HelperProxy.new
describe "#initialize" do
it "sets the view context" do
view_context = double
helper_proxy = HelperProxy.new(view_context)
view_context.should_receive(:foo).with("bar")
helper_proxy.foo("bar")
expect(helper_proxy.send(:view_context)).to be view_context
end
end
describe "#method_missing" do
it "proxies methods to the view context" do
view_context = double
helper_proxy = HelperProxy.new(view_context)
view_context.should_receive(:foo).with("bar")
helper_proxy.foo("bar")
end
end
end
end

View file

@ -7,8 +7,8 @@ module Draper
let(:controller) { Class.new(base) { include ViewContext } }
it "saves the superclass's view context" do
ViewContext.should_receive(:current=).with(:controller_view_context)
controller.new.view_context
expect(ViewContext.current).to be :controller_view_context
end
it "returns the superclass's view context" do
@ -19,6 +19,7 @@ module Draper
describe ".controller" do
it "returns the stored controller from RequestStore" do
RequestStore.stub store: {current_controller: :stored_controller}
expect(ViewContext.controller).to be :stored_controller
end
end
@ -36,23 +37,39 @@ module Draper
describe ".current" do
it "returns the stored view context from RequestStore" do
RequestStore.stub store: {current_view_context: :stored_view_context}
expect(ViewContext.current).to be :stored_view_context
end
it "falls back to building a view context" do
RequestStore.stub store: {}
ViewContext.should_receive(:build).and_return(:new_view_context)
expect(ViewContext.current).to be :new_view_context
context "when no view context is stored" do
it "builds a view context" do
RequestStore.stub store: {}
ViewContext.stub build_strategy: ->{ :new_view_context }
HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
expect(ViewContext.current).to be :new_helper_proxy
end
it "stores the built view context" do
store = {}
RequestStore.stub store: store
ViewContext.stub build_strategy: ->{ :new_view_context }
HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
ViewContext.current
expect(store[:current_view_context]).to be :new_helper_proxy
end
end
end
describe ".current=" do
it "stores a view context in RequestStore" do
it "stores a helper proxy for the view context in RequestStore" do
store = {}
RequestStore.stub store: store
HelperProxy.stub(:new).with(:stored_view_context).and_return(:stored_helper_proxy)
ViewContext.current = :stored_view_context
expect(store[:current_view_context]).to be :stored_view_context
expect(store[:current_view_context]).to be :stored_helper_proxy
end
end
@ -62,18 +79,38 @@ module Draper
RequestStore.stub store: store
ViewContext.clear!
expect(store[:current_controller]).to be_nil
expect(store[:current_view_context]).to be_nil
expect(store).not_to have_key :current_controller
expect(store).not_to have_key :current_view_context
end
end
describe ".build" do
it "calls the build strategy" do
it "returns a new view context using the build strategy" do
ViewContext.stub build_strategy: ->{ :new_view_context }
expect(ViewContext.build).to be :new_view_context
end
end
describe ".build!" do
it "returns a helper proxy for the new view context" do
ViewContext.stub build_strategy: ->{ :new_view_context }
HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
expect(ViewContext.build!).to be :new_helper_proxy
end
it "stores the helper proxy" do
store = {}
RequestStore.stub store: store
ViewContext.stub build_strategy: ->{ :new_view_context }
HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
ViewContext.build!
expect(store[:current_view_context]).to be :new_helper_proxy
end
end
describe ".build_strategy" do
it "defaults to full" do
expect(ViewContext.build_strategy).to be_a ViewContext::BuildStrategy::Full

View file

@ -12,4 +12,10 @@ describe "A decorator spec" do
it "can access helpers through `h`" do
expect(h.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
end
it "gets the same helper object as a decorator" do
decorator = Draper::Decorator.new(Object.new)
expect(helpers).to be decorator.helpers
end
end

View file

@ -12,4 +12,10 @@ describe "A decorator test" do
it "can access helpers through `h`" do
assert_equal "<p>Help!</p>", h.content_tag(:p, "Help!")
end
it "gets the same helper object as a decorator" do
decorator = Draper::Decorator.new(Object.new)
assert_same decorator.helpers, helpers
end
end

View file

@ -12,4 +12,10 @@ class HelpersTest < Draper::TestCase
def test_access_helpers_through_h
assert_equal "<p>Help!</p>", h.content_tag(:p, "Help!")
end
def test_same_helper_object_as_decorators
decorator = Draper::Decorator.new(Object.new)
assert_same decorator.helpers, helpers
end
end

View file

@ -1,39 +1,39 @@
shared_examples_for "view helpers" do |subject|
describe "#helpers" do
it "returns the class's helpers" do
expect(subject.helpers).to be subject.class.helpers
it "returns the current view context" do
Draper::ViewContext.stub current: :current_view_context
expect(subject.helpers).to be :current_view_context
end
it "is aliased to #h" do
expect(subject.h).to be subject.helpers
Draper::ViewContext.stub current: :current_view_context
expect(subject.h).to be :current_view_context
end
end
describe "#localize" do
it "delegates to #helpers" do
subject.stub helpers: double
subject.helpers.should_receive(:localize).with(:an_object, some: "parameter")
subject.localize(:an_object, some: "parameter")
end
it "is aliased to #l" do
subject.stub helpers: double
subject.helpers.should_receive(:localize).with(:an_object, some: "parameter")
subject.l(:an_object, some: "parameter")
end
end
describe ".helpers" do
it "returns a HelperProxy" do
expect(subject.class.helpers).to be_a Draper::HelperProxy
end
it "memoizes" do
helpers = subject.class.helpers
expect(subject.class.helpers).to be helpers
it "returns the current view context" do
Draper::ViewContext.stub current: :current_view_context
expect(subject.class.helpers).to be :current_view_context
end
it "is aliased to .h" do
expect(subject.class.h).to be subject.class.helpers
Draper::ViewContext.stub current: :current_view_context
expect(subject.class.h).to be :current_view_context
end
end
end