aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/core_ext/range
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/core_ext/range')
-rw-r--r--activesupport/lib/active_support/core_ext/range/compare_range.rb70
-rw-r--r--activesupport/lib/active_support/core_ext/range/conversions.rb60
-rw-r--r--activesupport/lib/active_support/core_ext/range/each.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_range.rb30
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/range/overlaps.rb2
6 files changed, 143 insertions, 48 deletions
diff --git a/activesupport/lib/active_support/core_ext/range/compare_range.rb b/activesupport/lib/active_support/core_ext/range/compare_range.rb
new file mode 100644
index 0000000000..ea1dc29a76
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/range/compare_range.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module ActiveSupport
+ module CompareWithRange
+ # Extends the default Range#=== to support range comparisons.
+ # (1..5) === (1..5) # => true
+ # (1..5) === (2..3) # => true
+ # (1..5) === (1...6) # => true
+ # (1..5) === (2..6) # => false
+ #
+ # The native Range#=== behavior is untouched.
+ # ('a'..'f') === ('c') # => true
+ # (5..9) === (11) # => false
+ def ===(value)
+ if value.is_a?(::Range)
+ # 1...10 includes 1..9 but it does not include 1..10.
+ # 1..10 includes 1...11 but it does not include 1...12.
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
+ super(value.first) && value_max.send(operator, last)
+ else
+ super
+ end
+ end
+
+ # Extends the default Range#include? to support range comparisons.
+ # (1..5).include?(1..5) # => true
+ # (1..5).include?(2..3) # => true
+ # (1..5).include?(1...6) # => true
+ # (1..5).include?(2..6) # => false
+ #
+ # The native Range#include? behavior is untouched.
+ # ('a'..'f').include?('c') # => true
+ # (5..9).include?(11) # => false
+ def include?(value)
+ if value.is_a?(::Range)
+ # 1...10 includes 1..9 but it does not include 1..10.
+ # 1..10 includes 1...11 but it does not include 1...12.
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
+ super(value.first) && value_max.send(operator, last)
+ else
+ super
+ end
+ end
+
+ # Extends the default Range#cover? to support range comparisons.
+ # (1..5).cover?(1..5) # => true
+ # (1..5).cover?(2..3) # => true
+ # (1..5).cover?(1...6) # => true
+ # (1..5).cover?(2..6) # => false
+ #
+ # The native Range#cover? behavior is untouched.
+ # ('a'..'f').cover?('c') # => true
+ # (5..9).cover?(11) # => false
+ def cover?(value)
+ if value.is_a?(::Range)
+ # 1...10 covers 1..9 but it does not cover 1..10.
+ # 1..10 covers 1...11 but it does not cover 1...12.
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
+ super(value.first) && value_max.send(operator, last)
+ else
+ super
+ end
+ end
+ end
+end
+
+Range.prepend(ActiveSupport::CompareWithRange)
diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb
index 965436c23a..024e32db40 100644
--- a/activesupport/lib/active_support/core_ext/range/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -1,31 +1,41 @@
-module ActiveSupport::RangeWithFormat
- RANGE_FORMATS = {
- :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
- }
+# frozen_string_literal: true
- # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
- #
- # range = (1..100) # => 1..100
- #
- # range.to_s # => "1..100"
- # range.to_s(:db) # => "BETWEEN '1' AND '100'"
- #
- # == Adding your own range formats to to_s
- # You can add your own formats to the Range::RANGE_FORMATS hash.
- # Use the format name as the hash key and a Proc instance.
- #
- # # config/initializers/range_formats.rb
- # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
- def to_s(format = :default)
- if formatter = RANGE_FORMATS[format]
- formatter.call(first, last)
- else
- super()
+module ActiveSupport
+ module RangeWithFormat
+ RANGE_FORMATS = {
+ db: -> (start, stop) do
+ case start
+ when String then "BETWEEN '#{start}' AND '#{stop}'"
+ else
+ "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
+ end
+ end
+ }
+
+ # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
+ #
+ # range = (1..100) # => 1..100
+ #
+ # range.to_s # => "1..100"
+ # range.to_s(:db) # => "BETWEEN '1' AND '100'"
+ #
+ # == Adding your own range formats to to_s
+ # You can add your own formats to the Range::RANGE_FORMATS hash.
+ # Use the format name as the hash key and a Proc instance.
+ #
+ # # config/initializers/range_formats.rb
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
+ def to_s(format = :default)
+ if formatter = RANGE_FORMATS[format]
+ formatter.call(first, last)
+ else
+ super()
+ end
end
- end
- alias_method :to_default_s, :to_s
- alias_method :to_formatted_s, :to_s
+ alias_method :to_default_s, :to_s
+ alias_method :to_formatted_s, :to_s
+ end
end
Range.prepend(ActiveSupport::RangeWithFormat)
diff --git a/activesupport/lib/active_support/core_ext/range/each.rb b/activesupport/lib/active_support/core_ext/range/each.rb
index dc6dad5ced..2f22cd0e92 100644
--- a/activesupport/lib/active_support/core_ext/range/each.rb
+++ b/activesupport/lib/active_support/core_ext/range/each.rb
@@ -1,3 +1,7 @@
+# frozen_string_literal: true
+
+require "active_support/time_with_zone"
+
module ActiveSupport
module EachTimeWithZone #:nodoc:
def each(&block)
@@ -13,7 +17,7 @@ module ActiveSupport
private
def ensure_iteration_allowed
- raise TypeError, "can't iterate from #{first.class}" if first.is_a?(Time)
+ raise TypeError, "can't iterate from #{first.class}" if first.is_a?(TimeWithZone)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb
index c69e1e3fb9..2da2c587a3 100644
--- a/activesupport/lib/active_support/core_ext/range/include_range.rb
+++ b/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -1,23 +1,9 @@
-module ActiveSupport
- module IncludeWithRange #:nodoc:
- # Extends the default Range#include? to support range comparisons.
- # (1..5).include?(1..5) # => true
- # (1..5).include?(2..3) # => true
- # (1..5).include?(2..6) # => false
- #
- # The native Range#include? behavior is untouched.
- # ('a'..'f').include?('c') # => true
- # (5..9).include?(11) # => false
- def include?(value)
- if value.is_a?(::Range)
- # 1...10 includes 1..9 but it does not include 1..10.
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
- super(value.first) && value.last.send(operator, last)
- else
- super
- end
- end
- end
-end
+# frozen_string_literal: true
-Range.prepend(ActiveSupport::IncludeWithRange)
+require "active_support/deprecation"
+
+ActiveSupport::Deprecation.warn "You have required `active_support/core_ext/range/include_range`. " \
+"This file will be removed in Rails 6.1. You should require `active_support/core_ext/range/compare_range` " \
+ "instead."
+
+require "active_support/core_ext/range/compare_range"
diff --git a/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb b/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb
new file mode 100644
index 0000000000..5f80acf68e
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require "active_support/time_with_zone"
+
+module ActiveSupport
+ module IncludeTimeWithZone #:nodoc:
+ # Extends the default Range#include? to support ActiveSupport::TimeWithZone.
+ #
+ # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
+ #
+ def include?(value)
+ if first.is_a?(TimeWithZone)
+ cover?(value)
+ elsif last.is_a?(TimeWithZone)
+ cover?(value)
+ else
+ super
+ end
+ end
+ end
+end
+
+Range.prepend(ActiveSupport::IncludeTimeWithZone)
diff --git a/activesupport/lib/active_support/core_ext/range/overlaps.rb b/activesupport/lib/active_support/core_ext/range/overlaps.rb
index 603657c180..f753607f8b 100644
--- a/activesupport/lib/active_support/core_ext/range/overlaps.rb
+++ b/activesupport/lib/active_support/core_ext/range/overlaps.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Range
# Compare two ranges and see if they overlap each other
# (1..5).overlaps?(4..6) # => true