aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG.md16
-rw-r--r--activesupport/activesupport.gemspec1
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/cache.rb2
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb3
-rw-r--r--activesupport/lib/active_support/callbacks.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/array/grouping.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/big_decimal/conversions.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/hash/keys.rb118
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/numeric.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/numeric/conversions.rb135
-rw-r--r--activesupport/lib/active_support/core_ext/object/deep_dup.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/object/duplicable.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/object/instance_variables.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/time/conversions.rb1
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb1
-rw-r--r--activesupport/lib/active_support/deprecation/behaviors.rb4
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb4
-rw-r--r--activesupport/lib/active_support/inflections.rb2
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb21
-rw-r--r--activesupport/lib/active_support/json/encoding.rb18
-rw-r--r--activesupport/lib/active_support/locale/en.yml99
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb8
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb2
-rw-r--r--activesupport/lib/active_support/number_helper.rb531
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb12
-rw-r--r--activesupport/lib/active_support/testing/performance.rb7
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb12
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb15
-rw-r--r--activesupport/lib/active_support/xml_mini.rb9
-rw-r--r--activesupport/test/caching_test.rb9
-rw-r--r--activesupport/test/constantize_test_cases.rb37
-rw-r--r--activesupport/test/core_ext/bigdecimal_test.rb5
-rw-r--r--activesupport/test/core_ext/class/attribute_test.rb7
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb4
-rw-r--r--activesupport/test/core_ext/duplicable_test.rb4
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb5
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb205
-rw-r--r--activesupport/test/core_ext/module_test.rb2
-rw-r--r--activesupport/test/core_ext/numeric_ext_test.rb261
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb35
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb74
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb8
-rw-r--r--activesupport/test/inflector_test_cases.rb1
-rw-r--r--activesupport/test/json/encoding_test.rb6
-rw-r--r--activesupport/test/log_subscriber_test.rb2
-rw-r--r--activesupport/test/number_helper_test.rb375
-rw-r--r--activesupport/test/test_case_test.rb58
-rw-r--r--activesupport/test/testing/performance_test.rb40
-rw-r--r--activesupport/test/ts_isolated.rb2
60 files changed, 2133 insertions, 186 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 636aca2b8f..a818ef0c5d 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,21 @@
## Rails 4.0.0 (unreleased) ##
+* ActionView::Helpers::NumberHelper methods have been moved to ActiveSupport::NumberHelper and are now available via
+ Numeric#to_s. Numeric#to_s now accepts the formatting options :phone, :currency, :percentage, :delimited,
+ :rounded, :human, and :human_size. *Andrew Mutz*
+
+* Add `Hash#transform_keys`, `Hash#transform_keys!`, `Hash#deep_transform_keys`, and `Hash#deep_transform_keys!`. *Mark McSpadden*
+
+* Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri*
+
+* Add `:instance_accessor` option for `class_attribute`. *Alexey Vakhov*
+
+* `constantize` now looks in the ancestor chain. *Marc-Andre Lafortune & Andrew White*
+
+* Adds `Hash#deep_stringify_keys` and `Hash#deep_stringify_keys!` to convert all keys from a +Hash+ instance into strings *Lucas Húngaro*
+
+* Adds `Hash#deep_symbolize_keys` and `Hash#deep_symbolize_keys!` to convert all keys from a +Hash+ instance into symbols *Lucas Húngaro*
+
* `Object#try` can't call private methods. *Vasiliy Ermolovich*
* `AS::Callbacks#run_callbacks` remove `key` argument. *Francesco Rodriguez*
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 2c874e932e..30221f2401 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
s.description = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing.'
s.required_ruby_version = '>= 1.9.3'
+ s.license = 'MIT'
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 8f018dcbc6..56d6676961 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -25,6 +25,7 @@ require 'securerandom'
require "active_support/dependencies/autoload"
require "active_support/version"
require "active_support/logger"
+require "active_support/lazy_load_hooks"
module ActiveSupport
extend ActiveSupport::Autoload
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 55791bfa56..a62214d604 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -405,7 +405,7 @@ module ActiveSupport
raise NotImplementedError.new("#{self.class.name} does not support increment")
end
- # Increment an integer value in the cache.
+ # Decrement an integer value in the cache.
#
# Options are passed to the underlying cache implementation.
#
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index 89bdb741d0..5be63af342 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -81,7 +81,8 @@ module ActiveSupport
if File.exist?(file_name)
File.open(file_name) { |f| Marshal.load(f) }
end
- rescue
+ rescue => e
+ logger.error("FileStoreError (#{e}): #{e.message}") if logger
nil
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 4e319b4bba..a9253c186d 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -310,13 +310,13 @@ module ActiveSupport
method << "value = nil"
method << "halted = false"
- callbacks = "value = yield if block_given? && !halted"
+ callbacks = "value = !halted && (!block_given? || yield)"
reverse_each do |callback|
callbacks = callback.apply(callbacks)
end
method << callbacks
- method << "halted ? false : (block_given? ? value : true)"
+ method << "value"
method.join("\n")
end
@@ -328,26 +328,17 @@ module ActiveSupport
# if it was not yet defined.
# This generated method plays caching role.
def __define_callbacks(kind, object) #:nodoc:
- name = __callback_runner_name(kind)
+ chain = object.send("_#{kind}_callbacks")
+ name = "_run_callbacks_#{chain.object_id.abs}"
unless object.respond_to?(name, true)
- str = object.send("_#{kind}_callbacks").compile
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}() #{str} end
+ def #{name}() #{chain.compile} end
protected :#{name}
RUBY_EVAL
end
name
end
- def __reset_runner(symbol)
- name = __callback_runner_name(symbol)
- undef_method(name) if method_defined?(name)
- end
-
- def __callback_runner_name(kind)
- "_run__#{self.name.hash.abs}__#{kind}__callbacks"
- end
-
# This is used internally to append, prepend and skip callbacks to the
# CallbackChain.
#
@@ -359,7 +350,6 @@ module ActiveSupport
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
chain = target.send("_#{name}_callbacks")
yield target, chain.dup, type, filters, options
- target.__reset_runner(name)
end
end
@@ -447,12 +437,9 @@ module ActiveSupport
chain = target.send("_#{symbol}_callbacks").dup
callbacks.each { |c| chain.delete(c) }
target.send("_#{symbol}_callbacks=", chain)
- target.__reset_runner(symbol)
end
self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
-
- __reset_runner(symbol)
end
# Define sets of events in the object lifecycle that support callbacks.
diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb
index ac1ae53db0..a184eb492a 100644
--- a/activesupport/lib/active_support/core_ext/array/grouping.rb
+++ b/activesupport/lib/active_support/core_ext/array/grouping.rb
@@ -2,18 +2,21 @@ class Array
# Splits or iterates over the array in groups of size +number+,
# padding any remaining slots with +fill_with+ unless it is +false+.
#
- # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
# ["1", "2", "3"]
# ["4", "5", "6"]
- # ["7", nil, nil]
+ # ["7", "8", "9"]
+ # ["10", nil, nil]
#
- # %w(1 2 3).in_groups_of(2, '&nbsp;') {|group| p group}
+ # %w(1 2 3 4 5).in_groups_of(2, '&nbsp;') {|group| p group}
# ["1", "2"]
- # ["3", "&nbsp;"]
+ # ["3", "4"]
+ # ["5", "&nbsp;"]
#
- # %w(1 2 3).in_groups_of(2, false) {|group| p group}
+ # %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
# ["1", "2"]
- # ["3"]
+ # ["3", "4"]
+ # ["5"]
def in_groups_of(number, fill_with = nil)
if fill_with == false
collection = self
@@ -42,10 +45,10 @@ class Array
# ["5", "6", "7", nil]
# ["8", "9", "10", nil]
#
- # %w(1 2 3 4 5 6 7).in_groups(3, '&nbsp;') {|group| p group}
- # ["1", "2", "3"]
- # ["4", "5", "&nbsp;"]
- # ["6", "7", "&nbsp;"]
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, '&nbsp;') {|group| p group}
+ # ["1", "2", "3", "4"]
+ # ["5", "6", "7", "&nbsp;"]
+ # ["8", "9", "10", "&nbsp;"]
#
# %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
# ["1", "2", "3"]
diff --git a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb
index 3ec7e576c8..5dc5710c53 100644
--- a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb
@@ -17,8 +17,13 @@ class BigDecimal
end
DEFAULT_STRING_FORMAT = 'F'
- def to_formatted_s(format = DEFAULT_STRING_FORMAT)
- _original_to_s(format)
+ def to_formatted_s(*args)
+ if args[0].is_a?(Symbol)
+ super
+ else
+ format = args[0] || DEFAULT_STRING_FORMAT
+ _original_to_s(format)
+ end
end
alias_method :_original_to_s, :to_s
alias_method :to_s, :to_formatted_s
diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb
index c64685a694..7b6f8ab0a1 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute.rb
@@ -65,10 +65,12 @@ class Class
# To opt out of the instance writer method, pass :instance_writer => false.
#
# object.setting = false # => NoMethodError
+ #
+ # To opt out of both instance methods, pass :instance_accessor => false.
def class_attribute(*attrs)
options = attrs.extract_options!
- instance_reader = options.fetch(:instance_reader, true)
- instance_writer = options.fetch(:instance_writer, true)
+ instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
+ instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
attrs.each do |name|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 3e36c54eba..8a7eb6bc6b 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -202,7 +202,7 @@ class Date
acts_like?(:time) ? result.change(:hour => 0) : result
end
- # Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00)
+ # Returns a new Date/DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00)
def beginning_of_month
acts_like?(:time) ? change(:day => 1, :hour => 0) : change(:day => 1)
end
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index 02d5a7080f..03efe6a19a 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -65,11 +65,15 @@ class Range #:nodoc:
# Optimize range sum to use arithmetic progression if a block is not given and
# we have a range of numeric values.
def sum(identity = 0)
- if block_given? || !(first.instance_of?(Integer) && last.instance_of?(Integer))
+ if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
super
else
actual_last = exclude_end? ? (last - 1) : last
- (actual_last - first + 1) * (actual_last + first) / 2
+ if actual_last >= first
+ (actual_last - first + 1) * (actual_last + first) / 2
+ else
+ identity
+ end
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 469dc41f2d..7c72ead36c 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -57,8 +57,8 @@ class Hash
# "TrueClass" => "boolean",
# "FalseClass" => "boolean",
# "Date" => "date",
- # "DateTime" => "datetime",
- # "Time" => "datetime"
+ # "DateTime" => "dateTime",
+ # "Time" => "dateTime"
# }
#
# By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
@@ -129,7 +129,7 @@ class Hash
else
xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
- # Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
+ # Turn { :files => { :file => #<StringIO> } } into { :files => #<StringIO> } so it is compatible with
# how multipart uploaded files from HTML appear
xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
end
diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb
index be4d611ce7..8e728691c6 100644
--- a/activesupport/lib/active_support/core_ext/hash/keys.rb
+++ b/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -1,46 +1,59 @@
class Hash
- # Return a new hash with all keys converted to strings.
+ # Return a new hash with all keys converted using the block operation.
#
- # { :name => 'Rob', :years => '28' }.stringify_keys
- # #=> { "name" => "Rob", "years" => "28" }
- def stringify_keys
+ # hash = { name: 'Rob', age: '28' }
+ #
+ # hash.transform_keys{ |key| key.to_s.upcase }
+ # # => { "NAME" => "Rob", "AGE" => "28" }
+ def transform_keys
result = {}
keys.each do |key|
- result[key.to_s] = self[key]
+ result[yield(key)] = self[key]
end
result
end
- # Destructively convert all keys to strings. Same as
- # +stringify_keys+, but modifies +self+.
- def stringify_keys!
+ # Destructively convert all keys using the block operations.
+ # Same as transform_keys but modifies +self+
+ def transform_keys!
keys.each do |key|
- self[key.to_s] = delete(key)
+ self[yield(key)] = delete(key)
end
self
end
+ # Return a new hash with all keys converted to strings.
+ #
+ # hash = { name: 'Rob', age: '28' }
+ #
+ # hash.stringify_keys
+ # #=> { "name" => "Rob", "age" => "28" }
+ def stringify_keys
+ transform_keys{ |key| key.to_s }
+ end
+
+ # Destructively convert all keys to strings. Same as
+ # +stringify_keys+, but modifies +self+.
+ def stringify_keys!
+ transform_keys!{ |key| key.to_s }
+ end
+
# Return a new hash with all keys converted to symbols, as long as
# they respond to +to_sym+.
#
- # { 'name' => 'Rob', 'years' => '28' }.symbolize_keys
- # #=> { :name => "Rob", :years => "28" }
+ # hash = { 'name' => 'Rob', 'age' => '28' }
+ #
+ # hash.symbolize_keys
+ # #=> { name: "Rob", age: "28" }
def symbolize_keys
- result = {}
- keys.each do |key|
- result[(key.to_sym rescue key)] = self[key]
- end
- result
+ transform_keys{ |key| key.to_sym rescue key }
end
alias_method :to_options, :symbolize_keys
# Destructively convert all keys to symbols, as long as they respond
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
def symbolize_keys!
- keys.each do |key|
- self[(key.to_sym rescue key)] = delete(key)
- end
- self
+ transform_keys!{ |key| key.to_sym rescue key }
end
alias_method :to_options!, :symbolize_keys!
@@ -57,4 +70,69 @@ class Hash
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
end
end
+
+ # Return a new hash with all keys converted by the block operation.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ #
+ # hash = { person: { name: 'Rob', age: '28' } }
+ #
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
+ # # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
+ def deep_transform_keys(&block)
+ result = {}
+ each do |key, value|
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
+ end
+ result
+ end
+
+ # Destructively convert all keys by using the block operation.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_transform_keys!(&block)
+ keys.each do |key|
+ value = delete(key)
+ self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
+ end
+ self
+ end
+
+ # Return a new hash with all keys converted to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ #
+ # hash = { person: { name: 'Rob', age: '28' } }
+ #
+ # hash.deep_stringify_keys
+ # # => { "person" => { "name" => "Rob", "age" => "28" } }
+ def deep_stringify_keys
+ deep_transform_keys{ |key| key.to_s }
+ end
+
+ # Destructively convert all keys to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys!
+ deep_transform_keys!{ |key| key.to_s }
+ end
+
+ # Return a new hash with all keys converted to symbols, as long as
+ # they respond to +to_sym+. This includes the keys from the root hash
+ # and from all nested hashes.
+ #
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
+ #
+ # hash.deep_symbolize_keys
+ # # => { person: { name: "Rob", age: "28" } }
+ def deep_symbolize_keys
+ deep_transform_keys{ |key| key.to_sym rescue key }
+ end
+
+ # Destructively convert all keys to symbols, as long as they respond
+ # to +to_sym+. This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_symbolize_keys!
+ deep_transform_keys!{ |key| key.to_sym rescue key }
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index f914425827..b8cb2e347f 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -48,17 +48,17 @@ class Module
#
# module AppConfiguration
# mattr_accessor :google_api_key
- # self.google_api_key = "123456789"
#
- # mattr_accessor :paypal_url
- # self.paypal_url = "www.sandbox.paypal.com"
+ # self.google_api_key = "123456789"
# end
#
+ # AppConfiguration.google_api_key # => "123456789"
# AppConfiguration.google_api_key = "overriding the api key!"
+ # AppConfiguration.google_api_key # => "overriding the api key!"
#
- # To opt out of the instance writer method, pass :instance_writer => false.
- # To opt out of the instance reader method, pass :instance_reader => false.
- # To opt out of both instance methods, pass :instance_accessor => false.
+ # To opt out of the instance writer method, pass instance_writer: false.
+ # To opt out of the instance reader method, pass instance_reader: false.
+ # To opt out of both instance methods, pass instance_accessor: false.
def mattr_accessor(*syms)
mattr_reader(*syms)
mattr_writer(*syms)
diff --git a/activesupport/lib/active_support/core_ext/numeric.rb b/activesupport/lib/active_support/core_ext/numeric.rb
index 3805cf7990..a6bc0624be 100644
--- a/activesupport/lib/active_support/core_ext/numeric.rb
+++ b/activesupport/lib/active_support/core_ext/numeric.rb
@@ -1,2 +1,3 @@
require 'active_support/core_ext/numeric/bytes'
require 'active_support/core_ext/numeric/time'
+require 'active_support/core_ext/numeric/conversions'
diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb
new file mode 100644
index 0000000000..2bbfa78639
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb
@@ -0,0 +1,135 @@
+require 'active_support/core_ext/big_decimal/conversions'
+require 'active_support/number_helper'
+
+class Numeric
+
+ # Provides options for converting numbers into formatted strings.
+ # Options are provided for phone numbers, currency, percentage,
+ # precision, positional notation, file size and pretty printing.
+ #
+ # ==== Options
+ #
+ # For details on which formats use which options, see ActiveSupport::NumberHelper
+ #
+ # ==== Examples
+ #
+ # Phone Numbers:
+ # 5551234.to_s(:phone) # => 555-1234
+ # 1235551234.to_s(:phone) # => 123-555-1234
+ # 1235551234.to_s(:phone, :area_code => true) # => (123) 555-1234
+ # 1235551234.to_s(:phone, :delimiter => " ") # => 123 555 1234
+ # 1235551234.to_s(:phone, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
+ # 1235551234.to_s(:phone, :country_code => 1) # => +1-123-555-1234
+ # 1235551234.to_s(:phone, :country_code => 1, :extension => 1343, :delimiter => ".")
+ # # => +1.123.555.1234 x 1343
+ #
+ # Currency:
+ # 1234567890.50.to_s(:currency) # => $1,234,567,890.50
+ # 1234567890.506.to_s(:currency) # => $1,234,567,890.51
+ # 1234567890.506.to_s(:currency, :precision => 3) # => $1,234,567,890.506
+ # 1234567890.506.to_s(:currency, :locale => :fr) # => 1 234 567 890,51 €
+ # -1234567890.50.to_s(:currency, :negative_format => "(%u%n)")
+ # # => ($1,234,567,890.50)
+ # 1234567890.50.to_s(:currency, :unit => "&pound;", :separator => ",", :delimiter => "")
+ # # => &pound;1234567890,50
+ # 1234567890.50.to_s(:currency, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
+ # # => 1234567890,50 &pound;
+ #
+ # Percentage:
+ # 100.to_s(:percentage) # => 100.000%
+ # 100.to_s(:percentage, :precision => 0) # => 100%
+ # 1000.to_s(:percentage, :delimiter => '.', :separator => ',') # => 1.000,000%
+ # 302.24398923423.to_s(:percentage, :precision => 5) # => 302.24399%
+ # 1000.to_s(:percentage, :locale => :fr) # => 1 000,000%
+ # 100.to_s(:percentage, :format => "%n %") # => 100 %
+ #
+ # Delimited:
+ # 12345678.to_s(:delimited) # => 12,345,678
+ # 12345678.05.to_s(:delimited) # => 12,345,678.05
+ # 12345678.to_s(:delimited, :delimiter => ".") # => 12.345.678
+ # 12345678.to_s(:delimited, :delimiter => ",") # => 12,345,678
+ # 12345678.05.to_s(:delimited, :separator => " ") # => 12,345,678 05
+ # 12345678.05.to_s(:delimited, :locale => :fr) # => 12 345 678,05
+ # 98765432.98.to_s(:delimited, :delimiter => " ", :separator => ",")
+ # # => 98 765 432,98
+ #
+ # Rounded:
+ # 111.2345.to_s(:rounded) # => 111.235
+ # 111.2345.to_s(:rounded, :precision => 2) # => 111.23
+ # 13.to_s(:rounded, :precision => 5) # => 13.00000
+ # 389.32314.to_s(:rounded, :precision => 0) # => 389
+ # 111.2345.to_s(:rounded, :significant => true) # => 111
+ # 111.2345.to_s(:rounded, :precision => 1, :significant => true) # => 100
+ # 13.to_s(:rounded, :precision => 5, :significant => true) # => 13.000
+ # 111.234.to_s(:rounded, :locale => :fr) # => 111,234
+ # 13.to_s(:rounded, :precision => 5, :significant => true, :strip_insignificant_zeros => true)
+ # # => 13
+ # 389.32314.to_s(:rounded, :precision => 4, :significant => true) # => 389.3
+ # 1111.2345.to_s(:rounded, :precision => 2, :separator => ',', :delimiter => '.')
+ # # => 1.111,23
+ #
+ # Human-friendly size in Bytes:
+ # 123.to_s(:human_size) # => 123 Bytes
+ # 1234.to_s(:human_size) # => 1.21 KB
+ # 12345.to_s(:human_size) # => 12.1 KB
+ # 1234567.to_s(:human_size) # => 1.18 MB
+ # 1234567890.to_s(:human_size) # => 1.15 GB
+ # 1234567890123.to_s(:human_size) # => 1.12 TB
+ # 1234567.to_s(:human_size, :precision => 2) # => 1.2 MB
+ # 483989.to_s(:human_size, :precision => 2) # => 470 KB
+ # 1234567.to_s(:human_size, :precision => 2, :separator => ',') # => 1,2 MB
+ # 1234567890123.to_s(:human_size, :precision => 5) # => "1.1229 TB"
+ # 524288000.to_s(:human_size, :precision => 5) # => "500 MB"
+ #
+ # Human-friendly format:
+ # 123.to_s(:human) # => "123"
+ # 1234.to_s(:human) # => "1.23 Thousand"
+ # 12345.to_s(:human) # => "12.3 Thousand"
+ # 1234567.to_s(:human) # => "1.23 Million"
+ # 1234567890.to_s(:human) # => "1.23 Billion"
+ # 1234567890123.to_s(:human) # => "1.23 Trillion"
+ # 1234567890123456.to_s(:human) # => "1.23 Quadrillion"
+ # 1234567890123456789.to_s(:human) # => "1230 Quadrillion"
+ # 489939.to_s(:human, :precision => 2) # => "490 Thousand"
+ # 489939.to_s(:human, :precision => 4) # => "489.9 Thousand"
+ # 1234567.to_s(:human, :precision => 4,
+ # :significant => false) # => "1.2346 Million"
+ # 1234567.to_s(:human, :precision => 1,
+ # :separator => ',',
+ # :significant => false) # => "1,2 Million"
+ def to_formatted_s(format = :default, options = {})
+ case format
+ when :phone
+ return ActiveSupport::NumberHelper.number_to_phone(self, options)
+ when :currency
+ return ActiveSupport::NumberHelper.number_to_currency(self, options)
+ when :percentage
+ return ActiveSupport::NumberHelper.number_to_percentage(self, options)
+ when :delimited
+ return ActiveSupport::NumberHelper.number_to_delimited(self, options)
+ when :rounded
+ return ActiveSupport::NumberHelper.number_to_rounded(self, options)
+ when :human
+ return ActiveSupport::NumberHelper.number_to_human(self, options)
+ when :human_size
+ return ActiveSupport::NumberHelper.number_to_human_size(self, options)
+ else
+ self.to_default_s
+ end
+ end
+
+ [Float, Fixnum, Bignum, BigDecimal].each do |klass|
+ klass.send(:alias_method, :to_default_s, :to_s)
+
+ klass.send(:define_method, :to_s) do |*args|
+ if args[0].is_a?(Symbol)
+ format = args[0]
+ options = args[1] || {}
+
+ self.to_formatted_s(format, options)
+ else
+ to_default_s(*args)
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb
index 883f5f556c..f55fbc282e 100644
--- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb
+++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/duplicable'
+
class Object
# Returns a deep copy of object if it's duplicable. If it's
# not duplicable, returns +self+.
diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb
index 9d1630bb7c..f1b755c2c4 100644
--- a/activesupport/lib/active_support/core_ext/object/duplicable.rb
+++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb
@@ -19,7 +19,7 @@
class Object
# Can you safely dup this object?
#
- # False for +nil+, +false+, +true+, symbols, numbers, class and module objects;
+ # False for +nil+, +false+, +true+, symbol, and number objects;
# true otherwise.
def duplicable?
true
@@ -81,30 +81,6 @@ class Numeric
end
end
-class Class
- # Classes are not duplicable:
- #
- # c = Class.new # => #<Class:0x10328fd80>
- # c.dup # => #<Class:0x10328fd80>
- #
- # Note +dup+ returned the same class object.
- def duplicable?
- false
- end
-end
-
-class Module
- # Modules are not duplicable:
- #
- # m = Module.new # => #<Module:0x10328b6e0>
- # m.dup # => #<Module:0x10328b6e0>
- #
- # Note +dup+ returned the same module object.
- def duplicable?
- false
- end
-end
-
require 'bigdecimal'
class BigDecimal
begin
diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
index 91fdf93eb2..40821fd619 100644
--- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb
+++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -1,6 +1,6 @@
class Object
- # Returns a hash that maps instance variable names without "@" to their
- # corresponding values. Keys are strings both in Ruby 1.8 and 1.9.
+ # Returns a hash with string keys that maps instance variable names without "@" to their
+ # corresponding values.
#
# class C
# def initialize(x, y)
@@ -9,12 +9,11 @@ class Object
# end
#
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
- def instance_values #:nodoc:
+ def instance_values
Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
end
- # Returns an array of instance variable names including "@". They are strings
- # both in Ruby 1.8 and 1.9.
+ # Returns an array of instance variable names including "@".
#
# class C
# def initialize(x, y)
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index 48eb546a7d..30c835f5cd 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -7,6 +7,10 @@ class Object
#
# If try is called without a method to call, it will yield any given block with the object.
#
+ # Please also note that +try+ is defined on +Object+, therefore it won't work with
+ # subclasses of +BasicObject+. For example, using try with +SimpleDelegator+ will
+ # delegate +try+ to target instead of calling it on delegator itself.
+ #
# ==== Examples
#
# Without +try+
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index 5c32a2453d..8fa8157d65 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -1,5 +1,3 @@
-require 'active_support/multibyte'
-
class String
# If you pass a single Fixnum, returns a substring of one character at that
# position. The first character of the string is at position 0, the next at
diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb
index 2478f42290..8644529806 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/string/multibyte'
-
class String
# Returns the string, first removing all whitespace on both ends of
# the string, and then changing remaining consecutive whitespace
@@ -33,7 +31,7 @@ class String
# # => "Once upon a time in a..."
#
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
- # for a total length not exceeding <tt>:length</tt>:
+ # for a total length not exceeding <tt>length</tt>:
#
# 'And they found that many people were sleeping better.'.truncate(25, :omission => '... (continued)')
# # => "And they f... (continued)"
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 6bda970e40..5226ff0cbe 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -150,6 +150,18 @@ module ActiveSupport #:nodoc:
dup.concat(other)
end
+ def %(args)
+ args = Array(args).map do |arg|
+ if !html_safe? || arg.html_safe?
+ arg
+ else
+ ERB::Util.h(arg)
+ end
+ end
+
+ self.class.new(super(args))
+ end
+
def html_safe?
defined?(@html_safe) && @html_safe
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index a0f610d60c..92b8417150 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -253,7 +253,7 @@ class Time
:hour => 23,
:min => 59,
:sec => 59,
- :usec => 999999.999
+ :usec => Rational(999999999, 1000)
)
end
@@ -268,7 +268,7 @@ class Time
change(
:min => 59,
:sec => 59,
- :usec => 999999.999
+ :usec => Rational(999999999, 1000)
)
end
@@ -288,7 +288,7 @@ class Time
:hour => 23,
:min => 59,
:sec => 59,
- :usec => 999999.999
+ :usec => Rational(999999999, 1000)
)
end
alias :at_end_of_month :end_of_month
@@ -321,7 +321,7 @@ class Time
:hour => 23,
:min => 59,
:sec => 59,
- :usec => 999999.999
+ :usec => Rational(999999999, 1000)
)
end
alias :at_end_of_year :end_of_year
diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb
index 4f852fd780..10ca26acf2 100644
--- a/activesupport/lib/active_support/core_ext/time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/time/conversions.rb
@@ -5,6 +5,7 @@ class Time
DATE_FORMATS = {
:db => '%Y-%m-%d %H:%M:%S',
:number => '%Y%m%d%H%M%S',
+ :nsec => '%Y%m%d%H%M%S%9N',
:time => '%H:%M',
:short => '%d %b %H:%M',
:long => '%B %d, %Y %H:%M',
diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb
index a1626ebeba..4045db3232 100644
--- a/activesupport/lib/active_support/dependencies/autoload.rb
+++ b/activesupport/lib/active_support/dependencies/autoload.rb
@@ -1,5 +1,4 @@
require "active_support/inflector/methods"
-require "active_support/lazy_load_hooks"
module ActiveSupport
module Autoload
diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb
index 9102537810..fc962dcb57 100644
--- a/activesupport/lib/active_support/deprecation/behaviors.rb
+++ b/activesupport/lib/active_support/deprecation/behaviors.rb
@@ -16,9 +16,9 @@ module ActiveSupport
#
# Available behaviors:
#
- # [+stderr+] Log all deprecation warnings to +$stderr+.
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
# [+log+] Log all deprecation warnings to +Rails.logger+.
- # [+notify] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
+ # [+notify+] Use <tt>ActiveSupport::Notifications</tt> to notify +deprecation.rails+.
# [+silence+] Do nothing.
#
# Setting behaviors only affects deprecations that happen after boot time.
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 91459f3e5b..6e1c0da991 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -141,9 +141,13 @@ module ActiveSupport
end
def stringify_keys!; self end
+ def deep_stringify_keys!; self end
def stringify_keys; dup end
+ def deep_stringify_keys; dup end
undef :symbolize_keys!
+ undef :deep_symbolize_keys!
def symbolize_keys; to_hash.symbolize_keys end
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys end
def to_options!; self end
# Convert to a Hash with String keys.
diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb
index 7eb61cd1a0..c04c2ed15b 100644
--- a/activesupport/lib/active_support/inflections.rb
+++ b/activesupport/lib/active_support/inflections.rb
@@ -26,7 +26,7 @@ module ActiveSupport
inflect.singular(/(ss)$/i, '\1')
inflect.singular(/(n)ews$/i, '\1ews')
inflect.singular(/([ti])a$/i, '\1um')
- inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1\2sis')
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
inflect.singular(/([^f])ves$/i, '\1fe')
inflect.singular(/(hive)s$/i, '\1')
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 48296841aa..2acc6ddee5 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -198,12 +198,29 @@ module ActiveSupport
#
# NameError is raised when the name is not in CamelCase or the constant is
# unknown.
- def constantize(camel_cased_word) #:nodoc:
+ def constantize(camel_cased_word)
names = camel_cased_word.split('::')
names.shift if names.empty? || names.first.empty?
names.inject(Object) do |constant, name|
- constant.const_get(name, false)
+ if constant == Object
+ constant.const_get(name)
+ else
+ candidate = constant.const_get(name)
+ next candidate if constant.const_defined?(name, false)
+ next candidate unless Object.const_defined?(name)
+
+ # Go down the ancestors to check it it's owned
+ # directly before we reach Object or the end of ancestors.
+ constant = constant.ancestors.inject do |const, ancestor|
+ break const if ancestor == Object
+ break ancestor if ancestor.const_defined?(name, false)
+ const
+ end
+
+ # owner is in Object, so raise
+ constant.const_get(name, false)
+ end
end
end
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index a6e4e7ced2..41fe61e790 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -159,18 +159,18 @@ class Struct #:nodoc:
end
class TrueClass
- AS_JSON = ActiveSupport::JSON::Variable.new('true').freeze
- def as_json(options = nil) AS_JSON end #:nodoc:
+ def as_json(options = nil) self end #:nodoc:
+ def encode_json(encoder) to_s end #:nodoc:
end
class FalseClass
- AS_JSON = ActiveSupport::JSON::Variable.new('false').freeze
- def as_json(options = nil) AS_JSON end #:nodoc:
+ def as_json(options = nil) self end #:nodoc:
+ def encode_json(encoder) to_s end #:nodoc:
end
class NilClass
- AS_JSON = ActiveSupport::JSON::Variable.new('null').freeze
- def as_json(options = nil) AS_JSON end #:nodoc:
+ def as_json(options = nil) self end #:nodoc:
+ def encode_json(encoder) 'null' end #:nodoc:
end
class String
@@ -189,8 +189,8 @@ end
class Float
# Encoding Infinity or NaN to JSON should return "null". The default returns
- # "Infinity" or "NaN" what breaks parsing the JSON. E.g. JSON.parse('[NaN]').
- def as_json(options = nil) finite? ? self : NilClass::AS_JSON end #:nodoc:
+ # "Infinity" or "NaN" breaks parsing the JSON. E.g. JSON.parse('[NaN]').
+ def as_json(options = nil) finite? ? self : nil end #:nodoc:
end
class BigDecimal
@@ -208,7 +208,7 @@ class BigDecimal
if finite?
ActiveSupport.encode_big_decimal_as_string ? to_s : self
else
- NilClass::AS_JSON
+ nil
end
end
end
diff --git a/activesupport/lib/active_support/locale/en.yml b/activesupport/lib/active_support/locale/en.yml
index a1499bcc90..18c7d47026 100644
--- a/activesupport/lib/active_support/locale/en.yml
+++ b/activesupport/lib/active_support/locale/en.yml
@@ -34,3 +34,102 @@ en:
words_connector: ", "
two_words_connector: " and "
last_word_connector: ", and "
+ number:
+ # Used in NumberHelper.number_to_delimited()
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
+ format:
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
+ separator: "."
+ # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
+ delimiter: ","
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
+ precision: 3
+ # If set to true, precision will mean the number of significant digits instead
+ # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
+ significant: false
+ # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
+ strip_insignificant_zeros: false
+
+ # Used in NumberHelper.number_to_currency()
+ currency:
+ format:
+ # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
+ format: "%u%n"
+ unit: "$"
+ # These five are to override number.format and are optional
+ separator: "."
+ delimiter: ","
+ precision: 2
+ significant: false
+ strip_insignificant_zeros: false
+
+ # Used in NumberHelper.number_to_percentage()
+ percentage:
+ format:
+ # These five are to override number.format and are optional
+ # separator:
+ delimiter: ""
+ # precision:
+ # significant: false
+ # strip_insignificant_zeros: false
+ format: "%n%"
+
+ # Used in NumberHelper.number_to_rounded()
+ precision:
+ format:
+ # These five are to override number.format and are optional
+ # separator:
+ delimiter: ""
+ # precision:
+ # significant: false
+ # strip_insignificant_zeros: false
+
+ # Used in NumberHelper.number_to_human_size() and NumberHelper.number_to_human()
+ human:
+ format:
+ # These five are to override number.format and are optional
+ # separator:
+ delimiter: ""
+ precision: 3
+ significant: true
+ strip_insignificant_zeros: true
+ # Used in number_to_human_size()
+ storage_units:
+ # Storage units output formatting.
+ # %u is the storage unit, %n is the number (default: 2 MB)
+ format: "%n %u"
+ units:
+ byte:
+ one: "Byte"
+ other: "Bytes"
+ kb: "KB"
+ mb: "MB"
+ gb: "GB"
+ tb: "TB"
+ # Used in NumberHelper.number_to_human()
+ decimal_units:
+ format: "%n %u"
+ # Decimal units output formatting
+ # By default we will only quantify some of the exponents
+ # but the commented ones might be defined or overridden
+ # by the user.
+ units:
+ # femto: Quadrillionth
+ # pico: Trillionth
+ # nano: Billionth
+ # micro: Millionth
+ # mili: Thousandth
+ # centi: Hundredth
+ # deci: Tenth
+ unit: ""
+ # ten:
+ # one: Ten
+ # other: Tens
+ # hundred: Hundred
+ thousand: Thousand
+ million: Million
+ billion: Billion
+ trillion: Trillion
+ quadrillion: Quadrillion
+
+ \ No newline at end of file
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 7b7fc81e6c..b65ea6208c 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -61,8 +61,12 @@ module ActiveSupport
@logged = Hash.new { |h,k| h[k] = [] }
end
- def method_missing(level, message)
- @logged[level] << message
+ def method_missing(level, message = nil)
+ if block_given?
+ @logged[level] << yield
+ else
+ @logged[level] << message
+ end
end
def logged(level)
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index 4fe925f7f4..87b1d76026 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -76,7 +76,7 @@ module ActiveSupport #:nodoc:
#
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
def split(*args)
- @wrapped_string.split(*args).map { |i| i.mb_chars }
+ @wrapped_string.split(*args).map { |i| self.class.new(i) }
end
# Works like like <tt>String#slice!</tt>, but returns an instance of Chars, or nil if the string was not
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
new file mode 100644
index 0000000000..fc97782697
--- /dev/null
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -0,0 +1,531 @@
+require 'active_support/core_ext/big_decimal/conversions'
+require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/hash/keys'
+require 'active_support/i18n'
+
+module ActiveSupport
+ module NumberHelper
+ extend self
+
+ DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :negative_format => "-%u%n", :unit => "$", :separator => ".", :delimiter => ",",
+ :precision => 2, :significant => false, :strip_insignificant_zeros => false }
+
+ # Formats a +number+ into a US phone number (e.g., (555)
+ # 123-9876). You can customize the format in the +options+ hash.
+ #
+ # ==== Options
+ #
+ # * <tt>:area_code</tt> - Adds parentheses around the area code.
+ # * <tt>:delimiter</tt> - Specifies the delimiter to use
+ # (defaults to "-").
+ # * <tt>:extension</tt> - Specifies an extension to add to the
+ # end of the generated number.
+ # * <tt>:country_code</tt> - Sets the country code for the phone
+ # number.
+ # ==== Examples
+ #
+ # number_to_phone(5551234) # => 555-1234
+ # number_to_phone("5551234") # => 555-1234
+ # number_to_phone(1235551234) # => 123-555-1234
+ # number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
+ # number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
+ # number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
+ # number_to_phone(1235551234, :country_code => 1) # => +1-123-555-1234
+ # number_to_phone("123a456") # => 123a456
+ #
+ # number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
+ # # => +1.123.555.1234 x 1343
+ def number_to_phone(number, options = {})
+ return unless number
+ options = options.symbolize_keys
+
+ number = number.to_s.strip
+ area_code = options[:area_code]
+ delimiter = options[:delimiter] || "-"
+ extension = options[:extension]
+ country_code = options[:country_code]
+
+ if area_code
+ 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.start_with?(delimiter) && !delimiter.blank?
+ end
+
+ str = ''
+ str << "+#{country_code}#{delimiter}" unless country_code.blank?
+ str << number
+ str << " x #{extension}" unless extension.blank?
+ str
+ end
+
+ # Formats a +number+ into a currency string (e.g., $13.65). You
+ # can customize the format in the +options+ hash.
+ #
+ # ==== Options
+ #
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
+ # (defaults to current locale).
+ # * <tt>:precision</tt> - Sets the level of precision (defaults
+ # to 2).
+ # * <tt>:unit</tt> - Sets the denomination of the currency
+ # (defaults to "$").
+ # * <tt>:separator</tt> - Sets the separator between the units
+ # (defaults to ".").
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
+ # to ",").
+ # * <tt>:format</tt> - Sets the format for non-negative numbers
+ # (defaults to "%u%n"). Fields are <tt>%u</tt> for the
+ # currency, and <tt>%n</tt> for the number.
+ # * <tt>:negative_format</tt> - Sets the format for negative
+ # numbers (defaults to prepending an hyphen to the formatted
+ # number given by <tt>:format</tt>). Accepts the same fields
+ # than <tt>:format</tt>, except <tt>%n</tt> is here the
+ # absolute value of the number.
+ #
+ # ==== Examples
+ #
+ # number_to_currency(1234567890.50) # => $1,234,567,890.50
+ # number_to_currency(1234567890.506) # => $1,234,567,890.51
+ # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506
+ # number_to_currency(1234567890.506, :locale => :fr) # => 1 234 567 890,51 €
+ # number_to_currency("123a456") # => $123a456
+ #
+ # number_to_currency(-1234567890.50, :negative_format => "(%u%n)")
+ # # => ($1,234,567,890.50)
+ # number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "")
+ # # => &pound;1234567890,50
+ # number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
+ # # => 1234567890,50 &pound;
+ def number_to_currency(number, options = {})
+ return unless number
+ options = options.symbolize_keys
+
+ currency = translations_for('currency', options[:locale])
+ currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
+
+ defaults = DEFAULT_CURRENCY_VALUES.merge(defaults_translations(options[:locale])).merge!(currency)
+ defaults[:negative_format] = "-" + options[:format] if options[:format]
+ options = defaults.merge!(options)
+
+ unit = options.delete(:unit)
+ format = options.delete(:format)
+
+ if number.to_f.phase != 0
+ format = options.delete(:negative_format)
+ number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
+ end
+
+ formatted_number = format.gsub('%n', self.number_to_rounded(number, options)).gsub('%u', unit)
+ formatted_number
+ end
+
+ # Formats a +number+ as a percentage string (e.g., 65%). You can
+ # customize the format in the +options+ hash.
+ #
+ # ==== Options
+ #
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
+ # (defaults to current locale).
+ # * <tt>:precision</tt> - Sets the precision of the number
+ # (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the #
+ # of significant_digits. If +false+, the # of fractional
+ # digits (defaults to +false+).
+ # * <tt>:separator</tt> - Sets the separator between the
+ # fractional and integer digits (defaults to ".").
+ # * <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%").
+ #
+ # ==== Examples
+ #
+ # number_to_percentage(100) # => 100.000%
+ # number_to_percentage("98") # => 98.000%
+ # number_to_percentage(100, :precision => 0) # => 100%
+ # number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
+ # 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 %
+ #
+ def number_to_percentage(number, options = {})
+ return unless number
+ options = options.symbolize_keys
+
+ defaults = format_translations('percentage', options[:locale])
+ options = defaults.merge!(options)
+
+ format = options[:format] || "%n%"
+
+ formatted_number = format.gsub('%n', self.number_to_rounded(number, options))
+ formatted_number
+ end
+
+ # Formats a +number+ with grouped thousands using +delimiter+
+ # (e.g., 12,324). You can customize the format in the +options+
+ # hash.
+ #
+ # ==== Options
+ #
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
+ # (defaults to current locale).
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
+ # to ",").
+ # * <tt>:separator</tt> - Sets the separator between the
+ # fractional and integer digits (defaults to ".").
+ #
+ # ==== Examples
+ #
+ # number_to_delimited(12345678) # => 12,345,678
+ # number_to_delimited("123456") # => 123,456
+ # number_to_delimited(12345678.05) # => 12,345,678.05
+ # number_to_delimited(12345678, :delimiter => ".") # => 12.345.678
+ # number_to_delimited(12345678, :delimiter => ",") # => 12,345,678
+ # number_to_delimited(12345678.05, :separator => " ") # => 12,345,678 05
+ # number_to_delimited(12345678.05, :locale => :fr) # => 12 345 678,05
+ # number_to_delimited("112a") # => 112a
+ # number_to_delimited(98765432.98, :delimiter => " ", :separator => ",")
+ # # => 98 765 432,98
+ def number_to_delimited(number, options = {})
+ options = options.symbolize_keys
+
+ return number unless valid_float?(number)
+
+ 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])
+ end
+
+ # Formats a +number+ with the specified level of
+ # <tt>:precision</tt> (e.g., 112.32 has a precision of 2 if
+ # +:significant+ is +false+, and 5 if +:significant+ is +true+).
+ # You can customize the format in the +options+ hash.
+ #
+ # ==== Options
+ #
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
+ # (defaults to current locale).
+ # * <tt>:precision</tt> - Sets the precision of the number
+ # (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the #
+ # of significant_digits. If +false+, the # of fractional
+ # digits (defaults to +false+).
+ # * <tt>:separator</tt> - Sets the separator between the
+ # fractional and integer digits (defaults to ".").
+ # * <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+).
+ #
+ # ==== Examples
+ #
+ # number_to_rounded(111.2345) # => 111.235
+ # number_to_rounded(111.2345, :precision => 2) # => 111.23
+ # number_to_rounded(13, :precision => 5) # => 13.00000
+ # number_to_rounded(389.32314, :precision => 0) # => 389
+ # number_to_rounded(111.2345, :significant => true) # => 111
+ # number_to_rounded(111.2345, :precision => 1, :significant => true) # => 100
+ # number_to_rounded(13, :precision => 5, :significant => true) # => 13.000
+ # number_to_rounded(111.234, :locale => :fr) # => 111,234
+ #
+ # number_to_rounded(13, :precision => 5, :significant => true, :strip_insignificant_zeros => true)
+ # # => 13
+ #
+ # number_to_rounded(389.32314, :precision => 4, :significant => true) # => 389.3
+ # number_to_rounded(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
+ # # => 1.111,23
+ def number_to_rounded(number, options = {})
+ options = options.symbolize_keys
+
+ return number unless valid_float?(number)
+ number = Float(number)
+
+ defaults = format_translations('precision', options[:locale])
+ options = defaults.merge!(options)
+
+ precision = options.delete :precision
+ significant = options.delete :significant
+ strip_insignificant_zeros = options.delete :strip_insignificant_zeros
+
+ if significant and precision > 0
+ if number == 0
+ digits, rounded_number = 1, 0
+ else
+ digits = (Math.log10(number.abs) + 1).floor
+ rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
+ digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
+ end
+ precision -= digits
+ precision = precision > 0 ? precision : 0 #don't let it be negative
+ else
+ rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
+ rounded_number = rounded_number.zero? ? rounded_number.abs : rounded_number #prevent showing negative zeros
+ end
+ formatted_number = self.number_to_delimited("%01.#{precision}f" % rounded_number, options)
+ if strip_insignificant_zeros
+ escaped_separator = Regexp.escape(options[:separator])
+ formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
+ else
+ formatted_number
+ end
+ end
+
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
+
+ # Formats the bytes in +number+ into a more understandable
+ # representation (e.g., giving it 1500 yields 1.5 KB). This
+ # method is useful for reporting file sizes to users. You can
+ # customize the format in the +options+ hash.
+ #
+ # See <tt>number_to_human</tt> if you want to pretty-print a
+ # generic number.
+ #
+ # ==== Options
+ #
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
+ # (defaults to current locale).
+ # * <tt>:precision</tt> - Sets the precision of the number
+ # (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the #
+ # of significant_digits. If +false+, the # of fractional
+ # digits (defaults to +true+)
+ # * <tt>:separator</tt> - Sets the separator between the
+ # fractional and integer digits (defaults to ".").
+ # * <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)
+ #
+ # ==== Examples
+ #
+ # number_to_human_size(123) # => 123 Bytes
+ # number_to_human_size(1234) # => 1.21 KB
+ # number_to_human_size(12345) # => 12.1 KB
+ # number_to_human_size(1234567) # => 1.18 MB
+ # number_to_human_size(1234567890) # => 1.15 GB
+ # number_to_human_size(1234567890123) # => 1.12 TB
+ # number_to_human_size(1234567, :precision => 2) # => 1.2 MB
+ # number_to_human_size(483989, :precision => 2) # => 470 KB
+ # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,2 MB
+ #
+ # Non-significant zeros after the fractional separator are
+ # stripped out by default (set
+ # <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
+ # 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 = options.symbolize_keys
+
+ return number unless valid_float?(number)
+ number = Float(number)
+
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
+
+ #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)
+
+ storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
+
+ base = options[:prefix] == :si ? 1000 : 1024
+
+ if number.to_i < base
+ unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
+ storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
+ else
+ max_exp = STORAGE_UNITS.size - 1
+ exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
+ number /= base ** exponent
+
+ unit_key = STORAGE_UNITS[exponent]
+ unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
+
+ formatted_number = self.number_to_rounded(number, options)
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
+ end
+ end
+
+ DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
+ -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze
+
+ # Pretty prints (formats and approximates) a number in a way it
+ # is more readable by humans (eg.: 1200000000 becomes "1.2
+ # Billion"). This is useful for numbers that can get very large
+ # (and too hard to read).
+ #
+ # See <tt>number_to_human_size</tt> if you want to print a file
+ # size.
+ #
+ # You can also define you own unit-quantifier names if you want
+ # to use other decimal units (eg.: 1500 becomes "1.5
+ # kilometers", 0.150 becomes "150 milliliters", etc). You may
+ # define a wide range of unit quantifiers, even fractional ones
+ # (centi, deci, mili, etc).
+ #
+ # ==== Options
+ #
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
+ # (defaults to current locale).
+ # * <tt>:precision</tt> - Sets the precision of the number
+ # (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the #
+ # of significant_digits. If +false+, the # of fractional
+ # digits (defaults to +true+)
+ # * <tt>:separator</tt> - Sets the separator between the
+ # fractional and integer digits (defaults to ".").
+ # * <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>:units</tt> - A Hash of unit quantifier names. Or a
+ # string containing an i18n scope where to find this hash. It
+ # might have the following keys:
+ # * *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:
+ # * %u - The quantifier (ex.: 'thousand')
+ # * %n - The number
+ #
+ # ==== Examples
+ #
+ # number_to_human(123) # => "123"
+ # number_to_human(1234) # => "1.23 Thousand"
+ # number_to_human(12345) # => "12.3 Thousand"
+ # number_to_human(1234567) # => "1.23 Million"
+ # number_to_human(1234567890) # => "1.23 Billion"
+ # number_to_human(1234567890123) # => "1.23 Trillion"
+ # number_to_human(1234567890123456) # => "1.23 Quadrillion"
+ # number_to_human(1234567890123456789) # => "1230 Quadrillion"
+ # number_to_human(489939, :precision => 2) # => "490 Thousand"
+ # number_to_human(489939, :precision => 4) # => "489.9 Thousand"
+ # number_to_human(1234567, :precision => 4,
+ # :significant => false) # => "1.2346 Million"
+ # number_to_human(1234567, :precision => 1,
+ # :separator => ',',
+ # :significant => false) # => "1,2 Million"
+ #
+ # Non-significant zeros after the decimal separator are stripped
+ # out by default (set <tt>:strip_insignificant_zeros</tt> to
+ # +false+ to change that):
+ # number_to_human(12345012345, :significant_digits => 6) # => "12.345 Billion"
+ # number_to_human(500000000, :precision => 5) # => "500 Million"
+ #
+ # ==== Custom Unit Quantifiers
+ #
+ # You can also use your own custom unit quantifiers:
+ # number_to_human(500000, :units => {:unit => "ml", :thousand => "lt"}) # => "500 lt"
+ #
+ # If in your I18n locale you have:
+ # distance:
+ # centi:
+ # one: "centimeter"
+ # other: "centimeters"
+ # unit:
+ # one: "meter"
+ # other: "meters"
+ # thousand:
+ # one: "kilometer"
+ # other: "kilometers"
+ # billion: "gazillion-distance"
+ #
+ # Then you could do:
+ #
+ # number_to_human(543934, :units => :distance) # => "544 kilometers"
+ # number_to_human(54393498, :units => :distance) # => "54400 kilometers"
+ # number_to_human(54393498000, :units => :distance) # => "54.4 gazillion-distance"
+ # number_to_human(343, :units => :distance, :precision => 1) # => "300 meters"
+ # number_to_human(1, :units => :distance) # => "1 meter"
+ # number_to_human(0.34, :units => :distance) # => "34 centimeters"
+ def number_to_human(number, options = {})
+ options = options.symbolize_keys
+
+ return number unless valid_float?(number)
+ number = Float(number)
+
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
+
+ #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)
+
+ inverted_du = DECIMAL_UNITS.invert
+
+ units = options.delete :units
+ unit_exponents = case units
+ when Hash
+ units
+ when String, Symbol
+ I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
+ when nil
+ I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true)
+ else
+ raise ArgumentError, ":units must be a Hash or String translation scope."
+ end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
+
+ number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
+ display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
+ number /= 10 ** display_exponent
+
+ unit = case units
+ when Hash
+ units[DECIMAL_UNITS[display_exponent]]
+ when String, Symbol
+ I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
+ else
+ I18n.translate(:"number.human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
+ end
+
+ decimal_format = options[:format] || I18n.translate(:'number.human.decimal_units.format', :locale => options[:locale], :default => "%n %u")
+ formatted_number = self.number_to_rounded(number, options)
+ decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip
+ end
+
+ def self.private_module_and_instance_method(method_name)
+ private method_name
+ private_class_method method_name
+ end
+ private_class_method :private_module_and_instance_method
+
+ def format_translations(namespace, locale)
+ defaults_translations(locale).merge(translations_for(namespace, locale))
+ end
+ private_module_and_instance_method :format_translations
+
+ def defaults_translations(locale)
+ I18n.translate(:'number.format', :locale => locale, :default => {})
+ end
+ private_module_and_instance_method :defaults_translations
+
+ def translations_for(namespace, locale)
+ I18n.translate(:"number.#{namespace}.format", :locale => locale, :default => {})
+ end
+ private_module_and_instance_method :translations_for
+
+ def valid_float?(number)
+ Float(number)
+ rescue ArgumentError, TypeError
+ false
+ end
+ private_module_and_instance_method :valid_float?
+
+ end
+end
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 8edd3960c7..1a3693f766 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -5,16 +5,20 @@ YAML.add_builtin_type("omap") do |type, val|
end
module ActiveSupport
- # The order of iteration over hashes in Ruby 1.8 is undefined. For example, you do not know the
- # order in which +keys+ will return keys, or +each+ yield pairs. <tt>ActiveSupport::OrderedHash</tt>
- # implements a hash that preserves insertion order, as in Ruby 1.9:
+ # <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
+ # insertion order.
#
# oh = ActiveSupport::OrderedHash.new
# oh[:a] = 1
# oh[:b] = 2
# oh.keys # => [:a, :b], this order is guaranteed
#
- # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with other implementations.
+ # Also, maps the +omap+ feature for YAML files
+ # (See http://yaml.org/type/omap.html) to support ordered items
+ # when loading from yaml.
+ #
+ # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
+ # with other implementations.
class OrderedHash < ::Hash
def to_yaml_type
"!tag:yaml.org,2002:omap"
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index ec6986654e..517926c74d 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -3,7 +3,8 @@ require 'rails/version'
require 'active_support/concern'
require 'active_support/core_ext/class/delegating_attributes'
require 'active_support/core_ext/string/inflections'
-require 'action_view/helpers/number_helper'
+require 'active_support/core_ext/module/delegation'
+require 'active_support/number_helper'
module ActiveSupport
module Testing
@@ -195,7 +196,7 @@ module ActiveSupport
end
class Base
- include ActionView::Helpers::NumberHelper
+ include ActiveSupport::NumberHelper
attr_reader :total
@@ -239,7 +240,7 @@ module ActiveSupport
class Amount < Base
def format(measurement)
- number_with_delimiter(measurement.floor)
+ number_to_delimited(measurement.floor)
end
end
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index 772c7b4209..527fa555b7 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -4,6 +4,14 @@ require 'active_support/callbacks'
module ActiveSupport
module Testing
module SetupAndTeardown
+
+ PASSTHROUGH_EXCEPTIONS = [
+ NoMemoryError,
+ SignalException,
+ Interrupt,
+ SystemExit
+ ]
+
extend ActiveSupport::Concern
included do
@@ -28,11 +36,15 @@ module ActiveSupport
run_callbacks :setup do
result = super
end
+ rescue *PASSTHROUGH_EXCEPTIONS
+ raise
rescue Exception => e
result = runner.puke(self.class, method_name, e)
ensure
begin
run_callbacks :teardown
+ rescue *PASSTHROUGH_EXCEPTIONS
+ raise
rescue Exception => e
result = runner.puke(self.class, method_name, e)
end
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 67ac1b6ccd..451520ac5c 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -317,8 +317,7 @@ module ActiveSupport
# Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+.
def method_missing(sym, *args, &block)
- result = time.__send__(sym, *args, &block)
- result.acts_like?(:time) ? self.class.new(nil, time_zone, result) : result
+ wrap_with_time_zone time.__send__(sym, *args, &block)
end
private
@@ -336,11 +335,21 @@ module ActiveSupport
end
def transfer_time_values_to_utc_constructor(time)
- ::Time.utc_time(time.year, time.month, time.day, time.hour, time.min, time.sec, time.respond_to?(:usec) ? time.usec : 0)
+ ::Time.utc_time(time.year, time.month, time.day, time.hour, time.min, time.sec, time.respond_to?(:nsec) ? Rational(time.nsec, 1000) : 0)
end
def duration_of_variable_length?(obj)
ActiveSupport::Duration === obj && obj.parts.any? {|p| p[0].in?([:years, :months, :days]) }
end
+
+ def wrap_with_time_zone(time)
+ if time.acts_like?(:time)
+ self.class.new(nil, time_zone, time)
+ elsif time.is_a?(Range)
+ wrap_with_time_zone(time.begin)..wrap_with_time_zone(time.end)
+ else
+ time
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
index 677e9910bb..88e18f6fff 100644
--- a/activesupport/lib/active_support/xml_mini.rb
+++ b/activesupport/lib/active_support/xml_mini.rb
@@ -39,8 +39,8 @@ module ActiveSupport
"TrueClass" => "boolean",
"FalseClass" => "boolean",
"Date" => "date",
- "DateTime" => "datetime",
- "Time" => "datetime",
+ "DateTime" => "dateTime",
+ "Time" => "dateTime",
"Array" => "array",
"Hash" => "hash"
} unless defined?(TYPE_NAMES)
@@ -48,7 +48,7 @@ module ActiveSupport
FORMATTING = {
"symbol" => Proc.new { |symbol| symbol.to_s },
"date" => Proc.new { |date| date.to_s(:db) },
- "datetime" => Proc.new { |time| time.xmlschema },
+ "dateTime" => Proc.new { |time| time.xmlschema },
"binary" => Proc.new { |binary| ::Base64.encode64(binary) },
"yaml" => Proc.new { |yaml| yaml.to_yaml }
} unless defined?(FORMATTING)
@@ -111,6 +111,7 @@ module ActiveSupport
type_name ||= TYPE_NAMES[value.class.name]
type_name ||= value.class.name if value && !value.respond_to?(:to_str)
type_name = type_name.to_s if type_name
+ type_name = "dateTime" if type_name == "datetime"
key = rename_key(key.to_s, options)
@@ -145,7 +146,7 @@ module ActiveSupport
"#{left}#{middle.tr('_ ', '--')}#{right}"
end
- # TODO: Add support for other encodings
+ # TODO: Add support for other encodings
def _parse_binary(bin, entity) #:nodoc:
case entity['encoding']
when 'base64'
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index d62b782e2d..a75db47be8 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -553,6 +553,9 @@ class FileStoreTest < ActiveSupport::TestCase
@cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60)
@peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60)
@cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), :expires_in => 60)
+
+ @buffer = StringIO.new
+ @cache.logger = ActiveSupport::Logger.new(@buffer)
end
def teardown
@@ -612,6 +615,12 @@ class FileStoreTest < ActiveSupport::TestCase
ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/)
end
end
+
+ def test_log_exception_when_cache_read_fails
+ File.expects(:exist?).raises(StandardError, "failed")
+ @cache.send(:read_entry, "winston", {})
+ assert_present @buffer.string
+ end
end
class MemoryStoreTest < ActiveSupport::TestCase
diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb
index 135f894056..ec05213409 100644
--- a/activesupport/test/constantize_test_cases.rb
+++ b/activesupport/test/constantize_test_cases.rb
@@ -1,16 +1,41 @@
module Ace
module Base
class Case
+ class Dice
+ end
+ end
+ class Fase < Case
+ end
+ end
+ class Gas
+ include Base
+ end
+end
+
+class Object
+ module AddtlGlobalConstants
+ class Case
+ class Dice
+ end
end
end
+ include AddtlGlobalConstants
end
module ConstantizeTestCases
def run_constantize_tests_on
assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") }
assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") }
+ assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") }
+ assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") }
+ assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") }
+ assert_nothing_raised { assert_equal Ace::Gas::Case::Dice, yield("Ace::Gas::Case::Dice") }
+ assert_nothing_raised { assert_equal Case::Dice, yield("Case::Dice") }
+ assert_nothing_raised { assert_equal Case::Dice, yield("Object::Case::Dice") }
assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") }
assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal Object, yield("") }
+ assert_nothing_raised { assert_equal Object, yield("::") }
assert_raise(NameError) { yield("UnknownClass") }
assert_raise(NameError) { yield("UnknownClass::Ace") }
assert_raise(NameError) { yield("UnknownClass::Ace::Base") }
@@ -18,13 +43,23 @@ module ConstantizeTestCases
assert_raise(NameError) { yield("InvalidClass\n") }
assert_raise(NameError) { yield("Ace::ConstantizeTestCases") }
assert_raise(NameError) { yield("Ace::Base::ConstantizeTestCases") }
+ assert_raise(NameError) { yield("Ace::Gas::Base") }
+ assert_raise(NameError) { yield("Ace::Gas::ConstantizeTestCases") }
end
def run_safe_constantize_tests_on
assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") }
assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") }
+ assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") }
+ assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") }
+ assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") }
+ assert_nothing_raised { assert_equal Ace::Gas::Case::Dice, yield("Ace::Gas::Case::Dice") }
+ assert_nothing_raised { assert_equal Case::Dice, yield("Case::Dice") }
+ assert_nothing_raised { assert_equal Case::Dice, yield("Object::Case::Dice") }
assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") }
assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal Object, yield("") }
+ assert_nothing_raised { assert_equal Object, yield("::") }
assert_nothing_raised { assert_equal nil, yield("UnknownClass") }
assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace") }
assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace::Base") }
@@ -33,6 +68,8 @@ module ConstantizeTestCases
assert_nothing_raised { assert_equal nil, yield("blargle") }
assert_nothing_raised { assert_equal nil, yield("Ace::ConstantizeTestCases") }
assert_nothing_raised { assert_equal nil, yield("Ace::Base::ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal nil, yield("Ace::Gas::Base") }
+ assert_nothing_raised { assert_equal nil, yield("Ace::Gas::ConstantizeTestCases") }
assert_nothing_raised { assert_equal nil, yield("#<Class:0x7b8b718b>::Nested_1") }
end
end
diff --git a/activesupport/test/core_ext/bigdecimal_test.rb b/activesupport/test/core_ext/bigdecimal_test.rb
index e24a089650..a5987044b9 100644
--- a/activesupport/test/core_ext/bigdecimal_test.rb
+++ b/activesupport/test/core_ext/bigdecimal_test.rb
@@ -14,4 +14,9 @@ class BigDecimalTest < ActiveSupport::TestCase
bd = BigDecimal.new '10'
assert_equal bd, bd.to_d
end
+
+ def test_to_s
+ bd = BigDecimal.new '0.01'
+ assert_equal '0.01', bd.to_s
+ end
end
diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb
index e290a6e012..1c3ba8a7a0 100644
--- a/activesupport/test/core_ext/class/attribute_test.rb
+++ b/activesupport/test/core_ext/class/attribute_test.rb
@@ -66,6 +66,13 @@ class ClassAttributeTest < ActiveSupport::TestCase
assert_raise(NoMethodError) { object.setting? }
end
+ test 'disabling both instance writer and reader' do
+ object = Class.new { class_attribute :setting, :instance_accessor => false }.new
+ assert_raise(NoMethodError) { object.setting }
+ assert_raise(NoMethodError) { object.setting? }
+ assert_raise(NoMethodError) { object.setting = 'boom' }
+ end
+
test 'works well with singleton classes' do
object = @klass.new
object.singleton_class.setting = 'foo'
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 760d138623..e14a137f84 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -374,14 +374,14 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
def test_end_of_day
- assert_equal Time.local(2005,2,21,23,59,59,999999.999), Date.new(2005,2,21).end_of_day
+ assert_equal Time.local(2005,2,21,23,59,59,Rational(999999999, 1000)), Date.new(2005,2,21).end_of_day
end
def test_end_of_day_when_zone_is_set
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'UTC' do
with_tz_default zone do
- assert_equal zone.local(2005,2,21,23,59,59,999999.999), Date.new(2005,2,21).end_of_day
+ assert_equal zone.local(2005,2,21,23,59,59,Rational(999999999, 1000)), Date.new(2005,2,21).end_of_day
assert_equal zone, Date.new(2005,2,21).end_of_day.time_zone
end
end
diff --git a/activesupport/test/core_ext/duplicable_test.rb b/activesupport/test/core_ext/duplicable_test.rb
index 1105353e45..e0566e012c 100644
--- a/activesupport/test/core_ext/duplicable_test.rb
+++ b/activesupport/test/core_ext/duplicable_test.rb
@@ -5,8 +5,8 @@ require 'active_support/core_ext/numeric/time'
class DuplicableTest < ActiveSupport::TestCase
RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, 5.seconds]
- YES = ['1', Object.new, /foo/, [], {}, Time.now]
- NO = [Class.new, Module.new]
+ YES = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new]
+ NO = []
begin
bd = BigDecimal.new('4.56')
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 0bf48dd378..0a1abac767 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -84,6 +84,11 @@ class EnumerableTests < ActiveSupport::TestCase
assert_equal 10, (1..4.5).sum
assert_equal 6, (1...4).sum
assert_equal 'abc', ('a'..'c').sum
+ assert_equal 50_000_005_000_000, (0..10_000_000).sum
+ assert_equal 0, (10..0).sum
+ assert_equal 5, (10..0).sum(5)
+ assert_equal 10, (10..10).sum
+ assert_equal 42, (10...10).sum(42)
end
def test_index_by
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 8239054117..5d422ce5ad 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -4,6 +4,7 @@ require 'bigdecimal'
require 'active_support/core_ext/string/access'
require 'active_support/ordered_hash'
require 'active_support/core_ext/object/conversions'
+require 'active_support/core_ext/object/deep_dup'
require 'active_support/inflections'
class HashExtTest < ActiveSupport::TestCase
@@ -24,56 +25,207 @@ class HashExtTest < ActiveSupport::TestCase
def setup
@strings = { 'a' => 1, 'b' => 2 }
+ @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } }
@symbols = { :a => 1, :b => 2 }
+ @nested_symbols = { :a => { :b => { :c => 3 } } }
@mixed = { :a => 1, 'b' => 2 }
+ @nested_mixed = { 'a' => { :b => { 'c' => 3 } } }
@fixnums = { 0 => 1, 1 => 2 }
+ @nested_fixnums = { 0 => { 1 => { 2 => 3} } }
@illegal_symbols = { [] => 3 }
+ @nested_illegal_symbols = { [] => { [] => 3} }
+ @upcase_strings = { 'A' => 1, 'B' => 2 }
+ @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } }
end
def test_methods
h = {}
+ assert_respond_to h, :transform_keys
+ assert_respond_to h, :transform_keys!
+ assert_respond_to h, :deep_transform_keys
+ assert_respond_to h, :deep_transform_keys!
assert_respond_to h, :symbolize_keys
assert_respond_to h, :symbolize_keys!
+ assert_respond_to h, :deep_symbolize_keys
+ assert_respond_to h, :deep_symbolize_keys!
assert_respond_to h, :stringify_keys
assert_respond_to h, :stringify_keys!
+ assert_respond_to h, :deep_stringify_keys
+ assert_respond_to h, :deep_stringify_keys!
assert_respond_to h, :to_options
assert_respond_to h, :to_options!
end
+ def test_transform_keys
+ assert_equal @upcase_strings, @strings.transform_keys{ |key| key.to_s.upcase }
+ assert_equal @upcase_strings, @symbols.transform_keys{ |key| key.to_s.upcase }
+ assert_equal @upcase_strings, @mixed.transform_keys{ |key| key.to_s.upcase }
+ end
+
+ def test_transform_keys_not_mutates
+ transformed_hash = @mixed.dup
+ transformed_hash.transform_keys{ |key| key.to_s.upcase }
+ assert_equal @mixed, transformed_hash
+ end
+
+ def test_deep_transform_keys
+ assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase }
+ assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase }
+ assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase }
+ end
+
+ def test_deep_transform_keys_not_mutates
+ transformed_hash = @nested_mixed.deep_dup
+ transformed_hash.deep_transform_keys{ |key| key.to_s.upcase }
+ assert_equal @nested_mixed, transformed_hash
+ end
+
+ def test_transform_keys!
+ assert_equal @upcase_strings, @symbols.dup.transform_keys!{ |key| key.to_s.upcase }
+ assert_equal @upcase_strings, @strings.dup.transform_keys!{ |key| key.to_s.upcase }
+ assert_equal @upcase_strings, @mixed.dup.transform_keys!{ |key| key.to_s.upcase }
+ end
+
+ def test_transform_keys_with_bang_mutates
+ transformed_hash = @mixed.dup
+ transformed_hash.transform_keys!{ |key| key.to_s.upcase }
+ assert_equal @upcase_strings, transformed_hash
+ assert_equal @mixed, { :a => 1, "b" => 2 }
+ end
+
+ def test_deep_transform_keys!
+ assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
+ assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
+ assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
+ end
+
+ def test_deep_transform_keys_with_bang_mutates
+ transformed_hash = @nested_mixed.deep_dup
+ transformed_hash.deep_transform_keys!{ |key| key.to_s.upcase }
+ assert_equal @nested_upcase_strings, transformed_hash
+ assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } }
+ end
+
def test_symbolize_keys
assert_equal @symbols, @symbols.symbolize_keys
assert_equal @symbols, @strings.symbolize_keys
assert_equal @symbols, @mixed.symbolize_keys
end
+ def test_symbolize_keys_not_mutates
+ transformed_hash = @mixed.dup
+ transformed_hash.symbolize_keys
+ assert_equal @mixed, transformed_hash
+ end
+
+ def test_deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys
+ end
+
+ def test_deep_symbolize_keys_not_mutates
+ transformed_hash = @nested_mixed.deep_dup
+ transformed_hash.deep_symbolize_keys
+ assert_equal @nested_mixed, transformed_hash
+ end
+
def test_symbolize_keys!
assert_equal @symbols, @symbols.dup.symbolize_keys!
assert_equal @symbols, @strings.dup.symbolize_keys!
assert_equal @symbols, @mixed.dup.symbolize_keys!
end
+ def test_symbolize_keys_with_bang_mutates
+ transformed_hash = @mixed.dup
+ transformed_hash.deep_symbolize_keys!
+ assert_equal @symbols, transformed_hash
+ assert_equal @mixed, { :a => 1, "b" => 2 }
+ end
+
+ def test_deep_symbolize_keys!
+ assert_equal @nested_symbols, @nested_symbols.deep_dup.deep_symbolize_keys!
+ assert_equal @nested_symbols, @nested_strings.deep_dup.deep_symbolize_keys!
+ assert_equal @nested_symbols, @nested_mixed.deep_dup.deep_symbolize_keys!
+ end
+
+ def test_deep_symbolize_keys_with_bang_mutates
+ transformed_hash = @nested_mixed.deep_dup
+ transformed_hash.deep_symbolize_keys!
+ assert_equal @nested_symbols, transformed_hash
+ assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } }
+ end
+
def test_symbolize_keys_preserves_keys_that_cant_be_symbolized
assert_equal @illegal_symbols, @illegal_symbols.symbolize_keys
assert_equal @illegal_symbols, @illegal_symbols.dup.symbolize_keys!
end
+ def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_symbolize_keys
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_dup.deep_symbolize_keys!
+ end
+
def test_symbolize_keys_preserves_fixnum_keys
assert_equal @fixnums, @fixnums.symbolize_keys
assert_equal @fixnums, @fixnums.dup.symbolize_keys!
end
+ def test_deep_symbolize_keys_preserves_fixnum_keys
+ assert_equal @nested_fixnums, @nested_fixnums.deep_symbolize_keys
+ assert_equal @nested_fixnums, @nested_fixnums.deep_dup.deep_symbolize_keys!
+ end
+
def test_stringify_keys
assert_equal @strings, @symbols.stringify_keys
assert_equal @strings, @strings.stringify_keys
assert_equal @strings, @mixed.stringify_keys
end
+ def test_stringify_keys_not_mutates
+ transformed_hash = @mixed.dup
+ transformed_hash.stringify_keys
+ assert_equal @mixed, transformed_hash
+ end
+
+ def test_deep_stringify_keys
+ assert_equal @nested_strings, @nested_symbols.deep_stringify_keys
+ assert_equal @nested_strings, @nested_strings.deep_stringify_keys
+ assert_equal @nested_strings, @nested_mixed.deep_stringify_keys
+ end
+
+ def test_deep_stringify_keys_not_mutates
+ transformed_hash = @nested_mixed.deep_dup
+ transformed_hash.deep_stringify_keys
+ assert_equal @nested_mixed, transformed_hash
+ end
+
def test_stringify_keys!
assert_equal @strings, @symbols.dup.stringify_keys!
assert_equal @strings, @strings.dup.stringify_keys!
assert_equal @strings, @mixed.dup.stringify_keys!
end
+ def test_stringify_keys_with_bang_mutates
+ transformed_hash = @mixed.dup
+ transformed_hash.stringify_keys!
+ assert_equal @strings, transformed_hash
+ assert_equal @mixed, { :a => 1, "b" => 2 }
+ end
+
+ def test_deep_stringify_keys!
+ assert_equal @nested_strings, @nested_symbols.deep_dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_strings.deep_dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_mixed.deep_dup.deep_stringify_keys!
+ end
+
+ def test_deep_stringify_keys_with_bang_mutates
+ transformed_hash = @nested_mixed.deep_dup
+ transformed_hash.deep_stringify_keys!
+ assert_equal @nested_strings, transformed_hash
+ assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } }
+ end
+
def test_symbolize_keys_for_hash_with_indifferent_access
assert_instance_of Hash, @symbols.with_indifferent_access.symbolize_keys
assert_equal @symbols, @symbols.with_indifferent_access.symbolize_keys
@@ -81,22 +233,46 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys
end
+ def test_deep_symbolize_keys_for_hash_with_indifferent_access
+ assert_instance_of Hash, @nested_symbols.with_indifferent_access.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_symbols.with_indifferent_access.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_strings.with_indifferent_access.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_mixed.with_indifferent_access.deep_symbolize_keys
+ end
+
+
def test_symbolize_keys_bang_for_hash_with_indifferent_access
assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! }
assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! }
assert_raise(NoMethodError) { @mixed.with_indifferent_access.dup.symbolize_keys! }
end
+ def test_deep_symbolize_keys_bang_for_hash_with_indifferent_access
+ assert_raise(NoMethodError) { @nested_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! }
+ assert_raise(NoMethodError) { @nested_strings.with_indifferent_access.deep_dup.deep_symbolize_keys! }
+ assert_raise(NoMethodError) { @nested_mixed.with_indifferent_access.deep_dup.deep_symbolize_keys! }
+ end
+
def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access
assert_equal @illegal_symbols, @illegal_symbols.with_indifferent_access.symbolize_keys
assert_raise(NoMethodError) { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! }
end
+ def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.with_indifferent_access.deep_symbolize_keys
+ assert_raise(NoMethodError) { @nested_illegal_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! }
+ end
+
def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access
assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys
assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! }
end
+ def test_deep_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access
+ assert_equal @nested_fixnums, @nested_fixnums.with_indifferent_access.deep_symbolize_keys
+ assert_raise(NoMethodError) { @nested_fixnums.with_indifferent_access.deep_dup.deep_symbolize_keys! }
+ end
+
def test_stringify_keys_for_hash_with_indifferent_access
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.stringify_keys
assert_equal @strings, @symbols.with_indifferent_access.stringify_keys
@@ -104,6 +280,13 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @strings, @mixed.with_indifferent_access.stringify_keys
end
+ def test_deep_stringify_keys_for_hash_with_indifferent_access
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.deep_stringify_keys
+ assert_equal @nested_strings, @nested_symbols.with_indifferent_access.deep_stringify_keys
+ assert_equal @nested_strings, @nested_strings.with_indifferent_access.deep_stringify_keys
+ assert_equal @nested_strings, @nested_mixed.with_indifferent_access.deep_stringify_keys
+ end
+
def test_stringify_keys_bang_for_hash_with_indifferent_access
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.dup.stringify_keys!
assert_equal @strings, @symbols.with_indifferent_access.dup.stringify_keys!
@@ -111,6 +294,13 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
end
+ def test_deep_stringify_keys_bang_for_hash_with_indifferent_access
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_symbols.with_indifferent_access.deep_dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_strings.with_indifferent_access.deep_dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_mixed.with_indifferent_access.deep_dup.deep_stringify_keys!
+ end
+
def test_nested_under_indifferent_access
foo = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
assert_kind_of ActiveSupport::HashWithIndifferentAccess, foo["foo"]
@@ -297,6 +487,17 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal 1, h[:first]
end
+ def test_deep_stringify_and_deep_symbolize_keys_on_indifferent_preserves_hash
+ h = HashWithIndifferentAccess.new
+ h[:first] = 1
+ h = h.deep_stringify_keys
+ assert_equal 1, h['first']
+ h = HashWithIndifferentAccess.new
+ h['first'] = 1
+ h = h.deep_symbolize_keys
+ assert_equal 1, h[:first]
+ end
+
def test_to_options_on_indifferent_preserves_hash
h = HashWithIndifferentAccess.new
h['first'] = 1
@@ -672,8 +873,8 @@ class HashToXmlTest < ActiveSupport::TestCase
:created_at => Time.utc(1999,2,2),
:local_created_at => Time.utc(1999,2,2).in_time_zone('Eastern Time (US & Canada)')
}.to_xml(@xml_options)
- assert_match %r{<created-at type=\"datetime\">1999-02-02T00:00:00Z</created-at>}, xml
- assert_match %r{<local-created-at type=\"datetime\">1999-02-01T19:00:00-05:00</local-created-at>}, xml
+ assert_match %r{<created-at type=\"dateTime\">1999-02-02T00:00:00Z</created-at>}, xml
+ assert_match %r{<local-created-at type=\"dateTime\">1999-02-01T19:00:00-05:00</local-created-at>}, xml
end
def test_multiple_records_from_xml_with_attributes_other_than_type_ignores_them_without_exploding
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 6e1b3ca010..bd41311739 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -234,7 +234,7 @@ class ModuleTest < ActiveSupport::TestCase
def test_local_constant_names
ActiveSupport::Deprecation.silence do
- assert_equal %w(Constant1 Constant3), Ab.local_constant_names
+ assert_equal %w(Constant1 Constant3), Ab.local_constant_names.sort.map(&:to_s)
end
end
end
diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb
index 1cb1e25d4c..435f4aa5a1 100644
--- a/activesupport/test/core_ext/numeric_ext_test.rb
+++ b/activesupport/test/core_ext/numeric_ext_test.rb
@@ -186,3 +186,264 @@ class NumericExtSizeTest < ActiveSupport::TestCase
assert_equal 3458764513820540928, 3.exabyte
end
end
+
+class NumericExtFormattingTest < ActiveSupport::TestCase
+ def kilobytes(number)
+ number * 1024
+ end
+
+ def megabytes(number)
+ kilobytes(number) * 1024
+ end
+
+ def gigabytes(number)
+ megabytes(number) * 1024
+ end
+
+ def terabytes(number)
+ gigabytes(number) * 1024
+ end
+
+ def test_to_s__phone
+ assert_equal("555-1234", 5551234.to_s(:phone))
+ assert_equal("800-555-1212", 8005551212.to_s(:phone))
+ assert_equal("(800) 555-1212", 8005551212.to_s(:phone, :area_code => true))
+ assert_equal("800 555 1212", 8005551212.to_s(:phone, :delimiter => " "))
+ assert_equal("(800) 555-1212 x 123", 8005551212.to_s(:phone, :area_code => true, :extension => 123))
+ assert_equal("800-555-1212", 8005551212.to_s(:phone, :extension => " "))
+ assert_equal("555.1212", 5551212.to_s(:phone, :delimiter => '.'))
+ assert_equal("+1-800-555-1212", 8005551212.to_s(:phone, :country_code => 1))
+ assert_equal("+18005551212", 8005551212.to_s(:phone, :country_code => 1, :delimiter => ''))
+ assert_equal("22-555-1212", 225551212.to_s(:phone))
+ assert_equal("+45-22-555-1212", 225551212.to_s(:phone, :country_code => 45))
+ end
+
+ def test_to_s__currency
+ assert_equal("$1,234,567,890.50", 1234567890.50.to_s(:currency))
+ assert_equal("$1,234,567,890.51", 1234567890.506.to_s(:currency))
+ assert_equal("-$1,234,567,890.50", -1234567890.50.to_s(:currency))
+ assert_equal("-$ 1,234,567,890.50", -1234567890.50.to_s(:currency, :format => "%u %n"))
+ assert_equal("($1,234,567,890.50)", -1234567890.50.to_s(:currency, :negative_format => "(%u%n)"))
+ assert_equal("$1,234,567,892", 1234567891.50.to_s(:currency, :precision => 0))
+ assert_equal("$1,234,567,890.5", 1234567890.50.to_s(:currency, :precision => 1))
+ assert_equal("&pound;1234567890,50", 1234567890.50.to_s(:currency, :unit => "&pound;", :separator => ",", :delimiter => ""))
+ end
+
+
+ def test_to_s__rounded
+ assert_equal("-111.235", -111.2346.to_s(:rounded))
+ assert_equal("111.235", 111.2346.to_s(:rounded))
+ assert_equal("31.83", 31.825.to_s(:rounded, :precision => 2))
+ assert_equal("111.23", 111.2346.to_s(:rounded, :precision => 2))
+ assert_equal("111.00", 111.to_s(:rounded, :precision => 2))
+ assert_equal("3268", (32.6751 * 100.00).to_s(:rounded, :precision => 0))
+ assert_equal("112", 111.50.to_s(:rounded, :precision => 0))
+ assert_equal("1234567892", 1234567891.50.to_s(:rounded, :precision => 0))
+ assert_equal("0", 0.to_s(:rounded, :precision => 0))
+ assert_equal("0.00100", 0.001.to_s(:rounded, :precision => 5))
+ assert_equal("0.001", 0.00111.to_s(:rounded, :precision => 3))
+ assert_equal("10.00", 9.995.to_s(:rounded, :precision => 2))
+ assert_equal("11.00", 10.995.to_s(:rounded, :precision => 2))
+ assert_equal("0.00", -0.001.to_s(:rounded, :precision => 2))
+ end
+
+ def test_to_s__percentage
+ assert_equal("100.000%", 100.to_s(:percentage))
+ assert_equal("100%", 100.to_s(:percentage, :precision => 0))
+ assert_equal("302.06%", 302.0574.to_s(:percentage, :precision => 2))
+ assert_equal("123.4%", 123.400.to_s(:percentage, :precision => 3, :strip_insignificant_zeros => true))
+ assert_equal("1.000,000%", 1000.to_s(:percentage, :delimiter => '.', :separator => ','))
+ assert_equal("1000.000 %", 1000.to_s(:percentage, :format => "%n %"))
+ end
+
+ def test_to_s__delimited
+ assert_equal("12,345,678", 12345678.to_s(:delimited))
+ assert_equal("0", 0.to_s(:delimited))
+ assert_equal("123", 123.to_s(:delimited))
+ assert_equal("123,456", 123456.to_s(:delimited))
+ assert_equal("123,456.78", 123456.78.to_s(:delimited))
+ assert_equal("123,456.789", 123456.789.to_s(:delimited))
+ assert_equal("123,456.78901", 123456.78901.to_s(:delimited))
+ assert_equal("123,456,789.78901", 123456789.78901.to_s(:delimited))
+ assert_equal("0.78901", 0.78901.to_s(:delimited))
+ end
+
+ def test_to_s__delimited__with_options_hash
+ assert_equal '12 345 678', 12345678.to_s(:delimited, :delimiter => ' ')
+ assert_equal '12,345,678-05', 12345678.05.to_s(:delimited, :separator => '-')
+ assert_equal '12.345.678,05', 12345678.05.to_s(:delimited, :separator => ',', :delimiter => '.')
+ assert_equal '12.345.678,05', 12345678.05.to_s(:delimited, :delimiter => '.', :separator => ',')
+ end
+
+
+ def test_to_s__rounded_with_custom_delimiter_and_separator
+ assert_equal '31,83', 31.825.to_s(:rounded, :precision => 2, :separator => ',')
+ assert_equal '1.231,83', 1231.825.to_s(:rounded, :precision => 2, :separator => ',', :delimiter => '.')
+ end
+
+ def test_to_s__rounded__with_significant_digits
+ assert_equal "124000", 123987.to_s(:rounded, :precision => 3, :significant => true)
+ assert_equal "120000000", 123987876.to_s(:rounded, :precision => 2, :significant => true )
+ assert_equal "9775", 9775.to_s(:rounded, :precision => 4, :significant => true )
+ assert_equal "5.4", 5.3923.to_s(:rounded, :precision => 2, :significant => true )
+ assert_equal "5", 5.3923.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "1", 1.232.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "7", 7.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "1", 1.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "53", 52.7923.to_s(:rounded, :precision => 2, :significant => true )
+ assert_equal "9775.00", 9775.to_s(:rounded, :precision => 6, :significant => true )
+ assert_equal "5.392900", 5.3929.to_s(:rounded, :precision => 7, :significant => true )
+ assert_equal "0.0", 0.to_s(:rounded, :precision => 2, :significant => true )
+ assert_equal "0", 0.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "0.0001", 0.0001.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "0.000100", 0.0001.to_s(:rounded, :precision => 3, :significant => true )
+ assert_equal "0.0001", 0.0001111.to_s(:rounded, :precision => 1, :significant => true )
+ assert_equal "10.0", 9.995.to_s(:rounded, :precision => 3, :significant => true)
+ assert_equal "9.99", 9.994.to_s(:rounded, :precision => 3, :significant => true)
+ assert_equal "11.0", 10.995.to_s(:rounded, :precision => 3, :significant => true)
+ end
+
+ def test_to_s__rounded__with_strip_insignificant_zeros
+ assert_equal "9775.43", 9775.43.to_s(:rounded, :precision => 4, :strip_insignificant_zeros => true )
+ assert_equal "9775.2", 9775.2.to_s(:rounded, :precision => 6, :significant => true, :strip_insignificant_zeros => true )
+ assert_equal "0", 0.to_s(:rounded, :precision => 6, :significant => true, :strip_insignificant_zeros => true )
+ end
+
+ def test_to_s__rounded__with_significant_true_and_zero_precision
+ # Zero precision with significant is a mistake (would always return zero),
+ # so we treat it as if significant was false (increases backwards compatibility for number_to_human_size)
+ assert_equal "124", 123.987.to_s(:rounded, :precision => 0, :significant => true)
+ assert_equal "12", 12.to_s(:rounded, :precision => 0, :significant => true )
+ end
+
+ def test_to_s__human_size
+ assert_equal '0 Bytes', 0.to_s(:human_size)
+ assert_equal '1 Byte', 1.to_s(:human_size)
+ assert_equal '3 Bytes', 3.14159265.to_s(:human_size)
+ assert_equal '123 Bytes', 123.0.to_s(:human_size)
+ assert_equal '123 Bytes', 123.to_s(:human_size)
+ assert_equal '1.21 KB', 1234.to_s(:human_size)
+ assert_equal '12.1 KB', 12345.to_s(:human_size)
+ assert_equal '1.18 MB', 1234567.to_s(:human_size)
+ assert_equal '1.15 GB', 1234567890.to_s(:human_size)
+ assert_equal '1.12 TB', 1234567890123.to_s(:human_size)
+ assert_equal '1030 TB', terabytes(1026).to_s(:human_size)
+ assert_equal '444 KB', kilobytes(444).to_s(:human_size)
+ assert_equal '1020 MB', megabytes(1023).to_s(:human_size)
+ assert_equal '3 TB', terabytes(3).to_s(:human_size)
+ assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2)
+ assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4)
+ assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2)
+ assert_equal '1.01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4)
+ assert_equal '10 KB', kilobytes(10.000).to_s(:human_size, :precision => 4)
+ assert_equal '1 Byte', 1.1.to_s(:human_size)
+ assert_equal '10 Bytes', 10.to_s(:human_size)
+ end
+
+ def test_to_s__human_size_with_si_prefix
+ assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :prefix => :si)
+ assert_equal '123 Bytes', 123.0.to_s(:human_size, :prefix => :si)
+ assert_equal '123 Bytes', 123.to_s(:human_size, :prefix => :si)
+ assert_equal '1.23 KB', 1234.to_s(:human_size, :prefix => :si)
+ assert_equal '12.3 KB', 12345.to_s(:human_size, :prefix => :si)
+ assert_equal '1.23 MB', 1234567.to_s(:human_size, :prefix => :si)
+ assert_equal '1.23 GB', 1234567890.to_s(:human_size, :prefix => :si)
+ assert_equal '1.23 TB', 1234567890123.to_s(:human_size, :prefix => :si)
+ end
+
+ def test_to_s__human_size_with_options_hash
+ assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2)
+ assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4)
+ assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2)
+ assert_equal '1.01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4)
+ assert_equal '10 KB', kilobytes(10.000).to_s(:human_size, :precision => 4)
+ assert_equal '1 TB', 1234567890123.to_s(:human_size, :precision => 1)
+ assert_equal '500 MB', 524288000.to_s(:human_size, :precision=>3)
+ assert_equal '10 MB', 9961472.to_s(:human_size, :precision=>0)
+ assert_equal '40 KB', 41010.to_s(:human_size, :precision => 1)
+ assert_equal '40 KB', 41100.to_s(:human_size, :precision => 2)
+ assert_equal '1.0 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2, :strip_insignificant_zeros => false)
+ assert_equal '1.012 KB', kilobytes(1.0123).to_s(:human_size, :precision => 3, :significant => false)
+ assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 0, :significant => true) #ignores significant it precision is 0
+ end
+
+ def test_to_s__human_size_with_custom_delimiter_and_separator
+ assert_equal '1,01 KB', kilobytes(1.0123).to_s(:human_size, :precision => 3, :separator => ',')
+ assert_equal '1,01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4, :separator => ',')
+ assert_equal '1.000,1 TB', terabytes(1000.1).to_s(:human_size, :precision => 5, :delimiter => '.', :separator => ',')
+ end
+
+ def test_number_to_human
+ assert_equal '-123', -123.to_s(:human)
+ assert_equal '-0.5', -0.5.to_s(:human)
+ assert_equal '0', 0.to_s(:human)
+ assert_equal '0.5', 0.5.to_s(:human)
+ assert_equal '123', 123.to_s(:human)
+ assert_equal '1.23 Thousand', 1234.to_s(:human)
+ assert_equal '12.3 Thousand', 12345.to_s(:human)
+ assert_equal '1.23 Million', 1234567.to_s(:human)
+ assert_equal '1.23 Billion', 1234567890.to_s(:human)
+ assert_equal '1.23 Trillion', 1234567890123.to_s(:human)
+ assert_equal '1.23 Quadrillion', 1234567890123456.to_s(:human)
+ assert_equal '1230 Quadrillion', 1234567890123456789.to_s(:human)
+ assert_equal '490 Thousand', 489939.to_s(:human, :precision => 2)
+ assert_equal '489.9 Thousand', 489939.to_s(:human, :precision => 4)
+ assert_equal '489 Thousand', 489000.to_s(:human, :precision => 4)
+ assert_equal '489.0 Thousand', 489000.to_s(:human, :precision => 4, :strip_insignificant_zeros => false)
+ assert_equal '1.2346 Million', 1234567.to_s(:human, :precision => 4, :significant => false)
+ assert_equal '1,2 Million', 1234567.to_s(:human, :precision => 1, :significant => false, :separator => ',')
+ assert_equal '1 Million', 1234567.to_s(:human, :precision => 0, :significant => true, :separator => ',') #significant forced to false
+ end
+
+ def test_number_to_human_with_custom_units
+ #Only integers
+ volume = {:unit => "ml", :thousand => "lt", :million => "m3"}
+ assert_equal '123 lt', 123456.to_s(:human, :units => volume)
+ assert_equal '12 ml', 12.to_s(:human, :units => volume)
+ assert_equal '1.23 m3', 1234567.to_s(:human, :units => volume)
+
+ #Including fractionals
+ distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"}
+ assert_equal '1.23 mm', 0.00123.to_s(:human, :units => distance)
+ assert_equal '1.23 cm', 0.0123.to_s(:human, :units => distance)
+ assert_equal '1.23 dm', 0.123.to_s(:human, :units => distance)
+ assert_equal '1.23 m', 1.23.to_s(:human, :units => distance)
+ assert_equal '1.23 dam', 12.3.to_s(:human, :units => distance)
+ assert_equal '1.23 hm', 123.to_s(:human, :units => distance)
+ assert_equal '1.23 km', 1230.to_s(:human, :units => distance)
+ assert_equal '1.23 km', 1230.to_s(:human, :units => distance)
+ assert_equal '1.23 km', 1230.to_s(:human, :units => distance)
+ assert_equal '12.3 km', 12300.to_s(:human, :units => distance)
+
+ #The quantifiers don't need to be a continuous sequence
+ gangster = {:hundred => "hundred bucks", :million => "thousand quids"}
+ assert_equal '1 hundred bucks', 100.to_s(:human, :units => gangster)
+ assert_equal '25 hundred bucks', 2500.to_s(:human, :units => gangster)
+ assert_equal '25 thousand quids', 25000000.to_s(:human, :units => gangster)
+ assert_equal '12300 thousand quids', 12345000000.to_s(:human, :units => gangster)
+
+ #Spaces are stripped from the resulting string
+ assert_equal '4', 4.to_s(:human, :units => {:unit => "", :ten => 'tens '})
+ assert_equal '4.5 tens', 45.to_s(:human, :units => {:unit => "", :ten => ' tens '})
+ end
+
+ def test_number_to_human_with_custom_format
+ assert_equal '123 times Thousand', 123456.to_s(:human, :format => "%n times %u")
+ volume = {:unit => "ml", :thousand => "lt", :million => "m3"}
+ assert_equal '123.lt', 123456.to_s(:human, :units => volume, :format => "%n.%u")
+ end
+
+ def test_to_s__injected_on_proper_types
+ assert_equal Fixnum, 1230.class
+ assert_equal '1.23 Thousand', 1230.to_s(:human)
+
+ assert_equal Float, Float(1230).class
+ assert_equal '1.23 Thousand', Float(1230).to_s(:human)
+
+ assert_equal Bignum, (100**10).class
+ assert_equal '100000 Quadrillion', (100**10).to_s(:human)
+
+ assert_equal BigDecimal, BigDecimal("1000010").class
+ assert_equal '1 Million', BigDecimal("1000010").to_s(:human)
+ end
+end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 9010a4a716..e5b774425e 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -290,6 +290,10 @@ class StringInflectionsTest < ActiveSupport::TestCase
"\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding('UTF-8').truncate(10)
end
+ def test_truncate_should_not_be_html_safe
+ assert !"Hello World!".truncate(12).html_safe?
+ end
+
def test_constantize
run_constantize_tests_on do |string|
string.constantize
@@ -439,6 +443,37 @@ class OutputSafetyTest < ActiveSupport::TestCase
assert @other_string.html_safe?
end
+ test "Concatting safe onto unsafe with % yields unsafe" do
+ @other_string = "other%s"
+ string = @string.html_safe
+
+ @other_string = @other_string % string
+ assert !@other_string.html_safe?
+ end
+
+ test "Concatting unsafe onto safe with % yields escaped safe" do
+ @other_string = "other%s".html_safe
+ string = @other_string % "<foo>"
+
+ assert_equal "other&lt;foo&gt;", string
+ assert string.html_safe?
+ end
+
+ test "Concatting safe onto safe with % yields safe" do
+ @other_string = "other%s".html_safe
+ string = @string.html_safe
+
+ @other_string = @other_string % string
+ assert @other_string.html_safe?
+ end
+
+ test "Concatting with % doesn't modify a string" do
+ @other_string = ["<p>", "<b>", "<h1>"]
+ _ = "%s %s %s".html_safe % @other_string
+
+ assert_equal ["<p>", "<b>", "<h1>"], @other_string
+ end
+
test "Concatting a fixnum to safe always yields safe" do
string = @string.html_safe
string = string.concat(13)
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 4c1ed4b1ae..15c04bedf7 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -109,49 +109,49 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
def test_end_of_day
- assert_equal Time.local(2007,8,12,23,59,59,999999.999), Time.local(2007,8,12,10,10,10).end_of_day
+ assert_equal Time.local(2007,8,12,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,12,10,10,10).end_of_day
with_env_tz 'US/Eastern' do
- assert_equal Time.local(2007,4,2,23,59,59,999999.999), Time.local(2007,4,2,10,10,10).end_of_day, 'start DST'
- assert_equal Time.local(2007,10,29,23,59,59,999999.999), Time.local(2007,10,29,10,10,10).end_of_day, 'ends DST'
+ assert_equal Time.local(2007,4,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,4,2,10,10,10).end_of_day, 'start DST'
+ assert_equal Time.local(2007,10,29,23,59,59,Rational(999999999, 1000)), Time.local(2007,10,29,10,10,10).end_of_day, 'ends DST'
end
with_env_tz 'NZ' do
- assert_equal Time.local(2006,3,19,23,59,59,999999.999), Time.local(2006,3,19,10,10,10).end_of_day, 'ends DST'
- assert_equal Time.local(2006,10,1,23,59,59,999999.999), Time.local(2006,10,1,10,10,10).end_of_day, 'start DST'
+ assert_equal Time.local(2006,3,19,23,59,59,Rational(999999999, 1000)), Time.local(2006,3,19,10,10,10).end_of_day, 'ends DST'
+ assert_equal Time.local(2006,10,1,23,59,59,Rational(999999999, 1000)), Time.local(2006,10,1,10,10,10).end_of_day, 'start DST'
end
end
def test_end_of_week
- assert_equal Time.local(2008,1,6,23,59,59,999999.999), Time.local(2007,12,31,10,10,10).end_of_week
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,8,27,0,0,0).end_of_week #monday
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,8,28,0,0,0).end_of_week #tuesday
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,8,29,0,0,0).end_of_week #wednesday
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,8,30,0,0,0).end_of_week #thursday
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,8,31,0,0,0).end_of_week #friday
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,9,01,0,0,0).end_of_week #saturday
- assert_equal Time.local(2007,9,2,23,59,59,999999.999), Time.local(2007,9,02,0,0,0).end_of_week #sunday
+ assert_equal Time.local(2008,1,6,23,59,59,Rational(999999999, 1000)), Time.local(2007,12,31,10,10,10).end_of_week
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,27,0,0,0).end_of_week #monday
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,28,0,0,0).end_of_week #tuesday
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,29,0,0,0).end_of_week #wednesday
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,30,0,0,0).end_of_week #thursday
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,31,0,0,0).end_of_week #friday
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,9,01,0,0,0).end_of_week #saturday
+ assert_equal Time.local(2007,9,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,9,02,0,0,0).end_of_week #sunday
end
def test_end_of_hour
- assert_equal Time.local(2005,2,4,19,59,59,999999.999), Time.local(2005,2,4,19,30,10).end_of_hour
+ assert_equal Time.local(2005,2,4,19,59,59,Rational(999999999, 1000)), Time.local(2005,2,4,19,30,10).end_of_hour
end
def test_end_of_month
- assert_equal Time.local(2005,3,31,23,59,59,999999.999), Time.local(2005,3,20,10,10,10).end_of_month
- assert_equal Time.local(2005,2,28,23,59,59,999999.999), Time.local(2005,2,20,10,10,10).end_of_month
- assert_equal Time.local(2005,4,30,23,59,59,999999.999), Time.local(2005,4,20,10,10,10).end_of_month
+ assert_equal Time.local(2005,3,31,23,59,59,Rational(999999999, 1000)), Time.local(2005,3,20,10,10,10).end_of_month
+ assert_equal Time.local(2005,2,28,23,59,59,Rational(999999999, 1000)), Time.local(2005,2,20,10,10,10).end_of_month
+ assert_equal Time.local(2005,4,30,23,59,59,Rational(999999999, 1000)), Time.local(2005,4,20,10,10,10).end_of_month
end
def test_end_of_quarter
- assert_equal Time.local(2007,3,31,23,59,59,999999.999), Time.local(2007,2,15,10,10,10).end_of_quarter
- assert_equal Time.local(2007,3,31,23,59,59,999999.999), Time.local(2007,3,31,0,0,0).end_of_quarter
- assert_equal Time.local(2007,12,31,23,59,59,999999.999), Time.local(2007,12,21,10,10,10).end_of_quarter
- assert_equal Time.local(2007,6,30,23,59,59,999999.999), Time.local(2007,4,1,0,0,0).end_of_quarter
- assert_equal Time.local(2008,6,30,23,59,59,999999.999), Time.local(2008,5,31,0,0,0).end_of_quarter
+ assert_equal Time.local(2007,3,31,23,59,59,Rational(999999999, 1000)), Time.local(2007,2,15,10,10,10).end_of_quarter
+ assert_equal Time.local(2007,3,31,23,59,59,Rational(999999999, 1000)), Time.local(2007,3,31,0,0,0).end_of_quarter
+ assert_equal Time.local(2007,12,31,23,59,59,Rational(999999999, 1000)), Time.local(2007,12,21,10,10,10).end_of_quarter
+ assert_equal Time.local(2007,6,30,23,59,59,Rational(999999999, 1000)), Time.local(2007,4,1,0,0,0).end_of_quarter
+ assert_equal Time.local(2008,6,30,23,59,59,Rational(999999999, 1000)), Time.local(2008,5,31,0,0,0).end_of_quarter
end
def test_end_of_year
- assert_equal Time.local(2007,12,31,23,59,59,999999.999), Time.local(2007,2,22,10,10,10).end_of_year
- assert_equal Time.local(2007,12,31,23,59,59,999999.999), Time.local(2007,12,31,10,10,10).end_of_year
+ assert_equal Time.local(2007,12,31,23,59,59,Rational(999999999, 1000)), Time.local(2007,2,22,10,10,10).end_of_year
+ assert_equal Time.local(2007,12,31,23,59,59,Rational(999999999, 1000)), Time.local(2007,12,31,10,10,10).end_of_year
end
def test_beginning_of_year
@@ -517,7 +517,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,11,15), Time.local(2006,11,23,0,0,0).prev_week(:wednesday)
end
end
-
+
def test_last_week
with_env_tz 'US/Eastern' do
assert_equal Time.local(2005,2,21), Time.local(2005,3,1,15,15,10).last_week
@@ -557,12 +557,14 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
def test_to_s
- time = Time.utc(2005, 2, 21, 17, 44, 30)
+ time = Time.utc(2005, 2, 21, 17, 44, 30.12345678901)
assert_equal time.to_default_s, time.to_s
assert_equal time.to_default_s, time.to_s(:doesnt_exist)
assert_equal "2005-02-21 17:44:30", time.to_s(:db)
assert_equal "21 Feb 17:44", time.to_s(:short)
assert_equal "17:44", time.to_s(:time)
+ assert_equal "20050221174430", time.to_s(:number)
+ assert_equal "20050221174430123456789", time.to_s(:nsec)
assert_equal "February 21, 2005 17:44", time.to_s(:long)
assert_equal "February 21st, 2005 17:44", time.to_s(:long_ordinal)
with_env_tz "UTC" do
@@ -828,24 +830,32 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
def test_all_day
- assert_equal Time.local(2011,6,7,0,0,0)..Time.local(2011,6,7,23,59,59,999999.999), Time.local(2011,6,7,10,10,10).all_day
+ assert_equal Time.local(2011,6,7,0,0,0)..Time.local(2011,6,7,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_day
+ end
+
+ def test_all_day_with_timezone
+ beginning_of_day = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Hawaii"], Time.local(2011,6,7,0,0,0))
+ end_of_day = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Hawaii"], Time.local(2011,6,7,23,59,59,Rational(999999999, 1000)))
+
+ assert_equal beginning_of_day, ActiveSupport::TimeWithZone.new(Time.local(2011,6,7,10,10,10), ActiveSupport::TimeZone["Hawaii"]).all_day.begin
+ assert_equal end_of_day, ActiveSupport::TimeWithZone.new(Time.local(2011,6,7,10,10,10), ActiveSupport::TimeZone["Hawaii"]).all_day.end
end
def test_all_week
- assert_equal Time.local(2011,6,6,0,0,0)..Time.local(2011,6,12,23,59,59,999999.999), Time.local(2011,6,7,10,10,10).all_week
- assert_equal Time.local(2011,6,5,0,0,0)..Time.local(2011,6,11,23,59,59,999999.999), Time.local(2011,6,7,10,10,10).all_week(:sunday)
+ assert_equal Time.local(2011,6,6,0,0,0)..Time.local(2011,6,12,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_week
+ assert_equal Time.local(2011,6,5,0,0,0)..Time.local(2011,6,11,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_week(:sunday)
end
def test_all_month
- assert_equal Time.local(2011,6,1,0,0,0)..Time.local(2011,6,30,23,59,59,999999.999), Time.local(2011,6,7,10,10,10).all_month
+ assert_equal Time.local(2011,6,1,0,0,0)..Time.local(2011,6,30,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_month
end
def test_all_quarter
- assert_equal Time.local(2011,4,1,0,0,0)..Time.local(2011,6,30,23,59,59,999999.999), Time.local(2011,6,7,10,10,10).all_quarter
+ assert_equal Time.local(2011,4,1,0,0,0)..Time.local(2011,6,30,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_quarter
end
def test_all_year
- assert_equal Time.local(2011,1,1,0,0,0)..Time.local(2011,12,31,23,59,59,999999.999), Time.local(2011,6,7,10,10,10).all_year
+ assert_equal Time.local(2011,1,1,0,0,0)..Time.local(2011,12,31,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_year
end
protected
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index b62337e31b..1293f104e5 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -80,6 +80,14 @@ class TimeWithZoneTest < ActiveSupport::TestCase
ActiveSupport.use_standard_json_time_format = old
end
+ def test_nsec
+ local = Time.local(2011,6,7,23,59,59,Rational(999999999, 1000))
+ with_zone = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Hawaii"], local)
+
+ assert_equal local.nsec, with_zone.nsec
+ assert_equal with_zone.nsec, 999999999
+ end
+
def test_strftime
assert_equal '1999-12-31 19:00:00 EST -0500', @twz.strftime('%Y-%m-%d %H:%M:%S %Z %z')
end
diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb
index 4d10cfca25..9fa1f417e4 100644
--- a/activesupport/test/inflector_test_cases.rb
+++ b/activesupport/test/inflector_test_cases.rb
@@ -47,6 +47,7 @@ module InflectorTestCases
"medium" => "media",
"stadium" => "stadia",
"analysis" => "analyses",
+ "my_analysis" => "my_analyses",
"node_child" => "node_children",
"child" => "children",
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index 0566ebf291..212ee262a3 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -285,6 +285,12 @@ class TestJSONEncoding < ActiveSupport::TestCase
end
end
+ def test_nil_true_and_false_represented_as_themselves
+ assert_equal nil, nil.as_json
+ assert_equal true, true.as_json
+ assert_equal false, false.as_json
+ end
+
protected
def object_keys(json_object)
diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb
index 8e160714b1..2a0e8d20ed 100644
--- a/activesupport/test/log_subscriber_test.rb
+++ b/activesupport/test/log_subscriber_test.rb
@@ -11,7 +11,7 @@ class MyLogSubscriber < ActiveSupport::LogSubscriber
def foo(event)
debug "debug"
- info "info"
+ info { "info" }
warn "warn"
end
diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb
new file mode 100644
index 0000000000..9b7d7f020c
--- /dev/null
+++ b/activesupport/test/number_helper_test.rb
@@ -0,0 +1,375 @@
+require 'abstract_unit'
+require 'active_support/number_helper'
+
+module ActiveSupport
+ module NumberHelper
+ class NumberHelperTest < ActiveSupport::TestCase
+
+ class TestClassWithInstanceNumberHelpers
+ include ActiveSupport::NumberHelper
+ end
+
+ class TestClassWithClassNumberHelpers
+ extend ActiveSupport::NumberHelper
+ end
+
+ def setup
+ @instance_with_helpers = TestClassWithInstanceNumberHelpers.new
+ end
+
+ def kilobytes(number)
+ number * 1024
+ end
+
+ def megabytes(number)
+ kilobytes(number) * 1024
+ end
+
+ def gigabytes(number)
+ megabytes(number) * 1024
+ end
+
+ def terabytes(number)
+ gigabytes(number) * 1024
+ end
+
+ def test_number_to_phone
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal("555-1234", number_helper.number_to_phone(5551234))
+ assert_equal("800-555-1212", number_helper.number_to_phone(8005551212))
+ assert_equal("(800) 555-1212", number_helper.number_to_phone(8005551212, {:area_code => true}))
+ assert_equal("", number_helper.number_to_phone("", {:area_code => true}))
+ assert_equal("800 555 1212", number_helper.number_to_phone(8005551212, {:delimiter => " "}))
+ assert_equal("(800) 555-1212 x 123", number_helper.number_to_phone(8005551212, {:area_code => true, :extension => 123}))
+ assert_equal("800-555-1212", number_helper.number_to_phone(8005551212, :extension => " "))
+ assert_equal("555.1212", number_helper.number_to_phone(5551212, :delimiter => '.'))
+ assert_equal("800-555-1212", number_helper.number_to_phone("8005551212"))
+ assert_equal("+1-800-555-1212", number_helper.number_to_phone(8005551212, :country_code => 1))
+ assert_equal("+18005551212", number_helper.number_to_phone(8005551212, :country_code => 1, :delimiter => ''))
+ assert_equal("22-555-1212", number_helper.number_to_phone(225551212))
+ assert_equal("+45-22-555-1212", number_helper.number_to_phone(225551212, :country_code => 45))
+ end
+ end
+
+ def test_number_to_currency
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal("$1,234,567,890.50", number_helper.number_to_currency(1234567890.50))
+ assert_equal("$1,234,567,890.51", number_helper.number_to_currency(1234567890.506))
+ assert_equal("-$1,234,567,890.50", number_helper.number_to_currency(-1234567890.50))
+ assert_equal("-$ 1,234,567,890.50", number_helper.number_to_currency(-1234567890.50, {:format => "%u %n"}))
+ assert_equal("($1,234,567,890.50)", number_helper.number_to_currency(-1234567890.50, {:negative_format => "(%u%n)"}))
+ assert_equal("$1,234,567,892", number_helper.number_to_currency(1234567891.50, {:precision => 0}))
+ assert_equal("$1,234,567,890.5", number_helper.number_to_currency(1234567890.50, {:precision => 1}))
+ assert_equal("&pound;1234567890,50", number_helper.number_to_currency(1234567890.50, {:unit => "&pound;", :separator => ",", :delimiter => ""}))
+ assert_equal("$1,234,567,890.50", number_helper.number_to_currency("1234567890.50"))
+ assert_equal("1,234,567,890.50 K&#269;", number_helper.number_to_currency("1234567890.50", {:unit => "K&#269;", :format => "%n %u"}))
+ assert_equal("1,234,567,890.50 - K&#269;", number_helper.number_to_currency("-1234567890.50", {:unit => "K&#269;", :format => "%n %u", :negative_format => "%n - %u"}))
+ assert_equal("0.00", number_helper.number_to_currency(+0.0, {:unit => "", :negative_format => "(%n)"}))
+ assert_equal("(0.00)", number_helper.number_to_currency(-0.0, {:unit => "", :negative_format => "(%n)"}))
+ end
+ end
+
+ def test_number_to_percentage
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal("100.000%", number_helper.number_to_percentage(100))
+ assert_equal("100%", number_helper.number_to_percentage(100, {:precision => 0}))
+ assert_equal("302.06%", number_helper.number_to_percentage(302.0574, {:precision => 2}))
+ assert_equal("100.000%", number_helper.number_to_percentage("100"))
+ assert_equal("1000.000%", number_helper.number_to_percentage("1000"))
+ assert_equal("123.4%", number_helper.number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true))
+ assert_equal("1.000,000%", number_helper.number_to_percentage(1000, :delimiter => '.', :separator => ','))
+ assert_equal("1000.000 %", number_helper.number_to_percentage(1000, :format => "%n %"))
+ end
+ end
+
+ def test_to_delimited
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal("12,345,678", number_helper.number_to_delimited(12345678))
+ assert_equal("0", number_helper.number_to_delimited(0))
+ assert_equal("123", number_helper.number_to_delimited(123))
+ assert_equal("123,456", number_helper.number_to_delimited(123456))
+ assert_equal("123,456.78", number_helper.number_to_delimited(123456.78))
+ assert_equal("123,456.789", number_helper.number_to_delimited(123456.789))
+ assert_equal("123,456.78901", number_helper.number_to_delimited(123456.78901))
+ assert_equal("123,456,789.78901", number_helper.number_to_delimited(123456789.78901))
+ assert_equal("0.78901", number_helper.number_to_delimited(0.78901))
+ assert_equal("123,456.78", number_helper.number_to_delimited("123456.78"))
+ end
+ end
+
+ def test_to_delimited_with_options_hash
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '12 345 678', number_helper.number_to_delimited(12345678, :delimiter => ' ')
+ assert_equal '12,345,678-05', number_helper.number_to_delimited(12345678.05, :separator => '-')
+ assert_equal '12.345.678,05', number_helper.number_to_delimited(12345678.05, :separator => ',', :delimiter => '.')
+ assert_equal '12.345.678,05', number_helper.number_to_delimited(12345678.05, :delimiter => '.', :separator => ',')
+ end
+ end
+
+ def test_to_rounded
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal("-111.235", number_helper.number_to_rounded(-111.2346))
+ assert_equal("111.235", number_helper.number_to_rounded(111.2346))
+ assert_equal("31.83", number_helper.number_to_rounded(31.825, :precision => 2))
+ assert_equal("111.23", number_helper.number_to_rounded(111.2346, :precision => 2))
+ assert_equal("111.00", number_helper.number_to_rounded(111, :precision => 2))
+ assert_equal("111.235", number_helper.number_to_rounded("111.2346"))
+ assert_equal("31.83", number_helper.number_to_rounded("31.825", :precision => 2))
+ assert_equal("3268", number_helper.number_to_rounded((32.6751 * 100.00), :precision => 0))
+ assert_equal("112", number_helper.number_to_rounded(111.50, :precision => 0))
+ assert_equal("1234567892", number_helper.number_to_rounded(1234567891.50, :precision => 0))
+ assert_equal("0", number_helper.number_to_rounded(0, :precision => 0))
+ assert_equal("0.00100", number_helper.number_to_rounded(0.001, :precision => 5))
+ assert_equal("0.001", number_helper.number_to_rounded(0.00111, :precision => 3))
+ assert_equal("10.00", number_helper.number_to_rounded(9.995, :precision => 2))
+ assert_equal("11.00", number_helper.number_to_rounded(10.995, :precision => 2))
+ assert_equal("0.00", number_helper.number_to_rounded(-0.001, :precision => 2))
+ end
+ end
+
+ def test_to_rounded_with_custom_delimiter_and_separator
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '31,83', number_helper.number_to_rounded(31.825, :precision => 2, :separator => ',')
+ assert_equal '1.231,83', number_helper.number_to_rounded(1231.825, :precision => 2, :separator => ',', :delimiter => '.')
+ end
+ end
+
+ def test_to_rounded_with_significant_digits
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal "124000", number_helper.number_to_rounded(123987, :precision => 3, :significant => true)
+ assert_equal "120000000", number_helper.number_to_rounded(123987876, :precision => 2, :significant => true )
+ assert_equal "40000", number_helper.number_to_rounded("43523", :precision => 1, :significant => true )
+ assert_equal "9775", number_helper.number_to_rounded(9775, :precision => 4, :significant => true )
+ assert_equal "5.4", number_helper.number_to_rounded(5.3923, :precision => 2, :significant => true )
+ assert_equal "5", number_helper.number_to_rounded(5.3923, :precision => 1, :significant => true )
+ assert_equal "1", number_helper.number_to_rounded(1.232, :precision => 1, :significant => true )
+ assert_equal "7", number_helper.number_to_rounded(7, :precision => 1, :significant => true )
+ assert_equal "1", number_helper.number_to_rounded(1, :precision => 1, :significant => true )
+ assert_equal "53", number_helper.number_to_rounded(52.7923, :precision => 2, :significant => true )
+ assert_equal "9775.00", number_helper.number_to_rounded(9775, :precision => 6, :significant => true )
+ assert_equal "5.392900", number_helper.number_to_rounded(5.3929, :precision => 7, :significant => true )
+ assert_equal "0.0", number_helper.number_to_rounded(0, :precision => 2, :significant => true )
+ assert_equal "0", number_helper.number_to_rounded(0, :precision => 1, :significant => true )
+ assert_equal "0.0001", number_helper.number_to_rounded(0.0001, :precision => 1, :significant => true )
+ assert_equal "0.000100", number_helper.number_to_rounded(0.0001, :precision => 3, :significant => true )
+ assert_equal "0.0001", number_helper.number_to_rounded(0.0001111, :precision => 1, :significant => true )
+ assert_equal "10.0", number_helper.number_to_rounded(9.995, :precision => 3, :significant => true)
+ assert_equal "9.99", number_helper.number_to_rounded(9.994, :precision => 3, :significant => true)
+ assert_equal "11.0", number_helper.number_to_rounded(10.995, :precision => 3, :significant => true)
+ end
+ end
+
+ def test_to_rounded_with_strip_insignificant_zeros
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal "9775.43", number_helper.number_to_rounded(9775.43, :precision => 4, :strip_insignificant_zeros => true )
+ assert_equal "9775.2", number_helper.number_to_rounded(9775.2, :precision => 6, :significant => true, :strip_insignificant_zeros => true )
+ assert_equal "0", number_helper.number_to_rounded(0, :precision => 6, :significant => true, :strip_insignificant_zeros => true )
+ end
+ end
+
+ def test_to_rounded_with_significant_true_and_zero_precision
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ # Zero precision with significant is a mistake (would always return zero),
+ # so we treat it as if significant was false (increases backwards compatibility for number_to_human_size)
+ assert_equal "124", number_helper.number_to_rounded(123.987, :precision => 0, :significant => true)
+ assert_equal "12", number_helper.number_to_rounded(12, :precision => 0, :significant => true )
+ assert_equal "12", number_helper.number_to_rounded("12.3", :precision => 0, :significant => true )
+ end
+ end
+
+ def test_number_number_to_human_size
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '0 Bytes', number_helper.number_to_human_size(0)
+ assert_equal '1 Byte', number_helper.number_to_human_size(1)
+ assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265)
+ assert_equal '123 Bytes', number_helper.number_to_human_size(123.0)
+ assert_equal '123 Bytes', number_helper.number_to_human_size(123)
+ assert_equal '1.21 KB', number_helper.number_to_human_size(1234)
+ assert_equal '12.1 KB', number_helper.number_to_human_size(12345)
+ assert_equal '1.18 MB', number_helper.number_to_human_size(1234567)
+ assert_equal '1.15 GB', number_helper.number_to_human_size(1234567890)
+ assert_equal '1.12 TB', number_helper.number_to_human_size(1234567890123)
+ assert_equal '1030 TB', number_helper.number_to_human_size(terabytes(1026))
+ assert_equal '444 KB', number_helper.number_to_human_size(kilobytes(444))
+ assert_equal '1020 MB', number_helper.number_to_human_size(megabytes(1023))
+ assert_equal '3 TB', number_helper.number_to_human_size(terabytes(3))
+ assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2)
+ assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :precision => 4)
+ assert_equal '123 Bytes', number_helper.number_to_human_size('123')
+ assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2)
+ assert_equal '1.01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4)
+ assert_equal '10 KB', number_helper.number_to_human_size(kilobytes(10.000), :precision => 4)
+ assert_equal '1 Byte', number_helper.number_to_human_size(1.1)
+ assert_equal '10 Bytes', number_helper.number_to_human_size(10)
+ end
+ end
+
+ def test_number_to_human_size_with_si_prefix
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :prefix => :si)
+ assert_equal '123 Bytes', number_helper.number_to_human_size(123.0, :prefix => :si)
+ assert_equal '123 Bytes', number_helper.number_to_human_size(123, :prefix => :si)
+ assert_equal '1.23 KB', number_helper.number_to_human_size(1234, :prefix => :si)
+ assert_equal '12.3 KB', number_helper.number_to_human_size(12345, :prefix => :si)
+ assert_equal '1.23 MB', number_helper.number_to_human_size(1234567, :prefix => :si)
+ assert_equal '1.23 GB', number_helper.number_to_human_size(1234567890, :prefix => :si)
+ assert_equal '1.23 TB', number_helper.number_to_human_size(1234567890123, :prefix => :si)
+ end
+ end
+
+ def test_number_to_human_size_with_options_hash
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2)
+ assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :precision => 4)
+ assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2)
+ assert_equal '1.01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4)
+ assert_equal '10 KB', number_helper.number_to_human_size(kilobytes(10.000), :precision => 4)
+ assert_equal '1 TB', number_helper.number_to_human_size(1234567890123, :precision => 1)
+ assert_equal '500 MB', number_helper.number_to_human_size(524288000, :precision=>3)
+ assert_equal '10 MB', number_helper.number_to_human_size(9961472, :precision=>0)
+ assert_equal '40 KB', number_helper.number_to_human_size(41010, :precision => 1)
+ assert_equal '40 KB', number_helper.number_to_human_size(41100, :precision => 2)
+ assert_equal '1.0 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2, :strip_insignificant_zeros => false)
+ assert_equal '1.012 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 3, :significant => false)
+ assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 0, :significant => true) #ignores significant it precision is 0
+ end
+ end
+
+ def test_number_to_human_size_with_custom_delimiter_and_separator
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '1,01 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 3, :separator => ',')
+ assert_equal '1,01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4, :separator => ',')
+ assert_equal '1.000,1 TB', number_helper.number_to_human_size(terabytes(1000.1), :precision => 5, :delimiter => '.', :separator => ',')
+ end
+ end
+
+ def test_number_to_human
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '-123', number_helper.number_to_human(-123)
+ assert_equal '-0.5', number_helper.number_to_human(-0.5)
+ assert_equal '0', number_helper.number_to_human(0)
+ assert_equal '0.5', number_helper.number_to_human(0.5)
+ assert_equal '123', number_helper.number_to_human(123)
+ assert_equal '1.23 Thousand', number_helper.number_to_human(1234)
+ assert_equal '12.3 Thousand', number_helper.number_to_human(12345)
+ assert_equal '1.23 Million', number_helper.number_to_human(1234567)
+ assert_equal '1.23 Billion', number_helper.number_to_human(1234567890)
+ assert_equal '1.23 Trillion', number_helper.number_to_human(1234567890123)
+ assert_equal '1.23 Quadrillion', number_helper.number_to_human(1234567890123456)
+ assert_equal '1230 Quadrillion', number_helper.number_to_human(1234567890123456789)
+ assert_equal '490 Thousand', number_helper.number_to_human(489939, :precision => 2)
+ assert_equal '489.9 Thousand', number_helper.number_to_human(489939, :precision => 4)
+ assert_equal '489 Thousand', number_helper.number_to_human(489000, :precision => 4)
+ assert_equal '489.0 Thousand', number_helper.number_to_human(489000, :precision => 4, :strip_insignificant_zeros => false)
+ assert_equal '1.2346 Million', number_helper.number_to_human(1234567, :precision => 4, :significant => false)
+ assert_equal '1,2 Million', number_helper.number_to_human(1234567, :precision => 1, :significant => false, :separator => ',')
+ assert_equal '1 Million', number_helper.number_to_human(1234567, :precision => 0, :significant => true, :separator => ',') #significant forced to false
+ end
+ end
+
+ def test_number_to_human_with_custom_units
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ #Only integers
+ volume = {:unit => "ml", :thousand => "lt", :million => "m3"}
+ assert_equal '123 lt', number_helper.number_to_human(123456, :units => volume)
+ assert_equal '12 ml', number_helper.number_to_human(12, :units => volume)
+ assert_equal '1.23 m3', number_helper.number_to_human(1234567, :units => volume)
+
+ #Including fractionals
+ distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"}
+ assert_equal '1.23 mm', number_helper.number_to_human(0.00123, :units => distance)
+ assert_equal '1.23 cm', number_helper.number_to_human(0.0123, :units => distance)
+ assert_equal '1.23 dm', number_helper.number_to_human(0.123, :units => distance)
+ assert_equal '1.23 m', number_helper.number_to_human(1.23, :units => distance)
+ assert_equal '1.23 dam', number_helper.number_to_human(12.3, :units => distance)
+ assert_equal '1.23 hm', number_helper.number_to_human(123, :units => distance)
+ assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance)
+ assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance)
+ assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance)
+ assert_equal '12.3 km', number_helper.number_to_human(12300, :units => distance)
+
+ #The quantifiers don't need to be a continuous sequence
+ gangster = {:hundred => "hundred bucks", :million => "thousand quids"}
+ assert_equal '1 hundred bucks', number_helper.number_to_human(100, :units => gangster)
+ assert_equal '25 hundred bucks', number_helper.number_to_human(2500, :units => gangster)
+ assert_equal '25 thousand quids', number_helper.number_to_human(25000000, :units => gangster)
+ assert_equal '12300 thousand quids', number_helper.number_to_human(12345000000, :units => gangster)
+
+ #Spaces are stripped from the resulting string
+ assert_equal '4', number_helper.number_to_human(4, :units => {:unit => "", :ten => 'tens '})
+ assert_equal '4.5 tens', number_helper.number_to_human(45, :units => {:unit => "", :ten => ' tens '})
+ end
+ end
+
+ def test_number_to_human_with_custom_format
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal '123 times Thousand', number_helper.number_to_human(123456, :format => "%n times %u")
+ volume = {:unit => "ml", :thousand => "lt", :million => "m3"}
+ assert_equal '123.lt', number_helper.number_to_human(123456, :units => volume, :format => "%n.%u")
+ end
+ end
+
+ def test_number_helpers_should_return_nil_when_given_nil
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_nil number_helper.number_to_phone(nil)
+ assert_nil number_helper.number_to_currency(nil)
+ assert_nil number_helper.number_to_percentage(nil)
+ assert_nil number_helper.number_to_delimited(nil)
+ assert_nil number_helper.number_to_rounded(nil)
+ assert_nil number_helper.number_to_human_size(nil)
+ assert_nil number_helper.number_to_human(nil)
+ end
+ end
+
+ def test_number_helpers_do_not_mutate_options_hash
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ options = { 'raise' => true }
+
+ number_helper.number_to_phone(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_helper.number_to_currency(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_helper.number_to_percentage(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_helper.number_to_delimited(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_helper.number_to_rounded(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_helper.number_to_human_size(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_helper.number_to_human(1, options)
+ assert_equal({ 'raise' => true }, options)
+ end
+ end
+
+ def test_number_helpers_should_return_non_numeric_param_unchanged
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert_equal("+1-x x 123", number_helper.number_to_phone("x", :country_code => 1, :extension => 123))
+ assert_equal("x", number_helper.number_to_phone("x"))
+ assert_equal("$x.", number_helper.number_to_currency("x."))
+ assert_equal("$x", number_helper.number_to_currency("x"))
+ assert_equal("x%", number_helper.number_to_percentage("x"))
+ assert_equal("x", number_helper.number_to_delimited("x"))
+ assert_equal("x.", number_helper.number_to_rounded("x."))
+ assert_equal("x", number_helper.number_to_rounded("x"))
+ assert_equal "x", number_helper.number_to_human_size('x')
+ assert_equal "x", number_helper.number_to_human('x')
+ end
+ end
+
+ def test_extending_or_including_number_helper_correctly_hides_private_methods
+ [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper|
+ assert !number_helper.respond_to?(:valid_float?)
+ assert number_helper.respond_to?(:valid_float?, true)
+ end
+ end
+
+ end
+ end
+end
diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb
index e5b5547478..c02bfa8497 100644
--- a/activesupport/test/test_case_test.rb
+++ b/activesupport/test/test_case_test.rb
@@ -18,11 +18,9 @@ module ActiveSupport
end
end
- def test_callback_with_exception
+ def test_standard_error_raised_within_setup_callback_is_puked
tc = Class.new(TestCase) do
- def self.name
- nil
- end
+ def self.name; nil; end
setup :bad_callback
def bad_callback; raise 'oh noes' end
@@ -41,11 +39,9 @@ module ActiveSupport
assert_equal 'oh noes', exception.message
end
- def test_teardown_callback_with_exception
+ def test_standard_error_raised_within_teardown_callback_is_puked
tc = Class.new(TestCase) do
- def self.name
- nil
- end
+ def self.name; nil; end
teardown :bad_callback
def bad_callback; raise 'oh noes' end
@@ -63,5 +59,51 @@ module ActiveSupport
assert_equal test_name, name
assert_equal 'oh noes', exception.message
end
+
+ def test_passthrough_exception_raised_within_test_method_is_not_rescued
+ tc = Class.new(TestCase) do
+ def self.name; nil; end
+
+ def test_which_raises_interrupt; raise Interrupt; end
+ end
+
+ test_name = 'test_which_raises_interrupt'
+ fr = FakeRunner.new
+
+ test = tc.new test_name
+ assert_raises(Interrupt) { test.run fr }
+ end
+
+ def test_passthrough_exception_raised_within_setup_callback_is_not_rescued
+ tc = Class.new(TestCase) do
+ def self.name; nil; end
+
+ setup :callback_which_raises_interrupt
+ def callback_which_raises_interrupt; raise Interrupt; end
+ def test_true; assert true end
+ end
+
+ test_name = 'test_true'
+ fr = FakeRunner.new
+
+ test = tc.new test_name
+ assert_raises(Interrupt) { test.run fr }
+ end
+
+ def test_passthrough_exception_raised_within_teardown_callback_is_not_rescued
+ tc = Class.new(TestCase) do
+ def self.name; nil; end
+
+ teardown :callback_which_raises_interrupt
+ def callback_which_raises_interrupt; raise Interrupt; end
+ def test_true; assert true end
+ end
+
+ test_name = 'test_true'
+ fr = FakeRunner.new
+
+ test = tc.new test_name
+ assert_raises(Interrupt) { test.run fr }
+ end
end
end
diff --git a/activesupport/test/testing/performance_test.rb b/activesupport/test/testing/performance_test.rb
new file mode 100644
index 0000000000..74d7dae9e7
--- /dev/null
+++ b/activesupport/test/testing/performance_test.rb
@@ -0,0 +1,40 @@
+require 'abstract_unit'
+require 'active_support/testing/performance'
+
+
+module ActiveSupport
+ module Testing
+ class PerformanceTest < ActiveSupport::TestCase
+ def test_amount_format
+ amount_metric = ActiveSupport::Testing::Performance::Metrics[:amount].new
+ assert_equal "0", amount_metric.format(0)
+ assert_equal "1", amount_metric.format(1.23)
+ assert_equal "40,000,000", amount_metric.format(40000000)
+ end
+
+ def test_time_format
+ time_metric = ActiveSupport::Testing::Performance::Metrics[:time].new
+ assert_equal "0 ms", time_metric.format(0)
+ assert_equal "40 ms", time_metric.format(0.04)
+ assert_equal "41 ms", time_metric.format(0.0415)
+ assert_equal "1.23 sec", time_metric.format(1.23)
+ assert_equal "40000.00 sec", time_metric.format(40000)
+ assert_equal "-5000 ms", time_metric.format(-5)
+ end
+
+ def test_space_format
+ space_metric = ActiveSupport::Testing::Performance::Metrics[:digital_information_unit].new
+ assert_equal "0 Bytes", space_metric.format(0)
+ assert_equal "0 Bytes", space_metric.format(0.4)
+ assert_equal "1 Byte", space_metric.format(1.23)
+ assert_equal "123 Bytes", space_metric.format(123)
+ assert_equal "123 Bytes", space_metric.format(123.45)
+ assert_equal "12 KB", space_metric.format(12345)
+ assert_equal "1.2 MB", space_metric.format(1234567)
+ assert_equal "9.3 GB", space_metric.format(10**10)
+ assert_equal "91 TB", space_metric.format(10**14)
+ assert_equal "910000 TB", space_metric.format(10**18)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/ts_isolated.rb b/activesupport/test/ts_isolated.rb
index 938bb4ee99..2c217157d3 100644
--- a/activesupport/test/ts_isolated.rb
+++ b/activesupport/test/ts_isolated.rb
@@ -10,7 +10,7 @@ class TestIsolated < ActiveSupport::TestCase
define_method("test #{file}") do
command = "#{ruby} -Ilib:test #{file}"
result = silence_stderr { `#{command}` }
- assert_block("#{command}\n#{result}") { $?.to_i.zero? }
+ assert $?.to_i.zero?, "#{command}\n#{result}"
end
end
end