Skip to content

Commit

Permalink
Extended template caching to rxml and attempted to fix periodical cac…
Browse files Browse the repository at this point in the history
…hing issue [Stephan Kaes]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1902 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Jul 23, 2005
1 parent 98fb9e5 commit 7fe3fd2
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 41 deletions.
2 changes: 1 addition & 1 deletion actionpack/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

* Added support for per-action session management #1763

* Improved rendering speed on complicated templates by up to 25% #1234 [Stephan Kaes]. This did necessasitate a change to the internals of ActionView#render_template that now has four parameters. Developers of custom view handlers (like Amrita) need to update for that.
* Improved rendering speed on complicated templates by up to 100% (the more complex the templates, the higher the speedup) #1234 [Stephan Kaes]. This did necessasitate a change to the internals of ActionView#render_template that now has four parameters. Developers of custom view handlers (like Amrita) need to update for that.

* Added options hash as third argument to FormHelper#input, so you can do input('person', 'zip', :size=>10) #1719 [jeremye@bsa.ca.gov]

Expand Down
89 changes: 49 additions & 40 deletions actionpack/lib/action_view/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,17 @@ class ActionViewError < StandardError #:nodoc:
# More builder documentation can be found at http://builder.rubyforge.org.
class Base
include ERB::Util

attr_reader :first_render
attr_accessor :base_path, :assigns, :template_extension
attr_accessor :controller

attr_reader :logger, :params, :response, :session, :headers, :flash

# Turn on to cache the reading of templates from the file system. Doing so means that you have to restart the server
# when changing templates, but that rendering will be faster.
# Turn on to cache the reading of templates from the file system.
# Doing so means that you have to restart the server when changing
# templates, but it will save checking whether the file has changed
# on disk.
@@cache_template_loading = false
cattr_accessor :cache_template_loading

Expand All @@ -135,8 +137,8 @@ class Base
@@erb_trim_mode = '-'
cattr_accessor :erb_trim_mode

@@compiled_erb_templates = {}
@@erb_count = 0
@@compiled_templates = {}
@@template_count = 0
@@loaded_templates = {}
@@template_handlers = {}

Expand Down Expand Up @@ -165,15 +167,15 @@ def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)
# is made available as local variables.
def render_file(template_path, use_full_path = true, local_assigns = {})
@first_render = template_path if @first_render.nil?

if use_full_path
template_extension = pick_template_extension(template_path)
template_file_name = full_template_path(template_path, template_extension)
else
template_file_name = template_path
template_extension = template_path.split('.').last
end

template_source = read_template_file(template_file_name, template_extension)

begin
Expand All @@ -187,7 +189,7 @@ def render_file(template_path, use_full_path = true, local_assigns = {})
end
end
end

# Renders the template present at <tt>template_path</tt> (relative to the template_root).
# The hash in <tt>local_assigns</tt> is made available as local variables.
def render(options = {}, old_local_assigns = {})
Expand All @@ -196,7 +198,7 @@ def render(options = {}, old_local_assigns = {})
elsif options.is_a?(Hash)
options[:locals] ||= {}
options[:use_full_path] = options[:use_full_path].nil? ? true : options[:use_full_path]

if options[:file]
render_file(options[:file], options[:use_full_path], options[:locals])
elsif options[:partial] && options[:collection]
Expand All @@ -208,7 +210,7 @@ def render(options = {}, old_local_assigns = {})
end
end
end

# Renders the +template+ which is given as a string as either rhtml or rxml depending on <tt>template_extension</tt>.
# The hash in <tt>local_assigns</tt> is made available as local variables.
def render_template(template_extension, template, file_name = nil, local_assigns = {})
Expand All @@ -232,7 +234,7 @@ def pick_template_extension(template_path)#:nodoc:
raise ActionViewError, "No rhtml, rxml, or delegate template found for #{template_path}"
end
end

def delegate_template_exists?(template_path)#:nodoc:
@@template_handlers.find { |k,| template_exists?(template_path, k) }
end
Expand Down Expand Up @@ -271,70 +273,77 @@ def read_template_file(template_path, extension)
!@@cache_template_loading )
if read_file
@@loaded_templates[template_path] = info = File.read(template_path)
@@compiled_erb_templates[template_path] = nil if 'rhtml' == extension
@@compiled_templates[template_path] = nil
end
info
end

def evaluate_assigns(local_assigns = {})
@assigns.each { |key, value| instance_variable_set "@#{key}", value }
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
saved_locals = {}
local_assigns.each do |key, value|
varstr = "@_#{key}_"
saved_locals[varstr] = instance_variable_get varstr
instance_variable_set varstr, value
unless self.respond_to? key
self.class.class_eval "def #{key}; #{varstr}; end"
self.class.class_eval "def #{key}=(v); #{varstr} = v; end"
saved_locals[varstr] = instance_variable_get(varstr)
instance_variable_set(varstr, value)
unless self.respond_to?(key)
self.class.class_eval("def #{key}; #{varstr}; end")
self.class.class_eval("def #{key}=(v); #{varstr} = v; end")
end
end

saved_locals
end

def compile_erb_template(template, file_name)
def compile_template(extension, template, file_name)
cache_name = file_name || template

unless @@compiled_erb_templates[cache_name]
erb = ERB.new(template, nil, @@erb_trim_mode)
erb_name = 'run_erb_'
unless @@compiled_templates[cache_name]
t_name, t_arg, t_code = nil
case extension
when :rhtml
t_name = 'run_html_'
t_arg = ''
t_code = ERB.new(template, nil, @@erb_trim_mode).src
when :rxml
t_name = 'run_xml_'
t_arg = '(xml)'
t_code = template
end
if file_name
i = file_name.index(@base_path)
l = @base_path.length
s_file_name = i ? file_name[i+l+1,file_name.length-l-1] : file_name
s_file_name.sub!(/.rhtml$/,'')
s_file_name.sub!(/(.rhtml|.rxml)$/,'')
s_file_name.tr!('/:-', '_')
s_file_name.gsub!(/[^a-zA-Z0-9_]/){|s| s[0].to_s}
erb_name += s_file_name
t_name += s_file_name
else
@@erb_count += 1
erb_name += @@erb_count.to_s
@@template_count += 1
t_name += @@template_count.to_s
end
erb_def = "def #{erb_name}; #{erb.src}; end"
eval erb_def rescue raise ActionViewError, "ERROR defining #{erb_name}: #{erb_def}"
t_def = "def #{t_name}#{t_arg}; #{t_code}; end"
self.class.class_eval(t_def) rescue raise ActionViewError, "ERROR defining #{t_name}: #{t_def}"

@@compiled_erb_templates[cache_name] = erb_name.intern
@@compiled_templates[cache_name] = t_name.intern
@@loaded_templates[cache_name] = Time.now if file_name
logger.debug "Compiled erb template #{cache_name}\n ==> #{erb_name}" if logger
logger.info "Compiled template #{cache_name}\n ==> #{t_name}" if logger
end

@@compiled_erb_templates[cache_name]
@@compiled_templates[cache_name]
end

def rhtml_render(extension, template, file_name, local_assigns)
render_sym = compile_erb_template(template, file_name)
render_sym = compile_template(:rhtml, template, file_name)
saved_locals = evaluate_assigns(local_assigns)
result = self.send(render_sym)
saved_locals.each { |k,v| instance_variable_set(k, v) }
saved_locals.each{ |k,v| instance_variable_set(k, v) }
result
end

def rxml_render(extension, template, file_name, local_assigns)
@controller.headers["Content-Type"] ||= 'text/xml'
render_sym = compile_template(:rxml, template, file_name)
saved_locals = evaluate_assigns(local_assigns)
xml = Builder::XmlMarkup.new(:indent => 2)
result = eval(template, binding, '(template)(eval)', 1)
saved_locals.each { |k,v| instance_variable_set(k,v) }
result = self.send(render_sym, Builder::XmlMarkup.new(:indent => 2))
saved_locals.each{ |k,v| instance_variable_set(k, v) }
result
end

Expand All @@ -344,4 +353,4 @@ def delegate_render(handler, template, local_assigns)
end
end

require 'action_view/template_error'
require 'action_view/template_error'

0 comments on commit 7fe3fd2

Please sign in to comment.