aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG12
-rw-r--r--activesupport/lib/active_support.rb7
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb2
-rw-r--r--activesupport/lib/active_support/cache.rb2
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb2
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb50
-rw-r--r--activesupport/lib/active_support/cache/synchronized_memory_store.rb46
-rw-r--r--activesupport/lib/active_support/callbacks.rb2
-rw-r--r--activesupport/lib/active_support/clean_logger.rb127
-rw-r--r--activesupport/lib/active_support/core_ext/array/grouping.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb40
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/date/behavior.rb29
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb33
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/file/atomic.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/except.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/logger.rb129
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/module/aliasing.rb138
-rw-r--r--activesupport/lib/active_support/core_ext/module/introspection.rb154
-rw-r--r--activesupport/lib/active_support/core_ext/module/model_naming.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/module/synchronization.rb39
-rw-r--r--activesupport/lib/active_support/core_ext/object/misc.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/range/blockless_step.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/rexml.rb36
-rw-r--r--activesupport/lib/active_support/core_ext/string.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/behavior.rb13
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/time.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb37
-rw-r--r--activesupport/lib/active_support/core_ext/time/zones.rb2
-rw-r--r--activesupport/lib/active_support/deprecation.rb18
-rw-r--r--activesupport/lib/active_support/inflector.rb19
-rw-r--r--activesupport/lib/active_support/memoizable.rb2
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb5
-rw-r--r--activesupport/lib/active_support/option_merger.rb2
-rw-r--r--activesupport/lib/active_support/secure_random.rb197
-rw-r--r--activesupport/lib/active_support/string_inquirer.rb10
-rw-r--r--activesupport/lib/active_support/test_case.rb8
-rw-r--r--activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb6
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb96
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb2
-rwxr-xr-xactivesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb37
-rw-r--r--activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb65
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb30
-rw-r--r--activesupport/test/buffered_logger_test.rb3
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb23
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb75
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb5
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb43
-rw-r--r--activesupport/test/core_ext/module/synchronization_test.rb85
-rw-r--r--activesupport/test/core_ext/object_and_class_ext_test.rb5
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb6
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb117
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb74
-rw-r--r--activesupport/test/dependencies_test.rb18
-rw-r--r--activesupport/test/inflector_test.rb6
-rw-r--r--activesupport/test/inflector_test_cases.rb8
-rw-r--r--activesupport/test/multibyte_chars_test.rb4
-rw-r--r--activesupport/test/secure_random_test.rb15
63 files changed, 1500 insertions, 533 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 8d3b136d80..00da2a2284 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,17 @@
*Edge*
+* TimeWithZone #wday, #yday and #to_date avoid trip through #method_missing [Geoff Buesing]
+
+* Added Time, Date, DateTime and TimeWithZone #past?, #future? and #today? #720 [Clemens Kofler, Geoff Buesing]
+
+* Fixed Sri Jayawardenepura time zone to map to Asia/Colombo [Jamis Buck]
+
+* Added Inflector#parameterize for easy slug generation ("Donald E. Knuth".parameterize => "donald-e-knuth") #713 [Matt Darby]
+
+* Changed cache benchmarking to be reported in milliseconds [DHH]
+
+* Fix Ruby's Time marshaling bug in pre-1.9 versions of Ruby: utc instances are now correctly unmarshaled with a utc zone instead of the system local zone [#900 state:resolved] [Luca Guidi, Geoff Buesing]
+
* Add Array#in_groups which splits or iterates over the array in specified number of groups. #579. [Adrian Mugnolo] Example:
a = (1..10).to_a
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index ae3e2360cd..b30faff06d 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -28,7 +28,6 @@ require 'active_support/callbacks'
require 'active_support/core_ext'
-require 'active_support/clean_logger'
require 'active_support/buffered_logger'
require 'active_support/gzip'
@@ -55,9 +54,9 @@ require 'active_support/base64'
require 'active_support/time_with_zone'
-I18n.populate do
- I18n.load_translations File.dirname(__FILE__) + '/active_support/locale/en-US.yml'
-end
+require 'active_support/secure_random'
+
+I18n.load_path << File.dirname(__FILE__) + '/active_support/locale/en-US.yml'
Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector')
Dependencies = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Dependencies', 'ActiveSupport::Dependencies')
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 6553d72b4f..77e0b1d33f 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -116,7 +116,7 @@ module ActiveSupport
end
def clear_buffer
- @buffer[Thread.current] = []
+ @buffer.delete(Thread.current)
end
end
end
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 95eae3a77e..51a6309dce 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -62,7 +62,7 @@ module ActiveSupport
write(key, value, options)
@logger_off = false
- log("write (will save #{'%.5f' % seconds})", key, nil)
+ log("write (will save #{'%.2f' % (seconds * 1000)}ms)", key, nil)
value
end
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index 659bde64f0..ef533633b2 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -65,6 +65,6 @@ module ActiveSupport
end
end
end
- end
+ end
end
end
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index f3e4b8c13b..c1a713b4c5 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -3,63 +3,35 @@ module ActiveSupport
class MemoryStore < Store
def initialize
@data = {}
- @guard = Monitor.new
- end
-
- def fetch(key, options = {})
- @guard.synchronize do
- super
- end
end
def read(name, options = nil)
- @guard.synchronize do
- super
- @data[name]
- end
+ super
+ @data[name]
end
def write(name, value, options = nil)
- @guard.synchronize do
- super
- @data[name] = value.freeze
- end
+ super
+ @data[name] = value.freeze
end
def delete(name, options = nil)
- @guard.synchronize do
- @data.delete(name)
- end
+ super
+ @data.delete(name)
end
def delete_matched(matcher, options = nil)
- @guard.synchronize do
- @data.delete_if { |k,v| k =~ matcher }
- end
+ super
+ @data.delete_if { |k,v| k =~ matcher }
end
def exist?(name,options = nil)
- @guard.synchronize do
- @data.has_key?(name)
- end
- end
-
- def increment(key, amount = 1)
- @guard.synchronize do
- super
- end
- end
-
- def decrement(key, amount = 1)
- @guard.synchronize do
- super
- end
+ super
+ @data.has_key?(name)
end
def clear
- @guard.synchronize do
- @data.clear
- end
+ @data.clear
end
end
end
diff --git a/activesupport/lib/active_support/cache/synchronized_memory_store.rb b/activesupport/lib/active_support/cache/synchronized_memory_store.rb
new file mode 100644
index 0000000000..d2ff28768f
--- /dev/null
+++ b/activesupport/lib/active_support/cache/synchronized_memory_store.rb
@@ -0,0 +1,46 @@
+module ActiveSupport
+ module Cache
+ class SynchronizedMemoryStore < MemoryStore
+ def initialize
+ super
+ @guard = Monitor.new
+ end
+
+ def fetch(key, options = {})
+ @guard.synchronize { super }
+ end
+
+ def read(name, options = nil)
+ @guard.synchronize { super }
+ end
+
+ def write(name, value, options = nil)
+ @guard.synchronize { super }
+ end
+
+ def delete(name, options = nil)
+ @guard.synchronize { super }
+ end
+
+ def delete_matched(matcher, options = nil)
+ @guard.synchronize { super }
+ end
+
+ def exist?(name,options = nil)
+ @guard.synchronize { super }
+ end
+
+ def increment(key, amount = 1)
+ @guard.synchronize { super }
+ end
+
+ def decrement(key, amount = 1)
+ @guard.synchronize { super }
+ end
+
+ def clear
+ @guard.synchronize { super }
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 7b905930bb..5cdcaf5ad1 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -188,7 +188,7 @@ module ActiveSupport
"Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
"a block to be invoked, or an object responding to the callback method."
end
- end
+ end
end
def should_run_callback?(*args)
diff --git a/activesupport/lib/active_support/clean_logger.rb b/activesupport/lib/active_support/clean_logger.rb
deleted file mode 100644
index b4c27ebc9d..0000000000
--- a/activesupport/lib/active_support/clean_logger.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-require 'logger'
-require 'active_support/core_ext/class/attribute_accessors'
-
-# Extensions to the built in Ruby logger.
-#
-# If you want to use the default log formatter as defined in the Ruby core, then you
-# will need to set the formatter for the logger as in:
-#
-# logger.formatter = Formatter.new
-#
-# You can then specify the datetime format, for example:
-#
-# logger.datetime_format = "%Y-%m-%d"
-#
-# Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger
-class Logger
- # Set to false to disable the silencer
- cattr_accessor :silencer
- self.silencer = true
-
- # Silences the logger for the duration of the block.
- def silence(temporary_level = Logger::ERROR)
- if silencer
- begin
- old_logger_level, self.level = level, temporary_level
- yield self
- ensure
- self.level = old_logger_level
- end
- else
- yield self
- end
- end
-
- alias :old_datetime_format= :datetime_format=
- # Logging date-time format (string passed to +strftime+). Ignored if the formatter
- # does not respond to datetime_format=.
- def datetime_format=(datetime_format)
- formatter.datetime_format = datetime_format if formatter.respond_to?(:datetime_format=)
- end
-
- alias :old_datetime_format :datetime_format
- # Get the logging datetime format. Returns nil if the formatter does not support
- # datetime formatting.
- def datetime_format
- formatter.datetime_format if formatter.respond_to?(:datetime_format)
- end
-
- alias :old_formatter :formatter if method_defined?(:formatter)
- # Get the current formatter. The default formatter is a SimpleFormatter which only
- # displays the log message
- def formatter
- @formatter ||= SimpleFormatter.new
- end
-
- unless const_defined? :Formatter
- class Formatter
- Format = "%s, [%s#%d] %5s -- %s: %s\n"
-
- attr_accessor :datetime_format
-
- def initialize
- @datetime_format = nil
- end
-
- def call(severity, time, progname, msg)
- Format % [severity[0..0], format_datetime(time), $$, severity, progname,
- msg2str(msg)]
- end
-
- private
- def format_datetime(time)
- if @datetime_format.nil?
- time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
- else
- time.strftime(@datetime_format)
- end
- end
-
- def msg2str(msg)
- case msg
- when ::String
- msg
- when ::Exception
- "#{ msg.message } (#{ msg.class })\n" <<
- (msg.backtrace || []).join("\n")
- else
- msg.inspect
- end
- end
- end
- end
-
- # Simple formatter which only displays the message.
- class SimpleFormatter < Logger::Formatter
- # This method is invoked when a log event occurs
- def call(severity, timestamp, progname, msg)
- "#{String === msg ? msg : msg.inspect}\n"
- end
- end
-
- private
- alias old_format_message format_message
-
- # Ruby 1.8.3 transposed the msg and progname arguments to format_message.
- # We can't test RUBY_VERSION because some distributions don't keep Ruby
- # and its standard library in sync, leading to installations of Ruby 1.8.2
- # with Logger from 1.8.3 and vice versa.
- if method_defined?(:formatter=)
- def format_message(severity, timestamp, progname, msg)
- formatter.call(severity, timestamp, progname, msg)
- end
- else
- def format_message(severity, timestamp, msg, progname)
- formatter.call(severity, timestamp, progname, msg)
- end
-
- attr_writer :formatter
- public :formatter=
-
- alias old_format_datetime format_datetime
- def format_datetime(datetime) datetime end
-
- alias old_msg2str msg2str
- def msg2str(msg) msg end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb
index dd1484f8fa..f782f8facf 100644
--- a/activesupport/lib/active_support/core_ext/array/grouping.rb
+++ b/activesupport/lib/active_support/core_ext/array/grouping.rb
@@ -7,16 +7,16 @@ module ActiveSupport #:nodoc:
# 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) {|g| p g}
+ # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
# ["1", "2", "3"]
# ["4", "5", "6"]
# ["7", nil, nil]
#
- # %w(1 2 3).in_groups_of(2, '&nbsp;') {|g| p g}
+ # %w(1 2 3).in_groups_of(2, '&nbsp;') {|group| p group}
# ["1", "2"]
# ["3", "&nbsp;"]
#
- # %w(1 2 3).in_groups_of(2, false) {|g| p g}
+ # %w(1 2 3).in_groups_of(2, false) {|group| p group}
# ["1", "2"]
# ["3"]
def in_groups_of(number, fill_with = nil)
@@ -42,17 +42,17 @@ module ActiveSupport #:nodoc:
# Splits or iterates over the array in +number+ of groups, padding any
# remaining slots with +fill_with+ unless it is +false+.
#
- # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|g| p g}
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
# ["1", "2", "3", "4"]
# ["5", "6", "7", nil]
# ["8", "9", "10", nil]
#
- # %w(1 2 3 4 5 6 7).in_groups(3, '&nbsp;') {|g| p g}
+ # %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).in_groups(3, false) {|g| p g}
+ # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
# ["1", "2", "3"]
# ["4", "5"]
# ["6", "7"]
diff --git a/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb b/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb
index 94c7c779f7..bc9d578f38 100644
--- a/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb
@@ -4,35 +4,31 @@ module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module BigDecimal #:nodoc:
module Conversions
+ DEFAULT_STRING_FORMAT = 'F'.freeze
+ YAML_TAG = 'tag:yaml.org,2002:float'.freeze
+ YAML_MAPPING = { 'Infinity' => '.Inf', '-Infinity' => '-.Inf', 'NaN' => '.NaN' }
+
def self.included(base) #:nodoc:
- base.instance_eval do
+ base.class_eval do
alias_method :_original_to_s, :to_s
alias_method :to_s, :to_formatted_s
+
+ yaml_as YAML_TAG
end
end
-
- def to_formatted_s(format="F")
+
+ def to_formatted_s(format = DEFAULT_STRING_FORMAT)
_original_to_s(format)
end
-
- yaml_as "tag:yaml.org,2002:float"
- def to_yaml( opts = {} )
- YAML::quick_emit( nil, opts ) do |out|
- # This emits the number without any scientific notation.
- # I prefer it to using self.to_f.to_s, which would lose precision.
- #
- # Note that YAML allows that when reconstituting floats
- # to native types, some precision may get lost.
- # There is no full precision real YAML tag that I am aware of.
- str = self.to_s
- if str == "Infinity"
- str = ".Inf"
- elsif str == "-Infinity"
- str = "-.Inf"
- elsif str == "NaN"
- str = ".NaN"
- end
- out.scalar( "tag:yaml.org,2002:float", str, :plain )
+
+ # This emits the number without any scientific notation.
+ # This is better than self.to_f.to_s since it doesn't lose precision.
+ #
+ # Note that reconstituting YAML floats to native floats may lose precision.
+ def to_yaml(opts = {})
+ YAML.quick_emit(nil, opts) do |out|
+ string = to_s
+ out.scalar(YAML_TAG, YAML_MAPPING[string] || string, :plain)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index 8724a492bf..e6143a274b 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -91,14 +91,14 @@ class Class # :nodoc:
def inheritable_attributes
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
end
-
+
def write_inheritable_attribute(key, value)
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
@inheritable_attributes = {}
end
inheritable_attributes[key] = value
end
-
+
def write_inheritable_array(key, elements)
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
@@ -112,7 +112,7 @@ class Class # :nodoc:
def read_inheritable_attribute(key)
inheritable_attributes[key]
end
-
+
def reset_inheritable_attributes
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
end
@@ -123,7 +123,7 @@ class Class # :nodoc:
def inherited_with_inheritable_attributes(child)
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
-
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
else
@@ -131,7 +131,7 @@ class Class # :nodoc:
memo.update(key => value.duplicable? ? value.dup : value)
end
end
-
+
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
end
diff --git a/activesupport/lib/active_support/core_ext/date/behavior.rb b/activesupport/lib/active_support/core_ext/date/behavior.rb
index 6f8f7c6a82..bd378eb375 100644
--- a/activesupport/lib/active_support/core_ext/date/behavior.rb
+++ b/activesupport/lib/active_support/core_ext/date/behavior.rb
@@ -1,3 +1,5 @@
+require 'date'
+
module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module Date #:nodoc:
@@ -10,18 +12,29 @@ module ActiveSupport #:nodoc:
# Date memoizes some instance methods using metaprogramming to wrap
# the methods with one that caches the result in an instance variable.
+ #
# If a Date is frozen but the memoized method hasn't been called, the
# first call will result in a frozen object error since the memo
- # instance variable is uninitialized. Work around by eagerly memoizing
- # before freezing.
- def freeze #:nodoc:
- self.class.private_instance_methods(false).each do |m|
- if m.to_s =~ /\A__\d+__\Z/
- instance_variable_set(:"@#{m}", [send(m)])
+ # instance variable is uninitialized.
+ #
+ # Work around by eagerly memoizing before freezing.
+ #
+ # Ruby 1.9 uses a preinitialized instance variable so it's unaffected.
+ # This hack is as close as we can get to feature detection:
+ begin
+ ::Date.today.freeze.jd
+ rescue => frozen_object_error
+ if frozen_object_error.message =~ /frozen/
+ def freeze #:nodoc:
+ self.class.private_instance_methods(false).each do |m|
+ if m.to_s =~ /\A__\d+__\Z/
+ instance_variable_set(:"@#{m}", [send(m)])
+ end
+ end
+
+ super
end
end
-
- super
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index b5180c9592..43d70c7013 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -20,18 +20,33 @@ module ActiveSupport #:nodoc:
def yesterday
::Date.today.yesterday
end
-
+
# Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
def tomorrow
::Date.today.tomorrow
end
-
+
# Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today.
def current
::Time.zone_default ? ::Time.zone.today : ::Date.today
end
end
-
+
+ # Tells whether the Date object's date lies in the past
+ def past?
+ self < ::Date.current
+ end
+
+ # Tells whether the Date object's date is today
+ def today?
+ self.to_date == ::Date.current # we need the to_date because of DateTime
+ end
+
+ # Tells whether the Date object's date lies in the future
+ def future?
+ self > ::Date.current
+ 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 subtracts the specified number of seconds
def ago(seconds)
@@ -57,7 +72,7 @@ module ActiveSupport #:nodoc:
def end_of_day
to_time.end_of_day
end
-
+
def plus_with_duration(other) #:nodoc:
if ActiveSupport::Duration === other
other.since(self)
@@ -65,7 +80,7 @@ module ActiveSupport #:nodoc:
plus_without_duration(other)
end
end
-
+
def minus_with_duration(other) #:nodoc:
if ActiveSupport::Duration === other
plus_with_duration(-other)
@@ -73,8 +88,8 @@ module ActiveSupport #:nodoc:
minus_without_duration(other)
end
end
-
- # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
+
+ # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
# any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
def advance(options)
d = self
@@ -98,7 +113,7 @@ module ActiveSupport #:nodoc:
options[:day] || self.day
)
end
-
+
# Returns a new Date/DateTime representing the time a number of specified months ago
def months_ago(months)
advance(:months => -months)
@@ -161,7 +176,7 @@ module ActiveSupport #:nodoc:
days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
result = (self + 7).beginning_of_week + days_into_week[day]
self.acts_like?(:time) ? result.change(:hour => 0) : result
- end
+ 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)
def beginning_of_month
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 155c961a91..0099431e9d 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -7,7 +7,7 @@ module ActiveSupport #:nodoc:
module Calculations
def self.included(base) #:nodoc:
base.extend ClassMethods
-
+
base.class_eval do
alias_method :compare_without_coercion, :<=>
alias_method :<=>, :compare_with_coercion
@@ -19,6 +19,20 @@ module ActiveSupport #:nodoc:
def local_offset
::Time.local(2007).utc_offset.to_r / 86400
end
+
+ def current
+ ::Time.zone_default ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
+ end
+ end
+
+ # Tells whether the DateTime object's datetime lies in the past
+ def past?
+ self < ::DateTime.current
+ end
+
+ # Tells whether the DateTime object's datetime lies in the future
+ def future?
+ self > ::DateTime.current
end
# Seconds since midnight: DateTime.now.seconds_since_midnight
@@ -78,7 +92,7 @@ module ActiveSupport #:nodoc:
def end_of_day
change(:hour => 23, :min => 59, :sec => 59)
end
-
+
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0
#
# Example:
@@ -89,17 +103,17 @@ module ActiveSupport #:nodoc:
new_offset(0)
end
alias_method :getutc, :utc
-
+
# Returns true if offset == 0
def utc?
offset == 0
end
-
+
# Returns the offset value in seconds
def utc_offset
(offset * 86400).to_i
end
-
+
# Layers additional behavior on DateTime#<=> so that Time and ActiveSupport::TimeWithZone instances can be compared with a DateTime
def compare_with_coercion(other)
other = other.comparable_time if other.respond_to?(:comparable_time)
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index e451e9933a..788f3a7e9e 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -64,8 +64,28 @@ module Enumerable
end
end
+ # Iterates over a collection, passing the current element *and* the
+ # +memo+ to the block. Handy for building up hashes or
+ # reducing collections down to one object. Examples:
+ #
+ # %w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } #=> {'foo' => 'FOO', 'bar' => 'BAR'}
+ #
+ # *Note* that you can't use immutable objects like numbers, true or false as
+ # the memo. You would think the following returns 120, but since the memo is
+ # never changed, it does not.
+ #
+ # (1..5).each_with_object(1) { |value, memo| memo *= value } # => 1
+ #
+ def each_with_object(memo, &block)
+ returning memo do |m|
+ each do |element|
+ block.call(element, m)
+ end
+ end
+ end unless [].respond_to?(:each_with_object)
+
# Convert an enumerable to a hash. Examples:
- #
+ #
# people.index_by(&:login)
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb
index 4d3cf5423f..f988eff3d9 100644
--- a/activesupport/lib/active_support/core_ext/file/atomic.rb
+++ b/activesupport/lib/active_support/core_ext/file/atomic.rb
@@ -28,7 +28,7 @@ module ActiveSupport #:nodoc:
rescue Errno::ENOENT
# No old permissions, write a temp file to determine the defaults
check_name = ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}"
- new(check_name, "w")
+ open(check_name, "w") { }
old_stat = stat(check_name)
unlink(check_name)
end
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 2c606b401b..50dc7c61fc 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -156,7 +156,7 @@ module ActiveSupport #:nodoc:
XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value,
attributes
)
- end
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb
index f26d01553d..949976d741 100644
--- a/activesupport/lib/active_support/core_ext/hash/except.rb
+++ b/activesupport/lib/active_support/core_ext/hash/except.rb
@@ -10,7 +10,7 @@ module ActiveSupport #:nodoc:
module Except
# Returns a new hash without the given keys.
def except(*keys)
- clone.except!(*keys)
+ dup.except!(*keys)
end
# Replaces the hash without the given keys.
diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb
index 9c1fd274ac..c622554860 100644
--- a/activesupport/lib/active_support/core_ext/logger.rb
+++ b/activesupport/lib/active_support/core_ext/logger.rb
@@ -12,5 +12,132 @@ class Logger
end_eval
end
[:debug, :info, :error, :fatal].each {|level| define_around_helper(level) }
+end
-end \ No newline at end of file
+
+require 'logger'
+
+# Extensions to the built in Ruby logger.
+#
+# If you want to use the default log formatter as defined in the Ruby core, then you
+# will need to set the formatter for the logger as in:
+#
+# logger.formatter = Formatter.new
+#
+# You can then specify the datetime format, for example:
+#
+# logger.datetime_format = "%Y-%m-%d"
+#
+# Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger
+class Logger
+ # Set to false to disable the silencer
+ cattr_accessor :silencer
+ self.silencer = true
+
+ # Silences the logger for the duration of the block.
+ def silence(temporary_level = Logger::ERROR)
+ if silencer
+ begin
+ old_logger_level, self.level = level, temporary_level
+ yield self
+ ensure
+ self.level = old_logger_level
+ end
+ else
+ yield self
+ end
+ end
+
+ alias :old_datetime_format= :datetime_format=
+ # Logging date-time format (string passed to +strftime+). Ignored if the formatter
+ # does not respond to datetime_format=.
+ def datetime_format=(datetime_format)
+ formatter.datetime_format = datetime_format if formatter.respond_to?(:datetime_format=)
+ end
+
+ alias :old_datetime_format :datetime_format
+ # Get the logging datetime format. Returns nil if the formatter does not support
+ # datetime formatting.
+ def datetime_format
+ formatter.datetime_format if formatter.respond_to?(:datetime_format)
+ end
+
+ alias :old_formatter :formatter if method_defined?(:formatter)
+ # Get the current formatter. The default formatter is a SimpleFormatter which only
+ # displays the log message
+ def formatter
+ @formatter ||= SimpleFormatter.new
+ end
+
+ unless const_defined? :Formatter
+ class Formatter
+ Format = "%s, [%s#%d] %5s -- %s: %s\n"
+
+ attr_accessor :datetime_format
+
+ def initialize
+ @datetime_format = nil
+ end
+
+ def call(severity, time, progname, msg)
+ Format % [severity[0..0], format_datetime(time), $$, severity, progname,
+ msg2str(msg)]
+ end
+
+ private
+ def format_datetime(time)
+ if @datetime_format.nil?
+ time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
+ else
+ time.strftime(@datetime_format)
+ end
+ end
+
+ def msg2str(msg)
+ case msg
+ when ::String
+ msg
+ when ::Exception
+ "#{ msg.message } (#{ msg.class })\n" <<
+ (msg.backtrace || []).join("\n")
+ else
+ msg.inspect
+ end
+ end
+ end
+ end
+
+ # Simple formatter which only displays the message.
+ class SimpleFormatter < Logger::Formatter
+ # This method is invoked when a log event occurs
+ def call(severity, timestamp, progname, msg)
+ "#{String === msg ? msg : msg.inspect}\n"
+ end
+ end
+
+ private
+ alias old_format_message format_message
+
+ # Ruby 1.8.3 transposed the msg and progname arguments to format_message.
+ # We can't test RUBY_VERSION because some distributions don't keep Ruby
+ # and its standard library in sync, leading to installations of Ruby 1.8.2
+ # with Logger from 1.8.3 and vice versa.
+ if method_defined?(:formatter=)
+ def format_message(severity, timestamp, progname, msg)
+ formatter.call(severity, timestamp, progname, msg)
+ end
+ else
+ def format_message(severity, timestamp, msg, progname)
+ formatter.call(severity, timestamp, progname, msg)
+ end
+
+ attr_writer :formatter
+ public :formatter=
+
+ alias old_format_datetime format_datetime
+ def format_datetime(datetime) datetime end
+
+ alias old_msg2str msg2str
+ def msg2str(msg) msg end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb
index 34fcbd124b..da8d28ec13 100644
--- a/activesupport/lib/active_support/core_ext/module.rb
+++ b/activesupport/lib/active_support/core_ext/module.rb
@@ -7,7 +7,17 @@ require 'active_support/core_ext/module/introspection'
require 'active_support/core_ext/module/loading'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/model_naming'
+require 'active_support/core_ext/module/synchronization'
+
+module ActiveSupport
+ module CoreExtensions
+ # Various extensions for the Ruby core Module class.
+ module Module
+ # Nothing here. Only defined for API documentation purposes.
+ end
+ end
+end
class Module
- include ActiveSupport::CoreExt::Module::ModelNaming
+ include ActiveSupport::CoreExtensions::Module
end
diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb
index 1894e3b0a2..e640f64520 100644
--- a/activesupport/lib/active_support/core_ext/module/aliasing.rb
+++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb
@@ -1,70 +1,74 @@
-class Module
- # Encapsulates the common pattern of:
- #
- # alias_method :foo_without_feature, :foo
- # alias_method :foo, :foo_with_feature
- #
- # With this, you simply do:
- #
- # alias_method_chain :foo, :feature
- #
- # And both aliases are set up for you.
- #
- # Query and bang methods (foo?, foo!) keep the same punctuation:
- #
- # alias_method_chain :foo?, :feature
- #
- # is equivalent to
- #
- # alias_method :foo_without_feature?, :foo?
- # alias_method :foo?, :foo_with_feature?
- #
- # so you can safely chain foo, foo?, and foo! with the same feature.
- def alias_method_chain(target, feature)
- # Strip out punctuation on predicates or bang methods since
- # e.g. target?_without_feature is not a valid method name.
- aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
- yield(aliased_target, punctuation) if block_given?
-
- with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
-
- alias_method without_method, target
- alias_method target, with_method
-
- case
- when public_method_defined?(without_method)
- public target
- when protected_method_defined?(without_method)
- protected target
- when private_method_defined?(without_method)
- private target
- end
- end
+module ActiveSupport
+ module CoreExtensions
+ module Module
+ # Encapsulates the common pattern of:
+ #
+ # alias_method :foo_without_feature, :foo
+ # alias_method :foo, :foo_with_feature
+ #
+ # With this, you simply do:
+ #
+ # alias_method_chain :foo, :feature
+ #
+ # And both aliases are set up for you.
+ #
+ # Query and bang methods (foo?, foo!) keep the same punctuation:
+ #
+ # alias_method_chain :foo?, :feature
+ #
+ # is equivalent to
+ #
+ # alias_method :foo_without_feature?, :foo?
+ # alias_method :foo?, :foo_with_feature?
+ #
+ # so you can safely chain foo, foo?, and foo! with the same feature.
+ def alias_method_chain(target, feature)
+ # Strip out punctuation on predicates or bang methods since
+ # e.g. target?_without_feature is not a valid method name.
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
+ yield(aliased_target, punctuation) if block_given?
+
+ with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
- # Allows you to make aliases for attributes, which includes
- # getter, setter, and query methods.
- #
- # Example:
- #
- # class Content < ActiveRecord::Base
- # # has a title attribute
- # end
- #
- # class Email < Content
- # alias_attribute :subject, :title
- # end
- #
- # e = Email.find(1)
- # e.title # => "Superstars"
- # e.subject # => "Superstars"
- # e.subject? # => true
- # e.subject = "Megastars"
- # e.title # => "Megastars"
- def alias_attribute(new_name, old_name)
- module_eval <<-STR, __FILE__, __LINE__+1
- def #{new_name}; self.#{old_name}; end
- def #{new_name}?; self.#{old_name}?; end
- def #{new_name}=(v); self.#{old_name} = v; end
- STR
+ alias_method without_method, target
+ alias_method target, with_method
+
+ case
+ when public_method_defined?(without_method)
+ public target
+ when protected_method_defined?(without_method)
+ protected target
+ when private_method_defined?(without_method)
+ private target
+ end
+ end
+
+ # Allows you to make aliases for attributes, which includes
+ # getter, setter, and query methods.
+ #
+ # Example:
+ #
+ # class Content < ActiveRecord::Base
+ # # has a title attribute
+ # end
+ #
+ # class Email < Content
+ # alias_attribute :subject, :title
+ # end
+ #
+ # e = Email.find(1)
+ # e.title # => "Superstars"
+ # e.subject # => "Superstars"
+ # e.subject? # => true
+ # e.subject = "Megastars"
+ # e.title # => "Megastars"
+ def alias_attribute(new_name, old_name)
+ module_eval <<-STR, __FILE__, __LINE__+1
+ def #{new_name}; self.#{old_name}; end
+ def #{new_name}?; self.#{old_name}?; end
+ def #{new_name}=(v); self.#{old_name} = v; end
+ STR
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb
index 45f3e4bf5c..8beaff4b82 100644
--- a/activesupport/lib/active_support/core_ext/module/introspection.rb
+++ b/activesupport/lib/active_support/core_ext/module/introspection.rb
@@ -1,86 +1,90 @@
-class Module
- # Returns the name of the module containing this one.
- #
- # p M::N.parent_name # => "M"
- def parent_name
- unless defined? @parent_name
- @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
- end
- @parent_name
- end
+module ActiveSupport
+ module CoreExtensions
+ module Module
+ # Returns the name of the module containing this one.
+ #
+ # p M::N.parent_name # => "M"
+ def parent_name
+ unless defined? @parent_name
+ @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
+ end
+ @parent_name
+ end
- # Returns the module which contains this one according to its name.
- #
- # module M
- # module N
- # end
- # end
- # X = M::N
- #
- # p M::N.parent # => M
- # p X.parent # => M
- #
- # The parent of top-level and anonymous modules is Object.
- #
- # p M.parent # => Object
- # p Module.new.parent # => Object
- #
- def parent
- parent_name ? parent_name.constantize : Object
- end
+ # Returns the module which contains this one according to its name.
+ #
+ # module M
+ # module N
+ # end
+ # end
+ # X = M::N
+ #
+ # p M::N.parent # => M
+ # p X.parent # => M
+ #
+ # The parent of top-level and anonymous modules is Object.
+ #
+ # p M.parent # => Object
+ # p Module.new.parent # => Object
+ #
+ def parent
+ parent_name ? parent_name.constantize : Object
+ end
- # Returns all the parents of this module according to its name, ordered from
- # nested outwards. The receiver is not contained within the result.
- #
- # module M
- # module N
- # end
- # end
- # X = M::N
- #
- # p M.parents # => [Object]
- # p M::N.parents # => [M, Object]
- # p X.parents # => [M, Object]
- #
- def parents
- parents = []
- if parent_name
- parts = parent_name.split('::')
- until parts.empty?
- parents << (parts * '::').constantize
- parts.pop
+ # Returns all the parents of this module according to its name, ordered from
+ # nested outwards. The receiver is not contained within the result.
+ #
+ # module M
+ # module N
+ # end
+ # end
+ # X = M::N
+ #
+ # p M.parents # => [Object]
+ # p M::N.parents # => [M, Object]
+ # p X.parents # => [M, Object]
+ #
+ def parents
+ parents = []
+ if parent_name
+ parts = parent_name.split('::')
+ until parts.empty?
+ parents << (parts * '::').constantize
+ parts.pop
+ end
+ end
+ parents << Object unless parents.include? Object
+ parents
end
- end
- parents << Object unless parents.include? Object
- parents
- end
- if RUBY_VERSION < '1.9'
- # Returns the constants that have been defined locally by this object and
- # not in an ancestor. This method is exact if running under Ruby 1.9. In
- # previous versions it may miss some constants if their definition in some
- # ancestor is identical to their definition in the receiver.
- def local_constants
- inherited = {}
+ if RUBY_VERSION < '1.9'
+ # Returns the constants that have been defined locally by this object and
+ # not in an ancestor. This method is exact if running under Ruby 1.9. In
+ # previous versions it may miss some constants if their definition in some
+ # ancestor is identical to their definition in the receiver.
+ def local_constants
+ inherited = {}
+
+ ancestors.each do |anc|
+ next if anc == self
+ anc.constants.each { |const| inherited[const] = anc.const_get(const) }
+ end
- ancestors.each do |anc|
- next if anc == self
- anc.constants.each { |const| inherited[const] = anc.const_get(const) }
+ constants.select do |const|
+ !inherited.key?(const) || inherited[const].object_id != const_get(const).object_id
+ end
+ end
+ else
+ def local_constants #:nodoc:
+ constants(false)
+ end
end
- constants.select do |const|
- !inherited.key?(const) || inherited[const].object_id != const_get(const).object_id
+ # Returns the names of the constants defined locally rather than the
+ # constants themselves. See <tt>local_constants</tt>.
+ def local_constant_names
+ local_constants.map { |c| c.to_s }
end
end
- else
- def local_constants #:nodoc:
- constants(false)
- end
- end
-
- # Returns the names of the constants defined locally rather than the
- # constants themselves. See <tt>local_constants</tt>.
- def local_constant_names
- local_constants.map { |c| c.to_s }
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/model_naming.rb b/activesupport/lib/active_support/core_ext/module/model_naming.rb
index 5518f5417b..3ec4f3ba11 100644
--- a/activesupport/lib/active_support/core_ext/module/model_naming.rb
+++ b/activesupport/lib/active_support/core_ext/module/model_naming.rb
@@ -11,12 +11,12 @@ module ActiveSupport
end
end
- module CoreExt
+ module CoreExtensions
module Module
- module ModelNaming
- def model_name
- @model_name ||= ModelName.new(name)
- end
+ # Returns an ActiveSupport::ModelName object for module. It can be
+ # used to retrieve all kinds of naming-related information.
+ def model_name
+ @model_name ||= ModelName.new(name)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb
new file mode 100644
index 0000000000..251606024e
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/synchronization.rb
@@ -0,0 +1,39 @@
+class Module
+ # Synchronize access around a method, delegating synchronization to a
+ # particular mutex. A mutex (either a Mutex, or any object that responds to
+ # #synchronize and yields to a block) must be provided as a final :with option.
+ # The :with option should be a symbol or string, and can represent a method,
+ # constant, or instance or class variable.
+ # Example:
+ # class SharedCache
+ # @@lock = Mutex.new
+ # def expire
+ # ...
+ # end
+ # synchronize :expire, :with => :@@lock
+ # end
+ def synchronize(*methods)
+ options = methods.extract_options!
+ unless options.is_a?(Hash) && with = options[:with]
+ raise ArgumentError, "Synchronization needs a mutex. Supply an options hash with a :with key as the last argument (e.g. synchronize :hello, :with => :@mutex)."
+ end
+
+ methods.each do |method|
+ aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
+
+ if method_defined?("#{aliased_method}_without_synchronization#{punctuation}")
+ raise ArgumentError, "#{method} is already synchronized. Double synchronization is not currently supported."
+ end
+
+ module_eval(<<-EOS, __FILE__, __LINE__)
+ def #{aliased_method}_with_synchronization#{punctuation}(*args, &block)
+ #{with}.synchronize do
+ #{aliased_method}_without_synchronization#{punctuation}(*args, &block)
+ end
+ end
+ EOS
+
+ alias_method_chain method, :synchronization
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/object/misc.rb b/activesupport/lib/active_support/core_ext/object/misc.rb
index 8384a12327..06a7d05702 100644
--- a/activesupport/lib/active_support/core_ext/object/misc.rb
+++ b/activesupport/lib/active_support/core_ext/object/misc.rb
@@ -1,9 +1,4 @@
class Object
- unless respond_to?(:send!)
- # Anticipating Ruby 1.9 neutering send
- alias send! send
- end
-
# A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
#
# def foo
diff --git a/activesupport/lib/active_support/core_ext/range/blockless_step.rb b/activesupport/lib/active_support/core_ext/range/blockless_step.rb
index 39dac85636..6fa1eb5bee 100644
--- a/activesupport/lib/active_support/core_ext/range/blockless_step.rb
+++ b/activesupport/lib/active_support/core_ext/range/blockless_step.rb
@@ -8,7 +8,7 @@ module ActiveSupport #:nodoc:
end
if RUBY_VERSION < '1.9'
- def step_with_blockless(value, &block)
+ def step_with_blockless(value = 1, &block)
if block_given?
step_without_blockless(value, &block)
else
@@ -18,7 +18,7 @@ module ActiveSupport #:nodoc:
end
end
else
- def step_with_blockless(value, &block)
+ def step_with_blockless(value = 1, &block)
if block_given?
step_without_blockless(value, &block)
else
diff --git a/activesupport/lib/active_support/core_ext/rexml.rb b/activesupport/lib/active_support/core_ext/rexml.rb
new file mode 100644
index 0000000000..187f3e0f5e
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/rexml.rb
@@ -0,0 +1,36 @@
+require 'rexml/document'
+require 'rexml/entity'
+
+# Fixes the rexml vulnerability disclosed at:
+# http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/
+# This fix is identical to rexml-expansion-fix version 1.0.1
+
+# Earlier versions of rexml defined REXML::Version, newer ones REXML::VERSION
+unless (defined?(REXML::VERSION) ? REXML::VERSION : REXML::Version) > "3.1.7.2"
+ module REXML
+ class Entity < Child
+ undef_method :unnormalized
+ def unnormalized
+ document.record_entity_expansion! if document
+ v = value()
+ return nil if v.nil?
+ @unnormalized = Text::unnormalize(v, parent)
+ @unnormalized
+ end
+ end
+ class Document < Element
+ @@entity_expansion_limit = 10_000
+ def self.entity_expansion_limit= val
+ @@entity_expansion_limit = val
+ end
+
+ def record_entity_expansion!
+ @number_of_expansions ||= 0
+ @number_of_expansions += 1
+ if @number_of_expansions > @@entity_expansion_limit
+ raise "Number of entity expansions exceeded, processing aborted."
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb
index 25386af70a..7ff2f11eff 100644
--- a/activesupport/lib/active_support/core_ext/string.rb
+++ b/activesupport/lib/active_support/core_ext/string.rb
@@ -6,6 +6,7 @@ require 'active_support/core_ext/string/iterators'
require 'active_support/core_ext/string/unicode'
require 'active_support/core_ext/string/xchar'
require 'active_support/core_ext/string/filters'
+require 'active_support/core_ext/string/behavior'
class String #:nodoc:
include ActiveSupport::CoreExtensions::String::Access
@@ -15,4 +16,5 @@ class String #:nodoc:
include ActiveSupport::CoreExtensions::String::StartsEndsWith
include ActiveSupport::CoreExtensions::String::Iterators
include ActiveSupport::CoreExtensions::String::Unicode
+ include ActiveSupport::CoreExtensions::String::Behavior
end
diff --git a/activesupport/lib/active_support/core_ext/string/behavior.rb b/activesupport/lib/active_support/core_ext/string/behavior.rb
new file mode 100644
index 0000000000..a93ca3027f
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/string/behavior.rb
@@ -0,0 +1,13 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ module Behavior
+ # Enable more predictable duck-typing on String-like classes. See
+ # Object#acts_like?.
+ def acts_like_string?
+ true
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index 3bbad7dad8..de99fe5791 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -87,6 +87,25 @@ module ActiveSupport #:nodoc:
Inflector.demodulize(self)
end
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
+ #
+ # ==== Examples
+ #
+ # class Person
+ # def to_param
+ # "#{id}-#{name.parameterize}"
+ # end
+ # end
+ #
+ # @person = Person.find(1)
+ # # => #<Person id: 1, name: "Donald E. Knuth">
+ #
+ # <%= link_to(@person.name, person_path %>
+ # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
+ def parameterize
+ Inflector.parameterize(self)
+ end
+
# Creates the name of a table like Rails does for models to table names. This method
# uses the +pluralize+ method on the last word in the string.
#
diff --git a/activesupport/lib/active_support/core_ext/time.rb b/activesupport/lib/active_support/core_ext/time.rb
index ea50511a96..78bbfc917c 100644
--- a/activesupport/lib/active_support/core_ext/time.rb
+++ b/activesupport/lib/active_support/core_ext/time.rb
@@ -1,11 +1,32 @@
require 'date'
require 'time'
-# Ruby 1.8-cvs and 1.9 define private Time#to_date
class Time
+ # Ruby 1.8-cvs and 1.9 define private Time#to_date
%w(to_date to_datetime).each do |method|
public method if private_instance_methods.include?(method)
end
+
+ # Pre-1.9 versions of Ruby have a bug with marshaling Time instances, where utc instances are
+ # unmarshaled in the local zone, instead of utc. We're layering behavior on the _dump and _load
+ # methods so that utc instances can be flagged on dump, and coerced back to utc on load.
+ if RUBY_VERSION < '1.9'
+ class << self
+ alias_method :_original_load, :_load
+ def _load(marshaled_time)
+ time = _original_load(marshaled_time)
+ utc = time.instance_variable_get('@marshal_with_utc_coercion')
+ utc ? time.utc : time
+ end
+ end
+
+ alias_method :_original_dump, :_dump
+ def _dump(*args)
+ obj = self.frozen? ? self.dup : self
+ obj.instance_variable_set('@marshal_with_utc_coercion', utc?)
+ obj._original_dump(*args)
+ end
+ end
end
require 'active_support/core_ext/time/behavior'
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index cd234c9b89..3cc6d59907 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -9,13 +9,13 @@ module ActiveSupport #:nodoc:
base.class_eval do
alias_method :plus_without_duration, :+
alias_method :+, :plus_with_duration
-
+
alias_method :minus_without_duration, :-
alias_method :-, :minus_with_duration
-
+
alias_method :minus_without_coercion, :-
alias_method :-, :minus_with_coercion
-
+
alias_method :compare_without_coercion, :<=>
alias_method :<=>, :compare_with_coercion
end
@@ -28,9 +28,9 @@ module ActiveSupport #:nodoc:
def ===(other)
other.is_a?(::Time)
end
-
- # Return the number of days in the given month.
- # If no year is specified, it will use the current year.
+
+ # Return the number of days in the given month.
+ # If no year is specified, it will use the current year.
def days_in_month(month, year = now.year)
return 29 if month == 2 && ::Date.gregorian_leap?(year)
COMMON_YEAR_DAYS_IN_MONTH[month]
@@ -57,6 +57,21 @@ module ActiveSupport #:nodoc:
end
end
+ # Tells whether the Time object's time lies in the past
+ def past?
+ self < ::Time.current
+ end
+
+ # Tells whether the Time object's time is today
+ def today?
+ self.to_date == ::Date.current
+ end
+
+ # Tells whether the Time object's time lies in the future
+ def future?
+ self > ::Time.current
+ end
+
# Seconds since midnight: Time.now.seconds_since_midnight
def seconds_since_midnight
self.to_i - self.change(:hour => 0).to_i + (self.usec/1.0e+6)
@@ -106,7 +121,7 @@ module ActiveSupport #:nodoc:
(seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
end
rescue
- self.to_datetime.since(seconds)
+ self.to_datetime.since(seconds)
end
alias :in :since
@@ -199,7 +214,7 @@ module ActiveSupport #:nodoc:
change(:day => last_day, :hour => 23, :min => 59, :sec => 59, :usec => 0)
end
alias :at_end_of_month :end_of_month
-
+
# Returns a new Time representing the start of the quarter (1st of january, april, july, october, 0:00)
def beginning_of_quarter
beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
@@ -208,7 +223,7 @@ module ActiveSupport #:nodoc:
# Returns a new Time representing the end of the quarter (last day of march, june, september, december, 23:59:59)
def end_of_quarter
- change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month
+ beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month
end
alias :at_end_of_quarter :end_of_quarter
@@ -249,7 +264,7 @@ module ActiveSupport #:nodoc:
minus_without_duration(other)
end
end
-
+
# Time#- can also be used to determine the number of seconds between two Time instances.
# We're layering on additional behavior so that ActiveSupport::TimeWithZone instances
# are coerced into values that Time#- will recognize
@@ -257,7 +272,7 @@ module ActiveSupport #:nodoc:
other = other.comparable_time if other.respond_to?(:comparable_time)
minus_without_coercion(other)
end
-
+
# Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
# can be chronologically compared with a Time
def compare_with_coercion(other)
diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb
index 079ecdd48e..9d8eb73908 100644
--- a/activesupport/lib/active_support/core_ext/time/zones.rb
+++ b/activesupport/lib/active_support/core_ext/time/zones.rb
@@ -78,7 +78,7 @@ module ActiveSupport #:nodoc:
#
# Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
def in_time_zone(zone = ::Time.zone)
- ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.send!(:get_zone, zone))
+ ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.__send__(:get_zone, zone))
end
end
end
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index 01eb5df593..950bca60a6 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -109,7 +109,7 @@ module ActiveSupport
end
def deprecation_horizon
- '2.0'
+ '2.3'
end
end
@@ -162,6 +162,22 @@ module ActiveSupport
end
end
+ class DeprecatedObjectProxy < DeprecationProxy
+ def initialize(object, message)
+ @object = object
+ @message = message
+ end
+
+ private
+ def target
+ @object
+ end
+
+ def warn(callstack, called, args)
+ ActiveSupport::Deprecation.warn(@message, callstack)
+ end
+ end
+
# Stand-in for <tt>@request</tt>, <tt>@attributes</tt>, <tt>@params</tt>, etc.
# which emits deprecation warnings on any method call (except +inspect+).
class DeprecatedInstanceVariableProxy < DeprecationProxy #:nodoc:
diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
index 7ae9e0c6ab..8a917a9eb2 100644
--- a/activesupport/lib/active_support/inflector.rb
+++ b/activesupport/lib/active_support/inflector.rb
@@ -240,6 +240,25 @@ module ActiveSupport
def demodulize(class_name_in_module)
class_name_in_module.to_s.gsub(/^.*::/, '')
end
+
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
+ #
+ # ==== Examples
+ #
+ # class Person
+ # def to_param
+ # "#{id}-#{name.parameterize}"
+ # end
+ # end
+ #
+ # @person = Person.find(1)
+ # # => #<Person id: 1, name: "Donald E. Knuth">
+ #
+ # <%= link_to(@person.name, person_path %>
+ # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
+ def parameterize(string, sep = '-')
+ string.chars.normalize(:kd).to_s.gsub(/[^\x00-\x7F]+/, '').gsub(/[^a-z0-9_\-]+/i, sep).downcase
+ end
# Create the name of a table like Rails does for models to table names. This method
# uses the +pluralize+ method on the last word in the string.
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 6506238ac0..4786fd6e0b 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -60,7 +60,7 @@ module ActiveSupport
#{memoized_ivar} ||= {} unless frozen?
reload = args.pop if args.last == true || args.last == :reload
- if #{memoized_ivar}
+ if defined?(#{memoized_ivar}) && #{memoized_ivar}
if !reload && #{memoized_ivar}.has_key?(args)
#{memoized_ivar}[args]
elsif #{memoized_ivar}
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index 185d03020c..de2c83f8d1 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -49,6 +49,11 @@ module ActiveSupport::Multibyte #:nodoc:
false
end
+ # Enable more predictable duck-typing on String-like classes. See Object#acts_like?.
+ def acts_like_string?
+ true
+ end
+
# Create a new Chars instance.
def initialize(str)
@string = str.respond_to?(:string) ? str.string : str
diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb
index c77bca1ac9..b563b093ed 100644
--- a/activesupport/lib/active_support/option_merger.rb
+++ b/activesupport/lib/active_support/option_merger.rb
@@ -11,7 +11,7 @@ module ActiveSupport
private
def method_missing(method, *arguments, &block)
arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
- @context.send!(method, *arguments, &block)
+ @context.__send__(method, *arguments, &block)
end
end
end
diff --git a/activesupport/lib/active_support/secure_random.rb b/activesupport/lib/active_support/secure_random.rb
new file mode 100644
index 0000000000..688165f9a3
--- /dev/null
+++ b/activesupport/lib/active_support/secure_random.rb
@@ -0,0 +1,197 @@
+begin
+ require 'openssl'
+rescue LoadError
+end
+
+begin
+ require 'securerandom'
+rescue LoadError
+end
+
+module ActiveSupport
+ if defined?(::SecureRandom)
+ # Use Ruby 1.9's SecureRandom library whenever possible.
+ SecureRandom = ::SecureRandom # :nodoc:
+ else
+ # = Secure random number generator interface.
+ #
+ # This library is an interface for secure random number generator which is
+ # suitable for generating session key in HTTP cookies, etc.
+ #
+ # It supports following secure random number generators.
+ #
+ # * openssl
+ # * /dev/urandom
+ # * Win32
+ #
+ # *Note*: This module is based on the SecureRandom library from Ruby 1.9,
+ # revision 18786, August 23 2008. It's 100% interface-compatible with Ruby 1.9's
+ # SecureRandom library.
+ #
+ # == Example
+ #
+ # # random hexadecimal string.
+ # p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
+ # p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
+ # p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
+ # p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
+ # p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
+ # ...
+ #
+ # # random base64 string.
+ # p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
+ # p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
+ # p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
+ # p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
+ # p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
+ # p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
+ # ...
+ #
+ # # random binary string.
+ # p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
+ # p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
+ # ...
+ module SecureRandom
+ # SecureRandom.random_bytes generates a random binary string.
+ #
+ # The argument n specifies the length of the result string.
+ #
+ # If n is not specified, 16 is assumed.
+ # It may be larger in future.
+ #
+ # If secure random number generator is not available,
+ # NotImplementedError is raised.
+ def self.random_bytes(n=nil)
+ n ||= 16
+
+ if defined? OpenSSL::Random
+ return OpenSSL::Random.random_bytes(n)
+ end
+
+ if !defined?(@has_urandom) || @has_urandom
+ flags = File::RDONLY
+ flags |= File::NONBLOCK if defined? File::NONBLOCK
+ flags |= File::NOCTTY if defined? File::NOCTTY
+ flags |= File::NOFOLLOW if defined? File::NOFOLLOW
+ begin
+ File.open("/dev/urandom", flags) {|f|
+ unless f.stat.chardev?
+ raise Errno::ENOENT
+ end
+ @has_urandom = true
+ ret = f.readpartial(n)
+ if ret.length != n
+ raise NotImplementedError, "Unexpected partial read from random device"
+ end
+ return ret
+ }
+ rescue Errno::ENOENT
+ @has_urandom = false
+ end
+ end
+
+ if !defined?(@has_win32)
+ begin
+ require 'Win32API'
+
+ crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
+ @crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'LIP', 'L')
+
+ hProvStr = " " * 4
+ prov_rsa_full = 1
+ crypt_verifycontext = 0xF0000000
+
+ if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
+ raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
+ end
+ @hProv, = hProvStr.unpack('L')
+
+ @has_win32 = true
+ rescue LoadError
+ @has_win32 = false
+ end
+ end
+ if @has_win32
+ bytes = " " * n
+ if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
+ raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
+ end
+ return bytes
+ end
+
+ raise NotImplementedError, "No random device"
+ end
+
+ # SecureRandom.hex generates a random hex string.
+ #
+ # The argument n specifies the length of the random length.
+ # The length of the result string is twice of n.
+ #
+ # If n is not specified, 16 is assumed.
+ # It may be larger in future.
+ #
+ # If secure random number generator is not available,
+ # NotImplementedError is raised.
+ def self.hex(n=nil)
+ random_bytes(n).unpack("H*")[0]
+ end
+
+ # SecureRandom.base64 generates a random base64 string.
+ #
+ # The argument n specifies the length of the random length.
+ # The length of the result string is about 4/3 of n.
+ #
+ # If n is not specified, 16 is assumed.
+ # It may be larger in future.
+ #
+ # If secure random number generator is not available,
+ # NotImplementedError is raised.
+ def self.base64(n=nil)
+ [random_bytes(n)].pack("m*").delete("\n")
+ end
+
+ # SecureRandom.random_number generates a random number.
+ #
+ # If an positive integer is given as n,
+ # SecureRandom.random_number returns an integer:
+ # 0 <= SecureRandom.random_number(n) < n.
+ #
+ # If 0 is given or an argument is not given,
+ # SecureRandom.random_number returns an float:
+ # 0.0 <= SecureRandom.random_number() < 1.0.
+ def self.random_number(n=0)
+ if 0 < n
+ hex = n.to_s(16)
+ hex = '0' + hex if (hex.length & 1) == 1
+ bin = [hex].pack("H*")
+ mask = bin[0].ord
+ mask |= mask >> 1
+ mask |= mask >> 2
+ mask |= mask >> 4
+ begin
+ rnd = SecureRandom.random_bytes(bin.length)
+ rnd[0] = (rnd[0].ord & mask).chr
+ end until rnd < bin
+ rnd.unpack("H*")[0].hex
+ else
+ # assumption: Float::MANT_DIG <= 64
+ i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
+ Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
+ end
+ end
+
+ # Following code is based on David Garamond's GUID library for Ruby.
+ def self.lastWin32ErrorMessage # :nodoc:
+ get_last_error = Win32API.new("kernel32", "GetLastError", '', 'L')
+ format_message = Win32API.new("kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L')
+ format_message_ignore_inserts = 0x00000200
+ format_message_from_system = 0x00001000
+
+ code = get_last_error.call
+ msg = "\0" * 1024
+ len = format_message.call(format_message_ignore_inserts + format_message_from_system, 0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil)
+ msg[0, len].tr("\r", '').chomp
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb
index 65545748df..cd722a3cfb 100644
--- a/activesupport/lib/active_support/string_inquirer.rb
+++ b/activesupport/lib/active_support/string_inquirer.rb
@@ -1,4 +1,14 @@
module ActiveSupport
+ # Wrapping a string in this class gives you a prettier way to test
+ # for equality. The value returned by <tt>Rails.env</tt> is wrapped
+ # in a StringInquirer object so instead of calling this:
+ #
+ # Rails.env == "production"
+ #
+ # you can call this:
+ #
+ # Rails.env.production?
+ #
class StringInquirer < String
def method_missing(method_name, *arguments)
if method_name.to_s.ends_with?("?")
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 0f531b0c79..197e73b3e8 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -12,7 +12,13 @@ module ActiveSupport
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
defined = instance_method(test_name) rescue false
raise "#{test_name} is already defined in #{self}" if defined
- define_method(test_name, &block)
+ if block_given?
+ define_method(test_name, &block)
+ else
+ define_method(test_name) do
+ flunk "No implementation provided for #{name}"
+ end
+ end
end
end
end
diff --git a/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb b/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb
index 70a44eab8c..63d1ba6507 100644
--- a/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb
+++ b/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb
@@ -36,7 +36,11 @@ module Test
# post :delete, :id => ...
# end
def assert_difference(expressions, difference = 1, message = nil, &block)
- expression_evaluations = Array(expressions).collect{ |expression| lambda { eval(expression, block.send!(:binding)) } }
+ expression_evaluations = Array(expressions).map do |expression|
+ lambda do
+ eval(expression, block.__send__(:binding))
+ end
+ end
original_values = expression_evaluations.inject([]) { |memo, expression| memo << expression.call }
yield
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 4866fa0dc8..b7b8807c6d 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -1,6 +1,6 @@
require 'tzinfo'
module ActiveSupport
- # A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are
+ # A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are
# limited to UTC and the system's <tt>ENV['TZ']</tt> zone.
#
# You shouldn't ever need to create a TimeWithZone instance directly via <tt>new</tt> -- instead, Rails provides the methods
@@ -32,12 +32,12 @@ module ActiveSupport
class TimeWithZone
include Comparable
attr_reader :time_zone
-
+
def initialize(utc_time, time_zone, local_time = nil, period = nil)
@utc, @time_zone, @time = utc_time, time_zone, local_time
@period = @utc ? period : get_period_and_ensure_valid_local_time
end
-
+
# Returns a Time or DateTime instance that represents the time in +time_zone+.
def time
@time ||= period.to_local(@utc)
@@ -51,7 +51,7 @@ module ActiveSupport
alias_method :getgm, :utc
alias_method :getutc, :utc
alias_method :gmtime, :utc
-
+
# Returns the underlying TZInfo::TimezonePeriod.
def period
@period ||= time_zone.period_for_utc(@utc)
@@ -62,38 +62,38 @@ module ActiveSupport
return self if time_zone == new_zone
utc.in_time_zone(new_zone)
end
-
+
# Returns a <tt>Time.local()</tt> instance of the simultaneous time in your system's <tt>ENV['TZ']</tt> zone
def localtime
utc.getlocal
end
alias_method :getlocal, :localtime
-
+
def dst?
period.dst?
end
alias_method :isdst, :dst?
-
+
def utc?
time_zone.name == 'UTC'
end
alias_method :gmt?, :utc?
-
+
def utc_offset
period.utc_total_offset
end
alias_method :gmt_offset, :utc_offset
alias_method :gmtoff, :utc_offset
-
+
def formatted_offset(colon = true, alternate_utc_string = nil)
utc? && alternate_utc_string || utc_offset.to_utc_offset_s(colon)
end
-
+
# Time uses +zone+ to display the time zone abbreviation, so we're duck-typing it.
def zone
period.zone_identifier.to_s
end
-
+
def inspect
"#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
end
@@ -122,7 +122,7 @@ module ActiveSupport
%("#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}")
end
end
-
+
def to_yaml(options = {})
if options.kind_of?(YAML::Emitter)
utc.to_yaml(options)
@@ -130,19 +130,19 @@ module ActiveSupport
time.to_yaml(options).gsub('Z', formatted_offset(true, 'Z'))
end
end
-
+
def httpdate
utc.httpdate
end
-
+
def rfc2822
to_s(:rfc822)
end
alias_method :rfc822, :rfc2822
-
+
# <tt>:db</tt> format outputs time in UTC; all others output time in local.
# Uses TimeWithZone's +strftime+, so <tt>%Z</tt> and <tt>%z</tt> work correctly.
- def to_s(format = :default)
+ def to_s(format = :default)
return utc.to_s(format) if format == :db
if formatter = ::Time::DATE_FORMATS[format]
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
@@ -150,27 +150,39 @@ module ActiveSupport
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby 1.9 Time#to_s format
end
end
-
+
# Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and +formatted_offset+, respectively, before passing to
# Time#strftime, so that zone information is correct
def strftime(format)
format = format.gsub('%Z', zone).gsub('%z', formatted_offset(false))
time.strftime(format)
end
-
+
# Use the time in UTC for comparisons.
def <=>(other)
utc <=> other
end
-
+
def between?(min, max)
utc.between?(min, max)
end
-
+
+ def past?
+ utc.past?
+ end
+
+ def today?
+ time.today?
+ end
+
+ def future?
+ utc.future?
+ end
+
def eql?(other)
utc == other
end
-
+
def +(other)
# If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
# otherwise move forward from #utc, for accuracy when moving across DST boundaries
@@ -194,7 +206,7 @@ module ActiveSupport
result.in_time_zone(time_zone)
end
end
-
+
def since(other)
# If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
# otherwise move forward from #utc, for accuracy when moving across DST boundaries
@@ -204,7 +216,7 @@ module ActiveSupport
utc.since(other).in_time_zone(time_zone)
end
end
-
+
def ago(other)
since(-other)
end
@@ -218,53 +230,53 @@ module ActiveSupport
utc.advance(options).in_time_zone(time_zone)
end
end
-
- %w(year mon month day mday hour min sec).each do |method_name|
+
+ %w(year mon month day mday wday yday hour min sec to_date).each do |method_name|
class_eval <<-EOV
def #{method_name}
time.#{method_name}
end
EOV
end
-
+
def usec
time.respond_to?(:usec) ? time.usec : 0
end
-
+
def to_a
[time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
end
-
+
def to_f
utc.to_f
- end
-
+ end
+
def to_i
utc.to_i
end
alias_method :hash, :to_i
alias_method :tv_sec, :to_i
-
+
# A TimeWithZone acts like a Time, so just return +self+.
def to_time
self
end
-
+
def to_datetime
utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
end
-
+
# So that +self+ <tt>acts_like?(:time)</tt>.
def acts_like_time?
true
end
-
+
# Say we're a Time to thwart type checking.
def is_a?(klass)
klass == ::Time || super
end
alias_method :kind_of?, :is_a?
-
+
# Neuter freeze because freezing can cause problems with lazy loading of attributes.
def freeze
self
@@ -273,9 +285,9 @@ module ActiveSupport
def marshal_dump
[utc, time_zone.name, time]
end
-
+
def marshal_load(variables)
- initialize(variables[0].utc, ::Time.send!(:get_zone, variables[1]), variables[2].utc)
+ initialize(variables[0].utc, ::Time.__send__(:get_zone, variables[1]), variables[2].utc)
end
# Ensure proxy class responds to all methods that underlying time instance responds to.
@@ -290,10 +302,10 @@ module ActiveSupport
result = time.__send__(sym, *args, &block)
result.acts_like?(:time) ? self.class.new(nil, time_zone, result) : result
end
-
- private
+
+ private
def get_period_and_ensure_valid_local_time
- # we don't want a Time.local instance enforcing its own DST rules as well,
+ # we don't want a Time.local instance enforcing its own DST rules as well,
# so transfer time values to a utc constructor if necessary
@time = transfer_time_values_to_utc_constructor(@time) unless @time.utc?
begin
@@ -304,11 +316,11 @@ module ActiveSupport
retry
end
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)
end
-
+
def duration_of_variable_length?(obj)
ActiveSupport::Duration === obj && obj.parts.flatten.detect {|p| [:years, :months, :days].include? p }
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 788d40bfa8..a294dd0ba3 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -124,7 +124,7 @@ module ActiveSupport
"Kathmandu" => "Asia/Katmandu",
"Astana" => "Asia/Dhaka",
"Dhaka" => "Asia/Dhaka",
- "Sri Jayawardenepura" => "Asia/Dhaka",
+ "Sri Jayawardenepura" => "Asia/Colombo",
"Almaty" => "Asia/Almaty",
"Novosibirsk" => "Asia/Novosibirsk",
"Rangoon" => "Asia/Rangoon",
diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb
index 9e347d94e9..344c77aecf 100755
--- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb
+++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb
@@ -10,7 +10,8 @@ require 'i18n/exceptions'
module I18n
@@backend = nil
- @@default_locale = 'en-US'
+ @@load_path = nil
+ @@default_locale = :'en-US'
@@exception_handler = :default_exception_handler
class << self
@@ -49,26 +50,22 @@ module I18n
@@exception_handler = exception_handler
end
- # Allow client libraries to pass a block that populates the translation
- # storage. Decoupled for backends like a db backend that persist their
- # translations, so the backend can decide whether/when to yield or not.
- def populate(&block)
- backend.populate(&block)
- end
-
- # Allows client libraries to pass arguments that specify a source for
- # translation data to be loaded by the backend. The backend defines
- # acceptable sources.
+ # Allow clients to register paths providing translation data sources. The
+ # backend defines acceptable sources.
+ #
# E.g. the provided SimpleBackend accepts a list of paths to translation
# files which are either named *.rb and contain plain Ruby Hashes or are
- # named *.yml and contain YAML data.)
- def load_translations(*args)
- backend.load_translations(*args)
+ # named *.yml and contain YAML data. So for the SimpleBackend clients may
+ # register translation files like this:
+ # I18n.load_path << 'path/to/locale/en-US.yml'
+ def load_path
+ @@load_path ||= []
end
-
- # Stores translations for the given locale in the backend.
- def store_translations(locale, data)
- backend.store_translations locale, data
+
+ # Sets the load path instance. Custom implementations are expected to
+ # behave like a Ruby Array.
+ def load_path=(load_path)
+ @@load_path = load_path
end
# Translates, pluralizes and interpolates a given key using a given locale,
@@ -187,6 +184,4 @@ module I18n
keys.flatten.map{|k| k.to_sym}
end
end
-end
-
-
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb
index a53f7fe772..2dbaf8a405 100644
--- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb
+++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb
@@ -1,15 +1,11 @@
-require 'strscan'
+require 'yaml'
module I18n
module Backend
class Simple
- # Allow client libraries to pass a block that populates the translation
- # storage. Decoupled for backends like a db backend that persist their
- # translations, so the backend can decide whether/when to yield or not.
- def populate(&block)
- yield
- end
-
+ INTERPOLATION_RESERVED_KEYS = %w(scope default)
+ MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
+
# Accepts a list of paths to translation files. Loads translations from
# plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
# for details.
@@ -47,12 +43,15 @@ module I18n
raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
type = object.respond_to?(:sec) ? 'time' : 'date'
+ # TODO only translate these if format is a String?
formats = translate(locale, :"#{type}.formats")
format = formats[format.to_sym] if formats && formats[format.to_sym]
# TODO raise exception unless format found?
format = format.to_s.dup
- format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
+ # TODO only translate these if the format string is actually present
+ # TODO check which format strings are present, then bulk translate then, then replace them
+ format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
@@ -60,7 +59,16 @@ module I18n
object.strftime(format)
end
+ def initialized?
+ @initialized ||= false
+ end
+
protected
+
+ def init_translations
+ load_translations(*I18n.load_path)
+ @initialized = true
+ end
def translations
@translations ||= {}
@@ -73,6 +81,7 @@ module I18n
# <tt>%w(currency format)</tt>.
def lookup(locale, key, scope = [])
return unless key
+ init_translations unless initialized?
keys = I18n.send :normalize_translation_keys, locale, key, scope
keys.inject(translations){|result, k| result[k.to_sym] or return nil }
end
@@ -95,7 +104,7 @@ module I18n
rescue MissingTranslationData
nil
end
-
+
# Picks a translation from an array according to English pluralization
# rules. It will pick the first translation if count is not equal to 1
# and the second translation if it is equal to 1. Other backends can
@@ -108,7 +117,7 @@ module I18n
raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
entry[key]
end
-
+
# Interpolates values into a given string.
#
# interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
@@ -118,29 +127,27 @@ module I18n
# the <tt>{{...}}</tt> key in a string (once for the string and once for the
# interpolation).
def interpolate(locale, string, values = {})
- return string if !string.is_a?(String)
+ return string unless string.is_a?(String)
- string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}')
if string.respond_to?(:force_encoding)
- original_encoding = string.encoding
- string.force_encoding(Encoding::BINARY)
- end
- s = StringScanner.new(string)
-
- while s.skip_until(/\{\{/)
- s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\'
- start_pos = s.pos - 2
- key = s.scan_until(/\}\}/)[0..-3]
- end_pos = s.pos - 1
+ original_encoding = string.encoding
+ string.force_encoding(Encoding::BINARY)
+ end
- raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key)
- raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym
+ result = string.gsub(MATCH) do
+ escaped, pattern, key = $1, $2, $2.to_sym
- s.string[start_pos..end_pos] = values[key.to_sym].to_s
- s.unscan
+ if escaped
+ pattern
+ elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
+ raise ReservedInterpolationKey.new(pattern, string)
+ elsif !values.include?(key)
+ raise MissingInterpolationArgument.new(pattern, string)
+ else
+ values[key].to_s
+ end
end
-
- result = s.string
+
result.force_encoding(original_encoding) if original_encoding
result
end
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb
new file mode 100644
index 0000000000..f6531fa819
--- /dev/null
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb
@@ -0,0 +1,30 @@
+require 'tzinfo/timezone_definition'
+
+module TZInfo
+ module Definitions
+ module Asia
+ module Colombo
+ include TimezoneDefinition
+
+ timezone 'Asia/Colombo' do |tz|
+ tz.offset :o0, 19164, 0, :LMT
+ tz.offset :o1, 19172, 0, :MMT
+ tz.offset :o2, 19800, 0, :IST
+ tz.offset :o3, 19800, 1800, :IHST
+ tz.offset :o4, 19800, 3600, :IST
+ tz.offset :o5, 23400, 0, :LKT
+ tz.offset :o6, 21600, 0, :LKT
+
+ tz.transition 1879, 12, :o1, 17335550003, 7200
+ tz.transition 1905, 12, :o2, 52211763607, 21600
+ tz.transition 1942, 1, :o3, 116657485, 48
+ tz.transition 1942, 8, :o4, 9722413, 4
+ tz.transition 1945, 10, :o2, 38907909, 16
+ tz.transition 1996, 5, :o5, 832962600
+ tz.transition 1996, 10, :o6, 846266400
+ tz.transition 2006, 4, :o2, 1145039400
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb
index 6319c09210..28dd34334f 100644
--- a/activesupport/test/buffered_logger_test.rb
+++ b/activesupport/test/buffered_logger_test.rb
@@ -134,6 +134,7 @@ class BufferedLoggerTest < Test::Unit::TestCase
a.join
b.join
- assert_equal "a\nb\nc\nx\ny\nz\n", @output.string
+ assert @output.string.include?("a\nb\nc\n")
+ assert @output.string.include?("x\ny\nz\n")
end
end
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 0f3cf4c75c..b53c754780 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -210,6 +210,29 @@ class DateExtCalculationsTest < Test::Unit::TestCase
end
end
+ uses_mocha 'past?, today? and future?' do
+ def test_today
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, Date.new(1999, 12, 31).today?
+ assert_equal true, Date.new(2000,1,1).today?
+ assert_equal false, Date.new(2000,1,2).today?
+ end
+
+ def test_past
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal true, Date.new(1999, 12, 31).past?
+ assert_equal false, Date.new(2000,1,1).past?
+ assert_equal false, Date.new(2000,1,2).past?
+ end
+
+ def test_future
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, Date.new(1999, 12, 31).future?
+ assert_equal false, Date.new(2000,1,1).future?
+ assert_equal true, Date.new(2000,1,2).future?
+ end
+ end
+
uses_mocha 'TestDateCurrent' do
def test_current_returns_date_today_when_zone_default_not_set
with_env_tz 'US/Central' do
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 854a3a05e1..be3cd8b5d6 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -207,6 +207,81 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_match(/^2080-02-28T15:15:10-06:?00$/, DateTime.civil(2080, 2, 28, 15, 15, 10, -0.25).xmlschema)
end
+ uses_mocha 'Test DateTime past?, today? and future?' do
+ def test_today_with_offset
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, DateTime.civil(1999,12,31,23,59,59, Rational(-18000, 86400)).today?
+ assert_equal true, DateTime.civil(2000,1,1,0,0,0, Rational(-18000, 86400)).today?
+ assert_equal true, DateTime.civil(2000,1,1,23,59,59, Rational(-18000, 86400)).today?
+ assert_equal false, DateTime.civil(2000,1,2,0,0,0, Rational(-18000, 86400)).today?
+ end
+
+ def test_today_without_offset
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, DateTime.civil(1999,12,31,23,59,59).today?
+ assert_equal true, DateTime.civil(2000,1,1,0).today?
+ assert_equal true, DateTime.civil(2000,1,1,23,59,59).today?
+ assert_equal false, DateTime.civil(2000,1,2,0).today?
+ end
+
+ def test_past_with_offset
+ DateTime.stubs(:current).returns(DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)))
+ assert_equal true, DateTime.civil(2005,2,10,15,30,44, Rational(-18000, 86400)).past?
+ assert_equal false, DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)).past?
+ assert_equal false, DateTime.civil(2005,2,10,15,30,46, Rational(-18000, 86400)).past?
+ end
+
+ def test_past_without_offset
+ DateTime.stubs(:current).returns(DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)))
+ assert_equal true, DateTime.civil(2005,2,10,20,30,44).past?
+ assert_equal false, DateTime.civil(2005,2,10,20,30,45).past?
+ assert_equal false, DateTime.civil(2005,2,10,20,30,46).past?
+ end
+
+ def test_future_with_offset
+ DateTime.stubs(:current).returns(DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)))
+ assert_equal false, DateTime.civil(2005,2,10,15,30,44, Rational(-18000, 86400)).future?
+ assert_equal false, DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)).future?
+ assert_equal true, DateTime.civil(2005,2,10,15,30,46, Rational(-18000, 86400)).future?
+ end
+
+ def test_future_without_offset
+ DateTime.stubs(:current).returns(DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)))
+ assert_equal false, DateTime.civil(2005,2,10,20,30,44).future?
+ assert_equal false, DateTime.civil(2005,2,10,20,30,45).future?
+ assert_equal true, DateTime.civil(2005,2,10,20,30,46).future?
+ end
+ end
+
+ uses_mocha 'TestDateTimeCurrent' do
+ def test_current_returns_date_today_when_zone_default_not_set
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:now).returns Time.local(1999, 12, 31, 23, 59, 59)
+ assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current
+ end
+ end
+
+ def test_current_returns_time_zone_today_when_zone_default_set
+ Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:now).returns Time.local(1999, 12, 31, 23, 59, 59)
+ assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current
+ end
+ ensure
+ Time.zone_default = nil
+ end
+ end
+
+ def test_current_without_time_zone
+ assert DateTime.current.is_a?(DateTime)
+ end
+
+ def test_current_with_time_zone
+ with_env_tz 'US/Eastern' do
+ assert DateTime.current.is_a?(DateTime)
+ end
+ end
+
def test_acts_like_time
assert DateTime.new.acts_like_time?
end
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 2315d8f3db..deb9b7544d 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -58,6 +58,11 @@ class EnumerableTests < Test::Unit::TestCase
assert_equal Payment.new(0), [].sum(Payment.new(0))
end
+ def test_each_with_object
+ result = %w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase }
+ assert_equal({'foo' => 'FOO', 'bar' => 'BAR'}, result)
+ end
+
def test_index_by
payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ]
assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] },
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index fc8ed45358..44d48e7577 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -62,7 +62,7 @@ class HashExtTest < Test::Unit::TestCase
@symbols = @symbols.with_indifferent_access
@mixed = @mixed.with_indifferent_access
- assert_equal 'a', @strings.send!(:convert_key, :a)
+ assert_equal 'a', @strings.__send__(:convert_key, :a)
assert_equal 1, @strings.fetch('a')
assert_equal 1, @strings.fetch(:a.to_s)
@@ -75,9 +75,9 @@ class HashExtTest < Test::Unit::TestCase
hashes.each do |name, hash|
method_map.sort_by { |m| m.to_s }.each do |meth, expected|
- assert_equal(expected, hash.send!(meth, 'a'),
+ assert_equal(expected, hash.__send__(meth, 'a'),
"Calling #{name}.#{meth} 'a'")
- assert_equal(expected, hash.send!(meth, :a),
+ assert_equal(expected, hash.__send__(meth, :a),
"Calling #{name}.#{meth} :a")
end
end
@@ -341,6 +341,20 @@ class HashExtTest < Test::Unit::TestCase
assert_equal expected, original.except!(:c)
assert_equal expected, original
end
+
+ def test_except_with_original_frozen
+ original = { :a => 'x', :b => 'y' }
+ original.freeze
+ assert_nothing_raised { original.except(:a) }
+ end
+
+ uses_mocha 'except with expectation' do
+ def test_except_with_mocha_expectation_on_original
+ original = { :a => 'x', :b => 'y' }
+ original.expects(:delete).never
+ original.except(:a)
+ end
+ end
end
class IWriteMyOwnXML
@@ -733,7 +747,7 @@ class HashToXmlTest < Test::Unit::TestCase
def test_empty_string_works_for_typecast_xml_value
assert_nothing_raised do
- Hash.send!(:typecast_xml_value, "")
+ Hash.__send__(:typecast_xml_value, "")
end
end
@@ -839,6 +853,27 @@ class QueryTest < Test::Unit::TestCase
:person => {:id => [20, 10]}
end
+ def test_expansion_count_is_limited
+ assert_raises RuntimeError do
+ attack_xml = <<-EOT
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE member [
+ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
+ <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
+ <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;">
+ <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;">
+ <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;">
+ <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;">
+ <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
+ ]>
+ <member>
+ &a;
+ </member>
+ EOT
+ Hash.from_xml(attack_xml)
+ end
+ end
+
private
def assert_query_equal(expected, actual, message = nil)
assert_equal expected.split('&'), actual.to_query.split('&')
diff --git a/activesupport/test/core_ext/module/synchronization_test.rb b/activesupport/test/core_ext/module/synchronization_test.rb
new file mode 100644
index 0000000000..b1d4bc5e06
--- /dev/null
+++ b/activesupport/test/core_ext/module/synchronization_test.rb
@@ -0,0 +1,85 @@
+require 'abstract_unit'
+
+class SynchronizationTest < Test::Unit::TestCase
+ def setup
+ @target = Class.new
+ @target.cattr_accessor :mutex, :instance_writer => false
+ @target.mutex = Mutex.new
+ @instance = @target.new
+ end
+
+ def test_synchronize_aliases_method_chain_with_synchronize
+ @target.module_eval do
+ attr_accessor :value
+ synchronize :value, :with => :mutex
+ end
+ assert @instance.respond_to?(:value_with_synchronization)
+ assert @instance.respond_to?(:value_without_synchronization)
+ end
+
+ def test_synchronize_does_not_change_behavior
+ @target.module_eval do
+ attr_accessor :value
+ synchronize :value, :with => :mutex
+ end
+ expected = "some state"
+ @instance.value = expected
+ assert_equal expected, @instance.value
+ end
+
+ def test_synchronize_with_no_mutex_raises_an_argument_error
+ assert_raises(ArgumentError) do
+ @target.synchronize :to_s
+ end
+ end
+
+ def test_double_synchronize_raises_an_argument_error
+ @target.synchronize :to_s, :with => :mutex
+ assert_raises(ArgumentError) do
+ @target.synchronize :to_s, :with => :mutex
+ end
+ end
+
+ def dummy_sync
+ dummy = Object.new
+ def dummy.synchronize
+ @sync_count ||= 0
+ @sync_count += 1
+ yield
+ end
+ def dummy.sync_count; @sync_count; end
+ dummy
+ end
+
+ def test_mutex_is_entered_during_method_call
+ @target.mutex = dummy_sync
+ @target.synchronize :to_s, :with => :mutex
+ @instance.to_s
+ @instance.to_s
+ assert_equal 2, @target.mutex.sync_count
+ end
+
+ def test_can_synchronize_method_with_punctuation
+ @target.module_eval do
+ def dangerous?
+ @dangerous
+ end
+ def dangerous!
+ @dangerous = true
+ end
+ end
+ @target.synchronize :dangerous?, :dangerous!, :with => :mutex
+ @instance.dangerous!
+ assert @instance.dangerous?
+ end
+
+ def test_can_synchronize_singleton_methods
+ @target.mutex = dummy_sync
+ class << @target
+ synchronize :to_s, :with => :mutex
+ end
+ assert @target.respond_to?(:to_s_without_synchronization)
+ assert_nothing_raised { @target.to_s; @target.to_s }
+ assert_equal 2, @target.mutex.sync_count
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb
index b0a746fdc7..e88dcb52d5 100644
--- a/activesupport/test/core_ext/object_and_class_ext_test.rb
+++ b/activesupport/test/core_ext/object_and_class_ext_test.rb
@@ -108,11 +108,6 @@ class ClassExtTest < Test::Unit::TestCase
end
class ObjectTests < Test::Unit::TestCase
- def test_send_bang_aliases_send_before_19
- assert_respond_to 'a', :send!
- assert_equal 1, 'a'.send!(:size)
- end
-
def test_suppress_re_raises
assert_raises(LoadError) { suppress(ArgumentError) {raise LoadError} }
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index c9f959ef32..c0decf2c3f 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -201,3 +201,9 @@ class StringInflectionsTest < Test::Unit::TestCase
end
end
end
+
+class StringBehaviourTest < Test::Unit::TestCase
+ def test_acts_like_string
+ assert 'Bambi'.acts_like_string?
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 8740497b3d..8ceaedc7f4 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -117,6 +117,7 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
assert_equal Time.local(2007,3,31,23,59,59), Time.local(2007,3,31,0,0,0).end_of_quarter
assert_equal Time.local(2007,12,31,23,59,59), Time.local(2007,12,21,10,10,10).end_of_quarter
assert_equal Time.local(2007,6,30,23,59,59), Time.local(2007,4,1,0,0,0).end_of_quarter
+ assert_equal Time.local(2008,6,30,23,59,59), Time.local(2008,5,31,0,0,0).end_of_quarter
end
def test_end_of_year
@@ -524,13 +525,12 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
assert_equal Time.time_with_datetime_fallback(:utc, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, 0, 0)
- assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, DateTime.local_offset, 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, 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
- expected_to_overflow = Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1)
- unless expected_to_overflow.is_a?(Time)
+ unless time_is_64bits?
+ assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
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
@@ -546,7 +546,10 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
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(2039, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
- assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
+
+ unless time_is_64bits?
+ assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
+ end
end
def test_next_month_on_31st
@@ -561,6 +564,74 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
assert_nothing_raised { Time.now.xmlschema }
end
+ uses_mocha 'Test Time past?, today? and future?' do
+ def test_today_with_time_local
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, Time.local(1999,12,31,23,59,59).today?
+ assert_equal true, Time.local(2000,1,1,0).today?
+ assert_equal true, Time.local(2000,1,1,23,59,59).today?
+ assert_equal false, Time.local(2000,1,2,0).today?
+ end
+
+ def test_today_with_time_utc
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, Time.utc(1999,12,31,23,59,59).today?
+ assert_equal true, Time.utc(2000,1,1,0).today?
+ assert_equal true, Time.utc(2000,1,1,23,59,59).today?
+ assert_equal false, Time.utc(2000,1,2,0).today?
+ end
+
+ def test_past_with_time_current_as_time_local
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:current).returns(Time.local(2005,2,10,15,30,45))
+ assert_equal true, Time.local(2005,2,10,15,30,44).past?
+ assert_equal false, Time.local(2005,2,10,15,30,45).past?
+ assert_equal false, Time.local(2005,2,10,15,30,46).past?
+ assert_equal true, Time.utc(2005,2,10,20,30,44).past?
+ assert_equal false, Time.utc(2005,2,10,20,30,45).past?
+ assert_equal false, Time.utc(2005,2,10,20,30,46).past?
+ end
+ end
+
+ def test_past_with_time_current_as_time_with_zone
+ with_env_tz 'US/Eastern' do
+ twz = Time.utc(2005,2,10,15,30,45).in_time_zone('Central Time (US & Canada)')
+ Time.stubs(:current).returns(twz)
+ assert_equal true, Time.local(2005,2,10,10,30,44).past?
+ assert_equal false, Time.local(2005,2,10,10,30,45).past?
+ assert_equal false, Time.local(2005,2,10,10,30,46).past?
+ assert_equal true, Time.utc(2005,2,10,15,30,44).past?
+ assert_equal false, Time.utc(2005,2,10,15,30,45).past?
+ assert_equal false, Time.utc(2005,2,10,15,30,46).past?
+ end
+ end
+
+ def test_future_with_time_current_as_time_local
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:current).returns(Time.local(2005,2,10,15,30,45))
+ assert_equal false, Time.local(2005,2,10,15,30,44).future?
+ assert_equal false, Time.local(2005,2,10,15,30,45).future?
+ assert_equal true, Time.local(2005,2,10,15,30,46).future?
+ assert_equal false, Time.utc(2005,2,10,20,30,44).future?
+ assert_equal false, Time.utc(2005,2,10,20,30,45).future?
+ assert_equal true, Time.utc(2005,2,10,20,30,46).future?
+ end
+ end
+
+ def test_future_with_time_current_as_time_with_zone
+ with_env_tz 'US/Eastern' do
+ twz = Time.utc(2005,2,10,15,30,45).in_time_zone('Central Time (US & Canada)')
+ Time.stubs(:current).returns(twz)
+ assert_equal false, Time.local(2005,2,10,10,30,44).future?
+ assert_equal false, Time.local(2005,2,10,10,30,45).future?
+ assert_equal true, Time.local(2005,2,10,10,30,46).future?
+ assert_equal false, Time.utc(2005,2,10,15,30,44).future?
+ assert_equal false, Time.utc(2005,2,10,15,30,45).future?
+ assert_equal true, Time.utc(2005,2,10,15,30,46).future?
+ end
+ end
+ end
+
def test_acts_like_time
assert Time.new.acts_like_time?
end
@@ -624,4 +695,42 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
ensure
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
end
+
+ def time_is_64bits?
+ Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).is_a?(Time)
+ end
+end
+
+class TimeExtMarshalingTest < Test::Unit::TestCase
+ def test_marshaling_with_utc_instance
+ t = Time.utc(2000)
+ marshaled = Marshal.dump t
+ unmarshaled = Marshal.load marshaled
+ assert_equal t, unmarshaled
+ assert_equal t.zone, unmarshaled.zone
+ end
+
+ def test_marshaling_with_local_instance
+ t = Time.local(2000)
+ marshaled = Marshal.dump t
+ unmarshaled = Marshal.load marshaled
+ assert_equal t, unmarshaled
+ assert_equal t.zone, unmarshaled.zone
+ end
+
+ def test_marshaling_with_frozen_utc_instance
+ t = Time.utc(2000).freeze
+ marshaled = Marshal.dump t
+ unmarshaled = Marshal.load marshaled
+ assert_equal t, unmarshaled
+ assert_equal t.zone, unmarshaled.zone
+ end
+
+ def test_marshaling_with_frozen_local_instance
+ t = Time.local(2000).freeze
+ marshaled = Marshal.dump t
+ unmarshaled = Marshal.load marshaled
+ assert_equal t, unmarshaled
+ assert_equal t.zone, unmarshaled.zone
+ end
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index dfe04485be..72b540efe0 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -152,6 +152,50 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal false, @twz.between?(Time.utc(2000,1,1,0,0,1), Time.utc(2000,1,1,0,0,2))
end
+ uses_mocha 'TimeWithZone past?, today? and future?' do
+ def test_today
+ Date.stubs(:current).returns(Date.new(2000, 1, 1))
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.utc(1999,12,31,23,59,59) ).today?
+ assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.utc(2000,1,1,0) ).today?
+ assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.utc(2000,1,1,23,59,59) ).today?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.utc(2000,1,2,0) ).today?
+ end
+
+ def test_past_with_time_current_as_time_local
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:current).returns(Time.local(2005,2,10,15,30,45))
+ assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).past?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).past?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,46)).past?
+ end
+ end
+
+ def test_past_with_time_current_as_time_with_zone
+ twz = ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45) )
+ Time.stubs(:current).returns(twz)
+ assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).past?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).past?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,46)).past?
+ end
+
+ def test_future_with_time_current_as_time_local
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:current).returns(Time.local(2005,2,10,15,30,45))
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).future?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).future?
+ assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,46)).future?
+ end
+ end
+
+ def future_with_time_current_as_time_with_zone
+ twz = ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45) )
+ Time.stubs(:current).returns(twz)
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).future?
+ assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).future?
+ assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,46)).future?
+ end
+ end
+
def test_eql?
assert @twz.eql?(Time.utc(2000))
assert @twz.eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) )
@@ -353,7 +397,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
def test_date_part_value_methods
silence_warnings do # silence warnings raised by tzinfo gem
twz = ActiveSupport::TimeWithZone.new(Time.utc(1999,12,31,19,18,17,500), @time_zone)
- twz.stubs(:method_missing).returns(nil) #ensure these methods are defined directly on class
+ twz.expects(:method_missing).never
assert_equal 1999, twz.year
assert_equal 12, twz.month
assert_equal 31, twz.day
@@ -361,6 +405,8 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 18, twz.min
assert_equal 17, twz.sec
assert_equal 500, twz.usec
+ assert_equal 5, twz.wday
+ assert_equal 365, twz.yday
end
end
end
@@ -538,7 +584,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", twz.since(1.days + 1.second).inspect
assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", (twz + 1.days + 1.second).inspect
end
-
+
def test_advance_1_day_across_spring_dst_transition_backwards
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,10,30))
# In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long
@@ -548,7 +594,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.days).inspect
assert_equal "Sat, 01 Apr 2006 10:30:01 EST -05:00", twz.ago(1.days - 1.second).inspect
end
-
+
def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_spring_dst_transition
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30))
# In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long
@@ -565,7 +611,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(24.hours).inspect
assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:hours => 24).inspect
end
-
+
def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_spring_dst_transition_backwards
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,11,30))
# In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long
@@ -582,7 +628,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(24.hours).inspect
assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:hours => -24).inspect
end
-
+
def test_advance_1_day_across_fall_dst_transition
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30))
# In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long
@@ -593,7 +639,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", twz.since(1.days + 1.second).inspect
assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", (twz + 1.days + 1.second).inspect
end
-
+
def test_advance_1_day_across_fall_dst_transition_backwards
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,10,30))
# In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long
@@ -603,7 +649,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.days).inspect
assert_equal "Sat, 28 Oct 2006 10:30:01 EDT -04:00", twz.ago(1.days - 1.second).inspect
end
-
+
def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_fall_dst_transition
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30))
# In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long
@@ -620,7 +666,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(24.hours).inspect
assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:hours => 24).inspect
end
-
+
def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_fall_dst_transition_backwards
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,9,30))
# In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long
@@ -669,7 +715,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.month).inspect
assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.month).inspect
end
-
+
def test_advance_1_year
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2008,2,15,10,30))
assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.advance(:years => 1).inspect
@@ -679,7 +725,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.years_ago(1).inspect
assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", (twz - 1.year).inspect
end
-
+
def test_advance_1_year_during_dst
twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2008,7,15,10,30))
assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.advance(:years => 1).inspect
@@ -689,6 +735,14 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.years_ago(1).inspect
assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", (twz - 1.year).inspect
end
+
+ protected
+ def with_env_tz(new_tz = 'US/Eastern')
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
+ yield
+ ensure
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
+ end
end
class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 39c9c74c94..18ad784837 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -146,42 +146,42 @@ class DependenciesTest < Test::Unit::TestCase
def test_directories_manifest_as_modules_unless_const_defined
with_loading 'autoloading_fixtures' do
assert_kind_of Module, ModuleFolder
- Object.send! :remove_const, :ModuleFolder
+ Object.__send__ :remove_const, :ModuleFolder
end
end
def test_module_with_nested_class
with_loading 'autoloading_fixtures' do
assert_kind_of Class, ModuleFolder::NestedClass
- Object.send! :remove_const, :ModuleFolder
+ Object.__send__ :remove_const, :ModuleFolder
end
end
def test_module_with_nested_inline_class
with_loading 'autoloading_fixtures' do
assert_kind_of Class, ModuleFolder::InlineClass
- Object.send! :remove_const, :ModuleFolder
+ Object.__send__ :remove_const, :ModuleFolder
end
end
def test_directories_may_manifest_as_nested_classes
with_loading 'autoloading_fixtures' do
assert_kind_of Class, ClassFolder
- Object.send! :remove_const, :ClassFolder
+ Object.__send__ :remove_const, :ClassFolder
end
end
def test_class_with_nested_class
with_loading 'autoloading_fixtures' do
assert_kind_of Class, ClassFolder::NestedClass
- Object.send! :remove_const, :ClassFolder
+ Object.__send__ :remove_const, :ClassFolder
end
end
def test_class_with_nested_inline_class
with_loading 'autoloading_fixtures' do
assert_kind_of Class, ClassFolder::InlineClass
- Object.send! :remove_const, :ClassFolder
+ Object.__send__ :remove_const, :ClassFolder
end
end
@@ -190,7 +190,7 @@ class DependenciesTest < Test::Unit::TestCase
assert_kind_of Class, ClassFolder::ClassFolderSubclass
assert_kind_of Class, ClassFolder
assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
- Object.send! :remove_const, :ClassFolder
+ Object.__send__ :remove_const, :ClassFolder
end
end
@@ -199,7 +199,7 @@ class DependenciesTest < Test::Unit::TestCase
sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
assert defined?(ModuleFolder::NestedSibling)
assert_equal ModuleFolder::NestedSibling, sibling
- Object.send! :remove_const, :ModuleFolder
+ Object.__send__ :remove_const, :ModuleFolder
end
end
@@ -208,7 +208,7 @@ class DependenciesTest < Test::Unit::TestCase
assert ! defined?(ModuleFolder)
assert_raises(NameError) { ModuleFolder::Object }
assert_raises(NameError) { ModuleFolder::NestedClass::Object }
- Object.send! :remove_const, :ModuleFolder
+ Object.__send__ :remove_const, :ModuleFolder
end
end
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index 8eebe1be25..f304844e82 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -98,6 +98,12 @@ class InflectorTest < Test::Unit::TestCase
end
end
+ def test_parameterize
+ StringToParameterized.each do |some_string, parameterized_string|
+ assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string))
+ end
+ end
+
def test_classify
ClassNameToTableName.each do |class_name, table_name|
assert_equal(class_name, ActiveSupport::Inflector.classify(table_name))
diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb
index a9dd83a389..8057809dbd 100644
--- a/activesupport/test/inflector_test_cases.rb
+++ b/activesupport/test/inflector_test_cases.rb
@@ -142,6 +142,14 @@ module InflectorTestCases
"NodeChild" => "node_children"
}
+ StringToParameterized = {
+ "Donald E. Knuth" => "donald-e-knuth",
+ "Random text with *(bad)* characters" => "random-text-with-bad-characters",
+ "Malmö" => "malmo",
+ "Garçons" => "garcons",
+ "Allow_Under_Scores" => "allow_under_scores"
+ }
+
UnderscoreToHuman = {
"employee_salary" => "Employee salary",
"employee_id" => "Employee",
diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb
index 63cfadb7ec..a87309b038 100644
--- a/activesupport/test/multibyte_chars_test.rb
+++ b/activesupport/test/multibyte_chars_test.rb
@@ -167,6 +167,10 @@ class CharsTest < Test::Unit::TestCase
assert_equal false, 'test'.chars.respond_to?(:a_method_that_doesnt_exist)
end
+ def test_acts_like_string
+ assert 'Bambi'.chars.acts_like_string?
+ end
+
protected
def with_kcode(kcode)
diff --git a/activesupport/test/secure_random_test.rb b/activesupport/test/secure_random_test.rb
new file mode 100644
index 0000000000..b0b6c21a81
--- /dev/null
+++ b/activesupport/test/secure_random_test.rb
@@ -0,0 +1,15 @@
+require 'abstract_unit'
+
+class SecureRandomTest < Test::Unit::TestCase
+ def test_random_bytes
+ b1 = ActiveSupport::SecureRandom.random_bytes(64)
+ b2 = ActiveSupport::SecureRandom.random_bytes(64)
+ assert_not_equal b1, b2
+ end
+
+ def test_hex
+ b1 = ActiveSupport::SecureRandom.hex(64)
+ b2 = ActiveSupport::SecureRandom.hex(64)
+ assert_not_equal b1, b2
+ end
+end