Browse files

Merge pull request #7350 from slbug/date_time_ranges_with_infinite_bo…

…unds

Added ability to compare date/time with infinity
  • Loading branch information...
2 parents 4d240ec + 38f28dc commit e3ce5ea303ef431d0db97c3c3ea2204c22cd6e48 @rafaelfranca rafaelfranca committed Jan 3, 2013
View
13 activesupport/CHANGELOG.md
@@ -1,5 +1,18 @@
## Rails 4.0.0 (unreleased) ##
+* It's now possible to compare Date, DateTime, Time and TimeWithZone with Infinity
+ This allows to create date/time ranges with one infinite bound.
+ Example:
+
+ range = Range.new(Date.today, Float::INFINITY)
+
+ Also it's possible to check inclusion of date/time in range with conversion.
+
+ range.include?(Time.now + 1.year) # => true
+ range.include?(DateTime.now + 1.year) # => true
+
+ *Alexander Grebennik*
+
* Remove meaningless `ActiveSupport::FrozenObjectError`, which was just an alias of `RuntimeError`.
*Akira Matsuda*
View
1 activesupport/lib/active_support/core_ext/date.rb
@@ -2,4 +2,5 @@
require 'active_support/core_ext/date/calculations'
require 'active_support/core_ext/date/conversions'
require 'active_support/core_ext/date/zones'
+require 'active_support/core_ext/date/infinite_comparable'
View
5 activesupport/lib/active_support/core_ext/date/infinite_comparable.rb
@@ -0,0 +1,5 @@
+require 'active_support/core_ext/infinite_comparable'
+
+class Date
+ include InfiniteComparable
+end
View
1 activesupport/lib/active_support/core_ext/date_time.rb
@@ -2,3 +2,4 @@
require 'active_support/core_ext/date_time/calculations'
require 'active_support/core_ext/date_time/conversions'
require 'active_support/core_ext/date_time/zones'
+require 'active_support/core_ext/date_time/infinite_comparable'
View
7 activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -142,11 +142,4 @@ def utc?
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 <=>(other)
- super other.to_datetime
- end
-
end
View
5 activesupport/lib/active_support/core_ext/date_time/infinite_comparable.rb
@@ -0,0 +1,5 @@
+require 'active_support/core_ext/infinite_comparable'
+
+class DateTime
+ include InfiniteComparable
+end
View
30 activesupport/lib/active_support/core_ext/infinite_comparable.rb
@@ -0,0 +1,30 @@
+require 'active_support/concern'
+
+module InfiniteComparable
+ extend ActiveSupport::Concern
+
+ included do
+ alias_method_chain :<=>, :infinity
+ end
+
+ define_method '<=>_with_infinity' do |other|
+ if other.class == self.class
+ self.send(:'<=>_without_infinity', other)
+ # inf <=> inf
+ elsif other.respond_to?(:infinite?) && other.infinite? && respond_to?(:infinite?) && infinite?
+ infinite? <=> other.infinite?
+ # not_inf <=> inf
+ elsif other.respond_to?(:infinite?) && other.infinite?
+ -other.infinite?
+ # inf <=> not_inf
+ elsif respond_to?(:infinite?) && infinite?
+ infinite?
+ else
+ conversion = :"to_#{self.class.name.downcase}"
+
+ other = other.send(conversion) if other.respond_to?(conversion)
+
+ self.send(:'<=>_without_infinity', other)
+ end
+ end
+end
View
1 activesupport/lib/active_support/core_ext/numeric.rb
@@ -1,3 +1,4 @@
require 'active_support/core_ext/numeric/bytes'
require 'active_support/core_ext/numeric/time'
require 'active_support/core_ext/numeric/conversions'
+require 'active_support/core_ext/numeric/infinite_comparable'
View
11 activesupport/lib/active_support/core_ext/numeric/infinite_comparable.rb
@@ -0,0 +1,11 @@
+require 'active_support/core_ext/big_decimal/conversions'
+require 'active_support/number_helper'
+require 'active_support/core_ext/infinite_comparable'
+
+class Float
+ include InfiniteComparable
+end
+
+class BigDecimal
+ include InfiniteComparable
+end
View
1 activesupport/lib/active_support/core_ext/time.rb
@@ -3,3 +3,4 @@
require 'active_support/core_ext/time/conversions'
require 'active_support/core_ext/time/marshal'
require 'active_support/core_ext/time/zones'
+require 'active_support/core_ext/time/infinite_comparable'
View
5 activesupport/lib/active_support/core_ext/time/infinite_comparable.rb
@@ -0,0 +1,5 @@
+require 'active_support/core_ext/infinite_comparable'
+
+class Time
+ include InfiniteComparable
+end
View
7 activesupport/test/core_ext/date_ext_test.rb
@@ -353,6 +353,13 @@ def test_can_freeze_twice
Date.today.freeze.freeze
end
end
+
+ def test_compare_with_infinity
+ assert_nothing_raised do
+ assert_equal(-1, Date.today <=> Float::INFINITY)
+ assert_equal(1, Date.today <=> -Float::INFINITY)
+ end
+ end
end
class DateExtConversionsTest < ActiveSupport::TestCase
View
9 activesupport/test/core_ext/date_time_ext_test.rb
@@ -317,3 +317,12 @@ def with_env_tz(new_tz = 'US/Eastern')
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
end
end
+
+class DateTimeExtBehaviorTest < ActiveSupport::TestCase
+ def test_compare_with_infinity
+ assert_nothing_raised do
+ assert_equal(-1, DateTime.now <=> Float::INFINITY)
+ assert_equal(1, DateTime.now <=> -Float::INFINITY)
+ end
+ end
+end
View
64 activesupport/test/core_ext/numeric_ext_test.rb
@@ -447,3 +447,67 @@ def test_to_s__injected_on_proper_types
assert_equal '1 Million', BigDecimal("1000010").to_s(:human)
end
end
+
+class NumericExtBehaviorTest < ActiveSupport::TestCase
+ def setup
+ @inf = BigDecimal.new('Infinity')
+ end
+
+ def test_compare_infinity_with_date
+ assert_nothing_raised do
+ assert_equal(-1, -Float::INFINITY <=> Date.today)
+ assert_equal(1, Float::INFINITY <=> Date.today)
+ assert_equal(-1, -@inf <=> Date.today)
+ assert_equal(1, @inf <=> Date.today)
+ end
+ end
+
+ def test_compare_infinty_with_infinty
+ assert_nothing_raised do
+ assert_equal(-1, -Float::INFINITY <=> Float::INFINITY)
+ assert_equal(1, Float::INFINITY <=> -Float::INFINITY)
+ assert_equal(0, Float::INFINITY <=> Float::INFINITY)
+ assert_equal(0, -Float::INFINITY <=> -Float::INFINITY)
+
+ assert_equal(-1, -Float::INFINITY <=> BigDecimal::INFINITY)
+ assert_equal(1, Float::INFINITY <=> -BigDecimal::INFINITY)
+ assert_equal(0, Float::INFINITY <=> BigDecimal::INFINITY)
+ assert_equal(0, -Float::INFINITY <=> -BigDecimal::INFINITY)
+
+ assert_equal(-1, -BigDecimal::INFINITY <=> Float::INFINITY)
+ assert_equal(1, BigDecimal::INFINITY <=> -Float::INFINITY)
+ assert_equal(0, BigDecimal::INFINITY <=> Float::INFINITY)
+ assert_equal(0, -BigDecimal::INFINITY <=> -Float::INFINITY)
+ end
+ end
+
+ def test_compare_infinity_with_time
+ assert_nothing_raised do
+ assert_equal(-1, -Float::INFINITY <=> Time.now)
+ assert_equal(1, Float::INFINITY <=> Time.now)
+ assert_equal(-1, -@inf <=> Time.now)
+ assert_equal(1, @inf <=> Time.now)
+ end
+ end
+
+ def test_compare_infinity_with_datetime
+ assert_nothing_raised do
+ assert_equal(-1, -Float::INFINITY <=> DateTime.now)
+ assert_equal(1, Float::INFINITY <=> DateTime.now)
+ assert_equal(-1, -@inf <=> DateTime.now)
+ assert_equal(1, @inf <=> DateTime.now)
+ end
+ end
+
+ def test_compare_infinity_with_twz
+ time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ twz = ActiveSupport::TimeWithZone.new(Time.now, time_zone)
+
+ assert_nothing_raised do
+ assert_equal(-1, -Float::INFINITY <=> twz)
+ assert_equal(1, Float::INFINITY <=> twz)
+ assert_equal(-1, -@inf <=> twz)
+ assert_equal(1, @inf <=> twz)
+ end
+ end
+end
View
25 activesupport/test/core_ext/range_ext_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
require 'active_support/time'
require 'active_support/core_ext/range'
+require 'active_support/core_ext/numeric'
class RangeTest < ActiveSupport::TestCase
def test_to_s_from_dates
@@ -85,4 +86,28 @@ def test_no_overlaps_on_time
time_range_2 = Time.utc(2005, 12, 10, 17, 31)..Time.utc(2005, 12, 10, 18, 00)
assert !time_range_1.overlaps?(time_range_2)
end
+
+ def test_infinite_bounds
+ time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+
+ time = Time.now
+ date = Date.today
+ datetime = DateTime.now
+ twz = ActiveSupport::TimeWithZone.new(time, time_zone)
+
+ infinity1 = Float::INFINITY
+ infinity2 = BigDecimal.new('Infinity')
+
+ [infinity1, infinity2].each do |infinity|
+ [time, date, datetime, twz].each do |bound|
+ [time, date, datetime, twz].each do |value|
+ assert Range.new(bound, infinity).include?(value + 10.years)
+ assert Range.new(-infinity, bound).include?(value - 10.years)
+
+ assert !Range.new(bound, infinity).include?(value - 10.years)
+ assert !Range.new(-infinity, bound).include?(value + 10.years)
+ end
+ end
+ end
+ end
end
View
9 activesupport/test/core_ext/time_ext_test.rb
@@ -843,3 +843,12 @@ def test_last_quarter_on_31st
assert_equal Time.local(2004, 2, 29), Time.local(2004, 5, 31).last_quarter
end
end
+
+class TimeExtBehaviorTest < ActiveSupport::TestCase
+ def test_compare_with_infinity
+ assert_nothing_raised do
+ assert_equal(-1, Time.now <=> Float::INFINITY)
+ assert_equal(1, Time.now <=> -Float::INFINITY)
+ end
+ end
+end
View
12 activesupport/test/core_ext/time_with_zone_test.rb
@@ -1081,3 +1081,15 @@ def with_tz_default(tz = nil)
Time.zone = old_tz
end
end
+
+class TimeWithZoneExtBehaviorTest < ActiveSupport::TestCase
+ def test_compare_with_infinity
+ time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ twz = ActiveSupport::TimeWithZone.new(Time.now, time_zone)
+
+ assert_nothing_raised do
+ assert_equal(-1, twz <=> Float::INFINITY)
+ assert_equal(1, twz <=> -Float::INFINITY)
+ end
+ end
+end

0 comments on commit e3ce5ea

Please sign in to comment.