Compare commits

..

9 Commits

Author SHA1 Message Date
Charlie Somerville
76884dd7f7 Merge pull request #22 from github/actionview-proxy-module-method-cache-nuke
Don't globally invalidate the method and constant cache every view render
2013-10-25 11:43:48 -07:00
Charlie Somerville
29a72262aa here too 2013-10-25 12:46:48 -04:00
Charlie Somerville
76c5bf4f4b instantiate the cached helper class instead of extending AV::B 2013-10-25 12:46:48 -04:00
Charlie Somerville
416b7171b8 delete ActionView::Base#helpers because it's completely useless 2013-10-25 12:46:48 -04:00
Charlie Somerville
e82a3ba2a0 cache a class that is pre-included with the master helper module 2013-10-25 12:46:48 -04:00
Charlie Somerville
8837faac73 Merge pull request #21 from github/kill-blankslate
Kill blankslate
2013-10-25 09:42:01 -07:00
Charlie Somerville
20b12c3b42 call Kernel.block_given? instead of block_given? coz of BasicObject 2013-10-24 14:30:20 -04:00
Charlie Somerville
0cf06787af use fully qualified constant access here 2013-10-24 14:30:20 -04:00
Charlie Somerville
5efad05b11 💀 in a 🔥 blankslate 2013-10-24 14:30:20 -04:00
9 changed files with 33 additions and 172 deletions

View File

@@ -1273,8 +1273,7 @@ module ActionController #:nodoc:
end
def initialize_template_class(response)
response.template = ActionView::Base.new(self.class.view_paths, {}, self)
response.template.helpers.send :include, self.class.master_helper_module
response.template = self.class.master_helper_class.new(self.class.view_paths, {}, self)
response.redirected_to = nil
@performed_render = @performed_redirect = false
end

View File

@@ -69,6 +69,22 @@ module ActionController #:nodoc:
# N/A | Carolina Railhaws Training Workshop
#
module ClassMethods
# To avoid extending an instance of ActionView::Base with the master_helper_module
# every single time we render a view, we're caching a class that has
# master_helper_module already included that we can just instantiate.
def master_helper_class
return @master_helper_class if @master_helper_class
@master_helper_class = Class.new(ActionView::Base).tap do |klass|
klass.send(:include, master_helper_module)
end
end
def master_helper_module=(mod)
write_inheritable_attribute(:master_helper_module, mod)
@master_helper_class = nil
end
# Makes all the (instance) methods in the helper module available to templates rendered through this controller.
# See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
# available to the templates.
@@ -182,8 +198,7 @@ module ActionController #:nodoc:
# Provides a proxy to access helpers methods from outside the view.
def helpers
unless @helper_proxy
@helper_proxy = ActionView::Base.new
@helper_proxy.extend master_helper_module
@helper_proxy = master_helper_class.new
else
@helper_proxy
end

View File

@@ -203,24 +203,10 @@ module ActionView #:nodoc:
ActionView::PathSet.new(Array(value))
end
attr_reader :helpers
class ProxyModule < Module
def initialize(receiver)
@receiver = receiver
end
def include(*args)
super(*args)
@receiver.extend(*args)
end
end
def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
@assigns = assigns_for_first_render
@assigns_added = nil
@controller = controller
@helpers = ProxyModule.new(self)
self.view_paths = view_paths
@_first_render = nil

View File

@@ -116,8 +116,7 @@ module ActionView
end
def _view
view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller)
view.helpers.include master_helper_module
view = self.class.master_helper_class.new(ActionController::Base.view_paths, _assigns, @controller)
view.output_buffer = self.output_buffer
view
end

View File

@@ -1,114 +0,0 @@
#!/usr/bin/env ruby
#--
# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
# All rights reserved.
# Permission is granted for use, copying, modification, distribution,
# and distribution of modified versions of this work as long as the
# above copyright notice is included.
#++
######################################################################
# BlankSlate provides an abstract base class with no predefined
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
# BlankSlate is useful as a base class when writing classes that
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
#
class BlankSlate
class << self
# Hide the method named +name+ in the BlankSlate class. Don't
# hide +instance_eval+ or any method beginning with "__".
def hide(name)
if (instance_methods.include?(name) || instance_methods.include?(name.to_sym)) and
name !~ /^(__|instance_eval|object_id)/
@hidden_methods ||= {}
@hidden_methods[name] = instance_method(name)
undef_method name
end
end
def find_hidden_method(name)
@hidden_methods ||= {}
@hidden_methods[name] || superclass.find_hidden_method(name)
end
# Redefine a previously hidden method so that it may be called on a blank
# slate object.
def reveal(name)
bound_method = nil
unbound_method = find_hidden_method(name)
fail "Don't know how to reveal method '#{name}'" unless unbound_method
define_method(name) do |*args|
bound_method ||= unbound_method.bind(self)
bound_method.call(*args)
end
end
end
instance_methods.each { |m| hide(m) }
end
######################################################################
# Since Ruby is very dynamic, methods added to the ancestors of
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
# list of available BlankSlate methods. We handle this by defining a
# hook in the Object and Kernel classes that will hide any method
# defined after BlankSlate has been loaded.
#
module Kernel
class << self
alias_method :blank_slate_method_added, :method_added
# Detect method additions to Kernel and remove them in the
# BlankSlate class.
def method_added(name)
result = blank_slate_method_added(name)
return result if self != Kernel
BlankSlate.hide(name)
result
end
end
end
######################################################################
# Same as above, except in Object.
#
class Object
class << self
alias_method :blank_slate_method_added, :method_added
# Detect method additions to Object and remove them in the
# BlankSlate class.
def method_added(name)
result = blank_slate_method_added(name)
return result if self != Object
BlankSlate.hide(name)
result
end
def find_hidden_method(name)
nil
end
end
end
######################################################################
# Also, modules included into Object need to be scanned and have their
# instance methods removed from blank slate. In theory, modules
# included into Kernel would have to be removed as well, but a
# "feature" of Ruby prevents late includes into modules from being
# exposed in the first place.
#
class Module
alias blankslate_original_append_features append_features
def append_features(mod)
result = blankslate_original_append_features(mod)
return result if mod != Object
instance_methods.each do |name|
BlankSlate.hide(name)
end
result
end
end

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env ruby
#--
# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
# All rights reserved.
# Permission is granted for use, copying, modification, distribution,
# and distribution of modified versions of this work as long as the
# above copyright notice is included.
#++
require 'blankslate'
######################################################################
# BlankSlate has been promoted to a top level name and is now
# available as a standalone gem. We make the name available in the
# Builder namespace for compatibility.
#
module Builder
BlankSlate = ::BlankSlate
end

View File

@@ -18,8 +18,6 @@
# Style Sheets (CSS).
require 'builder/blankslate'
module Builder
# Create a Cascading Style Sheet (CSS) using Ruby.
@@ -89,7 +87,7 @@ module Builder
# background: red;
# }
#
class CSS < BlankSlate
class CSS < BasicObject
# Create a CSS builder.
#
@@ -155,7 +153,7 @@ module Builder
def group!(*args, &block)
args.each do |arg|
if arg.is_a?(Symbol)
if arg.is_a?(::Symbol)
instance_eval(&@library[arg])
else
instance_eval(&arg)
@@ -169,7 +167,7 @@ module Builder
end
def method_missing(sym, *args, &block)
sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol)
if block
_start_container(sym, args.first)
_css_block(block)

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env ruby
require 'builder/blankslate'
module Builder
# Generic error for builder
@@ -9,7 +7,7 @@ module Builder
# XmlBase is a base class for building XML builders. See
# Builder::XmlMarkup and Builder::XmlEvents for examples.
class XmlBase < BlankSlate
class XmlBase < BasicObject
# Create an XML markup builder.
#
@@ -37,10 +35,10 @@ module Builder
def method_missing(sym, *args, &block)
text = nil
attrs = nil
sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol)
args.each do |arg|
case arg
when Hash
when ::Hash
attrs ||= {}
attrs.merge!(arg)
else
@@ -50,7 +48,7 @@ module Builder
end
if block
unless text.nil?
raise ArgumentError, "XmlMarkup cannot mix a text argument with a block"
raise ::ArgumentError, "XmlMarkup cannot mix a text argument with a block"
end
_indent
_start_tag(sym, attrs)

View File

@@ -195,7 +195,7 @@ module Builder
end
def comment!(comment_text)
_ensure_no_block block_given?
_ensure_no_block ::Kernel.block_given?
_special("<!-- ", " -->", comment_text, nil)
end
@@ -210,13 +210,13 @@ module Builder
@target << "<!#{inst}"
args.each do |arg|
case arg
when String
when ::String
@target << %{ "#{arg}"} # " WART
when Symbol
when ::Symbol
@target << " #{arg}"
end
end
if block_given?
if ::Kernel.block_given?
@target << " ["
_newline
_nested_structures(block)
@@ -236,7 +236,7 @@ module Builder
# #=> <?aaa bbb="ccc"?>
#
def instruct!(directive_tag=:xml, attrs={})
_ensure_no_block block_given?
_ensure_no_block ::Kernel.block_given?
if directive_tag == :xml
a = { :version=>"1.0", :encoding=>"UTF-8" }
attrs = a.merge attrs
@@ -257,7 +257,7 @@ module Builder
# #=> <![CDATA[text to be included in cdata]]>
#
def cdata!(text)
_ensure_no_block block_given?
_ensure_no_block ::Kernel.block_given?
_special("<![CDATA[", "]]>", text, nil)
end
@@ -309,7 +309,7 @@ module Builder
def _attr_value(value)
case value
when Symbol
when ::Symbol
value.to_s
else
_escape_quote(value.to_s)