diff options
Diffstat (limited to 'activesupport')
8 files changed, 99 insertions, 81 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/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/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/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 |