aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support')
-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
46 files changed, 1031 insertions, 496 deletions
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