aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG.md29
-rw-r--r--activesupport/activesupport.gemspec1
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/basic_object.rb17
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/date/zones.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/zones.rb13
-rw-r--r--activesupport/lib/active_support/core_ext/thread.rb70
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb12
-rw-r--r--activesupport/lib/active_support/dependencies.rb3
-rw-r--r--activesupport/lib/active_support/deprecation/proxy_wrappers.rb2
-rw-r--r--activesupport/lib/active_support/duration.rb4
-rw-r--r--activesupport/lib/active_support/inflector/inflections.rb6
-rw-r--r--activesupport/lib/active_support/json/encoding.rb8
-rw-r--r--activesupport/lib/active_support/key_generator.rb8
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb7
-rw-r--r--activesupport/lib/active_support/proxy_object.rb13
-rw-r--r--activesupport/lib/active_support/time.rb21
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb2
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb2
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb10
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb2
-rw-r--r--activesupport/test/core_ext/duration_test.rb4
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb50
-rw-r--r--activesupport/test/core_ext/thread_test.rb77
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb64
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb128
-rw-r--r--activesupport/test/deprecation/basic_object_test.rb12
-rw-r--r--activesupport/test/json/encoding_test.rb19
34 files changed, 515 insertions, 113 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 450669968b..5e7121181d 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,4 +1,27 @@
## Rails 4.0.0 (unreleased) ##
+* Remove surrogate unicode character encoding from ActiveSupport::JSON.encode
+ The encoding scheme was broken for unicode characters outside the basic multilingual plane;
+ since json is assumed to be UTF-8, and we already force the encoding to UTF-8 simply pass through
+ the un-encoded characters.
+
+ *Brett Carter*
+
+* Deprecate `Time.time_with_date_fallback`, `Time.utc_time` and `Time.local_time`.
+ These methods were added to handle the limited range of Ruby's native Time
+ implementation. Those limitations no longer apply so we are deprecating them in 4.0
+ and they will be removed in 4.1.
+
+ *Andrew White*
+
+* Deprecate `Date#to_time_in_current_zone` and add `Date#in_time_zone`. *Andrew White*
+
+* Add `String#in_time_zone` method to convert a string to an ActiveSupport::TimeWithZone. *Andrew White*
+
+* Deprecate `ActiveSupport::BasicObject` in favor of `ActiveSupport::ProxyObject`.
+ This class is used for proxy classes. It avoids confusion with Ruby's BasicObject
+ class.
+
+ *Francesco Rodriguez*
* Patched Marshal#load to work with constant autoloading.
Fixes autoloading with cache stores that relay on Marshal(MemCacheStore and FileStore). [fixes #8167]
@@ -63,7 +86,7 @@
* Hash#extract! returns only those keys that present in the receiver.
- {:a => 1, :b => 2}.extract!(:a, :x) # => {:a => 1}
+ {a: 1, b: 2}.extract!(:a, :x) # => {:a => 1}
*Mikhail Dieterle*
@@ -141,7 +164,7 @@
You can choose which instance of the deprecator will be used.
- deprecate :method_name, :deprecator => deprecator_instance
+ deprecate :method_name, deprecator: deprecator_instance
You can use ActiveSupport::Deprecation in your gem.
@@ -159,7 +182,7 @@
def new_method
end
- deprecate :old_method => :new_method, :deprecator => deprecator
+ deprecate old_method: :new_method, deprecator: deprecator
end
MyGem.new.old_method
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index a4216d2cb4..4c9e59dbd2 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -24,4 +24,5 @@ Gem::Specification.new do |s|
s.add_dependency 'multi_json', '~> 1.3'
s.add_dependency 'tzinfo', '~> 0.3.33'
s.add_dependency 'minitest', '~> 4.1'
+ s.add_dependency 'thread_safe','~> 0.1'
end
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 4e397ea110..b602686114 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -40,6 +40,7 @@ module ActiveSupport
eager_autoload do
autoload :BacktraceCleaner
autoload :BasicObject
+ autoload :ProxyObject
autoload :Benchmarkable
autoload :Cache
autoload :Callbacks
diff --git a/activesupport/lib/active_support/basic_object.rb b/activesupport/lib/active_support/basic_object.rb
index 6ccb0cd525..d4d06b2aa4 100644
--- a/activesupport/lib/active_support/basic_object.rb
+++ b/activesupport/lib/active_support/basic_object.rb
@@ -1,13 +1,12 @@
-module ActiveSupport
- # A class with no predefined methods that behaves similarly to Builder's
- # BlankSlate. Used for proxy classes.
- class BasicObject < ::BasicObject
- undef_method :==
- undef_method :equal?
+require 'active_support/deprecation'
+require 'active_support/proxy_object'
- # Let ActiveSupport::BasicObject at least raise exceptions.
- def raise(*args)
- ::Object.send(:raise, *args)
+module ActiveSupport
+ # :nodoc:
+ class BasicObject < ProxyObject
+ def self.inherited(*)
+ ::ActiveSupport::Deprecation.warn 'ActiveSupport::BasicObject is deprecated! Use ActiveSupport::ProxyObject instead.'
+ super
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb
index 1c3d26ead4..1504e18839 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute.rb
@@ -72,6 +72,9 @@ class Class
instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
+ # We use class_eval here rather than define_method because class_attribute
+ # may be used in a performance sensitive context therefore the overhead that
+ # define_method introduces may become significant.
attrs.each do |name|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.#{name}() nil end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 439d380af7..421aa12100 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -53,19 +53,19 @@ class Date
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
# and then subtracts the specified number of seconds.
def ago(seconds)
- to_time_in_current_zone.since(-seconds)
+ in_time_zone.since(-seconds)
end
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
# and then adds the specified number of seconds
def since(seconds)
- to_time_in_current_zone.since(seconds)
+ in_time_zone.since(seconds)
end
alias :in :since
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
def beginning_of_day
- to_time_in_current_zone
+ in_time_zone
end
alias :midnight :beginning_of_day
alias :at_midnight :beginning_of_day
@@ -73,8 +73,9 @@ class Date
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)
def end_of_day
- to_time_in_current_zone.end_of_day
+ in_time_zone.end_of_day
end
+ alias :at_end_of_day :end_of_day
def plus_with_duration(other) #:nodoc:
if ActiveSupport::Duration === other
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 9120b0ba49..fe08ade7e0 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -75,10 +75,10 @@ class Date
#
# date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
def to_time(form = :local)
- ::Time.send("#{form}_time", year, month, day)
+ ::Time.send(form, year, month, day)
end
def xmlschema
- to_time_in_current_zone.xmlschema
+ in_time_zone.xmlschema
end
end
diff --git a/activesupport/lib/active_support/core_ext/date/zones.rb b/activesupport/lib/active_support/core_ext/date/zones.rb
index c1b3934722..b4548671bf 100644
--- a/activesupport/lib/active_support/core_ext/date/zones.rb
+++ b/activesupport/lib/active_support/core_ext/date/zones.rb
@@ -2,14 +2,36 @@ require 'date'
require 'active_support/core_ext/time/zones'
class Date
+ # *DEPRECATED*: Use +Date#in_time_zone+ instead.
+ #
# Converts Date to a TimeWithZone in the current zone if <tt>Time.zone</tt> or
# <tt>Time.zone_default</tt> is set, otherwise converts Date to a Time via
# Date#to_time.
def to_time_in_current_zone
+ ActiveSupport::Deprecation.warn 'Date#to_time_in_current_zone is deprecated. Use Date#in_time_zone instead', caller
+
if ::Time.zone
::Time.zone.local(year, month, day)
else
to_time
end
end
+
+ # Converts Date to a TimeWithZone in the current zone if Time.zone or Time.zone_default
+ # is set, otherwise converts Date to a Time via Date#to_time
+ #
+ # Time.zone = 'Hawaii' # => 'Hawaii'
+ # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
+ #
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
+ # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
+ #
+ # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
+ def in_time_zone(zone = ::Time.zone)
+ if zone
+ ::Time.find_zone!(zone).local(year, month, day)
+ else
+ to_time
+ end
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index f77d444479..fca5d4d679 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -110,6 +110,7 @@ class DateTime
def end_of_day
change(:hour => 23, :min => 59, :sec => 59)
end
+ alias :at_end_of_day :end_of_day
# Returns a new DateTime representing the start of the hour (hh:00:00).
def beginning_of_hour
@@ -121,6 +122,7 @@ class DateTime
def end_of_hour
change(:min => 59, :sec => 59)
end
+ alias :at_end_of_hour :end_of_hour
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
#
diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb
index ad864765a3..5d7cb81e38 100644
--- a/activesupport/lib/active_support/core_ext/string.rb
+++ b/activesupport/lib/active_support/core_ext/string.rb
@@ -11,3 +11,4 @@ require 'active_support/core_ext/string/exclude'
require 'active_support/core_ext/string/strip'
require 'active_support/core_ext/string/inquiry'
require 'active_support/core_ext/string/indent'
+require 'active_support/core_ext/string/zones'
diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb
index 9b9d83932e..9d3b81cf38 100644
--- a/activesupport/lib/active_support/core_ext/string/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/string/conversions.rb
@@ -21,7 +21,7 @@ class String
date_values[6] *= 1000000
offset = date_values.pop
- ::Time.send("#{form}_time", *date_values) - offset
+ ::Time.send(form, *date_values) - offset
end
end
diff --git a/activesupport/lib/active_support/core_ext/string/zones.rb b/activesupport/lib/active_support/core_ext/string/zones.rb
new file mode 100644
index 0000000000..e3f20eee29
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/string/zones.rb
@@ -0,0 +1,13 @@
+require 'active_support/core_ext/time/zones'
+
+class String
+ # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default
+ # is set, otherwise converts String to a Time via String#to_time
+ def in_time_zone(zone = ::Time.zone)
+ if zone
+ ::Time.find_zone!(zone).parse(self)
+ else
+ to_time
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/thread.rb b/activesupport/lib/active_support/core_ext/thread.rb
new file mode 100644
index 0000000000..6ad0b2d69c
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/thread.rb
@@ -0,0 +1,70 @@
+class Thread
+ LOCK = Mutex.new # :nodoc:
+
+ # Returns the value of a thread local variable that has been set. Note that
+ # these are different than fiber local values.
+ #
+ # Thread local values are carried along with threads, and do not respect
+ # fibers. For example:
+ #
+ # Thread.new {
+ # Thread.current.thread_variable_set("foo", "bar") # set a thread local
+ # Thread.current["foo"] = "bar" # set a fiber local
+ #
+ # Fiber.new {
+ # Fiber.yield [
+ # Thread.current.thread_variable_get("foo"), # get the thread local
+ # Thread.current["foo"], # get the fiber local
+ # ]
+ # }.resume
+ # }.join.value # => ['bar', nil]
+ #
+ # The value <tt>"bar"</tt> is returned for the thread local, where +nil+ is returned
+ # for the fiber local. The fiber is executed in the same thread, so the
+ # thread local values are available.
+ def thread_variable_get(key)
+ locals[key.to_sym]
+ end
+
+ # Sets a thread local with +key+ to +value+. Note that these are local to
+ # threads, and not to fibers. Please see Thread#thread_variable_get for
+ # more information.
+ def thread_variable_set(key, value)
+ locals[key.to_sym] = value
+ end
+
+ # Returns an an array of the names of the thread-local variables (as Symbols).
+ #
+ # thr = Thread.new do
+ # Thread.current.thread_variable_set(:cat, 'meow')
+ # Thread.current.thread_variable_set("dog", 'woof')
+ # end
+ # thr.join #=> #<Thread:0x401b3f10 dead>
+ # thr.thread_variables #=> [:dog, :cat]
+ #
+ # Note that these are not fiber local variables. Please see Thread#thread_variable_get
+ # for more details.
+ def thread_variables
+ locals.keys
+ end
+
+ # Returns <tt>true</tt> if the given string (or symbol) exists as a
+ # thread-local variable.
+ #
+ # me = Thread.current
+ # me.thread_variable_set(:oliver, "a")
+ # me.thread_variable?(:oliver) #=> true
+ # me.thread_variable?(:stanley) #=> false
+ #
+ # Note that these are not fiber local variables. Please see Thread#thread_variable_get
+ # for more details.
+ def thread_variable?(key)
+ locals.has_key?(key.to_sym)
+ end
+
+ private
+
+ def locals
+ @locals || LOCK.synchronize { @locals ||= {} }
+ end
+end unless Thread.instance_methods.include?(:thread_variable_set)
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 46c9f05c15..1f95f62229 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/time/conversions'
require 'active_support/time_with_zone'
require 'active_support/core_ext/time/zones'
require 'active_support/core_ext/date_and_time/calculations'
+require 'active_support/deprecation'
class Time
include DateAndTime::Calculations
@@ -25,10 +26,13 @@ class Time
end
end
+ # *DEPRECATED*: Use +Time#utc+ or +Time#local+ instead.
+ #
# Returns a new Time if requested year can be accommodated by Ruby's Time class
# (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
# otherwise returns a DateTime.
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
+ ActiveSupport::Deprecation.warn 'time_with_datetime_fallback is deprecated. Use Time#utc or Time#local instead', caller
time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
# This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138.
@@ -41,13 +45,19 @@ class Time
::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
end
+ # *DEPRECATED*: Use +Time#utc+ instead.
+ #
# Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:utc</tt>.
def utc_time(*args)
+ ActiveSupport::Deprecation.warn 'utc_time is deprecated. Use Time#utc instead', caller
time_with_datetime_fallback(:utc, *args)
end
+ # *DEPRECATED*: Use +Time#local+ instead.
+ #
# Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:local</tt>.
def local_time(*args)
+ ActiveSupport::Deprecation.warn 'local_time is deprecated. Use Time#local instead', caller
time_with_datetime_fallback(:local, *args)
end
@@ -160,6 +170,7 @@ class Time
:usec => Rational(999999999, 1000)
)
end
+ alias :at_end_of_day :end_of_day
# Returns a new Time representing the start of the hour (x:00)
def beginning_of_hour
@@ -175,6 +186,7 @@ class Time
:usec => Rational(999999999, 1000)
)
end
+ alias :at_end_of_hour :end_of_hour
# Returns a Range representing the whole day of the current time.
def all_day
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index efd351d741..fff4c776a9 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -1,5 +1,6 @@
require 'set'
require 'thread'
+require 'thread_safe'
require 'pathname'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/attribute_accessors'
@@ -517,7 +518,7 @@ module ActiveSupport #:nodoc:
class ClassCache
def initialize
- @store = Hash.new
+ @store = ThreadSafe::Cache.new
end
def empty?
diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
index 17e69c34a5..485dc91063 100644
--- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
@@ -30,7 +30,7 @@ module ActiveSupport
# @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!")
# @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!", deprecator_instance)
#
- # When someone execute any method expect +inspect+ on proxy object this will
+ # When someone executes any method except +inspect+ on proxy object this will
# trigger +warn+ method on +deprecator_instance+.
#
# Default deprecator is <tt>ActiveSupport::Deprecation</tt>
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 7e99646117..2cb1f408b6 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -1,4 +1,4 @@
-require 'active_support/basic_object'
+require 'active_support/proxy_object'
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/object/acts_like'
@@ -7,7 +7,7 @@ module ActiveSupport
# Time#advance, respectively. It mainly supports the methods on Numeric.
#
# 1.month.ago # equivalent to Time.now.advance(months: -1)
- class Duration < BasicObject
+ class Duration < ProxyObject
attr_accessor :value, :parts
def initialize(value, parts) #:nodoc:
diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb
index 6f259a093b..9cf4b2b2ba 100644
--- a/activesupport/lib/active_support/inflector/inflections.rb
+++ b/activesupport/lib/active_support/inflector/inflections.rb
@@ -1,3 +1,4 @@
+require 'thread_safe'
require 'active_support/core_ext/array/prepend_and_append'
require 'active_support/i18n'
@@ -24,9 +25,10 @@ module ActiveSupport
# singularization rules that is runs. This guarantees that your rules run
# before any of the rules that may already have been loaded.
class Inflections
+ @__instance__ = ThreadSafe::Cache.new
+
def self.instance(locale = :en)
- @__instance__ ||= Hash.new { |h, k| h[k] = new }
- @__instance__[locale]
+ @__instance__[locale] ||= new
end
attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 7a5c351ca8..832d1ce6d5 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -129,13 +129,7 @@ module ActiveSupport
def escape(string)
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
- json = string.
- gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
- gsub(/([\xC0-\xDF][\x80-\xBF]|
- [\xE0-\xEF][\x80-\xBF]{2}|
- [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
- s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
- }
+ json = string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] }
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8)
json
diff --git a/activesupport/lib/active_support/key_generator.rb b/activesupport/lib/active_support/key_generator.rb
index 6beb2b6afa..71654dbb87 100644
--- a/activesupport/lib/active_support/key_generator.rb
+++ b/activesupport/lib/active_support/key_generator.rb
@@ -1,4 +1,4 @@
-require 'mutex_m'
+require 'thread_safe'
require 'openssl'
module ActiveSupport
@@ -28,16 +28,14 @@ module ActiveSupport
class CachingKeyGenerator
def initialize(key_generator)
@key_generator = key_generator
- @cache_keys = {}.extend(Mutex_m)
+ @cache_keys = ThreadSafe::Cache.new
end
# Returns a derived key suitable for use. The default key_size is chosen
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
# i.e. OpenSSL::Digest::SHA1#block_length
def generate_key(salt, key_size=64)
- @cache_keys.synchronize do
- @cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size)
- end
+ @cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size)
end
end
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index 2e5bcf4639..7588fdb67c 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -1,4 +1,5 @@
require 'mutex_m'
+require 'thread_safe'
module ActiveSupport
module Notifications
@@ -11,7 +12,7 @@ module ActiveSupport
def initialize
@subscribers = []
- @listeners_for = {}
+ @listeners_for = ThreadSafe::Cache.new
super
end
@@ -44,7 +45,9 @@ module ActiveSupport
end
def listeners_for(name)
- synchronize do
+ # this is correctly done double-checked locking (ThreadSafe::Cache's lookups have volatile semantics)
+ @listeners_for[name] || synchronize do
+ # use synchronisation when accessing @subscribers
@listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
end
end
diff --git a/activesupport/lib/active_support/proxy_object.rb b/activesupport/lib/active_support/proxy_object.rb
new file mode 100644
index 0000000000..a2bdf1d790
--- /dev/null
+++ b/activesupport/lib/active_support/proxy_object.rb
@@ -0,0 +1,13 @@
+module ActiveSupport
+ # A class with no predefined methods that behaves similarly to Builder's
+ # BlankSlate. Used for proxy classes.
+ class ProxyObject < ::BasicObject
+ undef_method :==
+ undef_method :equal?
+
+ # Let ActiveSupport::BasicObject at least raise exceptions.
+ def raise(*args)
+ ::Object.send(:raise, *args)
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/time.rb b/activesupport/lib/active_support/time.rb
index bcd5d78b54..92a593965e 100644
--- a/activesupport/lib/active_support/time.rb
+++ b/activesupport/lib/active_support/time.rb
@@ -9,21 +9,12 @@ end
require 'date'
require 'time'
-require 'active_support/core_ext/time/marshal'
-require 'active_support/core_ext/time/acts_like'
-require 'active_support/core_ext/time/calculations'
-require 'active_support/core_ext/time/conversions'
-require 'active_support/core_ext/time/zones'
-
-require 'active_support/core_ext/date/acts_like'
-require 'active_support/core_ext/date/calculations'
-require 'active_support/core_ext/date/conversions'
-require 'active_support/core_ext/date/zones'
-
-require 'active_support/core_ext/date_time/acts_like'
-require 'active_support/core_ext/date_time/calculations'
-require 'active_support/core_ext/date_time/conversions'
-require 'active_support/core_ext/date_time/zones'
+require 'active_support/core_ext/time'
+require 'active_support/core_ext/date'
+require 'active_support/core_ext/date_time'
require 'active_support/core_ext/integer/time'
require 'active_support/core_ext/numeric/time'
+
+require 'active_support/core_ext/string/conversions'
+require 'active_support/core_ext/string/zones'
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index b931de3fac..0dbc198ea2 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -344,7 +344,7 @@ 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?(:nsec) ? Rational(time.nsec, 1000) : 0)
+ ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec, Rational(time.nsec, 1000))
end
def duration_of_variable_length?(obj)
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index d087955587..c5fbddcb5f 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -252,7 +252,7 @@ module ActiveSupport
# Time.zone = 'Hawaii' # => "Hawaii"
# Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
def local(*args)
- time = Time.utc_time(*args)
+ time = Time.utc(*args)
ActiveSupport::TimeWithZone.new(nil, self, time)
end
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 7ae1f67785..5e89a6e00b 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -34,7 +34,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
def test_to_time
assert_equal Time.local(2005, 2, 21), Date.new(2005, 2, 21).to_time
- assert_equal Time.local_time(2039, 2, 21), Date.new(2039, 2, 21).to_time
+ assert_equal Time.local(2039, 2, 21), Date.new(2039, 2, 21).to_time
silence_warnings do
0.upto(138) do |year|
[:utc, :local].each do |format|
@@ -354,3 +354,11 @@ class DateExtBehaviorTest < ActiveSupport::TestCase
end
end
end
+
+class DateExtConversionsTest < ActiveSupport::TestCase
+ def test_to_time_in_current_zone_is_deprecated
+ assert_deprecated(/to_time_in_current_zone/) do
+ Date.new(2012,6,7).to_time_in_current_zone
+ end
+ end
+end
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 3353465c1c..dfad3a90f8 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -42,7 +42,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
def test_to_time
assert_equal Time.utc(2005, 2, 21, 10, 11, 12), DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time
- assert_equal Time.utc_time(2039, 2, 21, 10, 11, 12), DateTime.new(2039, 2, 21, 10, 11, 12, 0).to_time
+ assert_equal Time.utc(2039, 2, 21, 10, 11, 12), DateTime.new(2039, 2, 21, 10, 11, 12, 0).to_time
# DateTimes with offsets other than 0 are returned unaltered
assert_equal DateTime.new(2005, 2, 21, 10, 11, 12, Rational(-5, 24)), DateTime.new(2005, 2, 21, 10, 11, 12, Rational(-5, 24)).to_time
# Fractional seconds are preserved
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index c8312aa653..2826f51f2d 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -21,7 +21,7 @@ class DurationTest < ActiveSupport::TestCase
assert ActiveSupport::Duration === 1.day
assert !(ActiveSupport::Duration === 1.day.to_i)
assert !(ActiveSupport::Duration === 'foo')
- assert !(ActiveSupport::Duration === ActiveSupport::BasicObject.new)
+ assert !(ActiveSupport::Duration === ActiveSupport::ProxyObject.new)
end
def test_equals
@@ -131,7 +131,7 @@ class DurationTest < ActiveSupport::TestCase
assert_equal Time.local(2009,3,29,0,0,0) + 1.day, Time.local(2009,3,30,0,0,0)
end
end
-
+
def test_delegation_with_block_works
counter = 0
assert_nothing_raised do
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 6720ed42f0..fa8839bcb3 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -161,30 +161,6 @@ class StringInflectionsTest < ActiveSupport::TestCase
assert_equal 97, 'abc'.ord
end
- def test_string_to_time
- assert_equal Time.utc(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time
- assert_equal Time.local(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time(:local)
- assert_equal Time.utc(2005, 2, 27, 23, 50, 19, 275038), "2005-02-27T23:50:19.275038".to_time
- assert_equal Time.local(2005, 2, 27, 23, 50, 19, 275038), "2005-02-27T23:50:19.275038".to_time(:local)
- assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time
- assert_equal Time.local_time(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time(:local)
- assert_equal Time.utc(2011, 2, 27, 23, 50), "2011-02-27 22:50 -0100".to_time
- assert_nil "".to_time
- end
-
- def test_string_to_datetime
- assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_datetime
- assert_equal 0, "2039-02-27 23:50".to_datetime.offset # use UTC offset
- assert_equal ::Date::ITALY, "2039-02-27 23:50".to_datetime.start # use Ruby's default start value
- assert_equal DateTime.civil(2039, 2, 27, 23, 50, 19 + Rational(275038, 1000000), "-04:00"), "2039-02-27T23:50:19.275038-04:00".to_datetime
- assert_nil "".to_datetime
- end
-
- def test_string_to_date
- assert_equal Date.new(2005, 2, 27), "2005-02-27".to_date
- assert_nil "".to_date
- end
-
def test_access
s = "hello"
assert_equal "h", s.at(0)
@@ -308,6 +284,32 @@ class StringInflectionsTest < ActiveSupport::TestCase
end
end
+class StringConversionsTest < ActiveSupport::TestCase
+ def test_string_to_time
+ assert_equal Time.utc(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time
+ assert_equal Time.local(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time(:local)
+ assert_equal Time.utc(2005, 2, 27, 23, 50, 19, 275038), "2005-02-27T23:50:19.275038".to_time
+ assert_equal Time.local(2005, 2, 27, 23, 50, 19, 275038), "2005-02-27T23:50:19.275038".to_time(:local)
+ assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time
+ assert_equal Time.local(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time(:local)
+ assert_equal Time.utc(2011, 2, 27, 23, 50), "2011-02-27 22:50 -0100".to_time
+ assert_nil "".to_time
+ end
+
+ def test_string_to_datetime
+ assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_datetime
+ assert_equal 0, "2039-02-27 23:50".to_datetime.offset # use UTC offset
+ assert_equal ::Date::ITALY, "2039-02-27 23:50".to_datetime.start # use Ruby's default start value
+ assert_equal DateTime.civil(2039, 2, 27, 23, 50, 19 + Rational(275038, 1000000), "-04:00"), "2039-02-27T23:50:19.275038-04:00".to_datetime
+ assert_nil "".to_datetime
+ end
+
+ def test_string_to_date
+ assert_equal Date.new(2005, 2, 27), "2005-02-27".to_date
+ assert_nil "".to_date
+ end
+end
+
class StringBehaviourTest < ActiveSupport::TestCase
def test_acts_like_string
assert 'Bambi'.acts_like_string?
diff --git a/activesupport/test/core_ext/thread_test.rb b/activesupport/test/core_ext/thread_test.rb
new file mode 100644
index 0000000000..b58f59a8d4
--- /dev/null
+++ b/activesupport/test/core_ext/thread_test.rb
@@ -0,0 +1,77 @@
+require 'abstract_unit'
+require 'active_support/core_ext/thread'
+
+class ThreadExt < ActiveSupport::TestCase
+ def test_main_thread_variable_in_enumerator
+ assert_equal Thread.main, Thread.current
+
+ Thread.current.thread_variable_set :foo, "bar"
+
+ thread, value = Fiber.new {
+ Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)]
+ }.resume
+
+ assert_equal Thread.current, thread
+ assert_equal Thread.current.thread_variable_get(:foo), value
+ end
+
+ def test_thread_variable_in_enumerator
+ Thread.new {
+ Thread.current.thread_variable_set :foo, "bar"
+
+ thread, value = Fiber.new {
+ Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)]
+ }.resume
+
+ assert_equal Thread.current, thread
+ assert_equal Thread.current.thread_variable_get(:foo), value
+ }.join
+ end
+
+ def test_thread_variables
+ assert_equal [], Thread.new { Thread.current.thread_variables }.join.value
+
+ t = Thread.new {
+ Thread.current.thread_variable_set(:foo, "bar")
+ Thread.current.thread_variables
+ }
+ assert_equal [:foo], t.join.value
+ end
+
+ def test_thread_variable?
+ refute Thread.new { Thread.current.thread_variable?("foo") }.join.value
+ t = Thread.new {
+ Thread.current.thread_variable_set("foo", "bar")
+ }.join
+
+ assert t.thread_variable?("foo")
+ assert t.thread_variable?(:foo)
+ refute t.thread_variable?(:bar)
+ end
+
+ def test_thread_variable_strings_and_symbols_are_the_same_key
+ t = Thread.new {}.join
+ t.thread_variable_set("foo", "bar")
+ assert_equal "bar", t.thread_variable_get(:foo)
+ end
+
+ def test_thread_variable_frozen
+ t = Thread.new { }.join
+ t.freeze
+ assert_raises(RuntimeError) do
+ t.thread_variable_set(:foo, "bar")
+ end
+ end
+
+ def test_thread_variable_security
+ t = Thread.new { sleep }
+
+ assert_raises(SecurityError) do
+ Thread.new { $SAFE = 4; t.thread_variable_get(:foo) }.join
+ end
+
+ assert_raises(SecurityError) do
+ Thread.new { $SAFE = 4; t.thread_variable_set(:foo, :baz) }.join
+ end
+ end
+end
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 0e75104fc6..70e07cefd1 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -567,45 +567,57 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
def test_time_with_datetime_fallback
- assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
- assert_equal Time.time_with_datetime_fallback(:local, 2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
- assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0)
- assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30)
- assert_equal Time.time_with_datetime_fallback(:utc, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, 0)
- assert_equal Time.time_with_datetime_fallback(:utc, 2005), Time.utc(2005)
- assert_equal Time.time_with_datetime_fallback(:utc, 2039), DateTime.civil(2039, 1, 1, 0, 0, 0, 0)
- assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30, 1), Time.utc(2005, 2, 21, 17, 44, 30, 1) #with usec
- # This won't overflow on 64bit linux
- unless time_is_64bits?
- assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1900, 2, 21, 17, 44, 30)
- assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1),
- DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
- assert_equal ::Date::ITALY, Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).start # use Ruby's default start value
- end
- silence_warnings do
- 0.upto(138) do |year|
- [:utc, :local].each do |format|
- assert_equal year, Time.time_with_datetime_fallback(format, year).year
+ ActiveSupport::Deprecation.silence do
+ assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.time_with_datetime_fallback(:local, 2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0)
+ assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30)
+ assert_equal Time.time_with_datetime_fallback(:utc, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, 0)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2005), Time.utc(2005)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2039), DateTime.civil(2039, 1, 1, 0, 0, 0, 0)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30, 1), Time.utc(2005, 2, 21, 17, 44, 30, 1) #with usec
+ # This won't overflow on 64bit linux
+ unless time_is_64bits?
+ assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1900, 2, 21, 17, 44, 30)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1),
+ DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
+ assert_equal ::Date::ITALY, Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).start # use Ruby's default start value
+ end
+ silence_warnings do
+ 0.upto(138) do |year|
+ [:utc, :local].each do |format|
+ assert_equal year, Time.time_with_datetime_fallback(format, year).year
+ end
end
end
end
end
def test_utc_time
- assert_equal Time.utc_time(2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
- assert_equal Time.utc_time(2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0)
- assert_equal Time.utc_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, 0)
+ ActiveSupport::Deprecation.silence do
+ assert_equal Time.utc_time(2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.utc_time(2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0)
+ assert_equal Time.utc_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, 0)
+ end
end
def test_local_time
- assert_equal Time.local_time(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
- assert_equal Time.local_time(2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30)
+ ActiveSupport::Deprecation.silence do
+ assert_equal Time.local_time(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.local_time(2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30)
- unless time_is_64bits?
- assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1901, 2, 21, 17, 44, 30)
+ unless time_is_64bits?
+ assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1901, 2, 21, 17, 44, 30)
+ end
end
end
+ def test_time_with_datetime_fallback_deprecations
+ assert_deprecated(/time_with_datetime_fallback/) { Time.time_with_datetime_fallback(:utc, 2012, 6, 7) }
+ assert_deprecated(/utc_time/) { Time.utc_time(2012, 6, 7) }
+ assert_deprecated(/local_time/) { Time.local_time(2012, 6, 7) }
+ end
+
def test_last_month_on_31st
assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).last_month
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index 1293f104e5..56020da035 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -953,3 +953,131 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
end
end
+
+class TimeWithZoneMethodsForDate < ActiveSupport::TestCase
+ def setup
+ @d = Date.civil(2000)
+ end
+
+ def teardown
+ Time.zone = nil
+ end
+
+ def test_in_time_zone
+ with_tz_default 'Alaska' do
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone.inspect
+ end
+ with_tz_default 'Hawaii' do
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @d.in_time_zone.inspect
+ end
+ with_tz_default nil do
+ assert_equal @d.to_time, @d.in_time_zone
+ end
+ end
+
+ def test_nil_time_zone
+ with_tz_default nil do
+ assert !@d.in_time_zone.respond_to?(:period), 'no period method'
+ end
+ end
+
+ def test_in_time_zone_with_argument
+ with_tz_default 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone)
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone('Alaska').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @d.in_time_zone('Hawaii').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @d.in_time_zone('UTC').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone(-9.hours).inspect
+ end
+ end
+
+ def test_in_time_zone_with_invalid_argument
+ assert_raise(ArgumentError) { @d.in_time_zone("No such timezone exists") }
+ assert_raise(ArgumentError) { @d.in_time_zone(-15.hours) }
+ assert_raise(ArgumentError) { @d.in_time_zone(Object.new) }
+ end
+
+ protected
+ def with_tz_default(tz = nil)
+ old_tz = Time.zone
+ Time.zone = tz
+ yield
+ ensure
+ Time.zone = old_tz
+ end
+end
+
+class TimeWithZoneMethodsForString < ActiveSupport::TestCase
+ def setup
+ @s = "Sat, 01 Jan 2000 00:00:00"
+ @u = "Sat, 01 Jan 2000 00:00:00 UTC +00:00"
+ @z = "Fri, 31 Dec 1999 19:00:00 EST -05:00"
+ end
+
+ def teardown
+ Time.zone = nil
+ end
+
+ def test_in_time_zone
+ with_tz_default 'Alaska' do
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone.inspect
+ assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone.inspect
+ assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone.inspect
+ end
+ with_tz_default 'Hawaii' do
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @s.in_time_zone.inspect
+ assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @u.in_time_zone.inspect
+ assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @z.in_time_zone.inspect
+ end
+ with_tz_default nil do
+ assert_equal @s.to_time, @s.in_time_zone
+ assert_equal @u.to_time, @u.in_time_zone
+ assert_equal @z.to_time, @z.in_time_zone
+ end
+ end
+
+ def test_nil_time_zone
+ with_tz_default nil do
+ assert !@s.in_time_zone.respond_to?(:period), 'no period method'
+ assert !@u.in_time_zone.respond_to?(:period), 'no period method'
+ assert !@z.in_time_zone.respond_to?(:period), 'no period method'
+ end
+ end
+
+ def test_in_time_zone_with_argument
+ with_tz_default 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone)
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone('Alaska').inspect
+ assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone('Alaska').inspect
+ assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone('Alaska').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @s.in_time_zone('Hawaii').inspect
+ assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @u.in_time_zone('Hawaii').inspect
+ assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @z.in_time_zone('Hawaii').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @s.in_time_zone('UTC').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @u.in_time_zone('UTC').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @z.in_time_zone('UTC').inspect
+ assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone(-9.hours).inspect
+ assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone(-9.hours).inspect
+ assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone(-9.hours).inspect
+ end
+ end
+
+ def test_in_time_zone_with_invalid_argument
+ assert_raise(ArgumentError) { @s.in_time_zone("No such timezone exists") }
+ assert_raise(ArgumentError) { @u.in_time_zone("No such timezone exists") }
+ assert_raise(ArgumentError) { @z.in_time_zone("No such timezone exists") }
+ assert_raise(ArgumentError) { @s.in_time_zone(-15.hours) }
+ assert_raise(ArgumentError) { @u.in_time_zone(-15.hours) }
+ assert_raise(ArgumentError) { @z.in_time_zone(-15.hours) }
+ assert_raise(ArgumentError) { @s.in_time_zone(Object.new) }
+ assert_raise(ArgumentError) { @u.in_time_zone(Object.new) }
+ assert_raise(ArgumentError) { @z.in_time_zone(Object.new) }
+ end
+
+ protected
+ def with_tz_default(tz = nil)
+ old_tz = Time.zone
+ Time.zone = tz
+ yield
+ ensure
+ Time.zone = old_tz
+ end
+end
diff --git a/activesupport/test/deprecation/basic_object_test.rb b/activesupport/test/deprecation/basic_object_test.rb
new file mode 100644
index 0000000000..4b5bed9eb1
--- /dev/null
+++ b/activesupport/test/deprecation/basic_object_test.rb
@@ -0,0 +1,12 @@
+require 'abstract_unit'
+require 'active_support/deprecation'
+require 'active_support/basic_object'
+
+
+class BasicObjectTest < ActiveSupport::TestCase
+ test 'BasicObject warns about deprecation when inherited from' do
+ warn = 'ActiveSupport::BasicObject is deprecated! Use ActiveSupport::ProxyObject instead.'
+ ActiveSupport::Deprecation.expects(:warn).with(warn).once
+ Class.new(ActiveSupport::BasicObject)
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index 5bb2a45c87..b6e2cd4529 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -112,21 +112,34 @@ class TestJSONEncoding < ActiveSupport::TestCase
def test_utf8_string_encoded_properly
result = ActiveSupport::JSON.encode('€2.99')
- assert_equal '"\\u20ac2.99"', result
+ assert_equal '"€2.99"', result
assert_equal(Encoding::UTF_8, result.encoding)
result = ActiveSupport::JSON.encode('✎☺')
- assert_equal '"\\u270e\\u263a"', result
+ assert_equal '"✎☺"', result
assert_equal(Encoding::UTF_8, result.encoding)
end
def test_non_utf8_string_transcodes
s = '二'.encode('Shift_JIS')
result = ActiveSupport::JSON.encode(s)
- assert_equal '"\\u4e8c"', result
+ assert_equal '"二"', result
assert_equal Encoding::UTF_8, result.encoding
end
+ def test_wide_utf8_chars
+ w = '𠜎'
+ result = ActiveSupport::JSON.encode(w)
+ assert_equal '"𠜎"', result
+ end
+
+ def test_wide_utf8_roundtrip
+ hash = { string: "𐒑" }
+ json = ActiveSupport::JSON.encode(hash)
+ decoded_hash = ActiveSupport::JSON.decode(json)
+ assert_equal "𐒑", decoded_hash['string']
+ end
+
def test_exception_raised_when_encoding_circular_reference_in_array
a = [1]
a << a