提交 e3ce5ea3 编写于 作者: R Rafael Mendonça França

Merge pull request #7350 from slbug/date_time_ranges_with_infinite_bounds

Added ability to compare date/time with infinity
## 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*
......
......@@ -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'
require 'active_support/core_ext/infinite_comparable'
class Date
include InfiniteComparable
end
......@@ -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'
......@@ -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
require 'active_support/core_ext/infinite_comparable'
class DateTime
include InfiniteComparable
end
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
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'
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
......@@ -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'
require 'active_support/core_ext/infinite_comparable'
class Time
include InfiniteComparable
end
......@@ -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
......
......@@ -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
......@@ -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
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
......@@ -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
......@@ -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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册