aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2009-09-21 21:14:04 +0100
committerPratik Naik <pratiknaik@gmail.com>2009-09-21 21:14:04 +0100
commit340be9bddd8e5902e0218a0101a40a17a4afd558 (patch)
treeef4de25f3f8eb610dc2235f0762b01cb1d464efd /actionpack/lib/action_view
parentb31cdb55422226cd45a2234a4b54986f1f611151 (diff)
parent1bbb9b2db05730194edfd7d2cef9f5fcb9d79e50 (diff)
downloadrails-340be9bddd8e5902e0218a0101a40a17a4afd558.tar.gz
rails-340be9bddd8e5902e0218a0101a40a17a4afd558.tar.bz2
rails-340be9bddd8e5902e0218a0101a40a17a4afd558.zip
Merge commit 'mainstream/master'
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb9
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb26
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb1
-rw-r--r--actionpack/lib/action_view/template/handlers/builder.rb2
-rw-r--r--actionpack/lib/action_view/template/inline.rb19
-rw-r--r--actionpack/lib/action_view/template/partial.rb18
-rw-r--r--actionpack/lib/action_view/template/renderable.rb93
-rw-r--r--actionpack/lib/action_view/template/resolver.rb185
-rw-r--r--actionpack/lib/action_view/template/template.rb6
10 files changed, 129 insertions, 232 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index c71840d41f..95f00cda39 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,3 +1,4 @@
+require 'thread'
require 'cgi'
require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
@@ -286,7 +287,9 @@ module ActionView
end
javascript_src_tag(joined_javascript_name, options)
else
- ensure_javascript_sources!(expand_javascript_sources(sources, recursive)).collect { |source| javascript_src_tag(source, options) }.join("\n")
+ sources = expand_javascript_sources(sources, recursive)
+ ensure_javascript_sources!(sources) if cache
+ sources.collect { |source| javascript_src_tag(source, options) }.join("\n")
end
end
@@ -435,7 +438,9 @@ module ActionView
end
stylesheet_tag(joined_stylesheet_name, options)
else
- ensure_stylesheet_sources!(expand_stylesheet_sources(sources, recursive)).collect { |source| stylesheet_tag(source, options) }.join("\n")
+ sources = expand_stylesheet_sources(sources, recursive)
+ ensure_stylesheet_sources!(sources) if cache
+ sources.collect { |source| stylesheet_tag(source, options) }.join("\n")
end
end
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 81029102b1..32b9c4a7dd 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -449,6 +449,15 @@ module ActionView
# <% end %>
# <% end %>
#
+ # Or a collection to be used:
+ #
+ # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # ...
+ # <% person_form.fields_for :projects, @active_projects do |project_fields| %>
+ # Name: <%= project_fields.text_field :name %>
+ # <% end %>
+ # <% end %>
+ #
# When projects is already an association on Person you can use
# +accepts_nested_attributes_for+ to define the writer method for you:
#
@@ -1037,18 +1046,21 @@ module ActionView
def fields_for_with_nested_attributes(association_name, args, block)
name = "#{object_name}[#{association_name}_attributes]"
- association = @object.send(association_name)
- explicit_object = args.first.to_model if args.first.respond_to?(:to_model)
+ association = args.first.to_model if args.first.respond_to?(:to_model)
+
+ if association.respond_to?(:new_record?)
+ association = [association] if @object.send(association_name).is_a?(Array)
+ elsif !association.is_a?(Array)
+ association = @object.send(association_name)
+ end
if association.is_a?(Array)
- children = explicit_object ? [explicit_object] : association
explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash)
-
- children.map do |child|
+ association.map do |child|
fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block)
end.join
- else
- fields_for_nested_model(name, explicit_object || association, args, block)
+ elsif association
+ fields_for_nested_model(name, association, args, block)
end
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index ff5a2134ff..7fae0f6b8d 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -106,7 +106,7 @@ module ActionView
# escape_once("&lt;&lt; Accept & Checkout")
# # => "&lt;&lt; Accept &amp; Checkout"
def escape_once(html)
- html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
+ ActiveSupport::Multibyte.clean(html.to_s).gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
end
private
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index b07304e361..204d4d71e1 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -1,4 +1,5 @@
require 'action_view/helpers/javascript_helper'
+require 'active_support/core_ext/array/access'
require 'active_support/core_ext/hash/keys'
module ActionView
diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb
index 5f381f7bf0..ba0d17b5af 100644
--- a/actionpack/lib/action_view/template/handlers/builder.rb
+++ b/actionpack/lib/action_view/template/handlers/builder.rb
@@ -6,7 +6,7 @@ module ActionView
self.default_format = Mime::XML
def compile(template)
- require 'builder'
+ require 'active_support/vendor/builder'
"xml = ::Builder::XmlMarkup.new(:indent => 2);" +
"self.output_buffer = xml.target!;" +
template.source +
diff --git a/actionpack/lib/action_view/template/inline.rb b/actionpack/lib/action_view/template/inline.rb
deleted file mode 100644
index 54efa543c8..0000000000
--- a/actionpack/lib/action_view/template/inline.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module ActionView #:nodoc:
- class InlineTemplate #:nodoc:
- include Renderable
-
- attr_reader :source, :extension, :method_segment
-
- def initialize(source, type = nil)
- @source = source
- @extension = type
- @method_segment = "inline_#{@source.hash.abs}"
- end
-
- private
- # Always recompile inline templates
- def recompile?
- true
- end
- end
-end
diff --git a/actionpack/lib/action_view/template/partial.rb b/actionpack/lib/action_view/template/partial.rb
deleted file mode 100644
index 30dec1dc5b..0000000000
--- a/actionpack/lib/action_view/template/partial.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module ActionView
- # NOTE: The template that this mixin is being included into is frozen
- # so you cannot set or modify any instance variables
- module RenderablePartial #:nodoc:
- extend ActiveSupport::Memoizable
-
- def variable_name
- name.sub(/\A_/, '').to_sym
- end
- memoize :variable_name
-
- def counter_name
- "#{variable_name}_counter".to_sym
- end
- memoize :counter_name
-
- end
-end
diff --git a/actionpack/lib/action_view/template/renderable.rb b/actionpack/lib/action_view/template/renderable.rb
deleted file mode 100644
index 7687578165..0000000000
--- a/actionpack/lib/action_view/template/renderable.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# encoding: utf-8
-
-module ActionView
- # NOTE: The template that this mixin is being included into is frozen
- # so you cannot set or modify any instance variables
- module Renderable #:nodoc:
- extend ActiveSupport::Memoizable
-
- def render(view, locals)
- compile(locals)
- view.send(method_name(locals), locals) {|*args| yield(*args) }
- end
-
- def load!
- names = CompiledTemplates.instance_methods.grep(/#{method_name_without_locals}/)
- names.each do |name|
- CompiledTemplates.class_eval do
- remove_method(name)
- end
- end
- super
- end
-
- private
-
- def filename
- 'compiled-template'
- end
-
- def handler
- Template.handler_class_for_extension(extension)
- end
- memoize :handler
-
- def compiled_source
- handler.call(self)
- end
- memoize :compiled_source
-
- def method_name_without_locals
- ['_run', extension, method_segment].compact.join('_')
- end
- memoize :method_name_without_locals
-
- def method_name(local_assigns)
- if local_assigns && local_assigns.any?
- method_name = method_name_without_locals.dup
- method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
- else
- method_name = method_name_without_locals
- end
- method_name.to_sym
- end
-
- # Compile and evaluate the template's code (if necessary)
- def compile(local_assigns)
- render_symbol = method_name(local_assigns)
-
- if !CompiledTemplates.method_defined?(render_symbol) || recompile?
- compile!(render_symbol, local_assigns)
- end
- end
-
- private
- def compile!(render_symbol, local_assigns)
- locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
-
- source = <<-end_src
- def #{render_symbol}(local_assigns)
- old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
- ensure
- self.output_buffer = old_output_buffer
- end
- end_src
-
- begin
- ActionView::CompiledTemplates.module_eval(source, filename.to_s, 0)
- rescue Exception => e # errors from template code
- if logger = defined?(ActionController) && Base.logger
- logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
- logger.debug "Function body: #{source}"
- logger.debug "Backtrace: #{e.backtrace.join("\n")}"
- end
-
- raise ActionView::TemplateError.new(self, {}, e)
- end
- end
-
- def recompile?
- false
- end
- end
-end
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 0b4c62d4d0..f5591ead09 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -1,9 +1,28 @@
require "pathname"
+require "active_support/core_ext/class"
require "action_view/template/template"
module ActionView
# Abstract superclass
class Resolver
+
+ class_inheritable_accessor(:registered_details)
+ self.registered_details = {}
+
+ def self.register_detail(name, options = {})
+ registered_details[name] = lambda do |val|
+ val ||= yield
+ val |= [nil] unless options[:allow_nil] == false
+ val
+ end
+ end
+
+ register_detail(:locale) { [I18n.locale] }
+ register_detail(:formats) { Mime::SET.symbols }
+ register_detail(:handlers, :allow_nil => false) do
+ TemplateHandlers.extensions
+ end
+
def initialize(options = {})
@cache = options[:cache]
@cached = {}
@@ -11,15 +30,18 @@ module ActionView
# Normalizes the arguments and passes it on to find_template
def find(*args)
- find_all_by_parts(*args).first
+ find_all(*args).first
end
-
- def find_all_by_parts(name, details = {}, prefix = nil, partial = nil)
- details[:locales] = [I18n.locale]
- name = name.to_s.gsub(handler_matcher, '').split("/")
- find_templates(name.pop, details, [prefix, *name].compact.join("/"), partial)
+
+ def find_all(name, details = {}, prefix = nil, partial = nil)
+ details = normalize_details(details)
+ name, prefix = normalize_name(name, prefix)
+
+ cached([name, details, prefix, partial]) do
+ find_templates(name, details, prefix, partial)
+ end
end
-
+
private
# This is what child classes implement. No defaults are needed
@@ -28,29 +50,26 @@ module ActionView
def find_templates(name, details, prefix, partial)
raise NotImplementedError
end
-
- def valid_handlers
- @valid_handlers ||= TemplateHandlers.extensions
- end
- def handler_matcher
- @handler_matcher ||= begin
- e = valid_handlers.join('|')
- /\.(?:#{e})$/
+ def normalize_details(details)
+ details = details.dup
+ # TODO: Refactor this concern out of the resolver
+ details.delete(:formats) if details[:formats] == [:"*/*"]
+ registered_details.each do |k, v|
+ details[k] = v.call(details[k])
end
+ details
end
- def handler_glob
- @handler_glob ||= begin
- e = TemplateHandlers.extensions.map{|h| ".#{h}"}.join(",")
- "{#{e}}"
- end
- end
-
- def formats_glob
- @formats_glob ||= begin
- '{' + Mime::SET.symbols.map { |l| ".#{l}," }.join + '}'
- end
+ # Support legacy foo.erb names even though we now ignore .erb
+ # as well as incorrectly putting part of the path in the template
+ # name instead of the prefix.
+ def normalize_name(name, prefix)
+ handlers = TemplateHandlers.extensions.join('|')
+ name = name.to_s.gsub(/\.(?:#{handlers})$/, '')
+
+ parts = name.split('/')
+ return parts.pop, [prefix, *parts].compact.join("/")
end
def cached(key)
@@ -60,80 +79,49 @@ module ActionView
end
end
- class FileSystemResolver < Resolver
-
- def self.cached_glob
- @@cached_glob ||= {}
- end
-
- def initialize(path, options = {})
- raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
- super(options)
- @path = Pathname.new(path).expand_path
- end
+ class PathResolver < Resolver
- # TODO: This is the currently needed API. Make this suck less
- # ==== <suck>
- attr_reader :path
+ EXTENSION_ORDER = [:locale, :formats, :handlers]
def to_s
- path.to_s
+ @path.to_s
end
+ alias to_path to_s
- def to_str
- path.to_s
+ def find_templates(name, details, prefix, partial)
+ path = build_path(name, details, prefix, partial)
+ query(path, EXTENSION_ORDER.map { |ext| details[ext] })
end
- def ==(path)
- to_str == path.to_str
- end
+ private
- def eql?(path)
- to_str == path.to_str
+ def build_path(name, details, prefix, partial)
+ path = ""
+ path << "#{prefix}/" unless prefix.empty?
+ path << (partial ? "_#{name}" : name)
+ path
end
- # ==== </suck>
-
- 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|
- 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
+ def query(path, exts)
+ query = "#{@path}/#{path}"
+ exts.each do |ext|
+ query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << '}'
end
- end
-
- private
- # :api: plugin
- def details_to_glob(name, details, prefix, partial, root)
- self.class.cached_glob[[name, prefix, partial, details, root]] ||= begin
- path = ""
- path << "#{prefix}/" unless prefix.empty?
- path << (partial ? "_#{name}" : name)
-
- extensions = ""
- [:locales, :formats].each do |k|
- extensions << if exts = details[k]
- '{' + exts.map {|e| ".#{e},"}.join + '}'
- else
- k == :formats ? formats_glob : ''
- end
- end
-
- "#{root}#{path}#{extensions}#{handler_glob}"
- end
+ Dir[query].map do |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
- # TODO: fix me
- # :api: plugin
+ # # 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+)$')
+ 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])
@@ -146,13 +134,32 @@ module ActionView
end
end
- class FileSystemResolverWithFallback < FileSystemResolver
+ class FileSystemResolver < PathResolver
+ def initialize(path, options = {})
+ raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
+ super(options)
+ @path = Pathname.new(path).expand_path
+ end
+ end
- def find_templates(name, details, prefix, partial)
- templates = super
- return super(name, details, prefix, partial, '') if templates.empty?
- templates
+ # OMG HAX
+ # TODO: remove hax
+ class FileSystemResolverWithFallback < Resolver
+ def initialize(path, options = {})
+ super(options)
+ @paths = [FileSystemResolver.new(path, options), FileSystemResolver.new("", options), FileSystemResolver.new("/", options)]
end
+ def find_templates(*args)
+ @paths.each do |p|
+ template = p.find_templates(*args)
+ return template unless template.empty?
+ end
+ []
+ end
+
+ def to_s
+ @paths.first.to_s
+ 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 7d6964e3e3..80c1bab7d5 100644
--- a/actionpack/lib/action_view/template/template.rb
+++ b/actionpack/lib/action_view/template/template.rb
@@ -27,8 +27,10 @@ module ActionView
end
def render(view, locals, &block)
- method_name = compile(locals, view)
- view.send(method_name, locals, &block)
+ ActiveSupport::Orchestra.instrument(:render_template, :identifier => identifier) do
+ method_name = compile(locals, view)
+ view.send(method_name, locals, &block)
+ end.result
rescue Exception => e
if e.is_a?(TemplateError)
e.sub_template_of(self)