diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext')
13 files changed, 132 insertions, 61 deletions
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb index f6cb1a384c..05abd83221 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb @@ -5,13 +5,13 @@ require "active_support/core_ext/object/try" module DateAndTime module Calculations DAYS_INTO_WEEK = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6 + sunday: 0, + monday: 1, + tuesday: 2, + wednesday: 3, + thursday: 4, + friday: 5, + saturday: 6 } WEEKEND_DAYS = [ 6, 0 ] @@ -60,6 +60,16 @@ module DateAndTime !WEEKEND_DAYS.include?(wday) end + # Returns true if the date/time falls before <tt>date_or_time</tt>. + def before?(date_or_time) + self < date_or_time + end + + # Returns true if the date/time falls after <tt>date_or_time</tt>. + def after?(date_or_time) + self > date_or_time + end + # Returns a new date/time the specified number of days ago. def days_ago(days) advance(days: -days) @@ -253,9 +263,8 @@ module DateAndTime # Week is assumed to start on +start_day+, default is # +Date.beginning_of_week+ or +config.beginning_of_week+ when set. def days_to_week_start(start_day = Date.beginning_of_week) - start_day_number = DAYS_INTO_WEEK[start_day] - current_day_number = wday != 0 ? wday - 1 : 6 - (current_day_number - start_day_number) % 7 + start_day_number = DAYS_INTO_WEEK.fetch(start_day) + (wday - start_day_number) % 7 end # Returns a new date/time representing the start of this week on the given day. @@ -336,8 +345,7 @@ module DateAndTime # today.next_occurring(:monday) # => Mon, 18 Dec 2017 # today.next_occurring(:thursday) # => Thu, 21 Dec 2017 def next_occurring(day_of_week) - current_day_number = wday != 0 ? wday - 1 : 6 - from_now = DAYS_INTO_WEEK.fetch(day_of_week) - current_day_number + from_now = DAYS_INTO_WEEK.fetch(day_of_week) - wday from_now += 7 unless from_now > 0 advance(days: from_now) end @@ -348,8 +356,7 @@ module DateAndTime # today.prev_occurring(:monday) # => Mon, 11 Dec 2017 # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017 def prev_occurring(day_of_week) - current_day_number = wday != 0 ? wday - 1 : 6 - ago = current_day_number - DAYS_INTO_WEEK.fetch(day_of_week) + ago = wday - DAYS_INTO_WEEK.fetch(day_of_week) ago += 7 unless ago > 0 advance(days: -ago) end @@ -364,7 +371,7 @@ module DateAndTime end def days_span(day) - (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7 + (DAYS_INTO_WEEK.fetch(day) - DAYS_INTO_WEEK.fetch(Date.beginning_of_week)) % 7 end def copy_time_to(other) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index f01d01e6aa..d87d63f287 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -1,14 +1,21 @@ # frozen_string_literal: true module Enumerable + INDEX_WITH_DEFAULT = Object.new + private_constant :INDEX_WITH_DEFAULT + # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements # when we omit an identity. + # :stopdoc: + # We can't use Refinements here because Refinements with Module which will be prepended # doesn't work well https://bugs.ruby-lang.org/issues/13446 alias :_original_sum_with_required_identity :sum private :_original_sum_with_required_identity + # :startdoc: + # Calculates a sum from the elements. # # payments.sum { |p| p.price * p.tax_rate } @@ -37,10 +44,11 @@ module Enumerable end end - # Convert an enumerable to a hash. + # Convert an enumerable to a hash keying it by the block return value. # # people.index_by(&:login) # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...} + # # people.index_by { |person| "#{person.first_name} #{person.last_name}" } # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...} def index_by @@ -53,6 +61,26 @@ module Enumerable end end + # Convert an enumerable to a hash keying it with the enumerable items and with the values returned in the block. + # + # post = Post.new(title: "hey there", body: "what's up?") + # + # %i( title body ).index_with { |attr_name| post.public_send(attr_name) } + # # => { title: "hey there", body: "what's up?" } + def index_with(default = INDEX_WITH_DEFAULT) + if block_given? + result = {} + each { |elem| result[elem] = yield(elem) } + result + elsif default != INDEX_WITH_DEFAULT + result = {} + each { |elem| result[elem] = default } + result + else + to_enum(:index_with) { size if respond_to?(:size) } + end + end + # Returns +true+ if the enumerable has more than 1 element. Functionally # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too, # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+ diff --git a/activesupport/lib/active_support/core_ext/load_error.rb b/activesupport/lib/active_support/core_ext/load_error.rb index 750f858fcc..6b0dcab905 100644 --- a/activesupport/lib/active_support/core_ext/load_error.rb +++ b/activesupport/lib/active_support/core_ext/load_error.rb @@ -4,6 +4,6 @@ class LoadError # Returns true if the given path name (except perhaps for the ".rb" # extension) is the missing file which caused the exception to be raised. def is_missing?(location) - location.sub(/\.rb$/, "".freeze) == path.sub(/\.rb$/, "".freeze) + location.sub(/\.rb$/, "".freeze) == path.to_s.sub(/\.rb$/, "".freeze) end end diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 580baffa2b..281eaa7d5f 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "active_support/core_ext/array/extract_options" -require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance @@ -163,10 +162,10 @@ class Module # parent class. Similarly if parent class changes the value then that would # change the value of subclasses too. # - # class Male < Person + # class Citizen < Person # end # - # Male.new.hair_colors << :blue + # Citizen.new.hair_colors << :blue # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue] # # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>. diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb index 4b9b6ea9bd..b1788a000b 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "active_support/core_ext/array/extract_options" -require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance @@ -137,7 +136,7 @@ class Module # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods. # # class Current - # mattr_accessor :user, instance_accessor: false + # thread_mattr_accessor :user, instance_accessor: false # end # # Current.new.user = "DHH" # => NoMethodError diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index ec3497173f..3128539112 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "set" -require "active_support/core_ext/regexp" class Module # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+ @@ -22,8 +21,9 @@ class Module # ==== Options # * <tt>:to</tt> - Specifies the target object # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix - # * <tt>:allow_nil</tt> - if set to true, prevents a +Module::DelegationError+ + # * <tt>:allow_nil</tt> - If set to true, prevents a +Module::DelegationError+ # from being raised + # * <tt>:private</tt> - If set to true, changes method visibility to private # # The macro receives one or more method names (specified as symbols or # strings) and the name of the target object via the <tt>:to</tt> option diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb index 2ca431ab10..ad6a9c6146 100644 --- a/activesupport/lib/active_support/core_ext/object/blank.rb +++ b/activesupport/lib/active_support/core_ext/object/blank.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "active_support/core_ext/regexp" require "concurrent/map" class Object diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb index abb461966a..bac6ff9c97 100644 --- a/activesupport/lib/active_support/core_ext/object/to_query.rb +++ b/activesupport/lib/active_support/core_ext/object/to_query.rb @@ -75,11 +75,14 @@ class Hash # # This method is also aliased as +to_param+. def to_query(namespace = nil) - collect do |key, value| + query = collect do |key, value| unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty? value.to_query(namespace ? "#{namespace}[#{key}]" : key) end - end.compact.sort! * "&" + end.compact + + query.sort! unless namespace.to_s.include?("[]") + query.join("&") end alias_method :to_param, :to_query diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index 2838fd76be..1d46add6e0 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -68,7 +68,7 @@ class Object # You can access these methods using the class name instead: # # class Phone < ActiveRecord::Base - # enum phone_number_type: [home: 0, office: 1, mobile: 2] + # enum phone_number_type: { home: 0, office: 1, mobile: 2 } # # with_options presence: true do # validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys } diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb index 4074e91d17..78814fd189 100644 --- a/activesupport/lib/active_support/core_ext/range.rb +++ b/activesupport/lib/active_support/core_ext/range.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "active_support/core_ext/range/conversions" -require "active_support/core_ext/range/include_range" +require "active_support/core_ext/range/compare_range" require "active_support/core_ext/range/include_time_with_zone" require "active_support/core_ext/range/overlaps" require "active_support/core_ext/range/each" 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..6f6d2a27bb --- /dev/null +++ b/activesupport/lib/active_support/core_ext/range/compare_range.rb @@ -0,0 +1,61 @@ +# 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) === (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. + operator = exclude_end? && !value.exclude_end? ? :< : :<= + super(value.first) && value.last.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?(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 + + # Extends the default Range#cover? to support range comparisons. + # (1..5).cover?(1..5) # => true + # (1..5).cover?(2..3) # => 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. + operator = exclude_end? && !value.exclude_end? ? :< : :<= + super(value.first) && value.last.send(operator, last) + else + super + end + end + end +end + +Range.prepend(ActiveSupport::CompareWithRange) 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 7ba1011921..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,25 +1,9 @@ # frozen_string_literal: true -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 +require "active_support/deprecation" -Range.prepend(ActiveSupport::IncludeWithRange) +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/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb index dadabb02e5..cdd81ae562 100644 --- a/activesupport/lib/active_support/core_ext/uri.rb +++ b/activesupport/lib/active_support/core_ext/uri.rb @@ -1,17 +1,8 @@ # frozen_string_literal: true require "uri" -str = "\xE6\x97\xA5" -parser = URI::Parser.new -needs_monkeypatch = - begin - str + str != parser.unescape(str + parser.escape(str).force_encoding(Encoding::UTF_8)) - rescue Encoding::CompatibilityError - true - end - -if needs_monkeypatch +if RUBY_VERSION < "2.6.0" require "active_support/core_ext/module/redefine_method" URI::Parser.class_eval do silence_redefinition_of_method :unescape |