aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md5
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/metal.rb10
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb29
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb24
-rw-r--r--actionpack/lib/action_view/flows.rb5
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb15
-rw-r--r--actionpack/lib/action_view/helpers/csrf_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb16
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb131
-rw-r--r--actionpack/lib/action_view/helpers/tags.rb48
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb5
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_select.rb8
-rw-r--r--actionpack/lib/action_view/helpers/tags/select.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/text_field.rb8
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb22
-rw-r--r--actionpack/lib/action_view/locale/en.yml1
-rw-r--r--actionpack/lib/action_view/template.rb5
-rw-r--r--actionpack/lib/action_view/template/error.rb4
-rw-r--r--actionpack/test/abstract_unit.rb15
-rw-r--r--actionpack/test/controller/base_test.rb6
-rw-r--r--actionpack/test/controller/force_ssl_test.rb3
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb7
-rw-r--r--actionpack/test/controller/rescue_test.rb4
-rw-r--r--actionpack/test/controller/routing_test.rb82
-rw-r--r--actionpack/test/dispatch/cookies_test.rb11
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb2
-rw-r--r--actionpack/test/dispatch/routing_test.rb23
-rw-r--r--actionpack/test/dispatch/show_exceptions_test.rb2
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb6
-rw-r--r--actionpack/test/template/date_helper_i18n_test.rb8
-rw-r--r--actionpack/test/template/date_helper_test.rb36
-rw-r--r--actionpack/test/template/form_helper_test.rb8
-rw-r--r--actionpack/test/template/form_options_helper_test.rb16
-rw-r--r--actionpack/test/template/html-scanner/sanitizer_test.rb2
-rw-r--r--actionpack/test/template/number_helper_test.rb26
-rw-r--r--actionpack/test/template/template_error_test.rb4
-rw-r--r--actionpack/test/template/url_helper_test.rb27
42 files changed, 465 insertions, 190 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 382a3cbd1d..5e78aba0cc 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,4 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+
+* Add `:format` option to number_to_percentage *Rodrigo Flores*
+
* Add `config.action_view.logger` to configure logger for ActionView. *Rafael França*
* Deprecated ActionController::Integration in favour of ActionDispatch::Integration
@@ -33,8 +36,6 @@
* Deprecate method_missing handling for not found actions, use action_missing instead. *Carlos Antonio da Silva*
-* Deprecate ActionController#performed?, check for response_body presence instead. *Carlos Antonio da Silva*
-
* Deprecate ActionController#rescue_action, ActionController#initialize_template_class, and ActionController#assign_shortcuts.
These methods were not being used internally anymore and are going to be removed in Rails 4. *Carlos Antonio da Silva*
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 4ce0624207..f13b1d5a60 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
s.add_dependency('activemodel', version)
s.add_dependency('rack-cache', '~> 1.1')
s.add_dependency('builder', '~> 3.0.0')
- s.add_dependency('rack', '~> 1.4.0')
+ s.add_dependency('rack', '~> 1.4.1')
s.add_dependency('rack-test', '~> 0.6.1')
s.add_dependency('journey', '~> 1.0.0')
s.add_dependency('sprockets', '~> 2.2.0')
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 3aab77a069..92433ab462 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -181,9 +181,13 @@ module ActionController
@_status = Rack::Utils.status_code(status)
end
- def response_body=(val)
- body = (val.nil? || val.respond_to?(:each)) ? val : [val]
- super body
+ def response_body=(body)
+ body = [body] unless body.nil? || body.respond_to?(:each)
+ super
+ end
+
+ def performed?
+ !!response_body
end
def dispatch(name, request) #:nodoc:
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index e8e465d3ba..ae04b53825 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -2,7 +2,7 @@ module ActionController
module ImplicitRender
def send_action(method, *args)
ret = super
- default_render unless response_body
+ default_render unless performed?
ret
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 39ff58a447..25f1db8228 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -191,6 +191,15 @@ module ActionDispatch
value
end
+ # Whether the given cookie is to be deleted by this CookieJar.
+ # Like <tt>[]=</tt>, you can pass in an options hash to test if a
+ # deletion applies to a specific <tt>:path</tt>, <tt>:domain</tt> etc.
+ def deleted?(key, options = {})
+ options.symbolize_keys!
+ handle_options(options)
+ @delete_cookies[key.to_s] == options
+ end
+
# Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
def clear(options = {})
@cookies.each_key{ |k| delete(k, options) }
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index db1e3198b3..e2d7a29079 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -2,6 +2,7 @@ require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/inclusion'
require 'active_support/inflector'
+require 'active_support/deprecation'
require 'action_dispatch/routing/redirection'
module ActionDispatch
@@ -54,6 +55,7 @@ module ActionDispatch
def initialize(set, scope, path, options)
@set, @scope = set, scope
+ @segment_keys = nil
@options = (@scope[:options] || {}).merge(options)
@path = normalize_path(path)
normalize_options!
@@ -213,7 +215,9 @@ module ActionDispatch
end
def segment_keys
- @segment_keys ||= Journey::Path::Pattern.new(
+ return @segment_keys if @segment_keys
+
+ @segment_keys = Journey::Path::Pattern.new(
Journey::Router::Strexp.compile(@path, requirements, SEPARATORS)
).names
end
@@ -464,7 +468,7 @@ module ActionDispatch
#
# get 'bacon', :to => 'food#bacon'
def get(*args, &block)
- map_method(:get, *args, &block)
+ map_method(:get, args, &block)
end
# Define a route that only recognizes HTTP POST.
@@ -474,7 +478,7 @@ module ActionDispatch
#
# post 'bacon', :to => 'food#bacon'
def post(*args, &block)
- map_method(:post, *args, &block)
+ map_method(:post, args, &block)
end
# Define a route that only recognizes HTTP PUT.
@@ -484,7 +488,7 @@ module ActionDispatch
#
# put 'bacon', :to => 'food#bacon'
def put(*args, &block)
- map_method(:put, *args, &block)
+ map_method(:put, args, &block)
end
# Define a route that only recognizes HTTP PUT.
@@ -494,15 +498,24 @@ module ActionDispatch
#
# delete 'broccoli', :to => 'food#broccoli'
def delete(*args, &block)
- map_method(:delete, *args, &block)
+ map_method(:delete, args, &block)
end
private
- def map_method(method, *args, &block)
+ def map_method(method, args, &block)
+ if args.length > 2
+ ActiveSupport::Deprecation.warn <<-eowarn
+The method signature of #{method}() is changing to:
+
+ #{method}(path, options = {}, &block)
+
+Calling with multiple paths is deprecated.
+ eowarn
+ end
+
options = args.extract_options!
options[:via] = method
- args.push(options)
- match(*args, &block)
+ match(*args, options, &block)
self
end
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 2c21887220..ac4dd7d927 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -360,7 +360,26 @@ module ActionDispatch
SEPARATORS,
anchor)
- Journey::Path::Pattern.new(strexp)
+ pattern = Journey::Path::Pattern.new(strexp)
+
+ builder = Journey::GTG::Builder.new pattern.spec
+
+ # Get all the symbol nodes followed by literals that are not the
+ # dummy node.
+ symbols = pattern.spec.grep(Journey::Nodes::Symbol).find_all { |n|
+ builder.followpos(n).first.literal?
+ }
+
+ # Get all the symbol nodes preceded by literals.
+ symbols.concat pattern.spec.find_all(&:literal?).map { |n|
+ builder.followpos(n).first
+ }.find_all(&:symbol?)
+
+ symbols.each { |x|
+ x.regexp = /(?:#{Regexp.union(x.regexp, '-')})+/
+ }
+
+ pattern
end
private :build_path
@@ -579,7 +598,8 @@ module ActionDispatch
params[key] = URI.parser.unescape(value)
end
end
-
+ old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
dispatcher = route.app
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
dispatcher = dispatcher.app
diff --git a/actionpack/lib/action_view/flows.rb b/actionpack/lib/action_view/flows.rb
index a8f740713f..c0e458cd41 100644
--- a/actionpack/lib/action_view/flows.rb
+++ b/actionpack/lib/action_view/flows.rb
@@ -22,11 +22,8 @@ module ActionView
def append(key, value)
@content[key] << value
end
+ alias_method :append!, :append
- # Called by provide
- def append!(key, value)
- @content[key] << value
- end
end
class StreamingFlow < OutputFlow #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 973135e2ea..1187956081 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -16,7 +16,9 @@ module ActionView
end
end
- module_eval "def content_tag(*) error_wrapping(super) end", __FILE__, __LINE__
+ def content_tag(*)
+ error_wrapping(super)
+ end
def tag(type, options, *)
tag_generate_errors?(options) ? error_wrapping(super) : super
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 5dbba3c4a7..134eaab8bc 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -422,7 +422,7 @@ module ActionView
if sources.is_a?(Array)
content_tag("video", options) do
- sources.map { |source| tag("source", :src => source) }.join.html_safe
+ sources.map { |source| tag("source", :src => path_to_video(source)) }.join.html_safe
end
else
options[:src] = path_to_video(sources)
@@ -441,10 +441,17 @@ module ActionView
# <audio src="/audios/sound.wav" />
# audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
# <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
- def audio_tag(source, options = {})
+ def audio_tag(sources, options = {})
options.symbolize_keys!
- options[:src] = path_to_audio(source)
- tag("audio", options)
+
+ if sources.is_a?(Array)
+ content_tag("audio", options) do
+ sources.collect { |source| tag("source", :src => path_to_audio(source)) }.join.html_safe
+ end
+ else
+ options[:src] = path_to_audio(sources)
+ tag("audio", options)
+ end
end
private
diff --git a/actionpack/lib/action_view/helpers/csrf_helper.rb b/actionpack/lib/action_view/helpers/csrf_helper.rb
index 1f2bc28cac..eeb0ed94b9 100644
--- a/actionpack/lib/action_view/helpers/csrf_helper.rb
+++ b/actionpack/lib/action_view/helpers/csrf_helper.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/string/strip'
-
module ActionView
# = Action View CSRF Helper
module Helpers
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f5077b034a..db9f5f5e9d 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -734,7 +734,7 @@ module ActionView
def select_day
if @options[:use_hidden] || @options[:discard_day]
- build_hidden(:day, day)
+ build_hidden(:day, day || 1)
else
build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false, :use_two_digit_numbers => @options[:use_two_digit_numbers])
end
@@ -742,7 +742,7 @@ module ActionView
def select_month
if @options[:use_hidden] || @options[:discard_month]
- build_hidden(:month, month)
+ build_hidden(:month, month || 1)
else
month_options = []
1.upto(12) do |month_number|
@@ -756,7 +756,7 @@ module ActionView
def select_year
if !@datetime || @datetime == 0
- val = ''
+ val = '1'
middle_year = Date.today.year
else
val = middle_year = year
@@ -836,7 +836,15 @@ module ActionView
end
def translated_date_order
- I18n.translate(:'date.order', :locale => @options[:locale]) || []
+ date_order = I18n.translate(:'date.order', :locale => @options[:locale]) || []
+
+ forbidden_elements = date_order - [:year, :month, :day]
+ if forbidden_elements.any?
+ raise StandardError,
+ "#{@options[:locale]}.date.order only accepts :year, :month and :day"
+ end
+
+ date_order
end
# Build full select tag from date type and options.
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 57b90a9c42..e97f602728 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -627,7 +627,7 @@ module ActionView
token_tag(authenticity_token)
else
html_options["method"] = "post"
- tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token)
+ method_tag(method) + token_tag(authenticity_token)
end
tags = utf8_enforcer_tag << method_tag
@@ -646,15 +646,6 @@ module ActionView
output.safe_concat("</form>")
end
- def token_tag(token)
- if token == false || !protect_against_forgery?
- ''
- else
- token ||= form_authenticity_token
- tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
- end
- end
-
# see http://www.w3.org/TR/html4/types.html#type-name
def sanitize_to_id(name)
name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_")
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 43122ef2ba..b0860f87c4 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -57,15 +57,11 @@ module ActionView
# # => +1.123.555.1234 x 1343
def number_to_phone(number, options = {})
return unless number
+ options = options.symbolize_keys
- begin
- Float(number)
- rescue ArgumentError, TypeError
- raise InvalidNumberError, number
- end if options[:raise]
+ parse_float(number, true) if options[:raise]
number = number.to_s.strip
- options = options.symbolize_keys
area_code = options[:area_code]
delimiter = options[:delimiter] || "-"
extension = options[:extension]
@@ -75,7 +71,7 @@ module ActionView
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
else
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
- number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
+ number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank?
end
str = []
@@ -122,14 +118,12 @@ module ActionView
# # => 1234567890,50 &pound;
def number_to_currency(number, options = {})
return unless number
+ options = options.symbolize_keys
- options.symbolize_keys!
-
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
+ currency = translations_for('currency', options[:locale])
currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
- defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
+ defaults = DEFAULT_CURRENCY_VALUES.merge(defaults_translations(options[:locale])).merge!(currency)
defaults[:negative_format] = "-" + options[:format] if options[:format]
options = defaults.merge!(options)
@@ -152,7 +146,6 @@ module ActionView
e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
end
end
-
end
# Formats a +number+ as a percentage string (e.g., 65%). You can customize the format in the +options+ hash.
@@ -169,6 +162,8 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator
# (defaults to +false+).
+ # * <tt>:format</tt> - Specifies the format of the percentage string
+ # The number field is <tt>%n</tt> (defaults to "%n%").
# * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# ==== Examples
@@ -180,26 +175,27 @@ module ActionView
# number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
# number_to_percentage(1000, :locale => :fr) # => 1 000,000%
# number_to_percentage("98a") # => 98a%
+ # number_to_percentage(100, :format => "%n %") # => 100 %
#
# number_to_percentage("98a", :raise => true) # => InvalidNumberError
def number_to_percentage(number, options = {})
return unless number
+ options = options.symbolize_keys
- options.symbolize_keys!
+ defaults = format_translations('percentage', options[:locale])
+ options = defaults.merge!(options)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(percentage)
-
- options = options.reverse_merge(defaults)
+ format = options[:format] || "%n%"
begin
- "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
+ value = number_with_precision(number, options.merge(:raise => true))
+ format.gsub(/%n/, value).html_safe
rescue InvalidNumberError => e
if options[:raise]
raise
else
- e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
+ formatted_number = format.gsub(/%n/, e.number)
+ e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
end
end
end
@@ -229,25 +225,15 @@ module ActionView
#
# number_with_delimiter("112a", :raise => true) # => raise InvalidNumberError
def number_with_delimiter(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ parse_float(number, options[:raise]) or return number
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- options = options.reverse_merge(defaults)
+ options = defaults_translations(options[:locale]).merge(options)
parts = number.to_s.to_str.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
parts.join(options[:separator]).html_safe
-
end
# Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision
@@ -264,6 +250,7 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator
# (defaults to +false+).
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# ==== Examples
# number_with_precision(111.2345) # => 111.235
@@ -282,23 +269,13 @@ module ActionView
# number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
# # => 1.111,23
def number_with_precision(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(precision_defaults)
+ defaults = format_translations('precision', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false
precision = options.delete :precision
significant = options.delete :significant
strip_insignificant_zeros = options.delete :strip_insignificant_zeros
@@ -323,7 +300,6 @@ module ActionView
else
formatted_number
end
-
end
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
@@ -343,6 +319,7 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+)
# * <tt>:prefix</tt> - If +:si+ formats the number using the SI prefix (defaults to :binary)
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
# ==== Examples
# number_to_human_size(123) # => 123 Bytes
# number_to_human_size(1234) # => 1.21 KB
@@ -359,23 +336,13 @@ module ActionView
# number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB"
# number_to_human_size(524288000, :precision => 5) # => "500 MB"
def number_to_human_size(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(human)
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults)
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
@@ -424,6 +391,7 @@ module ActionView
# * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>, <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt>
# * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt>
# * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are:
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# %u The quantifier (ex.: 'thousand')
# %n The number
@@ -478,23 +446,13 @@ module ActionView
# number_to_human(0.34, :units => :distance) # => "34 centimeters"
#
def number_to_human(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(human)
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults)
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
@@ -530,6 +488,25 @@ module ActionView
decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
end
+ private
+
+ def format_translations(namespace, locale)
+ defaults_translations(locale).merge(translations_for(namespace, locale))
+ end
+
+ def defaults_translations(locale)
+ I18n.translate(:'number.format', :locale => locale, :default => {})
+ end
+
+ def translations_for(namespace, locale)
+ I18n.translate(:"number.#{namespace}.format", :locale => locale, :default => {})
+ end
+
+ def parse_float(number, raise_error)
+ Float(number)
+ rescue ArgumentError, TypeError
+ raise InvalidNumberError, number if raise_error
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb
index 89b3efda5f..e874d4ca42 100644
--- a/actionpack/lib/action_view/helpers/tags.rb
+++ b/actionpack/lib/action_view/helpers/tags.rb
@@ -1,28 +1,30 @@
module ActionView
module Helpers
- module Tags
- autoload :Base, 'action_view/helpers/tags/base'
- autoload :Label, 'action_view/helpers/tags/label'
- autoload :TextField, 'action_view/helpers/tags/text_field'
- autoload :PasswordField, 'action_view/helpers/tags/password_field'
- autoload :HiddenField, 'action_view/helpers/tags/hidden_field'
- autoload :FileField, 'action_view/helpers/tags/file_field'
- autoload :SearchField, 'action_view/helpers/tags/search_field'
- autoload :TelField, 'action_view/helpers/tags/tel_field'
- autoload :UrlField, 'action_view/helpers/tags/url_field'
- autoload :EmailField, 'action_view/helpers/tags/email_field'
- autoload :NumberField, 'action_view/helpers/tags/number_field'
- autoload :RangeField, 'action_view/helpers/tags/range_field'
- autoload :TextArea, 'action_view/helpers/tags/text_area'
- autoload :CheckBox, 'action_view/helpers/tags/check_box'
- autoload :RadioButton, 'action_view/helpers/tags/radio_button'
- autoload :Select, 'action_view/helpers/tags/select'
- autoload :CollectionSelect, 'action_view/helpers/tags/collection_select'
- autoload :GroupedCollectionSelect, 'action_view/helpers/tags/grouped_collection_select'
- autoload :TimeZoneSelect, 'action_view/helpers/tags/time_zone_select'
- autoload :DateSelect, 'action_view/helpers/tags/date_select'
- autoload :TimeSelect, 'action_view/helpers/tags/time_select'
- autoload :DatetimeSelect, 'action_view/helpers/tags/datetime_select'
+ module Tags #:nodoc:
+ extend ActiveSupport::Autoload
+
+ autoload :Base
+ autoload :Label
+ autoload :TextField
+ autoload :PasswordField
+ autoload :HiddenField
+ autoload :FileField
+ autoload :SearchField
+ autoload :TelField
+ autoload :UrlField
+ autoload :EmailField
+ autoload :NumberField
+ autoload :RangeField
+ autoload :TextArea
+ autoload :CheckBox
+ autoload :RadioButton
+ autoload :Select
+ autoload :CollectionSelect
+ autoload :GroupedCollectionSelect
+ autoload :TimeZoneSelect
+ autoload :DateSelect
+ autoload :TimeSelect
+ autoload :DatetimeSelect
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index 24956beb9c..449f94d347 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -19,8 +19,9 @@ module ActionView
@auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
end
- def render(&block)
- raise "Abstract Method called"
+ # This is what child classes implement.
+ def render
+ raise NotImplementedError, "Subclasses must implement a render method"
end
private
diff --git a/actionpack/lib/action_view/helpers/tags/date_select.rb b/actionpack/lib/action_view/helpers/tags/date_select.rb
index 5912598ca1..5d706087b0 100644
--- a/actionpack/lib/action_view/helpers/tags/date_select.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_select.rb
@@ -12,10 +12,16 @@ module ActionView
error_wrapping(datetime_selector(@options, @html_options).send("select_#{select_type}").html_safe)
end
+ class << self
+ def select_type
+ @select_type ||= self.name.split("::").last.sub("Select", "").downcase
+ end
+ end
+
private
def select_type
- self.class.name.split("::").last.sub("Select", "").downcase
+ self.class.select_type
end
def datetime_selector(options, html_options)
diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb
index 71fd4d04b7..02b790db4e 100644
--- a/actionpack/lib/action_view/helpers/tags/select.rb
+++ b/actionpack/lib/action_view/helpers/tags/select.rb
@@ -4,6 +4,7 @@ module ActionView
class Select < Base #:nodoc:
def initialize(object_name, method_name, template_object, choices, options, html_options)
@choices = choices
+ @choices = @choices.to_a if @choices.is_a?(Range)
@html_options = html_options
super(object_name, method_name, template_object, options)
diff --git a/actionpack/lib/action_view/helpers/tags/text_field.rb b/actionpack/lib/action_view/helpers/tags/text_field.rb
index 0f81726eb4..ce5182d20f 100644
--- a/actionpack/lib/action_view/helpers/tags/text_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/text_field.rb
@@ -13,10 +13,16 @@ module ActionView
tag("input", options)
end
+ class << self
+ def field_type
+ @field_type ||= self.name.split("::").last.sub("Field", "").downcase
+ end
+ end
+
private
def field_type
- @field_type ||= self.class.name.split("::").last.sub("Field", "").downcase
+ self.class.field_type
end
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index ebd1f280a8..d27d49821b 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -327,7 +327,7 @@ module ActionView
method_tag = ''
if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
- method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
+ method_tag = method_tag(method)
end
form_method = method.to_s == 'get' ? 'get' : 'post'
@@ -336,10 +336,7 @@ module ActionView
remote = html_options.delete('remote')
- request_token_tag = ''
- if form_method == 'post' && protect_against_forgery?
- request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
- end
+ request_token_tag = form_method == 'post' ? token_tag : ''
url = options.is_a?(String) ? options : self.url_for(options)
name ||= url
@@ -476,7 +473,7 @@ module ActionView
# string given as the value.
# * <tt>:subject</tt> - Preset the subject line of the email.
# * <tt>:body</tt> - Preset the body of the email.
- # * <tt>:cc</tt> - Carbon Copy addition recipients on the email.
+ # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
# * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
#
# ==== Examples
@@ -670,6 +667,19 @@ module ActionView
bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
html_options
end
+
+ def token_tag(token=nil)
+ if token == false || !protect_against_forgery?
+ ''
+ else
+ token ||= form_authenticity_token
+ tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
+ end
+ end
+
+ def method_tag(method)
+ tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
+ end
end
end
end
diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml
index f2a83b92a9..7cca7d969a 100644
--- a/actionpack/lib/action_view/locale/en.yml
+++ b/actionpack/lib/action_view/locale/en.yml
@@ -37,6 +37,7 @@
# precision:
# significant: false
# strip_insignificant_zeros: false
+ format: "%n%"
# Used in number_to_precision()
precision:
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 593eaa2abf..edb3d427d5 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -288,7 +288,7 @@ module ActionView
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
- raise ActionView::Template::Error.new(self, {}, e)
+ raise ActionView::Template::Error.new(self, e)
end
end
@@ -297,13 +297,12 @@ module ActionView
e.sub_template_of(self)
raise e
else
- assigns = view.respond_to?(:assigns) ? view.assigns : {}
template = self
unless template.source
template = refresh(view)
template.encode!
end
- raise Template::Error.new(template, assigns, e)
+ raise Template::Error.new(template, e)
end
end
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index 83df2604bb..d8258f7b11 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -55,9 +55,9 @@ module ActionView
attr_reader :original_exception, :backtrace
- def initialize(template, assigns, original_exception)
+ def initialize(template, original_exception)
super(original_exception.message)
- @template, @assigns, @original_exception = template, assigns.dup, original_exception
+ @template, @original_exception = template, original_exception
@sub_templates = nil
@backtrace = original_exception.backtrace
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 0a25d7ba47..b1a5356ddd 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -344,6 +344,21 @@ module ActionDispatch
end
end
+module ActionDispatch
+ module RoutingVerbs
+ def get(uri_or_host, path = nil, port = nil)
+ host = uri_or_host.host unless path
+ path ||= uri_or_host.path
+
+ params = {'PATH_INFO' => path,
+ 'REQUEST_METHOD' => 'GET',
+ 'HTTP_HOST' => host}
+
+ routes.call(params)[2].join
+ end
+ end
+end
+
module RoutingTestHelpers
def url_for(set, options, recall = nil)
set.send(:url_for, options.merge(:only_path => true, :_path_segments => recall))
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index b95a524612..70e03d24ea 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -93,6 +93,12 @@ class ControllerInstanceTests < ActiveSupport::TestCase
Submodule::ContainedNonEmptyController.new]
end
+ def test_performed?
+ assert !@empty.performed?
+ @empty.response_body = ["sweet"]
+ assert @empty.performed?
+ end
+
def test_action_methods
@empty_controllers.each do |c|
assert_equal Set.new, c.class.action_methods, "#{c.controller_path} should be empty!"
diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb
index 125012631e..3ea3c06ac4 100644
--- a/actionpack/test/controller/force_ssl_test.rb
+++ b/actionpack/test/controller/force_ssl_test.rb
@@ -39,10 +39,8 @@ class ForceSSLFlash < ForceSSLController
@flashy = flash["that"]
render :inline => "hello"
end
-
end
-
class ForceSSLControllerLevelTest < ActionController::TestCase
tests ForceSSLControllerLevel
@@ -135,5 +133,4 @@ class ForceSSLFlashTest < ActionController::TestCase
assert_equal "hello", assigns["flash_copy"]["that"]
assert_equal "hello", assigns["flashy"]
end
-
end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 4a291582d8..e6d3fa74f2 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -1,6 +1,5 @@
require 'abstract_unit'
require 'digest/sha1'
-require 'active_support/core_ext/string/strip'
require "active_support/log_subscriber/test_helper"
# common controller actions
@@ -72,9 +71,7 @@ class CustomAuthenticityParamController < RequestForgeryProtectionController
end
end
-
# common test methods
-
module RequestForgeryProtectionTests
def setup
@token = "cf50faa3fe97702ca1ae"
@@ -246,10 +243,6 @@ class FreeCookieControllerTest < ActionController::TestCase
end
end
-
-
-
-
class CustomAuthenticityParamControllerTest < ActionController::TestCase
def setup
ActionController::Base.request_forgery_protection_token = :custom_token_name
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 86d6737cbb..9c51db135b 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -137,11 +137,11 @@ class RescueController < ActionController::Base
end
def io_error_in_view
- raise ActionView::TemplateError.new(nil, {}, IOError.new('this is io error'))
+ raise ActionView::TemplateError.new(nil, IOError.new('this is io error'))
end
def zero_division_error_in_view
- raise ActionView::TemplateError.new(nil, {}, ZeroDivisionError.new('this is zero division error'))
+ raise ActionView::TemplateError.new(nil, ZeroDivisionError.new('this is zero division error'))
end
protected
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index bec9eb16f3..44a40e0665 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -73,23 +73,76 @@ end
class LegacyRouteSetTests < ActiveSupport::TestCase
include RoutingTestHelpers
+ include ActionDispatch::RoutingVerbs
attr_reader :rs
+ alias :routes :rs
def setup
@rs = ::ActionDispatch::Routing::RouteSet.new
@response = nil
end
- def get(uri_or_host, path = nil, port = nil)
- host = uri_or_host.host unless path
- path ||= uri_or_host.path
+ def test_symbols_with_dashes
+ rs.draw do
+ match '/:artist/:song-omg', :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/faithfully-omg'))
+ assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash)
+ end
+
+ def test_id_with_dash
+ rs.draw do
+ match '/journey/:id', :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/faithfully-omg'))
+ assert_equal({"id"=>"faithfully-omg"}, hash)
+ end
- params = {'PATH_INFO' => path,
- 'REQUEST_METHOD' => 'GET',
- 'HTTP_HOST' => host}
+ def test_dash_with_custom_regexp
+ rs.draw do
+ match '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
- @rs.call(params)[2].join
+ hash = JSON.load get(URI('http://example.org/journey/123-omg'))
+ assert_equal({"artist"=>"journey", "song"=>"123"}, hash)
+ assert_equal 'Not Found', get(URI('http://example.org/journey/faithfully-omg'))
+ end
+
+ def test_pre_dash
+ rs.draw do
+ match '/:artist/omg-:song', :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/omg-faithfully'))
+ assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash)
+ end
+
+ def test_pre_dash_with_custom_regexp
+ rs.draw do
+ match '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/omg-123'))
+ assert_equal({"artist"=>"journey", "song"=>"123"}, hash)
+ assert_equal 'Not Found', get(URI('http://example.org/journey/omg-faithfully'))
end
def test_regexp_precidence
@@ -1327,7 +1380,20 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
end
-
+
+ def test_route_with_subdomain_and_constraints_must_receive_params
+ name_param = nil
+ set.draw do
+ match 'page/:name' => 'pages#show', :constraints => lambda {|request|
+ name_param = request.params[:name]
+ return true
+ }
+ end
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'mypage'},
+ set.recognize_path('http://subdomain.example.org/page/mypage'))
+ assert_equal(name_param, 'mypage')
+ end
+
def test_route_requirement_recognize_with_ignore_case
set.draw do
match 'page/:name' => 'pages#show',
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 6ebd02e85c..3e48d97e67 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -245,6 +245,17 @@ class CookiesTest < ActionController::TestCase
assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"
end
+ def test_deleted_cookie_predicate
+ cookies.delete("user_name")
+ assert cookies.deleted?("user_name")
+ assert_equal false, cookies.deleted?("another")
+ end
+
+ def test_deleted_cookie_predicate_with_mismatching_options
+ cookies.delete("user_name", :path => "/path")
+ assert_equal false, cookies.deleted?("user_name", :path => "/different")
+ end
+
def test_cookies_persist_throughout_request
response = get :authenticate
assert response.headers["Set-Cookie"] =~ /user_name=david/
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index c3a565990e..11c292d61a 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -34,7 +34,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
when "/unprocessable_entity"
raise ActionController::InvalidAuthenticityToken
when "/not_found_original_exception"
- raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new)
+ raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
else
raise "puke!"
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index c6e6ed4d6b..3689b17877 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -1,3 +1,4 @@
+# encoding: UTF-8
require 'erb'
require 'abstract_unit'
require 'controller/fake_controllers'
@@ -156,7 +157,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
resources :posts do
- get :archive, :toggle_view, :on => :collection
+ get :archive, :on => :collection
+ get :toggle_view, :on => :collection
post :preview, :on => :member
resource :subscription
@@ -2543,3 +2545,22 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest
assert_equal 'a b/c+d', @response.body
end
end
+
+class TestUnicodePaths < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ match "/#{Rack::Utils.escape("ほげ")}" => lambda { |env|
+ path_params = env['action_dispatch.request.path_parameters']
+ [200, { 'Content-Type' => 'text/plain' }, []]
+ }, :as => :unicode_path
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ test 'recognizes unicode path' do
+ get "/#{Rack::Utils.escape("ほげ")}"
+ assert_equal "200", @response.code
+ end
+end
diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb
index 4a6d5ddbf7..45f8fc11b3 100644
--- a/actionpack/test/dispatch/show_exceptions_test.rb
+++ b/actionpack/test/dispatch/show_exceptions_test.rb
@@ -11,7 +11,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest
when "/method_not_allowed"
raise ActionController::MethodNotAllowed
when "/not_found_original_exception"
- raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new)
+ raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
else
raise "puke!"
end
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index aa7304b3ed..45a8492d58 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -201,8 +201,8 @@ class AssetTagHelperTest < ActionView::TestCase
%(video_tag("error.avi", "size" => "x")) => %(<video src="/videos/error.avi" />),
%(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="http://media.rubyonrails.org/video/rails_blog_2.mov" />),
%(video_tag("//media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="//media.rubyonrails.org/video/rails_blog_2.mov" />),
- %(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="multiple.ogg" /><source src="multiple.avi" /></video>),
- %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="multiple.ogg" /><source src="multiple.avi" /></video>)
+ %(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>),
+ %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>)
}
AudioPathToTag = {
@@ -224,6 +224,8 @@ class AssetTagHelperTest < ActionView::TestCase
%(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(<audio autoplay="autoplay" controls="controls" src="/audios/rss.wav" />),
%(audio_tag("http://media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="http://media.rubyonrails.org/audio/rails_blog_2.mov" />),
%(audio_tag("//media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="//media.rubyonrails.org/audio/rails_blog_2.mov" />),
+ %(audio_tag(["audio.mp3", "audio.ogg"])) => %(<audio><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>),
+ %(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %(<audio autobuffer="autobuffer" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>)
}
def test_auto_discovery_link_tag
diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb
index e3d3d5ff77..ef3d7d97ee 100644
--- a/actionpack/test/template/date_helper_i18n_test.rb
+++ b/actionpack/test/template/date_helper_i18n_test.rb
@@ -118,4 +118,12 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase
I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:year, :month, :day]
datetime_select('post', 'updated_at', :locale => 'en')
end
+
+ def test_date_or_time_select_given_invalid_order
+ I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:invalid, :month, :day]
+
+ assert_raise StandardError do
+ datetime_select('post', 'updated_at', :locale => 'en')
+ end
+ end
end
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index fadfb59572..9e2f4ec347 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1587,7 +1587,7 @@ class DateHelperTest < ActionView::TestCase
start_year = Time.now.year-5
end_year = Time.now.year+5
- expected = '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i"/>' + "\n"
+ expected = '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n"
expected << %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
expected << "<option value=\"\"></option>\n"
start_year.upto(end_year) { |i| expected << %(<option value="#{i}">#{i}</option>\n) }
@@ -1601,6 +1601,40 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on", :order=>[:year, :month], :include_blank=>true)
end
+ def test_date_select_with_nil_and_blank_and_discard_month
+ @post = Post.new
+
+ start_year = Time.now.year-5
+ end_year = Time.now.year+5
+
+ expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
+ expected << "<option value=\"\"></option>\n"
+ start_year.upto(end_year) { |i| expected << %(<option value="#{i}">#{i}</option>\n) }
+ expected << "</select>\n"
+ expected << '<input name="post[written_on(2i)]" type="hidden" id="post_written_on_2i" value="1"/>' + "\n"
+ expected << '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", :discard_month => true, :include_blank=>true)
+ end
+
+ def test_date_select_with_nil_and_blank_and_discard_year
+ @post = Post.new
+
+ expected = '<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="1" />' + "\n"
+
+ expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n}
+ expected << "<option value=\"\"></option>\n"
+ 1.upto(12) { |i| expected << %(<option value="#{i}">#{Date::MONTHNAMES[i]}</option>\n) }
+ expected << "</select>\n"
+
+ expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n}
+ expected << "<option value=\"\"></option>\n"
+ 1.upto(31) { |i| expected << %(<option value="#{i}">#{i}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", :discard_year => true, :include_blank=>true)
+ end
+
def test_date_select_cant_override_discard_hour
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 5be6a2e4e5..39d4768861 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -115,6 +115,14 @@ class FormHelperTest < ActionView::TestCase
super
end
+ class FooTag < ActionView::Helpers::Tags::Base
+ def initialize; end
+ end
+
+ def test_tags_base_child_without_render_method
+ assert_raise(NotImplementedError) { FooTag.new.render }
+ end
+
def test_label
assert_dom_equal('<label for="post_title">Title</label>', label("post", "title"))
assert_dom_equal('<label for="post_title">The title goes here</label>', label("post", "title", "The title goes here"))
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 4a889beadd..a903e13bad 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -144,6 +144,13 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_range_options_for_select
+ assert_dom_equal(
+ "<option value=\"1\">1</option>\n<option value=\"2\">2</option>\n<option value=\"3\">3</option>",
+ options_for_select(1..3)
+ )
+ end
+
def test_array_options_for_string_include_in_other_string_bug_fix
assert_dom_equal(
"<option value=\"ruby\">ruby</option>\n<option value=\"rubyonrails\" selected=\"selected\">rubyonrails</option>",
@@ -671,6 +678,15 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_select_with_range
+ @post = Post.new
+ @post.category = 0
+ assert_dom_equal(
+ "<select id=\"post_category\" name=\"post[category]\"><option value=\"1\">1</option>\n<option value=\"2\">2</option>\n<option value=\"3\">3</option></select>",
+ select("post", "category", 1..3)
+ )
+ end
+
def test_collection_select
@post = Post.new
@post.author_name = "Babe"
diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb
index b4d751e405..32c655c5fd 100644
--- a/actionpack/test/template/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/template/html-scanner/sanitizer_test.rb
@@ -56,7 +56,6 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f"
end
- # TODO: Clean up
def test_sanitize_js_handlers
raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>}
assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>}
@@ -215,7 +214,6 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized img_hack, "<img>"
end
- # TODO: Clean up
def test_should_sanitize_attributes
assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'&gt;&lt;script&gt;alert()&lt;/script&gt;">blah</span>)
end
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index 8d679aac1d..482d953907 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -57,6 +57,7 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("1000.000%", number_to_percentage("1000"))
assert_equal("123.4%", number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true))
assert_equal("1.000,000%", number_to_percentage(1000, :delimiter => '.', :separator => ','))
+ assert_equal("1000.000 %", number_to_percentage(1000, :format => "%n %"))
end
def test_number_with_delimiter
@@ -267,6 +268,31 @@ class NumberHelperTest < ActionView::TestCase
assert_nil number_to_human(nil)
end
+ def test_number_helpers_do_not_mutate_options_hash
+ options = { 'raise' => true }
+
+ number_to_phone(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_currency(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_percentage(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_with_delimiter(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_with_precision(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_human_size(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_human(1, options)
+ assert_equal({ 'raise' => true }, options)
+ end
+
def test_number_helpers_should_return_non_numeric_param_unchanged
assert_equal("+1-x x 123", number_to_phone("x", :country_code => 1, :extension => 123))
assert_equal("x", number_to_phone("x"))
diff --git a/actionpack/test/template/template_error_test.rb b/actionpack/test/template/template_error_test.rb
index 3a874082d9..91424daeed 100644
--- a/actionpack/test/template/template_error_test.rb
+++ b/actionpack/test/template/template_error_test.rb
@@ -2,12 +2,12 @@ require "abstract_unit"
class TemplateErrorTest < ActiveSupport::TestCase
def test_provides_original_message
- error = ActionView::Template::Error.new("test", {}, Exception.new("original"))
+ error = ActionView::Template::Error.new("test", Exception.new("original"))
assert_equal "original", error.message
end
def test_provides_useful_inspect
- error = ActionView::Template::Error.new("test", {}, Exception.new("original"))
+ error = ActionView::Template::Error.new("test", Exception.new("original"))
assert_equal "#<ActionView::Template::Error: original>", error.inspect
end
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index d013a44e6c..cf4dafbac4 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -11,6 +11,9 @@ class UrlHelperTest < ActiveSupport::TestCase
# In those cases, we'll set up a simple mock
attr_accessor :controller, :request
+ cattr_accessor :request_forgery
+ self.request_forgery = false
+
routes = ActionDispatch::Routing::RouteSet.new
routes.draw do
match "/" => "foo#bar"
@@ -49,11 +52,22 @@ class UrlHelperTest < ActiveSupport::TestCase
assert_equal 'javascript:history.back()', url_for(:back)
end
- # todo: missing test cases
+ # TODO: missing test cases
def test_button_to_with_straight_url
assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com")
end
+ def test_button_to_with_straight_url_and_request_forgery
+ self.request_forgery = true
+
+ assert_dom_equal(
+ %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /><input name="form_token" type="hidden" value="secret" /></div></form>},
+ button_to("Hello", "http://www.example.com")
+ )
+ ensure
+ self.request_forgery = false
+ end
+
def test_button_to_with_form_class
assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"custom-class\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :form_class => 'custom-class')
end
@@ -435,9 +449,16 @@ class UrlHelperTest < ActiveSupport::TestCase
assert mail_to("me@domain.com", "My email", :encode => "hex").html_safe?
end
- # TODO: button_to looks at this ... why?
def protect_against_forgery?
- false
+ self.request_forgery
+ end
+
+ def form_authenticity_token
+ "secret"
+ end
+
+ def request_forgery_protection_token
+ "form_token"
end
private