aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG.md4
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb34
-rw-r--r--activesupport/lib/active_support/core_ext/date/operators.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/date_and_time/with_duration.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb11
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb61
-rw-r--r--activesupport/lib/active_support/core_ext/time/operators.rb36
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb4
-rw-r--r--activesupport/lib/active_support/testing/assertions.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb1
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb9
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb4
12 files changed, 120 insertions, 85 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index e77ebcb2f2..7658c8ba26 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Fix a range of values for parameters of the Time#change
+
+ *Nikolay Kondratyev*
+
* Add `Enumerable#pluck` to get the same values from arrays as from ActiveRecord
associations.
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 86d7fa1abf..c60e833441 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -1,13 +1,12 @@
require 'date'
+require 'active_support/duration'
require 'active_support/core_ext/object/acts_like'
require 'active_support/core_ext/date/zones'
-require 'active_support/core_ext/date/operators'
require 'active_support/core_ext/time/zones'
require 'active_support/core_ext/date_and_time/calculations'
class Date
include DateAndTime::Calculations
- prepend ActiveSupport::DateOperators
class << self
attr_accessor :beginning_of_week_default
@@ -86,6 +85,26 @@ class Date
end
alias :at_end_of_day :end_of_day
+ def plus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.since(self)
+ else
+ plus_without_duration(other)
+ end
+ end
+ alias_method :plus_without_duration, :+
+ alias_method :+, :plus_with_duration
+
+ def minus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ plus_with_duration(-other)
+ else
+ minus_without_duration(other)
+ end
+ end
+ alias_method :minus_without_duration, :-
+ alias_method :-, :minus_with_duration
+
# 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)
@@ -110,4 +129,15 @@ class Date
options.fetch(:day, day)
)
end
+
+ # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there.
+ def compare_with_coercion(other)
+ if other.is_a?(Time)
+ self.to_datetime <=> other
+ else
+ compare_without_coercion(other)
+ end
+ end
+ alias_method :compare_without_coercion, :<=>
+ alias_method :<=>, :compare_with_coercion
end
diff --git a/activesupport/lib/active_support/core_ext/date/operators.rb b/activesupport/lib/active_support/core_ext/date/operators.rb
deleted file mode 100644
index decf099624..0000000000
--- a/activesupport/lib/active_support/core_ext/date/operators.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'active_support/core_ext/date_and_time/with_duration'
-
-module ActiveSupport
- module DateOperators # :nodoc:
- include DateAndTime::WithDuration
-
- # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there.
- def <=>(other)
- if other.is_a?(Time)
- self.to_datetime <=> other
- else
- super
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/with_duration.rb b/activesupport/lib/active_support/core_ext/date_and_time/with_duration.rb
deleted file mode 100644
index 4a6c4013d5..0000000000
--- a/activesupport/lib/active_support/core_ext/date_and_time/with_duration.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require 'active_support/duration'
-
-module ActiveSupport
- module DateAndTime
- module WithDuration #:nodoc:
- def +(other) #:nodoc:
- if ActiveSupport::Duration === other
- other.since(self)
- else
- super
- end
- end
-
- def -(other) #:nodoc:
- if ActiveSupport::Duration === other
- self + (-other)
- else
- super
- end
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index d28f26260e..fc7531d088 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -76,8 +76,15 @@ module Enumerable
#
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
# => ["David", "Rafael", "Aaron"]
- def pluck(key)
- map { |element| element[key] }
+ #
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
+ # => [[1, "David"], [2, "Rafael"]]
+ def pluck(*keys)
+ if keys.many?
+ map { |element| keys.map { |key| element[key] } }
+ else
+ map { |element| element[keys.first] }
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index dd99dd667a..c554501893 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -1,12 +1,11 @@
+require 'active_support/duration'
require 'active_support/core_ext/time/conversions'
require 'active_support/time_with_zone'
require 'active_support/core_ext/time/zones'
-require 'active_support/core_ext/time/operators'
require 'active_support/core_ext/date_and_time/calculations'
class Time
include DateAndTime::Calculations
- prepend ActiveSupport::TimeOperators
COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
@@ -99,7 +98,7 @@ class Time
elsif zone
::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
else
- raise ArgumentError, 'argument out of range' if new_usec > 999999
+ raise ArgumentError, 'argument out of range' if new_usec >= 1000000
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
end
end
@@ -213,4 +212,60 @@ class Time
def all_day
beginning_of_day..end_of_day
end
+
+ def plus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.since(self)
+ else
+ plus_without_duration(other)
+ end
+ end
+ alias_method :plus_without_duration, :+
+ alias_method :+, :plus_with_duration
+
+ def minus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.until(self)
+ else
+ minus_without_duration(other)
+ end
+ end
+ alias_method :minus_without_duration, :-
+ alias_method :-, :minus_with_duration
+
+ # 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
+ def minus_with_coercion(other)
+ other = other.comparable_time if other.respond_to?(:comparable_time)
+ other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
+ end
+ alias_method :minus_without_coercion, :-
+ alias_method :-, :minus_with_coercion
+
+ # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
+ # can be chronologically compared with a Time
+ def compare_with_coercion(other)
+ # we're avoiding Time#to_datetime and Time#to_time because they're expensive
+ if other.class == Time
+ compare_without_coercion(other)
+ elsif other.is_a?(Time)
+ compare_without_coercion(other.to_time)
+ else
+ to_datetime <=> other
+ end
+ end
+ alias_method :compare_without_coercion, :<=>
+ alias_method :<=>, :compare_with_coercion
+
+ # Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
+ # can be eql? to an equivalent Time
+ def eql_with_coercion(other)
+ # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison
+ other = other.comparable_time if other.respond_to?(:comparable_time)
+ eql_without_coercion(other)
+ end
+ alias_method :eql_without_coercion, :eql?
+ alias_method :eql?, :eql_with_coercion
+
end
diff --git a/activesupport/lib/active_support/core_ext/time/operators.rb b/activesupport/lib/active_support/core_ext/time/operators.rb
deleted file mode 100644
index 161304dcb3..0000000000
--- a/activesupport/lib/active_support/core_ext/time/operators.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'active_support/core_ext/date_and_time/with_duration'
-
-module ActiveSupport
- module TimeOperators # :nodoc:
- include DateAndTime::WithDuration
-
- # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
- # can be chronologically compared with a Time
- def <=>(other)
- # we're avoiding Time#to_datetime and Time#to_time because they're expensive
- if other.class == Time
- super
- elsif other.is_a?(Time)
- super(other.to_time)
- else
- to_datetime <=> other
- end
- end
-
- # Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
- # can be eql? to an equivalent Time
- def eql?(other)
- # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison
- other = other.comparable_time if other.respond_to?(:comparable_time)
- super
- 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
- def -(other)
- other = other.comparable_time if other.respond_to?(:comparable_time)
- other.is_a?(DateTime) ? to_f - other.to_f : super
- end
- end
-end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index bde70d772d..49fd1723e2 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -68,9 +68,9 @@ module ActiveSupport
def camelize(term, uppercase_first_letter = true)
string = term.to_s
if uppercase_first_letter
- string = string.sub(/^[a-z\d]*/) { inflections.acronyms[$&] || $&.capitalize }
+ string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
else
- string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
+ string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
end
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
string.gsub!('/'.freeze, '::'.freeze)
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb
index 411dd29df5..d87ce3474d 100644
--- a/activesupport/lib/active_support/testing/assertions.rb
+++ b/activesupport/lib/active_support/testing/assertions.rb
@@ -28,7 +28,7 @@ module ActiveSupport
#
# An arbitrary expression is passed in and evaluated.
#
- # assert_difference 'assigns(:article).comments(:reload).size' do
+ # assert_difference 'Article.last.comments(:reload).size' do
# post :create, params: { comment: {...} }
# end
#
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index b0d7f3299f..412c72d27c 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -1,3 +1,4 @@
+require 'active_support/duration'
require 'active_support/values/time_zone'
require 'active_support/core_ext/object/acts_like'
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 21743cdea5..f09b7d8850 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -3,6 +3,8 @@ require 'active_support/core_ext/array'
require 'active_support/core_ext/enumerable'
Payment = Struct.new(:price)
+ExpandedPayment = Struct.new(:dollars, :cents)
+
class SummablePayment < Payment
def +(p) self.class.new(price + p.price) end
end
@@ -114,5 +116,12 @@ class EnumerableTests < ActiveSupport::TestCase
def test_pluck
payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ])
assert_equal [5, 15, 10], payments.pluck(:price)
+
+ payments = GenericEnumerable.new([
+ ExpandedPayment.new(5, 99),
+ ExpandedPayment.new(15, 0),
+ ExpandedPayment.new(10, 50)
+ ])
+ assert_equal [[5, 99], [15, 0], [10, 50]], payments.pluck(:dollars, :cents)
end
end
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index d59775001b..62868d146b 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -149,6 +149,9 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,3,19,23,59,59,Rational(999999999, 1000)), Time.local(2006,3,19,10,10,10).end_of_day, 'ends DST'
assert_equal Time.local(2006,10,1,23,59,59,Rational(999999999, 1000)), Time.local(2006,10,1,10,10,10).end_of_day, 'start DST'
end
+ with_env_tz 'Asia/Yekaterinburg' do
+ assert_equal Time.local(2015, 2, 8, 23, 59, 59, Rational(999999999, 1000)), Time.new(2015, 2, 8, 8, 0, 0, '+05:00').end_of_day
+ end
end
def test_end_of_hour
@@ -389,6 +392,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,44).change(:usec => 8)
assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,2).change(:nsec => 8000)
assert_raise(ArgumentError) { Time.local(2005,1,2,11,22,33, 8).change(:usec => 1, :nsec => 1) }
+ assert_nothing_raised(ArgumentError) { Time.new(2015, 5, 9, 10, 00, 00, '+03:00').change(nsec: 999999999) }
end
def test_utc_change