diff options
Diffstat (limited to 'activesupport/lib/active_support')
15 files changed, 159 insertions, 107 deletions
diff --git a/activesupport/lib/active_support/core_ext/array/inquiry.rb b/activesupport/lib/active_support/core_ext/array/inquiry.rb index de623c466c..e8f44cc378 100644 --- a/activesupport/lib/active_support/core_ext/array/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/array/inquiry.rb @@ -1,3 +1,5 @@ +require 'active_support/array_inquirer' + class Array # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way # to check its string-like contents. diff --git a/activesupport/lib/active_support/core_ext/array/wrap.rb b/activesupport/lib/active_support/core_ext/array/wrap.rb index 152eb02218..b611d34c27 100644 --- a/activesupport/lib/active_support/core_ext/array/wrap.rb +++ b/activesupport/lib/active_support/core_ext/array/wrap.rb @@ -3,7 +3,7 @@ class Array # # Specifically: # - # * If the argument is +nil+ an empty list is returned. + # * If the argument is +nil+ an empty array is returned. # * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned. # * Otherwise, returns an array with the argument as its single element. # @@ -15,12 +15,13 @@ class Array # # * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt> # moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns - # +nil+ right away. + # an array with the argument as its single element right away. # * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt> # raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value. - # * It does not call +to_a+ on the argument, but returns an empty array if argument is +nil+. + # * It does not call +to_a+ on the argument, if the argument does not respond to +to_ary+ + # it returns an array with the argument as its single element. # - # The second point is easily explained with some enumerables: + # The last point is easily explained with some enumerables: # # Array(foo: :bar) # => [[:foo, :bar]] # Array.wrap(foo: :bar) # => [{:foo=>:bar}] diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index a4c40b25ff..b6934b9c54 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -1,4 +1,7 @@ class Module + # NOTE: This method is deprecated. Please use <tt>Module#prepend</tt> that + # comes with Ruby 2.0 or newer instead. + # # Encapsulates the common pattern of: # # alias_method :foo_without_feature, :foo diff --git a/activesupport/lib/active_support/core_ext/module/concerning.rb b/activesupport/lib/active_support/core_ext/module/concerning.rb index 07a392404e..e26b594fc4 100644 --- a/activesupport/lib/active_support/core_ext/module/concerning.rb +++ b/activesupport/lib/active_support/core_ext/module/concerning.rb @@ -63,10 +63,10 @@ class Module # # == Mix-in noise exiled to its own file: # - # Once our chunk of behavior starts pushing the scroll-to-understand it's + # Once our chunk of behavior starts pushing the scroll-to-understand-it # boundary, we give in and move it to a separate file. At this size, the - # overhead feels in good proportion to the size of our extraction, despite - # diluting our at-a-glance sense of how things really work. + # increased overhead can be a reasonable tradeoff even if it reduces our + # at-a-glance perception of how things work. # # class Todo # # Other todo implementation 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 7d38e1d134..513c8b1d55 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -7,7 +7,7 @@ class Object # provided. Each method called on the block variable must take an options # hash as its final argument. # - # Without <tt>with_options></tt>, this code contains duplication: + # Without <tt>with_options</tt>, this code contains duplication: # # class Account < ActiveRecord::Base # has_many :customers, dependent: :destroy diff --git a/activesupport/lib/active_support/core_ext/range/each.rb b/activesupport/lib/active_support/core_ext/range/each.rb index f666480fe6..dc6dad5ced 100644 --- a/activesupport/lib/active_support/core_ext/range/each.rb +++ b/activesupport/lib/active_support/core_ext/range/each.rb @@ -1,27 +1,21 @@ -class Range #:nodoc: +module ActiveSupport + module EachTimeWithZone #:nodoc: + def each(&block) + ensure_iteration_allowed + super + end - def each_with_time_with_zone(&block) - ensure_iteration_allowed - each_without_time_with_zone(&block) - end - # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2: - # https://bugs.ruby-lang.org/issues/10847 - alias_method :each_without_time_with_zone, :each - alias_method :each, :each_with_time_with_zone + def step(n = 1, &block) + ensure_iteration_allowed + super + end - def step_with_time_with_zone(n = 1, &block) - ensure_iteration_allowed - step_without_time_with_zone(n, &block) - end - # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2: - # https://bugs.ruby-lang.org/issues/10847 - alias_method :step_without_time_with_zone, :step - alias_method :step, :step_with_time_with_zone + private - private - def ensure_iteration_allowed - if first.is_a?(Time) - raise TypeError, "can't iterate from #{first.class}" - end + def ensure_iteration_allowed + raise TypeError, "can't iterate from #{first.class}" if first.is_a?(Time) + end end end + +Range.prepend(ActiveSupport::EachTimeWithZone) 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 9d20920dd0..c69e1e3fb9 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,23 @@ -class Range - # 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_with_range?(value) - if value.is_a?(::Range) - # 1...10 includes 1..9 but it does not include 1..10. - operator = exclude_end? && !value.exclude_end? ? :< : :<= - include_without_range?(value.first) && value.last.send(operator, last) - else - include_without_range?(value) +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 - # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2: - # https://bugs.ruby-lang.org/issues/10847 - alias_method :include_without_range?, :include? - alias_method :include?, :include_with_range? end + +Range.prepend(ActiveSupport::IncludeWithRange) diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb index 7461d03acc..375ec1aef8 100644 --- a/activesupport/lib/active_support/core_ext/string/filters.rb +++ b/activesupport/lib/active_support/core_ext/string/filters.rb @@ -17,9 +17,8 @@ class String # str.squish! # => "foo bar boo" # str # => "foo bar boo" def squish! - gsub!(/\A[[:space:]]+/, '') - gsub!(/[[:space:]]+\z/, '') gsub!(/[[:space:]]+/, ' ') + strip! self end diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb index a03a66b96b..dedcdfdb60 100644 --- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb @@ -25,15 +25,17 @@ module ActiveSupport end end - # This DeprecatedObjectProxy transforms object to deprecated object. + # DeprecatedObjectProxy transforms an object into a deprecated object. It takes an object, + # a deprecation message, and optionally a deprecator. The deprecator defaults to + # <tt>ActiveSupport::Deprecator</tt> if none is specified. # - # @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!") - # @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!", deprecator_instance) + # deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated") + # # => <Object:0x007fb9b34c34b0> # - # When someone executes any method except +inspect+ on proxy object this will - # trigger +warn+ method on +deprecator_instance+. - # - # Default deprecator is <tt>ActiveSupport::Deprecation</tt> + # deprecated_object.to_s + # DEPRECATION WARNING: This object is now deprecated. + # (Backtrace) + # # => "<Object:0x007fb9b34c34b0>" class DeprecatedObjectProxy < DeprecationProxy def initialize(object, message, deprecator = ActiveSupport::Deprecation.instance) @object = object @@ -51,13 +53,15 @@ module ActiveSupport end end - # This DeprecatedInstanceVariableProxy transforms instance variable to - # deprecated instance variable. + # DeprecatedInstanceVariableProxy transforms an instance variable into a deprecated + # instance variable. It takes an instance of a class, a method on that class, and an + # instance variable. It optionally takes a deprecator as the last argument. The deprecator + # defaults to <tt>ActiveSupport::Deprecator</tt> if none is specified. # # class Example - # def initialize(deprecator) + # def initialize # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request, deprecator) - # @_request = :a_request + # @_request = :special_request # end # # def request @@ -69,12 +73,17 @@ module ActiveSupport # end # end # - # When someone execute any method on @request variable this will trigger - # +warn+ method on +deprecator_instance+ and will fetch <tt>@_request</tt> - # variable via +request+ method and execute the same method on non-proxy - # instance variable. + # example = Example.new + # # => #<Example:0x007fb9b31090b8 @_request=:special_request, @request=:special_request> + # + # example.old_request.to_s + # # => DEPRECATION WARNING: @request is deprecated! Call request.to_s instead of + # @request.to_s + # (Bactrace information…) + # "special_request" # - # Default deprecator is <tt>ActiveSupport::Deprecation</tt>. + # example.request.to_s + # # => "special_request" class DeprecatedInstanceVariableProxy < DeprecationProxy def initialize(instance, method, var = "@#{method}", deprecator = ActiveSupport::Deprecation.instance) @instance = instance @@ -93,15 +102,22 @@ module ActiveSupport end end - # This DeprecatedConstantProxy transforms constant to deprecated constant. + # DeprecatedConstantProxy transforms a constant into a deprecated constant. It takes the names of an old + # (deprecated) constant and a new contstant (both in string form), and optionally a deprecator. The + # deprecator defaults to <tt>ActiveSupport::Deprecator</tt> if none is specified. The deprecated constant + # now returns the return value of the new constant. + # + # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto) # - # OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST') - # OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST', deprecator_instance) + # (In a later update, the orignal implementation of `PLANETS` has been removed.) # - # When someone use old constant this will trigger +warn+ method on - # +deprecator_instance+. + # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune) + # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006') # - # Default deprecator is <tt>ActiveSupport::Deprecation</tt>. + # PLANETS.map { |planet| planet.capitalize } + # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead. + # (Bactrace information…) + # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"] class DeprecatedConstantProxy < DeprecationProxy def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance) @old_const = old_const diff --git a/activesupport/lib/active_support/rails.rb b/activesupport/lib/active_support/rails.rb index b05c3ff126..c8e3a4bf53 100644 --- a/activesupport/lib/active_support/rails.rb +++ b/activesupport/lib/active_support/rails.rb @@ -1,8 +1,8 @@ # This is private interface. # # Rails components cherry pick from Active Support as needed, but there are a -# few features that are used for sure some way or another and it is not worth -# to put individual requires absolutely everywhere. Think blank? for example. +# few features that are used for sure in some way or another and it is not worth +# putting individual requires absolutely everywhere. Think blank? for example. # # This file is loaded by every Rails component except Active Support itself, # but it does not belong to the Rails public interface. It is internal to diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 67aac32742..fcf5553061 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -68,7 +68,7 @@ module ActiveSupport raise ArgumentError, "#{klass} is neither an Exception nor a String" end - # put the new handler at the end because the list is read in reverse + # Put the new handler at the end because the list is read in reverse. self.rescue_handlers += [[key, options[:with]]] end end diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb index 8db423f0e9..1cd4b807ad 100644 --- a/activesupport/lib/active_support/subscriber.rb +++ b/activesupport/lib/active_support/subscriber.rb @@ -5,7 +5,7 @@ module ActiveSupport # ActiveSupport::Notifications. The subscriber dispatches notifications to # a registered object based on its given namespace. # - # An example would be Active Record subscriber responsible for collecting + # An example would be an Active Record subscriber responsible for collecting # statistics about queries: # # module ActiveRecord @@ -61,7 +61,7 @@ module ActiveSupport pattern = "#{event}.#{namespace}" - # don't add multiple subscribers (eg. if methods are redefined) + # Don't add multiple subscribers (eg. if methods are redefined). return if subscriber.patterns.include?(pattern) subscriber.patterns << pattern diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index 247df7423b..1de0a19998 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -69,17 +69,17 @@ module ActiveSupport else Tempfile.open("isolation") do |tmpfile| env = { - ISOLATION_TEST: self.class.name, - ISOLATION_OUTPUT: tmpfile.path + 'ISOLATION_TEST' => self.class.name, + 'ISOLATION_OUTPUT' => tmpfile.path } load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ") orig_args = ORIG_ARGV.join(" ") test_opts = "-n#{self.class.name}##{self.name}" - command = "#{Gem.ruby} #{load_paths} #{$0} #{orig_args} #{test_opts}" + command = "#{Gem.ruby} #{load_paths} #{$0} '#{orig_args}' #{test_opts}" # IO.popen lets us pass env in a cross-platform way - child = IO.popen([env, command]) + child = IO.popen(env, command) begin Process.wait(child.pid) diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index c28de4e21c..b0d7f3299f 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -169,12 +169,13 @@ module ActiveSupport end end - def encode_with(coder) - if coder.respond_to?(:represent_object) - coder.represent_object(nil, utc) - else - coder.represent_scalar(nil, utc.strftime("%Y-%m-%d %H:%M:%S.%9NZ")) - end + def init_with(coder) #:nodoc: + initialize(coder['utc'], coder['zone'], coder['time']) + end + + def encode_with(coder) #:nodoc: + coder.tag = '!ruby/object:ActiveSupport::TimeWithZone' + coder.map = { 'utc' => utc, 'zone' => time_zone, 'time' => time } end # Returns a string of the object's date and time in the format used by diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index da39f0d245..2699a064d7 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -348,24 +348,31 @@ module ActiveSupport # # Time.zone.parse('Mar 2000') # => Wed, 01 Mar 2000 00:00:00 HST -10:00 def parse(str, now=now()) - parts = Date._parse(str, false) - return if parts.empty? - - time = Time.new( - parts.fetch(:year, now.year), - parts.fetch(:mon, now.month), - parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day), - parts.fetch(:hour, 0), - parts.fetch(:min, 0), - parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0), - parts.fetch(:offset, 0) - ) - - if parts[:offset] - TimeWithZone.new(time.utc, self) - else - TimeWithZone.new(nil, self, time) - end + parts_to_time(Date._parse(str, false), now) + end + + # Parses +str+ according to +format+ and returns an ActiveSupport::TimeWithZone. + # + # Assumes that +str+ is a time in the time zone +self+, + # unless +format+ includes an explicit time zone. + # (This is the same behavior as +parse+.) + # In either case, the returned TimeWithZone has the timezone of +self+. + # + # Time.zone = 'Hawaii' # => "Hawaii" + # Time.zone.strptime('1999-12-31 14:00:00', '%Y-%m-%d %H:%M:%S') # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # + # If upper components are missing from the string, they are supplied from + # TimeZone#now: + # + # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # Time.zone.strptime('22:30:00', '%H:%M:%S') # => Fri, 31 Dec 1999 22:30:00 HST -10:00 + # + # However, if the date component is not provided, but any other upper + # components are supplied, then the day of the month defaults to 1: + # + # Time.zone.strptime('Mar 2000', '%b %Y') # => Wed, 01 Mar 2000 00:00:00 HST -10:00 + def strptime(str, format, now=now()) + parts_to_time(DateTime._strptime(str, format), now) end # Returns an ActiveSupport::TimeWithZone instance representing the current @@ -421,7 +428,36 @@ module ActiveSupport tzinfo.periods_for_local(time) end + def init_with(coder) #:nodoc: + initialize(coder['name']) + end + + def encode_with(coder) #:nodoc: + coder.tag ="!ruby/object:#{self.class}" + coder.map = { 'name' => tzinfo.name } + end + private + def parts_to_time(parts, now) + return if parts.empty? + + time = Time.new( + parts.fetch(:year, now.year), + parts.fetch(:mon, now.month), + parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day), + parts.fetch(:hour, 0), + parts.fetch(:min, 0), + parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0), + parts.fetch(:offset, 0) + ) + + if parts[:offset] + TimeWithZone.new(time.utc, self) + else + TimeWithZone.new(nil, self, time) + end + end + def time_now Time.now end |