aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG10
-rw-r--r--actionpack/lib/action_controller/assertions/response_assertions.rb4
-rw-r--r--actionpack/lib/action_controller/base.rb20
-rw-r--r--actionpack/lib/action_controller/caching/actions.rb4
-rw-r--r--actionpack/lib/action_controller/cgi_process.rb45
-rw-r--r--actionpack/lib/action_controller/filters.rb19
-rw-r--r--actionpack/lib/action_controller/headers.rb30
-rw-r--r--actionpack/lib/action_controller/rack_process.rb52
-rw-r--r--actionpack/lib/action_controller/request.rb165
-rw-r--r--actionpack/lib/action_controller/resources.rb42
-rw-r--r--actionpack/lib/action_controller/response.rb54
-rw-r--r--actionpack/lib/action_controller/routing/segments.rb3
-rw-r--r--actionpack/lib/action_controller/session/cookie_store.rb2
-rw-r--r--actionpack/lib/action_controller/test_process.rb44
-rw-r--r--actionpack/lib/action_view/base.rb5
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb7
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb576
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb56
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb4
-rw-r--r--actionpack/lib/action_view/partials.rb2
-rw-r--r--actionpack/lib/action_view/renderable.rb6
-rw-r--r--actionpack/lib/action_view/template.rb10
-rw-r--r--actionpack/test/controller/assert_select_test.rb33
-rw-r--r--actionpack/test/controller/caching_test.rb2
-rw-r--r--actionpack/test/controller/cgi_test.rb2
-rw-r--r--actionpack/test/controller/content_type_test.rb8
-rw-r--r--actionpack/test/controller/mime_responds_test.rb62
-rw-r--r--actionpack/test/controller/new_render_test.rb9
-rw-r--r--actionpack/test/controller/rack_test.rb23
-rw-r--r--actionpack/test/controller/render_test.rb37
-rw-r--r--actionpack/test/controller/request_test.rb95
-rw-r--r--actionpack/test/fixtures/_top_level_partial.html.erb1
-rw-r--r--actionpack/test/fixtures/_top_level_partial_only.erb1
-rw-r--r--actionpack/test/fixtures/test/_counter.html.erb1
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb3
-rw-r--r--actionpack/test/template/date_helper_i18n_test.rb22
-rw-r--r--actionpack/test/template/date_helper_test.rb299
-rw-r--r--actionpack/test/template/number_helper_i18n_test.rb26
-rw-r--r--actionpack/test/template/render_test.rb30
-rw-r--r--actionpack/test/template/url_helper_test.rb10
42 files changed, 1147 insertions, 683 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 177c6a354e..6f65d4003d 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -7,8 +7,14 @@
* Update Prototype to 1.6.0.2 #599 [Patrick Joyce]
* Conditional GET utility methods. [Jeremy Kemper]
- * etag!([:admin, post, current_user]) sets the ETag response header and returns head(:not_modified) if it matches the If-None-Match request header.
- * last_modified!(post.updated_at) sets Last-Modified and returns head(:not_modified) if it's no later than If-Modified-Since.
+ response.last_modified = @post.updated_at
+ response.etag = [:admin, @post, current_user]
+
+ if request.fresh?(response)
+ head :not_modified
+ else
+ # render ...
+ end
* All 2xx requests are considered successful [Josh Peek]
diff --git a/actionpack/lib/action_controller/assertions/response_assertions.rb b/actionpack/lib/action_controller/assertions/response_assertions.rb
index 765225ae24..e2e8bbdc71 100644
--- a/actionpack/lib/action_controller/assertions/response_assertions.rb
+++ b/actionpack/lib/action_controller/assertions/response_assertions.rb
@@ -87,11 +87,11 @@ module ActionController
#
def assert_template(expected = nil, message=nil)
clean_backtrace do
- rendered = @response.rendered_template
+ rendered = @response.rendered_template.to_s
msg = build_message(message, "expecting <?> but rendering with <?>", expected, rendered)
assert_block(msg) do
if expected.nil?
- @response.rendered_template.nil?
+ @response.rendered_template.blank?
else
rendered.to_s.match(expected)
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 5689a9825e..0fdbcbd26f 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -428,11 +428,7 @@ module ActionController #:nodoc:
# By default, all methods defined in ActionController::Base and included modules are hidden.
# More methods can be hidden using <tt>hide_actions</tt>.
def hidden_actions
- unless read_inheritable_attribute(:hidden_actions)
- write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods.map { |m| m.to_s })
- end
-
- read_inheritable_attribute(:hidden_actions)
+ read_inheritable_attribute(:hidden_actions) || write_inheritable_attribute(:hidden_actions, [])
end
# Hide each of the given methods from being callable as actions.
@@ -1199,7 +1195,7 @@ module ActionController #:nodoc:
end
def perform_action
- if self.class.action_methods.include?(action_name)
+ if action_methods.include?(action_name)
send(action_name)
default_render unless performed?
elsif respond_to? :method_missing
@@ -1208,7 +1204,7 @@ module ActionController #:nodoc:
elsif template_exists? && template_public?
default_render
else
- raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.to_a.sort.to_sentence}", caller
+ raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller
end
end
@@ -1234,7 +1230,15 @@ module ActionController #:nodoc:
end
def self.action_methods
- @action_methods ||= Set.new(public_instance_methods.map { |m| m.to_s }) - hidden_actions
+ @action_methods ||=
+ # All public instance methods of this class, including ancestors
+ public_instance_methods(true).map { |m| m.to_s }.to_set -
+ # Except for public instance methods of Base and its ancestors
+ Base.public_instance_methods(true).map { |m| m.to_s } +
+ # Be sure to include shadowed public instance methods of this class
+ public_instance_methods(false).map { |m| m.to_s } -
+ # And always exclude explicitly hidden actions
+ hidden_actions
end
def add_variables_to_assigns
diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb
index f3535f8330..b27ec486c0 100644
--- a/actionpack/lib/action_controller/caching/actions.rb
+++ b/actionpack/lib/action_controller/caching/actions.rb
@@ -38,8 +38,8 @@ module ActionController #:nodoc:
# caches_action :show, :cache_path => { :project => 1 }, :expires_in => 1.hour
# caches_action :feed, :cache_path => Proc.new { |controller|
# controller.params[:user_id] ?
- # controller.send(:user_list_url, c.params[:user_id], c.params[:id]) :
- # controller.send(:list_url, c.params[:id]) }
+ # controller.send(:user_list_url, controller.params[:user_id], controller.params[:id]) :
+ # controller.send(:list_url, controller.params[:id]) }
# end
#
# If you pass :layout => false, it will only cache your action content. It is useful when your layout has dynamic information.
diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb
index 8bc5e4c3a7..0ca27b30db 100644
--- a/actionpack/lib/action_controller/cgi_process.rb
+++ b/actionpack/lib/action_controller/cgi_process.rb
@@ -43,7 +43,7 @@ module ActionController #:nodoc:
:session_path => "/", # available to all paths in app
:session_key => "_session_id",
:cookie_only => true
- } unless const_defined?(:DEFAULT_SESSION_OPTIONS)
+ }
def initialize(cgi, session_options = {})
@cgi = cgi
@@ -61,53 +61,14 @@ module ActionController #:nodoc:
end
end
- # The request body is an IO input stream. If the RAW_POST_DATA environment
- # variable is already set, wrap it in a StringIO.
- def body
- if raw_post = env['RAW_POST_DATA']
- raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
- StringIO.new(raw_post)
- else
- @cgi.stdinput
- end
- end
-
- def query_parameters
- @query_parameters ||= self.class.parse_query_parameters(query_string)
- end
-
- def request_parameters
- @request_parameters ||= parse_formatted_request_parameters
+ def body_stream #:nodoc:
+ @cgi.stdinput
end
def cookies
@cgi.cookies.freeze
end
- def host_with_port_without_standard_port_handling
- if forwarded = env["HTTP_X_FORWARDED_HOST"]
- forwarded.split(/,\s?/).last
- elsif http_host = env['HTTP_HOST']
- http_host
- elsif server_name = env['SERVER_NAME']
- server_name
- else
- "#{env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
- end
- end
-
- def host
- host_with_port_without_standard_port_handling.sub(/:\d+$/, '')
- end
-
- def port
- if host_with_port_without_standard_port_handling =~ /:(\d+)$/
- $1.to_i
- else
- standard_port
- end
- end
-
def session
unless defined?(@session)
if @session_options == false
diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb
index 10dc0cc45b..1d7236f18a 100644
--- a/actionpack/lib/action_controller/filters.rb
+++ b/actionpack/lib/action_controller/filters.rb
@@ -109,16 +109,17 @@ module ActionController #:nodoc:
update_options! options
end
+ # override these to return true in appropriate subclass
def before?
- self.class == BeforeFilter
+ false
end
def after?
- self.class == AfterFilter
+ false
end
def around?
- self.class == AroundFilter
+ false
end
# Make sets of strings from :only/:except options
@@ -170,6 +171,10 @@ module ActionController #:nodoc:
:around
end
+ def around?
+ true
+ end
+
def call(controller, &block)
if should_run_callback?(controller)
method = filter_responds_to_before_and_after? ? around_proc : self.method
@@ -212,6 +217,10 @@ module ActionController #:nodoc:
:before
end
+ def before?
+ true
+ end
+
def call(controller, &block)
super
if controller.send!(:performed?)
@@ -224,6 +233,10 @@ module ActionController #:nodoc:
def type
:after
end
+
+ def after?
+ true
+ end
end
# Filters enable controllers to run shared pre- and post-processing code for its actions. These filters can be used to do
diff --git a/actionpack/lib/action_controller/headers.rb b/actionpack/lib/action_controller/headers.rb
index 7239438c49..139669c66f 100644
--- a/actionpack/lib/action_controller/headers.rb
+++ b/actionpack/lib/action_controller/headers.rb
@@ -1,31 +1,33 @@
+require 'active_support/memoizable'
+
module ActionController
module Http
class Headers < ::Hash
-
- def initialize(constructor = {})
- if constructor.is_a?(Hash)
+ extend ActiveSupport::Memoizable
+
+ def initialize(*args)
+ if args.size == 1 && args[0].is_a?(Hash)
super()
- update(constructor)
+ update(args[0])
else
- super(constructor)
+ super
end
end
-
+
def [](header_name)
if include?(header_name)
- super
+ super
else
- super(normalize_header(header_name))
+ super(env_name(header_name))
end
end
-
-
+
private
- # Takes an HTTP header name and returns it in the
- # format
- def normalize_header(header_name)
+ # Converts a HTTP header name to an environment variable name.
+ def env_name(header_name)
"HTTP_#{header_name.upcase.gsub(/-/, '_')}"
end
+ memoize :env_name
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb
index 7e0a6b091e..dcbcf8bc1d 100644
--- a/actionpack/lib/action_controller/rack_process.rb
+++ b/actionpack/lib/action_controller/rack_process.rb
@@ -3,7 +3,7 @@ require 'action_controller/session/cookie_store'
module ActionController #:nodoc:
class RackRequest < AbstractRequest #:nodoc:
- attr_accessor :env, :session_options
+ attr_accessor :session_options
attr_reader :cgi
class SessionFixationAttempt < StandardError #:nodoc:
@@ -15,7 +15,7 @@ module ActionController #:nodoc:
:session_path => "/", # available to all paths in app
:session_key => "_session_id",
:cookie_only => true
- } unless const_defined?(:DEFAULT_SESSION_OPTIONS)
+ }
def initialize(env, session_options = DEFAULT_SESSION_OPTIONS)
@session_options = session_options
@@ -30,35 +30,21 @@ module ActionController #:nodoc:
SERVER_NAME SERVER_PROTOCOL
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
- HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
+ HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
define_method(env.sub(/^HTTP_/n, '').downcase) do
@env[env]
end
end
- # The request body is an IO input stream. If the RAW_POST_DATA environment
- # variable is already set, wrap it in a StringIO.
- def body
- if raw_post = env['RAW_POST_DATA']
- StringIO.new(raw_post)
- else
- @env['rack.input']
- end
+ def body_stream #:nodoc:
+ @env['rack.input']
end
def key?(key)
@env.key?(key)
end
- def query_parameters
- @query_parameters ||= self.class.parse_query_parameters(query_string)
- end
-
- def request_parameters
- @request_parameters ||= parse_formatted_request_parameters
- end
-
def cookies
return {} unless @env["HTTP_COOKIE"]
@@ -70,34 +56,6 @@ module ActionController #:nodoc:
@env["rack.request.cookie_hash"]
end
- def host_with_port_without_standard_port_handling
- if forwarded = @env["HTTP_X_FORWARDED_HOST"]
- forwarded.split(/,\s?/).last
- elsif http_host = @env['HTTP_HOST']
- http_host
- elsif server_name = @env['SERVER_NAME']
- server_name
- else
- "#{env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
- end
- end
-
- def host
- host_with_port_without_standard_port_handling.sub(/:\d+$/, '')
- end
-
- def port
- if host_with_port_without_standard_port_handling =~ /:(\d+)$/
- $1.to_i
- else
- standard_port
- end
- end
-
- def remote_addr
- @env['REMOTE_ADDR']
- end
-
def server_port
@env['SERVER_PORT'].to_i
end
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index 60ff75fe2c..185518761d 100644
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -2,35 +2,35 @@ require 'tempfile'
require 'stringio'
require 'strscan'
-module ActionController
- # HTTP methods which are accepted by default.
- ACCEPTED_HTTP_METHODS = Set.new(%w( get head put post delete options ))
+require 'active_support/memoizable'
+module ActionController
# CgiRequest and TestRequest provide concrete implementations.
class AbstractRequest
+ extend ActiveSupport::Memoizable
+
def self.relative_url_root=(*args)
ActiveSupport::Deprecation.warn(
"ActionController::AbstractRequest.relative_url_root= has been renamed." +
"You can now set it with config.action_controller.relative_url_root=", caller)
end
- # The hash of CGI-like environment variables for this request, such as
- #
- # { 'SERVER_PROTOCOL' => 'HTTP/1.1', 'HTTP_ACCEPT_LANGUAGE' => 'en-us', ... }
+ HTTP_METHODS = %w(get head put post delete options)
+ HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
+
+ # The hash of environment variables for this request,
+ # such as { 'RAILS_ENV' => 'production' }.
attr_reader :env
# The true HTTP request \method as a lowercase symbol, such as <tt>:get</tt>.
# UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.
def request_method
- @request_method ||= begin
- method = ((@env['REQUEST_METHOD'] == 'POST' && !parameters[:_method].blank?) ? parameters[:_method].to_s : @env['REQUEST_METHOD']).downcase
- if ACCEPTED_HTTP_METHODS.include?(method)
- method.to_sym
- else
- raise UnknownHttpMethod, "#{method}, accepted HTTP methods are #{ACCEPTED_HTTP_METHODS.to_a.to_sentence}"
- end
- end
+ method = @env['REQUEST_METHOD']
+ method = parameters[:_method] if method == 'POST' && !parameters[:_method].blank?
+
+ HTTP_METHOD_LOOKUP[method] || raise(UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
end
+ memoize :request_method
# The HTTP request \method as a lowercase symbol, such as <tt>:get</tt>.
# Note, HEAD is returned as <tt>:get</tt> since the two are functionally
@@ -69,34 +69,60 @@ module ActionController
#
# request.headers["Content-Type"] # => "text/plain"
def headers
- @headers ||= ActionController::Http::Headers.new(@env)
+ ActionController::Http::Headers.new(@env)
end
+ memoize :headers
# Returns the content length of the request as an integer.
def content_length
- @content_length ||= env['CONTENT_LENGTH'].to_i
+ @env['CONTENT_LENGTH'].to_i
end
+ memoize :content_length
# The MIME type of the HTTP request, such as Mime::XML.
#
# For backward compatibility, the post \format is extracted from the
# X-Post-Data-Format HTTP header if present.
def content_type
- @content_type ||= Mime::Type.lookup(content_type_without_parameters)
+ Mime::Type.lookup(content_type_without_parameters)
end
+ memoize :content_type
# Returns the accepted MIME type for the request.
def accepts
- @accepts ||=
- begin
- header = @env['HTTP_ACCEPT'].to_s.strip
+ header = @env['HTTP_ACCEPT'].to_s.strip
- if header.empty?
- [content_type, Mime::ALL].compact
- else
- Mime::Type.parse(header)
- end
- end
+ if header.empty?
+ [content_type, Mime::ALL].compact
+ else
+ Mime::Type.parse(header)
+ end
+ end
+ memoize :accepts
+
+ def if_modified_since
+ if since = env['HTTP_IF_MODIFIED_SINCE']
+ Time.rfc2822(since)
+ end
+ end
+ memoize :if_modified_since
+
+ def if_none_match
+ env['HTTP_IF_NONE_MATCH']
+ end
+
+ def not_modified?(modified_at)
+ if_modified_since && modified_at && if_modified_since >= modified_at
+ end
+
+ def etag_matches?(etag)
+ if_none_match && if_none_match == etag
+ end
+
+ # Check response freshness (Last-Modified and ETag) against request
+ # If-Modified-Since and If-None-Match conditions.
+ def fresh?(response)
+ not_modified?(response.last_modified) || etag_matches?(response.etag)
end
# Returns the Mime type for the \format used in the request.
@@ -105,7 +131,7 @@ module ActionController
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
def format
- @format ||= begin
+ @format ||=
if parameters[:format]
Mime::Type.lookup_by_extension(parameters[:format])
elsif ActionController::Base.use_accept_header
@@ -115,7 +141,6 @@ module ActionController
else
Mime::Type.lookup_by_extension("html")
end
- end
end
@@ -203,22 +228,26 @@ EOM
@env['REMOTE_ADDR']
end
+ memoize :remote_ip
# Returns the lowercase name of the HTTP server software.
def server_software
(@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
end
+ memoize :server_software
# Returns the complete URL used for this request.
def url
protocol + host_with_port + request_uri
end
+ memoize :url
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
def protocol
ssl? ? 'https://' : 'http://'
end
+ memoize :protocol
# Is this an SSL request?
def ssl?
@@ -226,19 +255,36 @@ EOM
end
# Returns the \host for this request, such as "example.com".
+ def raw_host_with_port
+ if forwarded = env["HTTP_X_FORWARDED_HOST"]
+ forwarded.split(/,\s?/).last
+ else
+ env['HTTP_HOST'] || env['SERVER_NAME'] || "#{env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
+ end
+ end
+
+ # Returns the host for this request, such as example.com.
def host
+ raw_host_with_port.sub(/:\d+$/, '')
end
+ memoize :host
# Returns a \host:\port string for this request, such as "example.com" or
# "example.com:8080".
def host_with_port
- @host_with_port ||= host + port_string
+ "#{host}#{port_string}"
end
+ memoize :host_with_port
# Returns the port number of this request as an integer.
def port
- @port_as_int ||= @env['SERVER_PORT'].to_i
+ if raw_host_with_port =~ /:(\d+)$/
+ $1.to_i
+ else
+ standard_port
+ end
end
+ memoize :port
# Returns the standard \port number for this request's protocol.
def standard_port
@@ -251,7 +297,7 @@ EOM
# Returns a \port suffix like ":8080" if the \port number of this request
# is not the default HTTP \port 80 or HTTPS \port 443.
def port_string
- (port == standard_port) ? '' : ":#{port}"
+ port == standard_port ? '' : ":#{port}"
end
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
@@ -280,6 +326,7 @@ EOM
@env['QUERY_STRING'] || ''
end
end
+ memoize :query_string
# Returns the request URI, accounting for server idiosyncrasies.
# WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
@@ -289,21 +336,23 @@ EOM
(%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
else
# Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
- script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
- uri = @env['PATH_INFO']
- uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
- unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
- uri << '?' << env_qs
+ uri = @env['PATH_INFO'].to_s
+
+ if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
+ uri = uri.sub(/#{script_filename}\//, '')
end
- if uri.nil?
+ env_qs = @env['QUERY_STRING'].to_s
+ uri += "?#{env_qs}" unless env_qs.empty?
+
+ if uri.blank?
@env.delete('REQUEST_URI')
- uri
else
@env['REQUEST_URI'] = uri
end
end
end
+ memoize :request_uri
# Returns the interpreted \path to requested resource after all the installation
# directory of this application was taken into account.
@@ -314,6 +363,7 @@ EOM
path.sub!(%r/^#{ActionController::Base.relative_url_root}/, '')
path || ''
end
+ memoize :path
# Read the request \body. This is useful for web services that need to
# work with raw requests directly.
@@ -350,19 +400,41 @@ EOM
@path_parameters ||= {}
end
+ # The request body is an IO input stream. If the RAW_POST_DATA environment
+ # variable is already set, wrap it in a StringIO.
+ def body
+ if raw_post = env['RAW_POST_DATA']
+ raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
+ StringIO.new(raw_post)
+ else
+ body_stream
+ end
+ end
- #--
- # Must be implemented in the concrete request
- #++
+ def remote_addr
+ @env['REMOTE_ADDR']
+ end
- # The request \body as an IO input stream.
- def body
+ def referrer
+ @env['HTTP_REFERER']
end
+ alias referer referrer
+
- def query_parameters #:nodoc:
+ def query_parameters
+ @query_parameters ||= self.class.parse_query_parameters(query_string)
end
- def request_parameters #:nodoc:
+ def request_parameters
+ @request_parameters ||= parse_formatted_request_parameters
+ end
+
+
+ #--
+ # Must be implemented in the concrete request
+ #++
+
+ def body_stream #:nodoc:
end
def cookies #:nodoc:
@@ -389,8 +461,9 @@ EOM
# The raw content type string with its parameters stripped off.
def content_type_without_parameters
- @content_type_without_parameters ||= self.class.extract_content_type_without_parameters(content_type_with_parameters)
+ self.class.extract_content_type_without_parameters(content_type_with_parameters)
end
+ memoize :content_type_without_parameters
private
def content_type_from_legacy_post_data_format_header
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb
index 77b329b70e..becf6b0b63 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/resources.rb
@@ -481,8 +481,7 @@ module ActionController
resource.collection_methods.each do |method, actions|
actions.each do |action|
action_options = action_options_for(action, resource, method)
- map.named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options)
- map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}.:format", action_options)
+ map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options)
end
end
end
@@ -495,18 +494,15 @@ module ActionController
index_route_name << "_index"
end
- map.named_route(index_route_name, resource.path, index_action_options)
- map.named_route("formatted_#{index_route_name}", "#{resource.path}.:format", index_action_options)
+ map_named_routes(map, index_route_name, resource.path, index_action_options)
create_action_options = action_options_for("create", resource)
- map.connect(resource.path, create_action_options)
- map.connect("#{resource.path}.:format", create_action_options)
+ map_unnamed_routes(map, resource.path, create_action_options)
end
def map_default_singleton_actions(map, resource)
create_action_options = action_options_for("create", resource)
- map.connect(resource.path, create_action_options)
- map.connect("#{resource.path}.:format", create_action_options)
+ map_unnamed_routes(map, resource.path, create_action_options)
end
def map_new_actions(map, resource)
@@ -514,11 +510,9 @@ module ActionController
actions.each do |action|
action_options = action_options_for(action, resource, method)
if action == :new
- map.named_route("new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options)
- map.named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}.:format", action_options)
+ map_named_routes(map, "new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options)
else
- map.named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options)
- map.named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}.:format", action_options)
+ map_named_routes(map, "#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options)
end
end
end
@@ -532,22 +526,28 @@ module ActionController
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
action_path ||= Base.resources_path_names[action] || action
- map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options)
- map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}.:format",action_options)
+ map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options)
end
end
show_action_options = action_options_for("show", resource)
- map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options)
- map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options)
+ map_named_routes(map, "#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options)
update_action_options = action_options_for("update", resource)
- map.connect(resource.member_path, update_action_options)
- map.connect("#{resource.member_path}.:format", update_action_options)
+ map_unnamed_routes(map, resource.member_path, update_action_options)
destroy_action_options = action_options_for("destroy", resource)
- map.connect(resource.member_path, destroy_action_options)
- map.connect("#{resource.member_path}.:format", destroy_action_options)
+ map_unnamed_routes(map, resource.member_path, destroy_action_options)
+ end
+
+ def map_unnamed_routes(map, path_without_format, options)
+ map.connect(path_without_format, options)
+ map.connect("#{path_without_format}.:format", options)
+ end
+
+ def map_named_routes(map, name, path_without_format, options)
+ map.named_route(name, path_without_format, options)
+ map.named_route("formatted_#{name}", "#{path_without_format}.:format", options)
end
def add_conditions_for(conditions, method)
@@ -574,4 +574,4 @@ end
class ActionController::Routing::RouteSet::Mapper
include ActionController::Resources
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb
index da352b6993..a85fad0d39 100644
--- a/actionpack/lib/action_controller/response.rb
+++ b/actionpack/lib/action_controller/response.rb
@@ -37,12 +37,20 @@ module ActionController # :nodoc:
attr_accessor :body
# The headers of the response, as a Hash. It maps header names to header values.
attr_accessor :headers
- attr_accessor :session, :cookies, :assigns, :template, :redirected_to, :redirected_to_method_params, :layout
+ attr_accessor :session, :cookies, :assigns, :template, :layout
+ attr_accessor :redirected_to, :redirected_to_method_params
def initialize
@body, @headers, @session, @assigns = "", DEFAULT_HEADERS.merge("cookie" => []), [], []
end
+ def status; headers['Status'] end
+ def status=(status) headers['Status'] = status end
+
+ def location; headers['Location'] end
+ def location=(url) headers['Location'] = url end
+
+
# Sets the HTTP response's content MIME type. For example, in the controller
# you could write this:
#
@@ -70,35 +78,29 @@ module ActionController # :nodoc:
charset.blank? ? nil : charset.strip.split("=")[1]
end
- def redirect(to_url, response_status)
- self.headers["Status"] = response_status
- self.headers["Location"] = to_url
+ def last_modified
+ Time.rfc2822(headers['Last-Modified'])
+ end
- self.body = "<html><body>You are being <a href=\"#{to_url}\">redirected</a>.</body></html>"
+ def last_modified=(utc_time)
+ headers['Last-Modified'] = utc_time.httpdate
end
- def prepare!
- handle_conditional_get!
- convert_content_type!
- set_content_length!
+ def etag; headers['ETag'] end
+ def etag=(etag)
+ headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
end
- # Sets the Last-Modified response header. Returns whether it's older than
- # the If-Modified-Since request header.
- def last_modified!(utc_time)
- headers['Last-Modified'] ||= utc_time.httpdate
- if request && since = request.headers['HTTP_IF_MODIFIED_SINCE']
- utc_time <= Time.rfc2822(since)
- end
+ def redirect(url, status)
+ self.status = status
+ self.location = url
+ self.body = "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
end
- # Sets the ETag response header. Returns whether it matches the
- # If-None-Match request header.
- def etag!(tag)
- headers['ETag'] ||= %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(tag))}")
- if request && request.headers['HTTP_IF_NONE_MATCH'] == headers['ETag']
- true
- end
+ def prepare!
+ handle_conditional_get!
+ convert_content_type!
+ set_content_length!
end
private
@@ -106,15 +108,15 @@ module ActionController # :nodoc:
if nonempty_ok_response?
set_conditional_cache_control!
- if etag!(body)
- headers['Status'] = '304 Not Modified'
+ self.etag ||= body
+ if request && request.etag_matches?(etag)
+ self.status = '304 Not Modified'
self.body = ''
end
end
end
def nonempty_ok_response?
- status = headers['Status']
ok = !status || status[0..2] == '200'
ok && body.is_a?(String) && !body.empty?
end
diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb
index 75784c3b78..9d4b740a44 100644
--- a/actionpack/lib/action_controller/routing/segments.rb
+++ b/actionpack/lib/action_controller/routing/segments.rb
@@ -2,7 +2,8 @@ module ActionController
module Routing
class Segment #:nodoc:
RESERVED_PCHAR = ':@&=+$,;'
- UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze
+ SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}"
+ UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
# TODO: Convert :is_optional accessor to read only
attr_accessor :is_optional
diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_controller/session/cookie_store.rb
index b477c1f7da..5bf7503f04 100644
--- a/actionpack/lib/action_controller/session/cookie_store.rb
+++ b/actionpack/lib/action_controller/session/cookie_store.rb
@@ -129,7 +129,7 @@ class CGI::Session::CookieStore
private
# Marshal a session hash into safe cookie data. Include an integrity hash.
def marshal(session)
- data = ActiveSupport::Base64.encode64(Marshal.dump(session)).chop
+ data = ActiveSupport::Base64.encode64s(Marshal.dump(session))
"#{data}--#{generate_digest(data)}"
end
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index 66675aaa13..0c705207e3 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -23,7 +23,7 @@ module ActionController #:nodoc:
class TestRequest < AbstractRequest #:nodoc:
attr_accessor :cookies, :session_options
- attr_accessor :query_parameters, :request_parameters, :path, :session, :env
+ attr_accessor :query_parameters, :request_parameters, :path, :session
attr_accessor :host, :user_agent
def initialize(query_parameters = nil, request_parameters = nil, session = nil)
@@ -42,7 +42,7 @@ module ActionController #:nodoc:
end
# Wraps raw_post in a StringIO.
- def body
+ def body_stream #:nodoc:
StringIO.new(raw_post)
end
@@ -54,7 +54,7 @@ module ActionController #:nodoc:
def port=(number)
@env["SERVER_PORT"] = number.to_i
- @port_as_int = nil
+ port(true)
end
def action=(action_name)
@@ -68,6 +68,8 @@ module ActionController #:nodoc:
@env["REQUEST_URI"] = value
@request_uri = nil
@path = nil
+ request_uri(true)
+ path(true)
end
def request_uri=(uri)
@@ -77,21 +79,26 @@ module ActionController #:nodoc:
def accept=(mime_types)
@env["HTTP_ACCEPT"] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",")
+ accepts(true)
end
- def remote_addr=(addr)
- @env['REMOTE_ADDR'] = addr
+ def if_modified_since=(last_modified)
+ @env["HTTP_IF_MODIFIED_SINCE"] = last_modified
end
- def remote_addr
- @env['REMOTE_ADDR']
+ def if_none_match=(etag)
+ @env["HTTP_IF_NONE_MATCH"] = etag
end
- def request_uri
+ def remote_addr=(addr)
+ @env['REMOTE_ADDR'] = addr
+ end
+
+ def request_uri(*args)
@request_uri || super
end
- def path
+ def path(*args)
@path || super
end
@@ -113,17 +120,13 @@ module ActionController #:nodoc:
end
end
@parameters = nil # reset TestRequest#parameters to use the new path_parameters
- end
-
+ end
+
def recycle!
self.request_parameters = {}
self.query_parameters = {}
self.path_parameters = {}
- @request_method, @accepts, @content_type = nil, nil, nil
- end
-
- def referer
- @env["HTTP_REFERER"]
+ unmemoize_all
end
private
@@ -448,10 +451,13 @@ module ActionController #:nodoc:
end
def method_missing(selector, *args)
- return @controller.send!(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
- return super
+ if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
+ @controller.send(selector, *args)
+ else
+ super
+ end
end
-
+
# Shortcut for <tt>ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type)</tt>:
#
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index bdcb1dc246..ad59d92086 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -300,6 +300,8 @@ module ActionView #:nodoc:
# # => 'users/legacy.rhtml'
#
def pick_template(template_path)
+ return template_path if template_path.respond_to?(:render)
+
path = template_path.sub(/^\//, '')
if m = path.match(/(.*)\.(\w+)$/)
template_file_name, template_file_extension = m[1], m[2]
@@ -343,7 +345,8 @@ module ActionView #:nodoc:
ActiveSupport::Deprecation.warn("use_full_path option has been deprecated and has no affect.", caller)
end
- if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
+ if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) &&
+ template_path.is_a?(String) && !template_path.include?("/")
raise ActionViewError, <<-END_ERROR
Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 769eada120..c2b4f51c9c 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -463,7 +463,7 @@ module ActionView
end
private
- COMPUTED_PUBLIC_PATHS = ActiveSupport::Cache::MemoryStore.new.silence!.threadsafe!
+ COMPUTED_PUBLIC_PATHS = ActiveSupport::Cache::MemoryStore.new.silence!
# Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
# Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
@@ -618,6 +618,11 @@ module ActionView
def write_asset_file_contents(joined_asset_path, asset_paths)
FileUtils.mkdir_p(File.dirname(joined_asset_path))
File.open(joined_asset_path, "w+") { |cache| cache.write(join_asset_file_contents(asset_paths)) }
+
+ # Set mtime to the latest of the combined files to allow for
+ # consistent ETag without a shared filesystem.
+ mt = asset_paths.map { |p| File.mtime(File.join(ASSETS_DIR, p)) }.max
+ File.utime(mt, mt, joined_asset_path)
end
def collect_asset_files(*path)
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index c7a1d40ff2..953a2a9f86 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -13,9 +13,6 @@ module ActionView
# the select_month method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of
# "date[month]".
module DateHelper
- include ActionView::Helpers::TagHelper
- DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
-
# Reports the approximate distance in time between two Time or Date objects or integers as seconds.
# Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
# Distances are reported based on the following table:
@@ -52,7 +49,7 @@ module ActionView
# distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
# distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
# distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
- # distance_of_time_in_words(from_time, from_time + 4.years + 15.days + 30.minutes + 5.seconds) # => over 4 years
+ # distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => over 4 years
#
# to_time = Time.now + 6.years + 19.days
# distance_of_time_in_words(from_time, to_time, true) # => over 6 years
@@ -109,19 +106,36 @@ module ActionView
alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
# Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based
- # attribute (identified by +method+) on an object assigned to the template (identified by +object+). It's
- # possible to tailor the selects through the +options+ hash, which accepts all the keys that each of the
- # individual select builders do (like <tt>:use_month_numbers</tt> for select_month) as well as a range of discard
- # options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set
- # to true, they'll drop the respective select. Discarding the month select will also automatically discard the
- # day select. It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an
- # array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. Symbols may be omitted
- # and the respective select is not included.
- #
- # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of <tt>:year</tt>,
- # <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, and <tt>:second</tt>.
- #
- # Passing <tt>:disabled => true</tt> as part of the +options+ will make elements inaccessible for change.
+ # attribute (identified by +method+) on an object assigned to the template (identified by +object+). You can
+ # the output in the +options+ hash.
+ #
+ # ==== Options
+ # * <tt>:use_month_numbers</tt> - Set to true if you want to use month numbers rather than month names (e.g.
+ # "2" instead of "February").
+ # * <tt>:use_short_month</tt> - Set to true if you want to use the abbreviated month name instead of the full
+ # name (e.g. "Feb" instead of "February").
+ # * <tt>:add_month_number</tt> - Set to true if you want to show both, the month's number and name (e.g.
+ # "2 - February" instead of "February").
+ # * <tt>:use_month_names</tt> - Set to an array with 12 month names if you want to customize month names.
+ # Note: You can also use Rails' new i18n functionality for this.
+ # * <tt>:date_separator</tt> - Specifies a string to separate the date fields. Default is "" (i.e. nothing).
+ # * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Time.now.year - 5</tt>.
+ # * <tt>:end_year</tt> - Set the end year for the year select. Default is <tt>Time.now.year + 5</tt>.
+ # * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day
+ # as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
+ # first of the given month in order to not create invalid dates like 31 February.
+ # * <tt>:discard_month</tt> - Set to true if you don't want to show a month select. This includes the month
+ # as a hidden field instead of showing a select field. Also note that this implicitly sets :discard_day to true.
+ # * <tt>:discard_year</tt> - Set to true if you don't want to show a year select. This includes the year
+ # as a hidden field instead of showing a select field.
+ # * <tt>:order</tt> - Set to an array containing <tt>:day</tt>, <tt>:month</tt> and <tt>:year</tt> do
+ # customize the order in which the select fields are shown. If you leave out any of the symbols, the respective
+ # select will not be shown (like when you set <tt>:discard_xxx => true</tt>. Defaults to the order defined in
+ # the respective locale (e.g. [:year, :month, :day] in the en-US locale that ships with Rails).
+ # * <tt>:include_blank</tt> - Include a blank option in every select field so it's possible to set empty
+ # dates.
+ # * <tt>:default</tt> - Set a default date if the affected date isn't set or is nil.
+ # * <tt>:disabled</tt> - Set to true if you want show the select fields as disabled.
#
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
@@ -165,9 +179,9 @@ module ActionView
InstanceTag.new(object_name, method, self, options.delete(:object)).to_date_select_tag(options, html_options)
end
- # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
- # time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
- # You can include the seconds with <tt>:include_seconds</tt>.
+ # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a
+ # specified time-based attribute (identified by +method+) on an object assigned to the template (identified by
+ # +object+). You can include the seconds with <tt>:include_seconds</tt>.
#
# This method will also generate 3 input hidden tags, for the actual year, month and day unless the option
# <tt>:ignore_date</tt> is set to +true+.
@@ -178,7 +192,8 @@ module ActionView
# # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
# time_select("post", "sunrise")
#
- # # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute
+ # # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted
+ # # attribute
# time_select("order", "submitted")
#
# # Creates a time select tag that, when POSTed, will be stored in the mail variable in the sent_at attribute
@@ -210,7 +225,8 @@ module ActionView
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
# ==== Examples
- # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute
+ # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on
+ # # attribute
# datetime_select("post", "written_on")
#
# # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
@@ -230,12 +246,12 @@ module ActionView
InstanceTag.new(object_name, method, self, options.delete(:object)).to_datetime_select_tag(options, html_options)
end
- # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
- # It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
- # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol,
- # it will be appended onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt>,
- # <tt>:datetime_separator</tt> and <tt>:time_separator</tt> keys to the +options+ to control visual display of
- # the elements.
+ # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the
+ # +datetime+. It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with
+ # an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not
+ # supply a Symbol, it will be appended onto the <tt>:order</tt> passed in. You can also add
+ # <tt>:date_separator</tt>, <tt>:datetime_separator</tt> and <tt>:time_separator</tt> keys to the +options+ to
+ # control visual display of the elements.
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
@@ -270,14 +286,13 @@ module ActionView
# select_datetime(my_date_time, :prefix => 'payday')
#
def select_datetime(datetime = Time.current, options = {}, html_options = {})
- separator = options[:datetime_separator] || ''
- select_date(datetime, options, html_options) + separator + select_time(datetime, options, html_options)
+ DateTimeSelector.new(datetime, options, html_options).select_datetime
end
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
# It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
- # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
- # will be appended onto the <tt>:order</tt> passed in.
+ # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol,
+ # it will be appended onto the <tt>:order</tt> passed in.
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
@@ -307,12 +322,7 @@ module ActionView
# select_date(my_date, :prefix => 'payday')
#
def select_date(date = Date.current, options = {}, html_options = {})
- options.reverse_merge!(:order => [], :date_separator => '')
- [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
-
- options[:order].inject([]) { |s, o|
- s << self.send("select_#{o}", date, options, html_options)
- }.join(options[:date_separator])
+ DateTimeSelector.new(date, options, html_options).select_date
end
# Returns a set of html select-tags (one for hour and minute)
@@ -343,9 +353,7 @@ module ActionView
# select_time(my_time, :time_separator => ':', :include_seconds => true)
#
def select_time(datetime = Time.current, options = {}, html_options = {})
- separator = options[:time_separator] || ''
- select_hour(datetime, options, html_options) + separator + select_minute(datetime, options, html_options) +
- (options[:include_seconds] ? separator + select_second(datetime, options, html_options) : '')
+ DateTimeSelector.new(datetime, options, html_options).select_time
end
# Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
@@ -366,15 +374,12 @@ module ActionView
# select_second(my_time, :field_name => 'interval')
#
def select_second(datetime, options = {}, html_options = {})
- val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
- options[:use_hidden] ?
- (options[:include_seconds] ? _date_hidden_html(options[:field_name] || 'second', val, options) : '') :
- _date_select_html(options[:field_name] || 'second', _date_build_options(val), options, html_options)
+ DateTimeSelector.new(datetime, options, html_options).select_second
end
# Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
- # Also can return a select tag with options by <tt>minute_step</tt> from 0 through 59 with the 00 minute selected
- # The <tt>minute</tt> can also be substituted for a minute number.
+ # Also can return a select tag with options by <tt>minute_step</tt> from 0 through 59 with the 00 minute
+ # selected. The <tt>minute</tt> can also be substituted for a minute number.
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
#
# ==== Examples
@@ -391,11 +396,7 @@ module ActionView
# select_minute(my_time, :field_name => 'stride')
#
def select_minute(datetime, options = {}, html_options = {})
- val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
- options[:use_hidden] ?
- _date_hidden_html(options[:field_name] || 'minute', val, options) :
- _date_select_html(options[:field_name] || 'minute',
- _date_build_options(val, :step => options[:minute_step]), options, html_options)
+ DateTimeSelector.new(datetime, options, html_options).select_minute
end
# Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
@@ -416,9 +417,7 @@ module ActionView
# select_minute(my_time, :field_name => 'stride')
#
def select_hour(datetime, options = {}, html_options = {})
- val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
- options[:use_hidden] ? _date_hidden_html(options[:field_name] || 'hour', val, options) :
- _date_select_html(options[:field_name] || 'hour', _date_build_options(val, :end => 23), options, html_options)
+ DateTimeSelector.new(datetime, options, html_options).select_hour
end
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
@@ -439,11 +438,7 @@ module ActionView
# select_day(my_time, :field_name => 'due')
#
def select_day(date, options = {}, html_options = {})
- val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
- options[:use_hidden] ? _date_hidden_html(options[:field_name] || 'day', val, options) :
- _date_select_html(options[:field_name] || 'day',
- _date_build_options(val, :start => 1, :end => 31, :leading_zeros => false),
- options, html_options)
+ DateTimeSelector.new(date, options, html_options).select_day
end
# Returns a select tag with options for each of the months January through December with the current month
@@ -481,36 +476,7 @@ module ActionView
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
#
def select_month(date, options = {}, html_options = {})
- locale = options[:locale]
-
- val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
- if options[:use_hidden]
- _date_hidden_html(options[:field_name] || 'month', val, options)
- else
- month_options = []
- month_names = options[:use_month_names] || begin
- key = options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
- I18n.translate key, :locale => locale
- end
- month_names.unshift(nil) if month_names.size < 13
-
- 1.upto(12) do |month_number|
- month_name = if options[:use_month_numbers]
- month_number
- elsif options[:add_month_numbers]
- month_number.to_s + ' - ' + month_names[month_number]
- else
- month_names[month_number]
- end
-
- month_options << ((val == month_number) ?
- content_tag(:option, month_name, :value => month_number, :selected => "selected") :
- content_tag(:option, month_name, :value => month_number)
- )
- month_options << "\n"
- end
- _date_select_html(options[:field_name] || 'month', month_options.join, options, html_options)
- end
+ DateTimeSelector.new(date, options, html_options).select_month
end
# Returns a select tag with options for each of the five years on each side of the current, which is selected.
@@ -537,158 +503,369 @@ module ActionView
# select_year(2006, :start_year => 2000, :end_year => 2010)
#
def select_year(date, options = {}, html_options = {})
- if !date || date == 0
+ DateTimeSelector.new(date, options, html_options).select_year
+ end
+ end
+
+ class DateTimeSelector #:nodoc:
+ extend ActiveSupport::Memoizable
+ include ActionView::Helpers::TagHelper
+
+ DEFAULT_PREFIX = 'date'.freeze unless const_defined?('DEFAULT_PREFIX')
+ POSITION = {
+ :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6
+ }.freeze unless const_defined?('POSITION')
+
+ def initialize(datetime, options = {}, html_options = {})
+ @options = options.dup
+ @html_options = html_options.dup
+ @datetime = datetime
+ end
+
+ def select_datetime
+ # TODO: Remove tag conditional
+ # Ideally we could just join select_date and select_date for the tag case
+ if @options[:tag] && @options[:ignore_date]
+ select_time
+ elsif @options[:tag]
+ order = date_order.dup
+ order -= [:hour, :minute, :second]
+
+ @options[:discard_year] ||= true unless order.include?(:year)
+ @options[:discard_month] ||= true unless order.include?(:month)
+ @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
+ @options[:discard_minute] ||= true if @options[:discard_hour]
+ @options[:discard_second] ||= true unless @options[:include_seconds] && !@options[:discard_minute]
+
+ # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
+ # valid (otherwise it could be 31 and february wouldn't be a valid date)
+ if @options[:discard_day] && !@options[:discard_month]
+ @datetime = @datetime.change(:day => 1)
+ end
+
+ [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
+ order += [:hour, :minute, :second] unless @options[:discard_hour]
+
+ build_selects_from_types(order)
+ else
+ "#{select_date}#{@options[:datetime_separator]}#{select_time}"
+ end
+ end
+
+ def select_date
+ order = date_order.dup
+
+ # TODO: Remove tag conditional
+ if @options[:tag]
+ @options[:discard_hour] = true
+ @options[:discard_minute] = true
+ @options[:discard_second] = true
+
+ @options[:discard_year] ||= true unless order.include?(:year)
+ @options[:discard_month] ||= true unless order.include?(:month)
+ @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
+
+ # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
+ # valid (otherwise it could be 31 and february wouldn't be a valid date)
+ if @options[:discard_day] && !@options[:discard_month]
+ @datetime = @datetime.change(:day => 1)
+ end
+ end
+
+ [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
+
+ build_selects_from_types(order)
+ end
+
+ def select_time
+ order = []
+
+ # TODO: Remove tag conditional
+ if @options[:tag]
+ @options[:discard_month] = true
+ @options[:discard_year] = true
+ @options[:discard_day] = true
+ @options[:discard_second] ||= true unless @options[:include_seconds]
+
+ order += [:year, :month, :day] unless @options[:ignore_date]
+ end
+
+ order += [:hour, :minute]
+ order << :second if @options[:include_seconds]
+
+ build_selects_from_types(order)
+ end
+
+ def select_second
+ if @options[:use_hidden] || @options[:discard_second]
+ build_hidden(:second, sec) if @options[:include_seconds]
+ else
+ build_options_and_select(:second, sec)
+ end
+ end
+
+ def select_minute
+ if @options[:use_hidden] || @options[:discard_minute]
+ build_hidden(:minute, min)
+ else
+ build_options_and_select(:minute, min, :step => @options[:minute_step])
+ end
+ end
+
+ def select_hour
+ if @options[:use_hidden] || @options[:discard_hour]
+ build_hidden(:hour, hour)
+ else
+ build_options_and_select(:hour, hour, :end => 23)
+ end
+ end
+
+ def select_day
+ if @options[:use_hidden] || @options[:discard_day]
+ build_hidden(:day, day)
+ else
+ build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false)
+ end
+ end
+
+ def select_month
+ if @options[:use_hidden] || @options[:discard_month]
+ build_hidden(:month, month)
+ else
+ month_options = []
+ 1.upto(12) do |month_number|
+ options = { :value => month_number }
+ options[:selected] = "selected" if month == month_number
+ month_options << content_tag(:option, month_name(month_number), options) + "\n"
+ end
+ build_select(:month, month_options.join)
+ end
+ end
+
+ def select_year
+ if !@datetime || @datetime == 0
val = ''
middle_year = Date.today.year
- elsif date.kind_of?(Fixnum)
- val = middle_year = date
else
- val = middle_year = date.year
+ val = middle_year = year
end
- if options[:use_hidden]
- _date_hidden_html(options[:field_name] || 'year', val, options)
+ if @options[:use_hidden] || @options[:discard_year]
+ build_hidden(:year, val)
else
- options[:start_year] ||= middle_year - 5
- options[:end_year] ||= middle_year + 5
- step = options[:start_year] < options[:end_year] ? 1 : -1
-
- _date_select_html(options[:field_name] || 'year',
- _date_build_options(val,
- :start => options[:start_year],
- :end => options[:end_year],
- :step => step,
- :leading_zeros => false
- ), options, html_options)
+ options = {}
+ options[:start] = @options[:start_year] || middle_year - 5
+ options[:end] = @options[:end_year] || middle_year + 5
+ options[:step] = options[:start] < options[:end] ? 1 : -1
+ options[:leading_zeros] = false
+
+ build_options_and_select(:year, val, options)
end
end
private
- def _date_build_options(selected, options={})
- options.reverse_merge!(:start => 0, :end => 59, :step => 1, :leading_zeros => true)
+ %w( sec min hour day month year ).each do |method|
+ define_method(method) do
+ @datetime.kind_of?(Fixnum) ? @datetime : @datetime.send(method) if @datetime
+ end
+ end
+
+ # Returns translated month names, but also ensures that a custom month
+ # name array has a leading nil element
+ def month_names
+ month_names = @options[:use_month_names] || translated_month_names
+ month_names.unshift(nil) if month_names.size < 13
+ month_names
+ end
+ memoize :month_names
+
+ # Returns translated month names
+ # => [nil, "January", "February", "March",
+ # "April", "May", "June", "July",
+ # "August", "September", "October",
+ # "November", "December"]
+ #
+ # If :use_short_month option is set
+ # => [nil, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ # "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+ def translated_month_names
+ begin
+ key = @options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
+ I18n.translate(key, :locale => @options[:locale])
+ end
+ end
+
+ # Lookup month name for number
+ # month_name(1) => "January"
+ #
+ # If :use_month_numbers option is passed
+ # month_name(1) => 1
+ #
+ # If :add_month_numbers option is passed
+ # month_name(1) => "1 - January"
+ def month_name(number)
+ if @options[:use_month_numbers]
+ number
+ elsif @options[:add_month_numbers]
+ "#{number} - #{month_names[number]}"
+ else
+ month_names[number]
+ end
+ end
+
+ def date_order
+ @options[:order] || translated_date_order
+ end
+ memoize :date_order
+
+ def translated_date_order
+ begin
+ I18n.translate(:'date.order', :locale => @options[:locale]) || []
+ end
+ end
+
+ # Build full select tag from date type and options
+ def build_options_and_select(type, selected, options = {})
+ build_select(type, build_options(selected, options))
+ end
+
+ # Build select option html from date value and options
+ # build_options(15, :start => 1, :end => 31)
+ # => "<option value="1">1</option>
+ # <option value=\"2\">2</option>
+ # <option value=\"3\">3</option>..."
+ def build_options(selected, options = {})
+ start = options.delete(:start) || 0
+ stop = options.delete(:end) || 59
+ step = options.delete(:step) || 1
+ leading_zeros = options.delete(:leading_zeros).nil? ? true : false
select_options = []
- (options[:start] || 0).step((options[:end] || 59), options[:step] || 1) do |i|
- value = options[:leading_zeros] ? sprintf("%02d", i) : i
+ start.step(stop, step) do |i|
+ value = leading_zeros ? sprintf("%02d", i) : i
tag_options = { :value => value }
tag_options[:selected] = "selected" if selected == i
-
select_options << content_tag(:option, value, tag_options)
end
select_options.join("\n") + "\n"
end
- def _date_select_html(type, html_options, options, select_tag_options = {})
- _date_name_and_id_from_options(options, type)
- select_options = {:id => options[:id], :name => options[:name]}
- select_options.merge!(:disabled => 'disabled') if options[:disabled]
- select_options.merge!(select_tag_options) unless select_tag_options.empty?
+ # Builds select tag from date type and html select options
+ # build_select(:month, "<option value="1">January</option>...")
+ # => "<select id="post_written_on_2i" name="post[written_on(2i)]">
+ # <option value="1">January</option>...
+ # </select>"
+ def build_select(type, select_options_as_html)
+ select_options = {
+ :id => input_id_from_type(type),
+ :name => input_name_from_type(type)
+ }.merge(@html_options)
+ select_options.merge!(:disabled => 'disabled') if @options[:disabled]
+
select_html = "\n"
- select_html << content_tag(:option, '', :value => '') + "\n" if options[:include_blank]
- select_html << html_options.to_s
+ select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
+ select_html << select_options_as_html.to_s
+
content_tag(:select, select_html, select_options) + "\n"
end
- def _date_hidden_html(type, value, options)
- _date_name_and_id_from_options(options, type)
- hidden_html = tag(:input, :type => "hidden", :id => options[:id], :name => options[:name], :value => value) + "\n"
+ # Builds hidden input tag for date part and value
+ # build_hidden(:year, 2008)
+ # => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />"
+ def build_hidden(type, value)
+ tag(:input, {
+ :type => "hidden",
+ :id => input_id_from_type(type),
+ :name => input_name_from_type(type),
+ :value => value
+ }) + "\n"
end
- def _date_name_and_id_from_options(options, type)
- options[:name] = (options[:prefix] || DEFAULT_PREFIX) + (options[:discard_type] ? '' : "[#{type}]")
- options[:id] = options[:name].gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
+ # Returns the name attribute for the input tag
+ # => post[written_on(1i)]
+ def input_name_from_type(type)
+ prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
+ prefix += "[#{@options[:index]}]" if @options[:index]
+
+ field_name = @options[:field_name] || type
+ if @options[:include_position]
+ field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
+ end
+
+ @options[:discard_type] ? prefix : "#{prefix}[#{field_name}]"
+ end
+
+ # Returns the id attribute for the input tag
+ # => "post_written_on_1i"
+ def input_id_from_type(type)
+ input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
+ end
+
+ # Given an ordering of datetime components, create the selection html
+ # and join them with their appropriate seperators
+ def build_selects_from_types(order)
+ select = ''
+ order.reverse.each do |type|
+ separator = separator(type) unless type == order.first # don't add on last field
+ select.insert(0, separator.to_s + send("select_#{type}").to_s)
+ end
+ select
+ end
+
+ # Returns the separator for a given datetime component
+ def separator(type)
+ case type
+ when :month, :day
+ @options[:date_separator]
+ when :hour
+ (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
+ when :minute
+ @options[:time_separator]
+ when :second
+ @options[:include_seconds] ? @options[:time_separator] : ""
+ end
end
end
class InstanceTag #:nodoc:
- include DateHelper
-
def to_date_select_tag(options = {}, html_options = {})
- date_or_time_select(options.merge(:discard_hour => true), html_options)
+ datetime_selector(options, html_options).select_date
end
def to_time_select_tag(options = {}, html_options = {})
- date_or_time_select(options.merge(:discard_year => true, :discard_month => true), html_options)
+ datetime_selector(options, html_options).select_time
end
def to_datetime_select_tag(options = {}, html_options = {})
- date_or_time_select(options, html_options)
+ datetime_selector(options, html_options).select_datetime
end
private
- def date_or_time_select(options, html_options = {})
- locale = options[:locale]
-
- defaults = { :discard_type => true }
- options = defaults.merge(options)
- datetime = value(object)
- datetime ||= default_time_from_options(options[:default]) unless options[:include_blank]
-
- position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }
-
- order = options[:order] ||= I18n.translate(:'date.order', :locale => locale)
-
- # Discard explicit and implicit by not being included in the :order
- discard = {}
- discard[:year] = true if options[:discard_year] or !order.include?(:year)
- discard[:month] = true if options[:discard_month] or !order.include?(:month)
- discard[:day] = true if options[:discard_day] or discard[:month] or !order.include?(:day)
- discard[:hour] = true if options[:discard_hour]
- discard[:minute] = true if options[:discard_minute] or discard[:hour]
- discard[:second] = true unless options[:include_seconds] && !discard[:minute]
-
- # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are valid
- # (otherwise it could be 31 and february wouldn't be a valid date)
- if datetime && discard[:day] && !discard[:month]
- datetime = datetime.change(:day => 1)
- end
-
- # Maintain valid dates by including hidden fields for discarded elements
- [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
-
- # Ensure proper ordering of :hour, :minute and :second
- [:hour, :minute, :second].each { |o| order.delete(o); order.push(o) }
-
- date_or_time_select = ''
- order.reverse.each do |param|
- # Send hidden fields for discarded elements once output has started
- # This ensures AR can reconstruct valid dates using ParseDate
- next if discard[param] && (date_or_time_select.empty? || options[:ignore_date])
-
- date_or_time_select.insert(0,
- self.send("select_#{param}",
- datetime,
- options_with_prefix(position[param], options.merge(:use_hidden => discard[param])),
- html_options))
- date_or_time_select.insert(0,
- case param
- when :hour then (discard[:year] && discard[:day] ? "" : " &mdash; ")
- when :minute then " : "
- when :second then options[:include_seconds] ? " : " : ""
- else ""
- end)
- end
-
- date_or_time_select
+ def datetime_selector(options, html_options)
+ datetime = value(object) || default_datetime(options)
+
+ options = options.dup
+ options[:field_name] = @method_name
+ options[:include_position] = true
+ options[:prefix] ||= @object_name
+ options[:index] ||= @auto_index
+ options[:datetime_separator] ||= ' &mdash; '
+ options[:time_separator] ||= ' : '
+
+ DateTimeSelector.new(datetime, options.merge(:tag => true), html_options)
end
- def options_with_prefix(position, options)
- prefix = "#{@object_name}"
- if options[:index]
- prefix << "[#{options[:index]}]"
- elsif @auto_index
- prefix << "[#{@auto_index}]"
- end
- options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
- end
+ def default_datetime(options)
+ return if options[:include_blank]
- def default_time_from_options(default)
- case default
+ case options[:default]
when nil
Time.current
when Date, Time
- default
+ options[:default]
else
+ default = options[:default].dup
+
# Rename :minute and :second to :min and :sec
default[:min] ||= default[:minute]
default[:sec] ||= default[:second]
@@ -699,8 +876,11 @@ module ActionView
default[key] ||= time.send(key)
end
- Time.utc_time(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec])
- end
+ Time.utc_time(
+ default[:year], default[:month], default[:day],
+ default[:hour], default[:min], default[:sec]
+ )
+ end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index e8ca02d760..e5777b71d7 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -155,10 +155,10 @@ module ActionView
# Creates a file upload field. If you are using file uploads then you will also need
# to set the multipart option for the form tag:
#
- # <%= form_tag { :action => "post" }, { :multipart => true } %>
+ # <% form_tag '/upload', :multipart => true do %>
# <label for="file">File to Upload</label> <%= file_field_tag "file" %>
# <%= submit_tag %>
- # <%= end_form_tag %>
+ # <% end %>
#
# The specified URL will then be passed a File object containing the selected file, or if the field
# was left blank, a StringIO object.
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 8c1dea2186..77f19b36a6 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -71,9 +71,9 @@ module ActionView
def number_to_currency(number, options = {})
options.symbolize_keys!
- defaults, currency = I18n.translate([:'number.format', :'number.currency.format'],
- :locale => options[:locale]) || [{},{}]
- defaults = defaults.merge(currency)
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
+ currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :raise => true) rescue {}
+ defaults = defaults.merge(currency)
precision = options[:precision] || defaults[:precision]
unit = options[:unit] || defaults[:unit]
@@ -109,9 +109,9 @@ module ActionView
def number_to_percentage(number, options = {})
options.symbolize_keys!
- defaults, percentage = I18n.translate([:'number.format', :'number.percentage.format'],
- :locale => options[:locale]) || [{},{}]
- defaults = defaults.merge(percentage)
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
+ percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :raise => true) rescue {}
+ defaults = defaults.merge(percentage)
precision = options[:precision] || defaults[:precision]
separator = options[:separator] || defaults[:separator]
@@ -151,7 +151,7 @@ module ActionView
options = args.extract_options!
options.symbolize_keys!
- defaults = I18n.translate(:'number.format', :locale => options[:locale]) || {}
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
unless args.empty?
ActiveSupport::Deprecation.warn('number_with_delimiter takes an option hash ' +
@@ -195,9 +195,10 @@ module ActionView
options = args.extract_options!
options.symbolize_keys!
- defaults, precision_defaults = I18n.translate([:'number.format', :'number.precision.format'],
- :locale => options[:locale]) || [{},{}]
- defaults = defaults.merge(precision_defaults)
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
+ precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale],
+ :raise => true) rescue {}
+ defaults = defaults.merge(precision_defaults)
unless args.empty?
ActiveSupport::Deprecation.warn('number_with_precision takes an option hash ' +
@@ -209,12 +210,14 @@ module ActionView
separator ||= (options[:separator] || defaults[:separator])
delimiter ||= (options[:delimiter] || defaults[:delimiter])
- rounded_number = (Float(number) * (10 ** precision)).round.to_f / 10 ** precision
- number_with_delimiter("%01.#{precision}f" % rounded_number,
- :separator => separator,
- :delimiter => delimiter)
- rescue
- number
+ begin
+ rounded_number = (Float(number) * (10 ** precision)).round.to_f / 10 ** precision
+ number_with_delimiter("%01.#{precision}f" % rounded_number,
+ :separator => separator,
+ :delimiter => delimiter)
+ rescue
+ number
+ end
end
STORAGE_UNITS = %w( Bytes KB MB GB TB ).freeze
@@ -251,8 +254,8 @@ module ActionView
options = args.extract_options!
options.symbolize_keys!
- defaults, human = I18n.translate([:'number.format', :'number.human.format'],
- :locale => options[:locale]) || [{},{}]
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
+ human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {}
defaults = defaults.merge(human)
unless args.empty?
@@ -272,13 +275,16 @@ module ActionView
number /= 1024 ** exponent
unit = STORAGE_UNITS[exponent]
- number_with_precision(number,
- :precision => precision,
- :separator => separator,
- :delimiter => delimiter
- ).sub(/(\d)(#{Regexp.escape(separator)}[1-9]*)?0+\z/, '\1') + " #{unit}"
- rescue
- number
+ begin
+ escaped_separator = Regexp.escape(separator)
+ number_with_precision(number,
+ :precision => precision,
+ :separator => separator,
+ :delimiter => delimiter
+ ).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') + " #{unit}"
+ rescue
+ number
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 022edf23c8..f9096d0029 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -558,7 +558,7 @@ module ActionView
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
- (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$])))*)* # path
+ (?:/(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))*)* # path
(?:\?[\w\+@%&=.;-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index f31502d99d..7ba42a3b72 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -442,7 +442,7 @@ module ActionView
# # => <a href="mailto:me@domain.com">me@domain.com</a>
#
# mail_to "me@domain.com", "My email", :encode => "javascript"
- # # => <script type="text/javascript">eval(unescape('%64%6f%63...%6d%65%6e'))</script>
+ # # => <script type="text/javascript">eval(decodeURIComponent('%64%6f%63...%27%29%3b'))</script>
#
# mail_to "me@domain.com", "My email", :encode => "hex"
# # => <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>
@@ -476,7 +476,7 @@ module ActionView
"document.write('#{content_tag("a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
string << sprintf("%%%x", c)
end
- "<script type=\"#{Mime::JS}\">eval(unescape('#{string}'))</script>"
+ "<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>"
elsif encode == "hex"
email_address_encoded = ''
email_address_obfuscated.each_byte do |c|
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb
index eb74d4a4c7..894b88534c 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/partials.rb
@@ -146,7 +146,7 @@ module ActionView
def find_partial_path(partial_path)
if partial_path.include?('/')
- "#{File.dirname(partial_path)}/_#{File.basename(partial_path)}"
+ File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
elsif respond_to?(:controller)
"#{controller.class.controller_path}/_#{partial_path}"
else
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb
index 5fe1ca86f3..89ac500717 100644
--- a/actionpack/lib/action_view/renderable.rb
+++ b/actionpack/lib/action_view/renderable.rb
@@ -31,10 +31,10 @@ module ActionView
view.send(:evaluate_assigns)
view.send(:set_controller_content_type, mime_type) if respond_to?(:mime_type)
- view.send(:execute, method(local_assigns), local_assigns)
+ view.send(:execute, method_name(local_assigns), local_assigns)
end
- def method(local_assigns)
+ def method_name(local_assigns)
if local_assigns && local_assigns.any?
local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
end
@@ -44,7 +44,7 @@ module ActionView
private
# Compile and evaluate the template's code (if necessary)
def compile(local_assigns)
- render_symbol = method(local_assigns)
+ render_symbol = method_name(local_assigns)
@@mutex.synchronize do
if recompile?(render_symbol)
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index b281ff61f2..5dc6708431 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -22,6 +22,14 @@ module ActionView #:nodoc:
end
memoize :format_and_extension
+ def multipart?
+ format && format.include?('.')
+ end
+
+ def content_type
+ format.gsub('.', '/')
+ end
+
def mime_type
Mime::Type.lookup_by_extension(format) if format
end
@@ -84,7 +92,7 @@ module ActionView #:nodoc:
# [base_path, name, format, extension]
def split(file)
if m = file.match(/^(.*\/)?([^\.]+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/)
- if m[5] # Mulipart formats
+ if m[5] # Multipart formats
[m[1], m[2], "#{m[3]}.#{m[4]}", m[5]]
elsif m[4] # Single format
[m[1], m[2], m[3], m[4]]
diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb
index 5af579f3e3..1531e7c21a 100644
--- a/actionpack/test/controller/assert_select_test.rb
+++ b/actionpack/test/controller/assert_select_test.rb
@@ -17,6 +17,8 @@ unless defined?(ActionMailer)
end
end
+ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
+
class AssertSelectTest < Test::Unit::TestCase
class AssertSelectController < ActionController::Base
def response_with=(content)
@@ -69,11 +71,10 @@ class AssertSelectTest < Test::Unit::TestCase
ActionMailer::Base.deliveries = []
end
-
def teardown
ActionMailer::Base.deliveries.clear
end
-
+
def assert_failure(message, &block)
e = assert_raises(AssertionFailedError, &block)
assert_match(message, e.message) if Regexp === message
@@ -91,7 +92,6 @@ class AssertSelectTest < Test::Unit::TestCase
assert_failure(/Expected at least 1 element matching \"p\", found 0/) { assert_select "p" }
end
-
def test_equality_true_false
render_html %Q{<div id="1"></div><div id="2"></div>}
assert_nothing_raised { assert_select "div" }
@@ -102,7 +102,6 @@ class AssertSelectTest < Test::Unit::TestCase
assert_nothing_raised { assert_select "p", false }
end
-
def test_equality_string_and_regexp
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
assert_nothing_raised { assert_select "div", "foo" }
@@ -116,7 +115,6 @@ class AssertSelectTest < Test::Unit::TestCase
assert_raises(AssertionFailedError) { assert_select "p", :text=>/foobar/ }
end
-
def test_equality_of_html
render_html %Q{<p>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</p>}
text = "\"This is not a big problem,\" he said."
@@ -135,7 +133,6 @@ class AssertSelectTest < Test::Unit::TestCase
assert_raises(AssertionFailedError) { assert_select "pre", :html=>text }
end
-
def test_counts
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
assert_nothing_raised { assert_select "div", 2 }
@@ -166,7 +163,6 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
def test_substitution_values
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
assert_select "div#?", /\d+/ do |elements|
@@ -181,7 +177,6 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
def test_nested_assert_select
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
assert_select "div" do |elements|
@@ -200,7 +195,7 @@ class AssertSelectTest < Test::Unit::TestCase
assert_select "#3", false
end
end
-
+
assert_failure(/Expected at least 1 element matching \"#4\", found 0\./) do
assert_select "div" do
assert_select "#4"
@@ -208,7 +203,6 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
def test_assert_select_text_match
render_html %Q{<div id="1"><span>foo</span></div><div id="2"><span>bar</span></div>}
assert_select "div" do
@@ -225,7 +219,6 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
# With single result.
def test_assert_select_from_rjs_with_single_result
render_rjs do |page|
@@ -255,19 +248,16 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
#
# Test css_select.
#
-
def test_css_select
render_html %Q{<div id="1"></div><div id="2"></div>}
assert 2, css_select("div").size
assert 0, css_select("p").size
end
-
def test_nested_css_select
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
assert_select "div#?", /\d+/ do |elements|
@@ -286,7 +276,6 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
# With one result.
def test_css_select_from_rjs_with_single_result
render_rjs do |page|
@@ -309,12 +298,10 @@ class AssertSelectTest < Test::Unit::TestCase
assert_equal 1, css_select("#2").size
end
-
#
# Test assert_select_rjs.
#
-
# Test that we can pick up all statements in the result.
def test_assert_select_rjs_picks_up_all_statements
render_rjs do |page|
@@ -381,7 +368,6 @@ class AssertSelectTest < Test::Unit::TestCase
assert_raises(AssertionFailedError) { assert_select_rjs "test4" }
end
-
def test_assert_select_rjs_for_replace
render_rjs do |page|
page.replace "test1", "<div id=\"1\">foo</div>"
@@ -479,7 +465,7 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
end
-
+
# Simple hide
def test_assert_select_rjs_for_hide
render_rjs do |page|
@@ -500,7 +486,7 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
end
-
+
# Simple toggle
def test_assert_select_rjs_for_toggle
render_rjs do |page|
@@ -521,7 +507,7 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
end
-
+
# Non-positioned insert.
def test_assert_select_rjs_for_nonpositioned_insert
render_rjs do |page|
@@ -568,7 +554,7 @@ class AssertSelectTest < Test::Unit::TestCase
assert_select "div", 4
end
end
-
+
# Simple selection from a single result.
def test_nested_assert_select_rjs_with_single_result
render_rjs do |page|
@@ -600,7 +586,6 @@ class AssertSelectTest < Test::Unit::TestCase
end
end
-
def test_feed_item_encoded
render_xml <<-EOF
<rss version="2.0">
@@ -654,7 +639,6 @@ EOF
end
end
-
#
# Test assert_select_email
#
@@ -670,7 +654,6 @@ EOF
end
end
-
protected
def render_html(html)
@controller.response_with = html
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 47a0fcf99d..b6cdd116e5 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -109,7 +109,7 @@ class PageCachingTest < Test::Unit::TestCase
uses_mocha("should_cache_ok_at_custom_path") do
def test_should_cache_ok_at_custom_path
- @request.expects(:path).returns("/index.html")
+ @request.stubs(:path).returns("/index.html")
get :ok
assert_response :ok
assert File.exist?("#{FILE_STORE_PATH}/index.html")
diff --git a/actionpack/test/controller/cgi_test.rb b/actionpack/test/controller/cgi_test.rb
index 8ca70f8595..813171857a 100644
--- a/actionpack/test/controller/cgi_test.rb
+++ b/actionpack/test/controller/cgi_test.rb
@@ -75,7 +75,7 @@ class CgiRequestTest < BaseCgiTest
assert_equal "rubyonrails.org:8080", @request.host_with_port
@request_hash['HTTP_X_FORWARDED_HOST'] = "www.firsthost.org, www.secondhost.org"
- assert_equal "www.secondhost.org", @request.host
+ assert_equal "www.secondhost.org", @request.host(true)
end
def test_http_host_with_default_port_overrides_server_port
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index d457d13aef..e1bc46bb56 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -128,23 +128,23 @@ class AcceptBasedContentTypeTest < ActionController::TestCase
def test_render_default_content_types_for_respond_to
- @request.env["HTTP_ACCEPT"] = Mime::HTML.to_s
+ @request.accept = Mime::HTML.to_s
get :render_default_content_types_for_respond_to
assert_equal Mime::HTML, @response.content_type
- @request.env["HTTP_ACCEPT"] = Mime::JS.to_s
+ @request.accept = Mime::JS.to_s
get :render_default_content_types_for_respond_to
assert_equal Mime::JS, @response.content_type
end
def test_render_default_content_types_for_respond_to_with_template
- @request.env["HTTP_ACCEPT"] = Mime::XML.to_s
+ @request.accept = Mime::XML.to_s
get :render_default_content_types_for_respond_to
assert_equal Mime::XML, @response.content_type
end
def test_render_default_content_types_for_respond_to_with_overwrite
- @request.env["HTTP_ACCEPT"] = Mime::RSS.to_s
+ @request.accept = Mime::RSS.to_s
get :render_default_content_types_for_respond_to
assert_equal Mime::XML, @response.content_type
end
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index 1701431858..0d508eb8df 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -177,7 +177,7 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_html
- @request.env["HTTP_ACCEPT"] = "text/html"
+ @request.accept = "text/html"
get :js_or_html
assert_equal 'HTML', @response.body
@@ -189,7 +189,7 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_all
- @request.env["HTTP_ACCEPT"] = "*/*"
+ @request.accept = "*/*"
get :js_or_html
assert_equal 'HTML', @response.body # js is not part of all
@@ -201,13 +201,13 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_xml
- @request.env["HTTP_ACCEPT"] = "application/xml"
+ @request.accept = "application/xml"
get :html_xml_or_rss
assert_equal 'XML', @response.body
end
def test_js_or_html
- @request.env["HTTP_ACCEPT"] = "text/javascript, text/html"
+ @request.accept = "text/javascript, text/html"
get :js_or_html
assert_equal 'JS', @response.body
@@ -232,7 +232,7 @@ class MimeControllerTest < Test::Unit::TestCase
'JSON' => %w(application/json text/x-json)
}.each do |body, content_types|
content_types.each do |content_type|
- @request.env['HTTP_ACCEPT'] = content_type
+ @request.accept = content_type
get :json_or_yaml
assert_equal body, @response.body
end
@@ -240,7 +240,7 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_js_or_anything
- @request.env["HTTP_ACCEPT"] = "text/javascript, */*"
+ @request.accept = "text/javascript, */*"
get :js_or_html
assert_equal 'JS', @response.body
@@ -252,34 +252,34 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_using_defaults
- @request.env["HTTP_ACCEPT"] = "*/*"
+ @request.accept = "*/*"
get :using_defaults
assert_equal "text/html", @response.content_type
assert_equal 'Hello world!', @response.body
- @request.env["HTTP_ACCEPT"] = "text/javascript"
+ @request.accept = "text/javascript"
get :using_defaults
assert_equal "text/javascript", @response.content_type
assert_equal '$("body").visualEffect("highlight");', @response.body
- @request.env["HTTP_ACCEPT"] = "application/xml"
+ @request.accept = "application/xml"
get :using_defaults
assert_equal "application/xml", @response.content_type
assert_equal "<p>Hello world!</p>\n", @response.body
end
def test_using_defaults_with_type_list
- @request.env["HTTP_ACCEPT"] = "*/*"
+ @request.accept = "*/*"
get :using_defaults_with_type_list
assert_equal "text/html", @response.content_type
assert_equal 'Hello world!', @response.body
- @request.env["HTTP_ACCEPT"] = "text/javascript"
+ @request.accept = "text/javascript"
get :using_defaults_with_type_list
assert_equal "text/javascript", @response.content_type
assert_equal '$("body").visualEffect("highlight");', @response.body
- @request.env["HTTP_ACCEPT"] = "application/xml"
+ @request.accept = "application/xml"
get :using_defaults_with_type_list
assert_equal "application/xml", @response.content_type
assert_equal "<p>Hello world!</p>\n", @response.body
@@ -298,55 +298,55 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_synonyms
- @request.env["HTTP_ACCEPT"] = "application/javascript"
+ @request.accept = "application/javascript"
get :js_or_html
assert_equal 'JS', @response.body
- @request.env["HTTP_ACCEPT"] = "application/x-xml"
+ @request.accept = "application/x-xml"
get :html_xml_or_rss
assert_equal "XML", @response.body
end
def test_custom_types
- @request.env["HTTP_ACCEPT"] = "application/crazy-xml"
+ @request.accept = "application/crazy-xml"
get :custom_type_handling
assert_equal "application/crazy-xml", @response.content_type
assert_equal 'Crazy XML', @response.body
- @request.env["HTTP_ACCEPT"] = "text/html"
+ @request.accept = "text/html"
get :custom_type_handling
assert_equal "text/html", @response.content_type
assert_equal 'HTML', @response.body
end
def test_xhtml_alias
- @request.env["HTTP_ACCEPT"] = "application/xhtml+xml,application/xml"
+ @request.accept = "application/xhtml+xml,application/xml"
get :html_or_xml
assert_equal 'HTML', @response.body
end
def test_firefox_simulation
- @request.env["HTTP_ACCEPT"] = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
+ @request.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
get :html_or_xml
assert_equal 'HTML', @response.body
end
def test_handle_any
- @request.env["HTTP_ACCEPT"] = "*/*"
+ @request.accept = "*/*"
get :handle_any
assert_equal 'HTML', @response.body
- @request.env["HTTP_ACCEPT"] = "text/javascript"
+ @request.accept = "text/javascript"
get :handle_any
assert_equal 'Either JS or XML', @response.body
- @request.env["HTTP_ACCEPT"] = "text/xml"
+ @request.accept = "text/xml"
get :handle_any
assert_equal 'Either JS or XML', @response.body
end
def test_handle_any_any
- @request.env["HTTP_ACCEPT"] = "*/*"
+ @request.accept = "*/*"
get :handle_any_any
assert_equal 'HTML', @response.body
end
@@ -357,31 +357,31 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_handle_any_any_explicit_html
- @request.env["HTTP_ACCEPT"] = "text/html"
+ @request.accept = "text/html"
get :handle_any_any
assert_equal 'HTML', @response.body
end
def test_handle_any_any_javascript
- @request.env["HTTP_ACCEPT"] = "text/javascript"
+ @request.accept = "text/javascript"
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_handle_any_any_xml
- @request.env["HTTP_ACCEPT"] = "text/xml"
+ @request.accept = "text/xml"
get :handle_any_any
assert_equal 'Whatever you ask for, I got it', @response.body
end
def test_rjs_type_skips_layout
- @request.env["HTTP_ACCEPT"] = "text/javascript"
+ @request.accept = "text/javascript"
get :all_types_with_layout
assert_equal 'RJS for all_types_with_layout', @response.body
end
def test_html_type_with_layout
- @request.env["HTTP_ACCEPT"] = "text/html"
+ @request.accept = "text/html"
get :all_types_with_layout
assert_equal '<html><div id="html">HTML for all_types_with_layout</div></html>', @response.body
end
@@ -460,7 +460,7 @@ class MimeControllerTest < Test::Unit::TestCase
end
def test_format_with_custom_response_type_and_request_headers
- @request.env["HTTP_ACCEPT"] = "text/iphone"
+ @request.accept = "text/iphone"
get :iphone_with_html_response_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
assert_equal "text/html", @response.content_type
@@ -470,7 +470,7 @@ class MimeControllerTest < Test::Unit::TestCase
get :iphone_with_html_response_type_without_layout
assert_equal '<html><div id="html_missing">Hello future from Firefox!</div></html>', @response.body
- @request.env["HTTP_ACCEPT"] = "text/iphone"
+ @request.accept = "text/iphone"
assert_raises(ActionView::MissingTemplate) { get :iphone_with_html_response_type_without_layout }
end
end
@@ -522,7 +522,7 @@ class MimeControllerLayoutsTest < Test::Unit::TestCase
get :index
assert_equal '<html><div id="html">Hello Firefox</div></html>', @response.body
- @request.env["HTTP_ACCEPT"] = "text/iphone"
+ @request.accept = "text/iphone"
get :index
assert_equal 'Hello iPhone', @response.body
end
@@ -533,7 +533,7 @@ class MimeControllerLayoutsTest < Test::Unit::TestCase
get :index
assert_equal 'Super Firefox', @response.body
- @request.env["HTTP_ACCEPT"] = "text/iphone"
+ @request.accept = "text/iphone"
get :index
assert_equal '<html><div id="super_iphone">Super iPhone</div></html>', @response.body
end
diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb
index d2a3a2b0b0..be99350cd2 100644
--- a/actionpack/test/controller/new_render_test.rb
+++ b/actionpack/test/controller/new_render_test.rb
@@ -136,6 +136,10 @@ class NewRenderTestController < ActionController::Base
render :partial => "partial_only", :layout => true
end
+ def partial_with_counter
+ render :partial => "counter", :locals => { :counter_counter => 5 }
+ end
+
def partial_with_locals
render :partial => "customer", :locals => { :customer => Customer.new("david") }
end
@@ -741,6 +745,11 @@ EOS
assert_equal "<title>Talking to the layout</title>\nAction was here!", @response.body
end
+ def test_partial_with_counter
+ get :partial_with_counter
+ assert_equal "5", @response.body
+ end
+
def test_partials_list
get :partials_list
assert_equal "goodbyeHello: davidHello: marygoodbye\n", @response.body
diff --git a/actionpack/test/controller/rack_test.rb b/actionpack/test/controller/rack_test.rb
index ab8bbc3bf9..d1650de1fc 100644
--- a/actionpack/test/controller/rack_test.rb
+++ b/actionpack/test/controller/rack_test.rb
@@ -64,58 +64,61 @@ end
class RackRequestTest < BaseRackTest
def test_proxy_request
- assert_equal 'glu.ttono.us', @request.host_with_port
+ assert_equal 'glu.ttono.us', @request.host_with_port(true)
end
def test_http_host
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "rubyonrails.org:8080"
- assert_equal "rubyonrails.org:8080", @request.host_with_port
+ assert_equal "rubyonrails.org", @request.host(true)
+ assert_equal "rubyonrails.org:8080", @request.host_with_port(true)
@env['HTTP_X_FORWARDED_HOST'] = "www.firsthost.org, www.secondhost.org"
- assert_equal "www.secondhost.org", @request.host
+ assert_equal "www.secondhost.org", @request.host(true)
end
def test_http_host_with_default_port_overrides_server_port
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "rubyonrails.org"
- assert_equal "rubyonrails.org", @request.host_with_port
+ assert_equal "rubyonrails.org", @request.host_with_port(true)
end
def test_host_with_port_defaults_to_server_name_if_no_host_headers
@env.delete "HTTP_X_FORWARDED_HOST"
@env.delete "HTTP_HOST"
- assert_equal "glu.ttono.us:8007", @request.host_with_port
+ assert_equal "glu.ttono.us:8007", @request.host_with_port(true)
end
def test_host_with_port_falls_back_to_server_addr_if_necessary
@env.delete "HTTP_X_FORWARDED_HOST"
@env.delete "HTTP_HOST"
@env.delete "SERVER_NAME"
- assert_equal "207.7.108.53:8007", @request.host_with_port
+ assert_equal "207.7.108.53", @request.host(true)
+ assert_equal 8007, @request.port(true)
+ assert_equal "207.7.108.53:8007", @request.host_with_port(true)
end
def test_host_with_port_if_http_standard_port_is_specified
@env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:80"
- assert_equal "glu.ttono.us", @request.host_with_port
+ assert_equal "glu.ttono.us", @request.host_with_port(true)
end
def test_host_with_port_if_https_standard_port_is_specified
@env['HTTP_X_FORWARDED_PROTO'] = "https"
@env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:443"
- assert_equal "glu.ttono.us", @request.host_with_port
+ assert_equal "glu.ttono.us", @request.host_with_port(true)
end
def test_host_if_ipv6_reference
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]"
- assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
+ assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host(true)
end
def test_host_if_ipv6_reference_with_port
@env.delete "HTTP_X_FORWARDED_HOST"
@env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]:8008"
- assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host
+ assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host(true)
end
def test_cgi_environment_variables
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 76832f5713..1b9b12acc6 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -15,9 +15,14 @@ class TestController < ActionController::Base
end
def conditional_hello
- etag! [:foo, 123]
- last_modified! Time.now.utc.beginning_of_day
- render :action => 'hello_world' unless performed?
+ response.last_modified = Time.now.utc.beginning_of_day
+ response.etag = [:foo, 123]
+
+ if request.fresh?(response)
+ head :not_modified
+ else
+ render :action => 'hello_world'
+ end
end
def render_hello_world
@@ -428,7 +433,7 @@ class RenderTest < Test::Unit::TestCase
end
def test_should_render_formatted_html_erb_template_with_faulty_accepts_header
- @request.env["HTTP_ACCEPT"] = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appliction/x-shockwave-flash, */*"
+ @request.accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appliction/x-shockwave-flash, */*"
get :formatted_xml_erb
assert_equal '<test>passed formatted html erb</test>', @response.body
end
@@ -490,16 +495,16 @@ class EtagRenderTest < Test::Unit::TestCase
end
def test_render_against_etag_request_should_304_when_match
- @request.headers["HTTP_IF_NONE_MATCH"] = etag_for("hello david")
+ @request.if_none_match = etag_for("hello david")
get :render_hello_world_from_variable
- assert_equal "304 Not Modified", @response.headers['Status']
+ assert_equal "304 Not Modified", @response.status
assert @response.body.empty?
end
def test_render_against_etag_request_should_200_when_no_match
- @request.headers["HTTP_IF_NONE_MATCH"] = etag_for("hello somewhere else")
+ @request.if_none_match = etag_for("hello somewhere else")
get :render_hello_world_from_variable
- assert_equal "200 OK", @response.headers['Status']
+ assert_equal "200 OK", @response.status
assert !@response.body.empty?
end
@@ -508,13 +513,13 @@ class EtagRenderTest < Test::Unit::TestCase
expected_etag = etag_for('hello david')
assert_equal expected_etag, @response.headers['ETag']
- @request.headers["HTTP_IF_NONE_MATCH"] = expected_etag
+ @request.if_none_match = expected_etag
get :render_hello_world_from_variable
- assert_equal "304 Not Modified", @response.headers['Status']
+ assert_equal "304 Not Modified", @response.status
- @request.headers["HTTP_IF_NONE_MATCH"] = "\"diftag\""
+ @request.if_none_match = "\"diftag\""
get :render_hello_world_from_variable
- assert_equal "200 OK", @response.headers['Status']
+ assert_equal "200 OK", @response.status
end
def render_with_404_shouldnt_have_etag
@@ -557,17 +562,17 @@ class LastModifiedRenderTest < Test::Unit::TestCase
end
def test_request_not_modified
- @request.headers["HTTP_IF_MODIFIED_SINCE"] = @last_modified
+ @request.if_modified_since = @last_modified
get :conditional_hello
- assert_equal "304 Not Modified", @response.headers['Status']
+ assert_equal "304 Not Modified", @response.status
assert @response.body.blank?, @response.body
assert_equal @last_modified, @response.headers['Last-Modified']
end
def test_request_modified
- @request.headers["HTTP_IF_MODIFIED_SINCE"] = 'Thu, 16 Jul 2008 00:00:00 GMT'
+ @request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT'
get :conditional_hello
- assert_equal "200 OK", @response.headers['Status']
+ assert_equal "200 OK", @response.status
assert !@response.body.blank?
assert_equal @last_modified, @response.headers['Last-Modified']
end
diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/controller/request_test.rb
index 7db5264840..226c1ac018 100644
--- a/actionpack/test/controller/request_test.rb
+++ b/actionpack/test/controller/request_test.rb
@@ -15,57 +15,57 @@ class RequestTest < Test::Unit::TestCase
assert_equal '0.0.0.0', @request.remote_ip
@request.remote_addr = '1.2.3.4'
- assert_equal '1.2.3.4', @request.remote_ip
+ assert_equal '1.2.3.4', @request.remote_ip(true)
@request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
- assert_equal '1.2.3.4', @request.remote_ip
+ assert_equal '1.2.3.4', @request.remote_ip(true)
@request.remote_addr = '192.168.0.1'
- assert_equal '2.3.4.5', @request.remote_ip
+ assert_equal '2.3.4.5', @request.remote_ip(true)
@request.env.delete 'HTTP_CLIENT_IP'
@request.remote_addr = '1.2.3.4'
@request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
- assert_equal '1.2.3.4', @request.remote_ip
+ assert_equal '1.2.3.4', @request.remote_ip(true)
@request.remote_addr = '127.0.0.1'
@request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1'
- assert_equal 'unknown', @request.remote_ip
+ assert_equal 'unknown', @request.remote_ip(true)
@request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
- assert_equal '3.4.5.6', @request.remote_ip
+ assert_equal '3.4.5.6', @request.remote_ip(true)
@request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
e = assert_raises(ActionController::ActionControllerError) {
- @request.remote_ip
+ @request.remote_ip(true)
}
assert_match /IP spoofing attack/, e.message
assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message
assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message
@request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9'
- assert_equal '8.8.8.8', @request.remote_ip
+ assert_equal '8.8.8.8', @request.remote_ip(true)
@request.env.delete 'HTTP_CLIENT_IP'
@request.env.delete 'HTTP_X_FORWARDED_FOR'
@@ -168,58 +168,58 @@ class RequestTest < Test::Unit::TestCase
ActionController::Base.relative_url_root = nil
# The following tests are for when REQUEST_URI is not supplied (as in IIS)
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
@request.env['SCRIPT_NAME'] = nil #"/path/dispatch.rb"
+ @request.set_REQUEST_URI nil
assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
assert_equal "/path/of/some/uri", @request.path
ActionController::Base.relative_url_root = '/path'
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
@request.env['SCRIPT_NAME'] = "/path/dispatch.rb"
- assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
- assert_equal "/of/some/uri", @request.path
+ @request.set_REQUEST_URI nil
+ assert_equal "/path/of/some/uri?mapped=1", @request.request_uri(true)
+ assert_equal "/of/some/uri", @request.path(true)
ActionController::Base.relative_url_root = nil
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/path/of/some/uri"
@request.env['SCRIPT_NAME'] = nil
+ @request.set_REQUEST_URI nil
assert_equal "/path/of/some/uri", @request.request_uri
assert_equal "/path/of/some/uri", @request.path
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/"
+ @request.set_REQUEST_URI nil
assert_equal "/", @request.request_uri
assert_equal "/", @request.path
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/?m=b"
+ @request.set_REQUEST_URI nil
assert_equal "/?m=b", @request.request_uri
assert_equal "/", @request.path
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/"
@request.env['SCRIPT_NAME'] = "/dispatch.cgi"
+ @request.set_REQUEST_URI nil
assert_equal "/", @request.request_uri
assert_equal "/", @request.path
ActionController::Base.relative_url_root = '/hieraki'
- @request.set_REQUEST_URI nil
@request.env['PATH_INFO'] = "/hieraki/"
@request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
+ @request.set_REQUEST_URI nil
assert_equal "/hieraki/", @request.request_uri
assert_equal "/", @request.path
ActionController::Base.relative_url_root = nil
@request.set_REQUEST_URI '/hieraki/dispatch.cgi'
ActionController::Base.relative_url_root = '/hieraki'
- assert_equal "/dispatch.cgi", @request.path
+ assert_equal "/dispatch.cgi", @request.path(true)
ActionController::Base.relative_url_root = nil
@request.set_REQUEST_URI '/hieraki/dispatch.cgi'
ActionController::Base.relative_url_root = '/foo'
- assert_equal "/hieraki/dispatch.cgi", @request.path
+ assert_equal "/hieraki/dispatch.cgi", @request.path(true)
ActionController::Base.relative_url_root = nil
# This test ensures that Rails uses REQUEST_URI over PATH_INFO
@@ -227,8 +227,8 @@ class RequestTest < Test::Unit::TestCase
@request.env['REQUEST_URI'] = "/some/path"
@request.env['PATH_INFO'] = "/another/path"
@request.env['SCRIPT_NAME'] = "/dispatch.cgi"
- assert_equal "/some/path", @request.request_uri
- assert_equal "/some/path", @request.path
+ assert_equal "/some/path", @request.request_uri(true)
+ assert_equal "/some/path", @request.path(true)
end
def test_host_with_default_port
@@ -244,13 +244,13 @@ class RequestTest < Test::Unit::TestCase
end
def test_server_software
- assert_equal nil, @request.server_software
+ assert_equal nil, @request.server_software(true)
@request.env['SERVER_SOFTWARE'] = 'Apache3.422'
- assert_equal 'apache', @request.server_software
+ assert_equal 'apache', @request.server_software(true)
@request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)'
- assert_equal 'lighttpd', @request.server_software
+ assert_equal 'lighttpd', @request.server_software(true)
end
def test_xml_http_request
@@ -280,44 +280,44 @@ class RequestTest < Test::Unit::TestCase
def test_symbolized_request_methods
[:get, :post, :put, :delete].each do |method|
- set_request_method_to method
+ self.request_method = method
assert_equal method, @request.method
end
end
def test_invalid_http_method_raises_exception
- set_request_method_to :random_method
assert_raises(ActionController::UnknownHttpMethod) do
- @request.method
+ self.request_method = :random_method
end
end
def test_allow_method_hacking_on_post
- set_request_method_to :post
+ self.request_method = :post
[:get, :head, :options, :put, :post, :delete].each do |method|
- @request.instance_eval { @parameters = { :_method => method } ; @request_method = nil }
+ @request.instance_eval { @parameters = { :_method => method.to_s } ; @request_method = nil }
+ @request.request_method(true)
assert_equal(method == :head ? :get : method, @request.method)
end
end
def test_invalid_method_hacking_on_post_raises_exception
- set_request_method_to :post
+ self.request_method = :post
@request.instance_eval { @parameters = { :_method => :random_method } ; @request_method = nil }
assert_raises(ActionController::UnknownHttpMethod) do
- @request.method
+ @request.request_method(true)
end
end
def test_restrict_method_hacking
@request.instance_eval { @parameters = { :_method => 'put' } }
[:get, :put, :delete].each do |method|
- set_request_method_to method
+ self.request_method = method
assert_equal method, @request.method
end
end
- def test_head_masquarading_as_get
- set_request_method_to :head
+ def test_head_masquerading_as_get
+ self.request_method = :head
assert_equal :get, @request.method
assert @request.get?
assert @request.head?
@@ -339,9 +339,16 @@ class RequestTest < Test::Unit::TestCase
end
def test_nil_format
- @request.instance_eval { @parameters = { :format => nil } }
+ ActionController::Base.use_accept_header, old =
+ false, ActionController::Base.use_accept_header
+
+ @request.instance_eval { @parameters = {} }
@request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
+ assert @request.xhr?
assert_equal Mime::JS, @request.format
+
+ ensure
+ ActionController::Base.use_accept_header = old
end
def test_content_type
@@ -384,9 +391,9 @@ class RequestTest < Test::Unit::TestCase
end
protected
- def set_request_method_to(method)
+ def request_method=(method)
@request.env['REQUEST_METHOD'] = method.to_s.upcase
- @request.instance_eval { @request_method = nil }
+ @request.request_method(true)
end
end
diff --git a/actionpack/test/fixtures/_top_level_partial.html.erb b/actionpack/test/fixtures/_top_level_partial.html.erb
new file mode 100644
index 0000000000..0b1c2e46e0
--- /dev/null
+++ b/actionpack/test/fixtures/_top_level_partial.html.erb
@@ -0,0 +1 @@
+top level partial html \ No newline at end of file
diff --git a/actionpack/test/fixtures/_top_level_partial_only.erb b/actionpack/test/fixtures/_top_level_partial_only.erb
new file mode 100644
index 0000000000..44f25b61d0
--- /dev/null
+++ b/actionpack/test/fixtures/_top_level_partial_only.erb
@@ -0,0 +1 @@
+top level partial \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_counter.html.erb b/actionpack/test/fixtures/test/_counter.html.erb
new file mode 100644
index 0000000000..fd245bfc70
--- /dev/null
+++ b/actionpack/test/fixtures/test/_counter.html.erb
@@ -0,0 +1 @@
+<%= counter_counter %> \ No newline at end of file
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 8410e82c3c..7e40a55dc5 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -425,7 +425,8 @@ class AssetTagHelperTest < ActionView::TestCase
stylesheet_link_tag(:all, :cache => true)
)
- assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css'))
+ expected = Dir["#{ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR}/*.css"].map { |p| File.mtime(p) }.max
+ assert_equal expected, File.mtime(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css'))
assert_dom_equal(
%(<link href="http://a0.example.com/stylesheets/money.css" media="screen" rel="stylesheet" type="text/css" />),
diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb
index aca3593921..2b40074498 100644
--- a/actionpack/test/template/date_helper_i18n_test.rb
+++ b/actionpack/test/template/date_helper_i18n_test.rb
@@ -3,22 +3,22 @@ require 'abstract_unit'
class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase
include ActionView::Helpers::DateHelper
attr_reader :request
-
+
def setup
@from = Time.mktime(2004, 6, 6, 21, 45, 0)
end
-
+
uses_mocha 'date_helper_distance_of_time_in_words_i18n_test' do
# distance_of_time_in_words
def test_distance_of_time_in_words_calls_i18n
{ # with include_seconds
- [2.seconds, true] => [:'less_than_x_seconds', 5],
- [9.seconds, true] => [:'less_than_x_seconds', 10],
- [19.seconds, true] => [:'less_than_x_seconds', 20],
- [30.seconds, true] => [:'half_a_minute', nil],
- [59.seconds, true] => [:'less_than_x_minutes', 1],
- [60.seconds, true] => [:'x_minutes', 1],
+ [2.seconds, true] => [:'less_than_x_seconds', 5],
+ [9.seconds, true] => [:'less_than_x_seconds', 10],
+ [19.seconds, true] => [:'less_than_x_seconds', 20],
+ [30.seconds, true] => [:'half_a_minute', nil],
+ [59.seconds, true] => [:'less_than_x_minutes', 1],
+ [60.seconds, true] => [:'x_minutes', 1],
# without include_seconds
[29.seconds, false] => [:'less_than_x_minutes', 1],
@@ -38,7 +38,7 @@ class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase
def assert_distance_of_time_in_words_translates_key(passed, expected)
diff, include_seconds = *passed
- key, count = *expected
+ key, count = *expected
to = @from + diff
options = {:locale => 'en-US', :scope => :'datetime.distance_in_words'}
@@ -49,11 +49,11 @@ class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase
end
end
end
-
+
class DateHelperSelectTagsI18nTests < Test::Unit::TestCase
include ActionView::Helpers::DateHelper
attr_reader :request
-
+
uses_mocha 'date_helper_select_tags_i18n_tests' do
def setup
I18n.stubs(:translate).with(:'date.month_names', :locale => 'en-US').returns Date::MONTHNAMES
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index d8c07e731b..1a645bccc6 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -557,11 +557,8 @@ class DateHelperTest < ActionView::TestCase
end
def test_select_date_with_incomplete_order
- expected = %(<select id="date_first_day" name="date[first][day]">\n)
- expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
- expected << "</select>\n"
-
- expected << %(<select id="date_first_year" name="date[first][year]">\n)
+ # NOTE: modified this test because of minimal API change
+ expected = %(<select id="date_first_year" name="date[first][year]">\n)
expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
expected << "</select>\n"
@@ -569,6 +566,10 @@ class DateHelperTest < ActionView::TestCase
expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n)
expected << "</select>\n"
+ expected << %(<select id="date_first_day" name="date[first][day]">\n)
+ expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
+ expected << "</select>\n"
+
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :order => [:day])
end
@@ -909,6 +910,10 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), { :datetime_separator => "&mdash;", :date_separator => "/", :time_separator => ":", :start_year => 2003, :end_year => 2005, :prefix => "date[first]"}, :class => 'selector')
end
+ def test_select_datetime_should_work_with_date
+ assert_nothing_raised { select_datetime(Date.today) }
+ end
+
def test_select_time
expected = %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
@@ -986,31 +991,8 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {:include_seconds => false}, :class => 'selector')
end
- uses_mocha 'TestDatetimeAndTimeSelectUseTimeCurrentAsDefault' do
- def test_select_datetime_uses_time_current_as_default
- time = stub(:year => 2004, :month => 6, :day => 15, :hour => 16, :min => 35, :sec => 0)
- Time.expects(:current).returns time
- expects(:select_date).with(time, anything, anything).returns('')
- expects(:select_time).with(time, anything, anything).returns('')
- select_datetime
- end
-
- def test_select_time_uses_time_current_as_default
- time = stub(:year => 2004, :month => 6, :day => 15, :hour => 16, :min => 35, :sec => 0)
- Time.expects(:current).returns time
- expects(:select_hour).with(time, anything, anything).returns('')
- expects(:select_minute).with(time, anything, anything).returns('')
- select_time
- end
-
- def test_select_date_uses_date_current_as_default
- date = stub(:year => 2004, :month => 6, :day => 15)
- Date.expects(:current).returns date
- expects(:select_year).with(date, anything, anything).returns('')
- expects(:select_month).with(date, anything, anything).returns('')
- expects(:select_day).with(date, anything, anything).returns('')
- select_date
- end
+ def test_select_time_should_work_with_date
+ assert_nothing_raised { select_time(Date.today) }
end
def test_date_select
@@ -1231,6 +1213,30 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_date_select_with_separator
+ @post = Post.new
+ @post.written_on = Date.new(2004, 6, 15)
+
+ expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
+ expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n}
+ expected << "</select>\n"
+
+ expected << " / "
+
+ expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n}
+ expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
+ expected << "</select>\n"
+
+ expected << " / "
+
+ expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n}
+ expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n}
+
+ expected << "</select>\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", { :date_separator => " / " })
+ end
+
def test_time_select
@post = Post.new
@post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
@@ -1330,6 +1336,33 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_time_select_with_separator
+ @post = Post.new
+ @post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
+
+ expected = %{<input type="hidden" id="post_written_on_1i" name="post[written_on(1i)]" value="2004" />\n}
+ expected << %{<input type="hidden" id="post_written_on_2i" name="post[written_on(2i)]" value="6" />\n}
+ expected << %{<input type="hidden" id="post_written_on_3i" name="post[written_on(3i)]" value="15" />\n}
+
+ expected << %(<select id="post_written_on_4i" name="post[written_on(4i)]">\n)
+ 0.upto(23) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 15}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ expected << " - "
+
+ expected << %(<select id="post_written_on_5i" name="post[written_on(5i)]">\n)
+ 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ expected << " - "
+
+ expected << %(<select id="post_written_on_6i" name="post[written_on(6i)]">\n)
+ 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 35}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, time_select("post", "written_on", { :time_separator => " - ", :include_seconds => true })
+ end
+
def test_datetime_select
@post = Post.new
@post.updated_at = Time.local(2004, 6, 15, 16, 35)
@@ -1412,6 +1445,47 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_datetime_select_with_separators
+ @post = Post.new
+ @post.updated_at = Time.local(2004, 6, 15, 15, 16, 35)
+
+ expected = %{<select id="post_updated_at_1i" name="post[updated_at(1i)]">\n}
+ expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n}
+ expected << "</select>\n"
+
+ expected << " / "
+
+ expected << %{<select id="post_updated_at_2i" name="post[updated_at(2i)]">\n}
+ expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
+ expected << "</select>\n"
+
+ expected << " / "
+
+ expected << %{<select id="post_updated_at_3i" name="post[updated_at(3i)]">\n}
+ expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n}
+ expected << "</select>\n"
+
+ expected << " , "
+
+ expected << %(<select id="post_updated_at_4i" name="post[updated_at(4i)]">\n)
+ 0.upto(23) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 15}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ expected << " - "
+
+ expected << %(<select id="post_updated_at_5i" name="post[updated_at(5i)]">\n)
+ 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ expected << " - "
+
+ expected << %(<select id="post_updated_at_6i" name="post[updated_at(6i)]">\n)
+ 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 35}>#{sprintf("%02d", i)}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, datetime_select("post", "updated_at", { :date_separator => " / ", :datetime_separator => " , ", :time_separator => " - ", :include_seconds => true })
+ end
+
def test_date_select_with_zero_value_and_no_start_year
expected = %(<select id="date_first_year" name="date[first][year]">\n)
(Date.today.year-5).upto(Date.today.year+1) { |y| expected << %(<option value="#{y}">#{y}</option>\n) }
@@ -1814,26 +1888,151 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, datetime_select("post", "updated_at", {}, :class => 'selector')
end
- uses_mocha 'TestInstanceTagDefaultTimeFromOptions' do
- def test_instance_tag_default_time_from_options_uses_time_current_as_default_when_hash_passed_as_arg
- dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3)
- Time.expects(:current).returns Time.now
- dummy_instance_tag.send!(:default_time_from_options, :hour => 2)
- end
-
- def test_instance_tag_default_time_from_options_respects_hash_arg_settings_when_time_falls_in_system_local_dst_spring_gap
- with_env_tz('US/Central') do
- dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3)
- Time.stubs(:now).returns Time.local(2006, 4, 2, 1)
- assert_equal 2, dummy_instance_tag.send!(:default_time_from_options, :hour => 2).hour
- end
- end
-
- def test_instance_tag_default_time_from_options_handles_far_future_date
- dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3)
- time = dummy_instance_tag.send!(:default_time_from_options, :year => 2050, :month => 2, :day => 10, :hour => 15, :min => 30, :sec => 45)
- assert_equal 2050, time.year
- end
+ def test_date_select_should_not_change_passed_options_hash
+ @post = Post.new
+ @post.updated_at = Time.local(2008, 7, 16, 23, 30)
+
+ options = {
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }
+ date_select(@post, :updated_at, options)
+
+ # note: the literal hash is intentional to show that the actual options hash isn't modified
+ # don't change this!
+ assert_equal({
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }, options)
+ end
+
+ def test_datetime_select_should_not_change_passed_options_hash
+ @post = Post.new
+ @post.updated_at = Time.local(2008, 7, 16, 23, 30)
+
+ options = {
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }
+ datetime_select(@post, :updated_at, options)
+
+ # note: the literal hash is intentional to show that the actual options hash isn't modified
+ # don't change this!
+ assert_equal({
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }, options)
+ end
+
+ def test_time_select_should_not_change_passed_options_hash
+ @post = Post.new
+ @post.updated_at = Time.local(2008, 7, 16, 23, 30)
+
+ options = {
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }
+ time_select(@post, :updated_at, options)
+
+ # note: the literal hash is intentional to show that the actual options hash isn't modified
+ # don't change this!
+ assert_equal({
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }, options)
+ end
+
+ def test_select_date_should_not_change_passed_options_hash
+ options = {
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }
+ select_date(Date.today, options)
+
+ # note: the literal hash is intentional to show that the actual options hash isn't modified
+ # don't change this!
+ assert_equal({
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }, options)
+ end
+
+ def test_select_datetime_should_not_change_passed_options_hash
+ options = {
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }
+ select_datetime(Time.now, options)
+
+ # note: the literal hash is intentional to show that the actual options hash isn't modified
+ # don't change this!
+ assert_equal({
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }, options)
+ end
+
+ def test_select_time_should_not_change_passed_options_hash
+ options = {
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }
+ select_time(Time.now, options)
+
+ # note: the literal hash is intentional to show that the actual options hash isn't modified
+ # don't change this!
+ assert_equal({
+ :order => [ :year, :month, :day ],
+ :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 },
+ :discard_type => false,
+ :include_blank => false,
+ :ignore_date => false,
+ :include_seconds => true
+ }, options)
end
protected
diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb
index ce0da398cc..2ee7f43a65 100644
--- a/actionpack/test/template/number_helper_i18n_test.rb
+++ b/actionpack/test/template/number_helper_i18n_test.rb
@@ -18,35 +18,35 @@ class NumberHelperI18nTests < Test::Unit::TestCase
end
def test_number_to_currency_translates_currency_formats
- I18n.expects(:translate).with(
- [:'number.format', :'number.currency.format'], :locale => 'en-US'
- ).returns([@number_defaults, @currency_defaults])
+ I18n.expects(:translate).with(:'number.format', :locale => 'en-US', :raise => true).returns(@number_defaults)
+ I18n.expects(:translate).with(:'number.currency.format', :locale => 'en-US',
+ :raise => true).returns(@currency_defaults)
number_to_currency(1, :locale => 'en-US')
end
def test_number_with_precision_translates_number_formats
- I18n.expects(:translate).with(
- [:'number.format', :'number.precision.format'], :locale => 'en-US'
- ).returns([@number_defaults, @precision_defaults])
+ I18n.expects(:translate).with(:'number.format', :locale => 'en-US', :raise => true).returns(@number_defaults)
+ I18n.expects(:translate).with(:'number.precision.format', :locale => 'en-US',
+ :raise => true).returns(@precision_defaults)
number_with_precision(1, :locale => 'en-US')
end
def test_number_with_delimiter_translates_number_formats
- I18n.expects(:translate).with(:'number.format', :locale => 'en-US').returns(@number_defaults)
+ I18n.expects(:translate).with(:'number.format', :locale => 'en-US', :raise => true).returns(@number_defaults)
number_with_delimiter(1, :locale => 'en-US')
end
def test_number_to_percentage_translates_number_formats
- I18n.expects(:translate).with(
- [:'number.format', :'number.percentage.format'], :locale => 'en-US'
- ).returns([@number_defaults, @percentage_defaults])
+ I18n.expects(:translate).with(:'number.format', :locale => 'en-US', :raise => true).returns(@number_defaults)
+ I18n.expects(:translate).with(:'number.percentage.format', :locale => 'en-US',
+ :raise => true).returns(@percentage_defaults)
number_to_percentage(1, :locale => 'en-US')
end
def test_number_to_human_size_translates_human_formats
- I18n.expects(:translate).with(
- [:'number.format', :'number.human.format'], :locale => 'en-US'
- ).returns([@number_defaults, @human_defaults])
+ I18n.expects(:translate).with(:'number.format', :locale => 'en-US', :raise => true).returns(@number_defaults)
+ I18n.expects(:translate).with(:'number.human.format', :locale => 'en-US',
+ :raise => true).returns(@human_defaults)
# can't be called with 1 because this directly returns without calling I18n.translate
number_to_human_size(1025, :locale => 'en-US')
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index b1af043099..31cfdce531 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -19,6 +19,10 @@ class ViewRenderTest < Test::Unit::TestCase
assert_equal "Hello world!", @view.render("test/hello_world")
end
+ def test_render_file_at_top_level
+ assert_equal 'Elastica', @view.render('/shared')
+ end
+
def test_render_file_with_full_path
template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world.erb')
assert_equal "Hello world!", @view.render(:file => template_path)
@@ -47,6 +51,24 @@ class ViewRenderTest < Test::Unit::TestCase
assert_equal "only partial", @view.render(:partial => "test/partial_only")
end
+ def test_render_partial_with_format
+ assert_equal 'partial html', @view.render(:partial => 'test/partial')
+ end
+
+ def test_render_partial_at_top_level
+ # file fixtures/_top_level_partial_only.erb (not fixtures/test)
+ assert_equal 'top level partial', @view.render(:partial => '/top_level_partial_only')
+ end
+
+ def test_render_partial_with_format_at_top_level
+ # file fixtures/_top_level_partial.html.erb (not fixtures/test, with format extension)
+ assert_equal 'top level partial html', @view.render(:partial => '/top_level_partial')
+ end
+
+ def test_render_partial_with_locals
+ assert_equal "5", @view.render(:partial => "test/counter", :locals => { :counter_counter => 5 })
+ end
+
def test_render_partial_with_errors
assert_raise(ActionView::TemplateError) { @view.render(:partial => "test/raise") }
end
@@ -54,14 +76,14 @@ class ViewRenderTest < Test::Unit::TestCase
def test_render_partial_collection
assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ])
end
-
+
def test_render_partial_collection_as
- assert_equal "david david davidmary mary mary",
+ assert_equal "david david davidmary mary mary",
@view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer)
end
-
+
def test_render_partial_collection_without_as
- assert_equal "local_inspector,local_inspector_counter,object",
+ assert_equal "local_inspector,local_inspector_counter,object",
@view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ])
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 867503fb29..3065d33c1b 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -277,7 +277,11 @@ class UrlHelperTest < ActionView::TestCase
end
def test_mail_to_with_javascript
- assert_dom_equal "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript")
+ assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript")
+ end
+
+ def test_mail_to_with_javascript_unicode
+ assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%75%6e%69%63%6f%64%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%3e%c3%ba%6e%69%63%6f%64%65%3c%2f%61%3e%27%29%3b'))</script>", mail_to("unicode@example.com", "Ășnicode", :encode => "javascript")
end
def test_mail_with_options
@@ -301,8 +305,8 @@ class UrlHelperTest < ActionView::TestCase
assert_dom_equal "<a href=\"&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d\">&#109;&#101;&#40;&#97;&#116;&#41;&#100;&#111;&#109;&#97;&#105;&#110;&#46;&#99;&#111;&#109;</a>", mail_to("me@domain.com", nil, :encode => "hex", :replace_at => "(at)")
assert_dom_equal "<a href=\"&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d\">My email</a>", mail_to("me@domain.com", "My email", :encode => "hex", :replace_at => "(at)")
assert_dom_equal "<a href=\"&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d\">&#109;&#101;&#40;&#97;&#116;&#41;&#100;&#111;&#109;&#97;&#105;&#110;&#40;&#100;&#111;&#116;&#41;&#99;&#111;&#109;</a>", mail_to("me@domain.com", nil, :encode => "hex", :replace_at => "(at)", :replace_dot => "(dot)")
- assert_dom_equal "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
- assert_dom_equal "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%6d%65%28%61%74%29%64%6f%6d%61%69%6e%28%64%6f%74%29%63%6f%6d%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
+ assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
+ assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%6d%65%28%61%74%29%64%6f%6d%61%69%6e%28%64%6f%74%29%63%6f%6d%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
end
def protect_against_forgery?