aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2009-04-30 13:29:33 +0100
committerPratik Naik <pratiknaik@gmail.com>2009-04-30 13:29:33 +0100
commit5f24ed718f92abe97fc3f50a36c9fb09499d0173 (patch)
treed097bb0e59c4a31c262fe83081e396219e7186bd /actionpack/lib/action_view
parent35ca877abc889d863747726e3da6e359ba928506 (diff)
parent79420e71e0e75d6f81e5284184bac4e7d0b02c30 (diff)
downloadrails-5f24ed718f92abe97fc3f50a36c9fb09499d0173.tar.gz
rails-5f24ed718f92abe97fc3f50a36c9fb09499d0173.tar.bz2
rails-5f24ed718f92abe97fc3f50a36c9fb09499d0173.zip
Merge commit 'mainstream/master'
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r--actionpack/lib/action_view/base.rb6
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb20
-rw-r--r--actionpack/lib/action_view/paths.rb12
-rw-r--r--actionpack/lib/action_view/render/rendering.rb13
-rw-r--r--actionpack/lib/action_view/template/error.rb4
-rw-r--r--actionpack/lib/action_view/template/handlers.rb2
-rw-r--r--actionpack/lib/action_view/template/path.rb68
-rw-r--r--actionpack/lib/action_view/template/template.rb216
-rw-r--r--actionpack/lib/action_view/test_case.rb12
9 files changed, 135 insertions, 218 deletions
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index efed19a21d..44bd401631 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -191,12 +191,14 @@ module ActionView #:nodoc:
ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading)
end
- attr_internal :request
+ attr_internal :request, :layout
delegate :controller_path, :to => :controller, :allow_nil => true
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
- :flash, :logger, :action_name, :controller_name, :to => :controller
+ :flash, :action_name, :controller_name, :to => :controller
+
+ delegate :logger, :to => :controller, :allow_nil => true
delegate :find_by_parts, :to => :view_paths
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index fb8122af35..1fbe012a95 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -686,7 +686,7 @@ module ActionView
# Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
# expression as an argument to another JavaScriptGenerator method.
def literal(code)
- ActiveSupport::JSON::Variable.new(code.to_s)
+ ::ActiveSupport::JSON::Variable.new(code.to_s)
end
# Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be
@@ -973,7 +973,7 @@ module ActionView
def loop_on_multiple_args(method, ids)
record(ids.size>1 ?
"#{javascript_object_for(ids)}.each(#{method})" :
- "#{method}(#{ActiveSupport::JSON.encode(ids.first)})")
+ "#{method}(#{javascript_object_for(ids.first)})")
end
def page
@@ -997,7 +997,7 @@ module ActionView
end
def javascript_object_for(object)
- ActiveSupport::JSON.encode(object)
+ ::ActiveSupport::JSON.encode(object)
end
def arguments_for_call(arguments, block = nil)
@@ -1139,7 +1139,7 @@ module ActionView
class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
def initialize(generator, id)
@id = id
- super(generator, "$(#{ActiveSupport::JSON.encode(id)})")
+ super(generator, "$(#{::ActiveSupport::JSON.encode(id)})")
end
# Allows access of element attributes through +attribute+. Examples:
@@ -1180,16 +1180,14 @@ module ActionView
# The JSON Encoder calls this to check for the +to_json+ method
# Since it's a blank slate object, I suppose it responds to anything.
- def respond_to?(method)
+ def respond_to?(*)
true
end
- def rails_to_json(options = nil)
+ def rails_to_json(*)
@variable
end
- alias to_json rails_to_json
-
private
def append_to_function_chain!(call)
@generator << @variable if @empty
@@ -1213,7 +1211,7 @@ module ActionView
enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block
else
add_variable_assignment!(variable)
- append_enumerable_function!("eachSlice(#{ActiveSupport::JSON.encode(number)});")
+ append_enumerable_function!("eachSlice(#{::ActiveSupport::JSON.encode(number)});")
end
end
@@ -1234,7 +1232,7 @@ module ActionView
def pluck(variable, property)
add_variable_assignment!(variable)
- append_enumerable_function!("pluck(#{ActiveSupport::JSON.encode(property)});")
+ append_enumerable_function!("pluck(#{::ActiveSupport::JSON.encode(property)});")
end
def zip(variable, *arguments, &block)
@@ -1298,7 +1296,7 @@ module ActionView
class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
def initialize(generator, pattern)
- super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})")
+ super(generator, "$$(#{::ActiveSupport::JSON.encode(pattern)})")
end
end
end
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index e48088f344..f6d021c92a 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -3,7 +3,7 @@ module ActionView #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
cache = !Object.const_defined?(:Rails) || Rails.configuration.cache_classes
- Template::FileSystemPath.new(obj, :cache => cache)
+ Template::FileSystemPathWithFallback.new(obj, :cache => cache)
else
obj
end
@@ -34,18 +34,18 @@ module ActionView #:nodoc:
end
def find_by_parts(path, details = {}, prefix = nil, partial = false)
- template_path = path.sub(/^\//, '')
+ # template_path = path.sub(/^\//, '')
+ template_path = path
each do |load_path|
if template = load_path.find_by_parts(template_path, details, prefix, partial)
return template
end
end
-
- Template.new(path, self)
- rescue ActionView::MissingTemplate => e
+
+ # TODO: Have a fallback absolute path?
extension = details[:formats] || []
- raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}")
+ raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}")
end
def find_by_parts?(path, extension = nil, prefix = nil, partial = false)
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 4213b09e48..6e368f27eb 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -46,8 +46,8 @@ module ActionView
locals ||= {}
if controller && layout
- response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response)
- logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger
+ @_layout = layout.identifier
+ logger.info("Rendering template within #{layout.identifier}") if logger
end
begin
@@ -76,7 +76,6 @@ module ActionView
end
end
rescue Exception => e
- raise e if template.is_a?(InlineTemplate) || !template.filename
if TemplateError === e
e.sub_template_of(template)
raise e
@@ -86,7 +85,9 @@ module ActionView
end
def _render_inline(inline, layout, options)
- content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {})
+ handler = Template.handler_class_for_extension(options[:type] || "erb")
+ template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
+ content = _render_template(template, options[:locals] || {})
layout ? _render_content_with_layout(content, layout, options[:locals]) : content
end
@@ -96,7 +97,7 @@ module ActionView
def _render_template_with_layout(template, layout = nil, options = {}, partial = false)
if controller && logger
- logger.info("Rendering #{template.path_without_extension}" +
+ logger.info("Rendering #{template.identifier}" +
(options[:status] ? " (#{options[:status]})" : ''))
end
@@ -107,7 +108,7 @@ module ActionView
_render_template(template, options[:locals] || {})
end
- return content unless layout && !template.exempt_from_layout?
+ return content unless layout
_render_content_with_layout(content, layout, options[:locals] || {})
end
end
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index 37cb1c7c6c..a06e80b294 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -12,7 +12,7 @@ module ActionView
end
def file_name
- @template.relative_path
+ @template.identifier
end
def message
@@ -30,7 +30,7 @@ module ActionView
def sub_template_message
if @sub_templates
"Trace of template inclusion: " +
- @sub_templates.collect { |template| template.relative_path }.join(", ")
+ @sub_templates.collect { |template| template.identifier }.join(", ")
else
""
end
diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb
index 448ab6731b..0590372d09 100644
--- a/actionpack/lib/action_view/template/handlers.rb
+++ b/actionpack/lib/action_view/template/handlers.rb
@@ -46,7 +46,7 @@ module ActionView #:nodoc:
end
def handler_class_for_extension(extension)
- registered_template_handler(extension) || @@default_template_handlers
+ (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers
end
end
end
diff --git a/actionpack/lib/action_view/template/path.rb b/actionpack/lib/action_view/template/path.rb
index 660a7e91a2..478bf96c9a 100644
--- a/actionpack/lib/action_view/template/path.rb
+++ b/actionpack/lib/action_view/template/path.rb
@@ -1,3 +1,5 @@
+require "pathname"
+
module ActionView
class Template
# Abstract super class
@@ -26,13 +28,6 @@ module ActionView
def find_templates(name, details, prefix, partial)
raise NotImplementedError
end
-
- # TODO: Refactor this to abstract out the file system
- def initialize_template(file)
- t = Template.new(file.split("#{self}/").last, self)
- t.load!
- t
- end
def valid_handlers
@valid_handlers ||= TemplateHandlers.extensions
@@ -44,10 +39,10 @@ module ActionView
/\.(?:#{e})$/
end
end
-
+
def handler_glob
- e = TemplateHandlers.extensions.join(',')
- ".{#{e}}"
+ e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join
+ "{#{e}}"
end
def formats_glob
@@ -69,23 +64,19 @@ module ActionView
def initialize(path, options = {})
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
super(options)
- @path = path
+ @path = Pathname.new(path).expand_path
end
-
+
# TODO: This is the currently needed API. Make this suck less
# ==== <suck>
attr_reader :path
def to_s
- if defined?(RAILS_ROOT)
- path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '')
- else
- path.to_s
- end
+ path.to_s
end
def to_str
- path.to_str
+ path.to_s
end
def ==(path)
@@ -97,11 +88,15 @@ module ActionView
end
# ==== </suck>
- def find_templates(name, details, prefix, partial)
- if glob = parts_to_glob(name, details, prefix, partial)
+ def find_templates(name, details, prefix, partial, root = "#{@path}/")
+ if glob = details_to_glob(name, details, prefix, partial, root)
cached(glob) do
Dir[glob].map do |path|
- initialize_template(path) unless File.directory?(path)
+ next if File.directory?(path)
+ source = File.read(path)
+ identifier = Pathname.new(path).expand_path.to_s
+
+ Template.new(source, identifier, *path_to_details(path))
end.compact
end
end
@@ -109,7 +104,8 @@ module ActionView
private
- def parts_to_glob(name, details, prefix, partial)
+ # :api: plugin
+ def details_to_glob(name, details, prefix, partial, root)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
@@ -123,8 +119,34 @@ module ActionView
end
end
- "#{@path}/#{path}#{extensions}#{handler_glob}"
+ "#{root}#{path}#{extensions}#{handler_glob}"
+ end
+
+ # TODO: fix me
+ # :api: plugin
+ def path_to_details(path)
+ # [:erb, :format => :html, :locale => :en, :partial => true/false]
+ if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$')
+ partial = m[1] == '_'
+ details = (m[2]||"").split('.').reject { |e| e.empty? }
+ handler = Template.handler_class_for_extension(m[3])
+
+ format = Mime[details.last] && details.pop.to_sym
+ locale = details.last && details.pop.to_sym
+
+ return handler, :format => format, :locale => locale, :partial => partial
+ end
end
end
+
+ class FileSystemPathWithFallback < FileSystemPath
+
+ def find_templates(name, details, prefix, partial)
+ templates = super
+ return super(name, details, prefix, partial, '') if templates.empty?
+ templates
+ end
+
+ end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb
index e541336613..dcc5006103 100644
--- a/actionpack/lib/action_view/template/template.rb
+++ b/actionpack/lib/action_view/template/template.rb
@@ -1,188 +1,80 @@
+# encoding: utf-8
+# This is so that templates compiled in this file are UTF-8
+
require 'set'
require "action_view/template/path"
-module ActionView #:nodoc:
+module ActionView
class Template
extend TemplateHandlers
- extend ActiveSupport::Memoizable
-
- module Loading
- def load!
- @cached = true
- # freeze
- end
- end
- include Loading
-
- include Renderable
-
- # Templates that are exempt from layouts
- @@exempt_from_layout = Set.new([/\.rjs$/])
-
- # Don't render layouts for templates with the given extensions.
- def self.exempt_from_layout(*extensions)
- regexps = extensions.collect do |extension|
- extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
- end
- @@exempt_from_layout.merge(regexps)
- end
-
- attr_accessor :template_path, :filename, :load_path, :base_path
- attr_accessor :locale, :name, :format, :extension
- delegate :to_s, :to => :path
-
- def initialize(template_path, load_paths = [])
- template_path = template_path.dup
- @load_path, @filename = find_full_path(template_path, load_paths)
- @base_path, @name, @locale, @format, @extension = split(template_path)
- @base_path.to_s.gsub!(/\/$/, '') # Push to split method
-
- # Extend with partial super powers
- extend RenderablePartial if @name =~ /^_/
- end
+ attr_reader :source, :identifier, :handler
- def accessible_paths
- paths = []
-
- if valid_extension?(extension)
- paths << path
- paths << path_without_extension
- if multipart?
- formats = format.split(".")
- paths << "#{path_without_format_and_extension}.#{formats.first}"
- paths << "#{path_without_format_and_extension}.#{formats.second}"
- end
- else
- # template without explicit template handler should only be reachable through its exact path
- paths << template_path
- end
-
- paths
+ def initialize(source, identifier, handler, details)
+ @source = source
+ @identifier = identifier
+ @handler = handler
+ @details = details
end
- def relative_path
- path = File.expand_path(filename)
- path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT)
- path
+ def render(view, locals, &blk)
+ method_name = compile(locals, view)
+ view.send(method_name, locals, &blk)
end
- memoize :relative_path
- def source
- File.read(filename)
+ # TODO: Figure out how to abstract this
+ def variable_name
+ identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end
- memoize :source
-
- def exempt_from_layout?
- @@exempt_from_layout.any? { |exempted| path =~ exempted }
- end
-
- def path_without_extension
- [base_path, [name, locale, format].compact.join('.')].compact.join('/')
- end
- memoize :path_without_extension
- def path_without_format_and_extension
- [base_path, [name, locale].compact.join('.')].compact.join('/')
+ # TODO: Figure out how to abstract this
+ def counter_name
+ "#{variable_name}_counter".to_sym
end
- memoize :path_without_format_and_extension
- def path
- [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/')
+ # TODO: kill hax
+ def partial?
+ @details[:partial]
end
- memoize :path
+ # TODO: Move out of Template
def mime_type
- Mime::Type.lookup_by_extension(format) if format && defined?(::Mime)
+ Mime::Type.lookup_by_extension(@details[:format].to_s) if @details[:format]
end
- memoize :mime_type
-
- def multipart?
- format && format.include?('.')
- end
-
- def content_type
- format && format.gsub('.', '/')
- end
private
-
- def format_and_extension
- (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions
- end
- memoize :format_and_extension
-
- def mtime
- File.mtime(filename)
- end
- memoize :mtime
-
- def method_segment
- relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord }
- end
- memoize :method_segment
-
- def stale?
- File.mtime(filename) > mtime
- end
-
- def recompile?
- !@cached
- end
-
- def valid_extension?(extension)
- !Template.registered_template_handler(extension).nil?
- end
- def valid_locale?(locale)
- I18n.available_locales.include?(locale.to_sym)
- end
+ def compile(locals, view)
+ method_name = build_method_name(locals)
+
+ return method_name if view.respond_to?(method_name)
+
+ locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join
+
+ source = <<-end_src
+ def #{method_name}(local_assigns)
+ old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)}
+ ensure
+ self.output_buffer = old_output_buffer
+ end
+ end_src
+
+ begin
+ ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0)
+ method_name
+ rescue Exception => e # errors from template code
+ if logger = (view && view.logger)
+ logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
+ logger.debug "Function body: #{source}"
+ logger.debug "Backtrace: #{e.backtrace.join("\n")}"
+ end
- def find_full_path(path, load_paths)
- load_paths = Array(load_paths) + [nil]
- load_paths.each do |load_path|
- file = load_path ? "#{load_path.to_str}/#{path}" : path
- return load_path, file if File.file?(file)
+ raise ActionView::TemplateError.new(self, {}, e)
end
- raise MissingTemplate.new(load_paths, path)
end
-
- # Returns file split into an array
- # [base_path, name, locale, format, extension]
- def split(file)
- if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
- base_path = m[1]
- name = m[2]
- extensions = m[3]
- else
- return
- end
-
- locale = nil
- format = nil
- extension = nil
-
- if m = extensions.split(".")
- if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three
- locale = m[0]
- format = m[1]
- extension = m[2]
- elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats
- format = "#{m[0]}.#{m[1]}"
- extension = m[2]
- elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension
- locale = m[0]
- extension = m[1]
- elsif valid_extension?(m[1]) # format and extension
- format = m[0]
- extension = m[1]
- elsif valid_extension?(m[0]) # Just extension
- extension = m[0]
- else # No extension
- format = m[0]
- end
- end
-
- [base_path, name, locale, format, extension]
+
+ def build_method_name(locals)
+ # TODO: is locals.keys.hash reliably the same?
+ "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index c8f204046b..50bed67f7d 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -7,15 +7,17 @@ module ActionView
@_rendered = { :template => nil, :partials => Hash.new(0) }
initialize_without_template_tracking(*args)
end
-
+
+ attr_internal :rendered
alias_method :_render_template_without_template_tracking, :_render_template
def _render_template(template, local_assigns = {})
- if template.respond_to?(:path) && !template.is_a?(InlineTemplate)
- @_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial)
- @_rendered[:template] ||= template
+ if template.respond_to?(:identifier)
+ @_rendered[:partials][template] += 1 if template.partial?
+ @_rendered[:template] ||= []
+ @_rendered[:template] << template
end
_render_template_without_template_tracking(template, local_assigns)
- end
+ end
end
class TestCase < ActiveSupport::TestCase