aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb15
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionpack/lib/action_view/template/resolver.rb105
-rw-r--r--actionpack/lib/action_view/testing/resolvers.rb12
5 files changed, 111 insertions, 28 deletions
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 48abf119f1..9025d9e24c 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -185,7 +185,7 @@ module ActionView
#
# is equivalent to something like:
#
- # <%= form_for @post, :as => :post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
+ # <%= form_for @post, :as => :post, :url => post_path(@post), :method => :put, :html => { :class => "edit_post", :id => "edit_post_45" } do |f| %>
# ...
# <% end %>
#
@@ -236,6 +236,16 @@ module ActionView
# Where <tt>@document = Document.find(params[:id])</tt> and
# <tt>@comment = Comment.new</tt>.
#
+ # === Setting the method
+ #
+ # You can force the form to use the full array of HTTP verbs by setting
+ #
+ # :method => (:get|:post|:put|:delete)
+ #
+ # in the options hash. If the verb is not GET or POST, which are natively supported by HTML forms, the
+ # form will be set to POST and a hidden input called _method will carry the intended verb for the server
+ # to interpret.
+ #
# === Unobtrusive JavaScript
#
# Specifying:
@@ -298,7 +308,7 @@ module ActionView
#
# In this case, if you use this:
#
- # <%= render :partial => f %>
+ # <%= render f %>
#
# The rendered template is <tt>people/_labelling_form</tt> and the local
# variable referencing the form builder is called
@@ -350,6 +360,7 @@ module ActionView
end
options[:html][:remote] = options.delete(:remote)
+ options[:html][:method] = options.delete(:method) if options.has_key?(:method)
options[:html][:authenticity_token] = options.delete(:authenticity_token)
builder = options[:parent_builder] = instantiate_builder(object_name, object, options, &proc)
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index cd3a3eac80..6eda23a9a3 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -47,6 +47,9 @@ module ActionView
"'" => "\\'" }
# Escape carrier returns and single and double quotes for JavaScript segments.
+ # Also available through the alias j(). This is particularly helpful in JavaScript responses, like:
+ #
+ # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
def escape_javascript(javascript)
if javascript
javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
@@ -55,6 +58,8 @@ module ActionView
end
end
+ alias_method :escape_javascript, :j
+
# Returns a JavaScript tag with the +content+ inside. Example:
# javascript_tag "alert('All is good')"
#
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 4e44843c4b..05a9c5b4f1 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -472,7 +472,7 @@ module ActionView
end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
- display_exponent = unit_exponents.find{|e| number_exponent >= e }
+ display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
number /= 10 ** display_exponent
unit = case units
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 589b2a1a76..6c1063592f 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -5,6 +5,25 @@ require "action_view/template"
module ActionView
# = Action View Resolver
class Resolver
+ # Keeps all information about view path and builds virtual path.
+ class Path < String
+ attr_reader :name, :prefix, :partial, :virtual
+ alias_method :partial?, :partial
+
+ def initialize(name, prefix, partial)
+ @name, @prefix, @partial = name, prefix, partial
+ rebuild(@name, @prefix, @partial)
+ end
+
+ def rebuild(name, prefix, partial)
+ @virtual = ""
+ @virtual << "#{prefix}/" unless prefix.empty?
+ @virtual << (partial ? "_#{name}" : name)
+
+ self.replace(@virtual)
+ end
+ end
+
cattr_accessor :caching
self.caching = true
@@ -41,10 +60,7 @@ module ActionView
# Helpers that builds a path. Useful for building virtual paths.
def build_path(name, prefix, partial)
- path = ""
- path << "#{prefix}/" unless prefix.empty?
- path << (partial ? "_#{name}" : name)
- path
+ Path.new(name, prefix, partial)
end
# Handles templates caching. If a key is given and caching is on
@@ -97,25 +113,24 @@ module ActionView
end
class PathResolver < Resolver
- EXTENSION_ORDER = [:locale, :formats, :handlers]
+ EXTENSIONS = [:locale, :formats, :handlers]
+ DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}"
+
+ def initialize(pattern=nil)
+ @pattern = pattern || DEFAULT_PATTERN
+ super()
+ end
private
def find_templates(name, prefix, partial, details)
path = build_path(name, prefix, partial)
- query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats])
+ extensions = Hash[EXTENSIONS.map { |ext| [ext, details[ext]] }.flatten(0)]
+ query(path, extensions, details[:formats])
end
def query(path, exts, formats)
- query = File.join(@path, path)
-
- query << exts.map { |ext|
- "{#{ext.compact.map { |e| ".#{e}" }.join(',')},}"
- }.join
-
- query.gsub!(/\{\.html,/, "{.html,.text.html,")
- query.gsub!(/\{\.text,/, "{.text,.text.plain,")
-
+ query = build_query(path, exts)
templates = []
sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] }
@@ -126,12 +141,28 @@ module ActionView
contents = File.open(p, "rb") {|io| io.read }
templates << Template.new(contents, File.expand_path(p), handler,
- :virtual_path => path, :format => format, :updated_at => mtime(p))
+ :virtual_path => path.virtual, :format => format, :updated_at => mtime(p))
end
templates
end
+ # Helper for building query glob string based on resolver's pattern.
+ def build_query(path, exts)
+ query = @pattern.dup
+ query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty...
+ query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name)
+
+ exts.each { |ext, variants|
+ query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}")
+ }
+
+ query.gsub!(/\.{html,/, ".{html,text.html,")
+ query.gsub!(/\.{text,/, ".{text,text.plain,")
+
+ File.expand_path(query, @path)
+ end
+
# Returns the file mtime from the filesystem.
def mtime(p)
File.stat(p).mtime
@@ -149,11 +180,47 @@ module ActionView
end
end
- # A resolver that loads files from the filesystem.
+ # A resolver that loads files from the filesystem. It allows to set your own
+ # resolving pattern. Such pattern can be a glob string supported by some variables.
+ #
+ # ==== Examples
+ #
+ # Default pattern, loads views the same way as previous versions of rails, eg. when you're
+ # looking for `users/new` it will produce query glob: `users/new{.{en},}{.{html,js},}{.{erb,haml,rjs},}`
+ #
+ # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}")
+ #
+ # This one allows you to keep files with different formats in seperated subdirectories,
+ # eg. `users/new.html` will be loaded from `users/html/new.erb` or `users/new.html.erb`,
+ # `users/new.js` from `users/js/new.erb` or `users/new.js.erb`, etc.
+ #
+ # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{.:handlers,}")
+ #
+ # If you don't specify pattern then the default will be used.
+ #
+ # In order to use any of the customized resolvers above in a Rails application, you just need
+ # to configure ActionController::Base.view_paths in an initializer, for example:
+ #
+ # ActionController::Base.view_paths = FileSystemResolver.new(
+ # Rails.root.join("app/views"),
+ # ":prefix{/:locale}/:action{.:formats,}{.:handlers,}"
+ # )
+ #
+ # ==== Pattern format and variables
+ #
+ # Pattern have to be a valid glob string, and it allows you to use the
+ # following variables:
+ #
+ # * <tt>:prefix</tt> - usualy the controller path
+ # * <tt>:action</tt> - name of the action
+ # * <tt>:locale</tt> - possible locale versions
+ # * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
+ # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
+ #
class FileSystemResolver < PathResolver
- def initialize(path)
+ def initialize(path, pattern=nil)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
- super()
+ super(pattern)
@path = File.expand_path(path)
end
diff --git a/actionpack/lib/action_view/testing/resolvers.rb b/actionpack/lib/action_view/testing/resolvers.rb
index 5c5cab7c7d..773dfcbb1d 100644
--- a/actionpack/lib/action_view/testing/resolvers.rb
+++ b/actionpack/lib/action_view/testing/resolvers.rb
@@ -8,8 +8,8 @@ module ActionView #:nodoc:
class FixtureResolver < PathResolver
attr_reader :hash
- def initialize(hash = {})
- super()
+ def initialize(hash = {}, pattern=nil)
+ super(pattern)
@hash = hash
end
@@ -21,8 +21,8 @@ module ActionView #:nodoc:
def query(path, exts, formats)
query = ""
- exts.each do |ext|
- query << '(' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)'
+ EXTENSIONS.each do |ext|
+ query << '(' << exts[ext].map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)'
end
query = /^(#{Regexp.escape(path)})#{query}$/
@@ -32,9 +32,9 @@ module ActionView #:nodoc:
next unless _path =~ query
handler, format = extract_handler_and_format(_path, formats)
templates << Template.new(source, _path, handler,
- :virtual_path => $1, :format => format, :updated_at => updated_at)
+ :virtual_path => path.virtual, :format => format, :updated_at => updated_at)
end
-
+
templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
end
end