diff options
Diffstat (limited to 'activesupport/lib/active_support')
7 files changed, 94 insertions, 41 deletions
diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb index 85122e39b2..befa1746c6 100644 --- a/activesupport/lib/active_support/array_inquirer.rb +++ b/activesupport/lib/active_support/array_inquirer.rb @@ -20,7 +20,7 @@ module ActiveSupport # variants.any?(:phone, :tablet) # => true # variants.any?('phone', 'desktop') # => true # variants.any?(:desktop, :watch) # => false - def any?(*candidates, &block) + def any?(*candidates) if candidates.none? super else @@ -32,7 +32,7 @@ module ActiveSupport private def respond_to_missing?(name, include_private = false) - name[-1] == "?" + (name[-1] == "?") || super end def method_missing(name, *args) diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb index 4a64872392..74baae3639 100644 --- a/activesupport/lib/active_support/core_ext/integer/time.rb +++ b/activesupport/lib/active_support/core_ext/integer/time.rb @@ -18,12 +18,12 @@ class Integer # # equivalent to Time.now.advance(months: 4, years: 5) # (4.months + 5.years).from_now def months - ActiveSupport::Duration.new(self * 30.days, [[:months, self]]) + ActiveSupport::Duration.months(self) end alias :month :months def years - ActiveSupport::Duration.new(self * 365.25.days.to_i, [[:years, self]]) + ActiveSupport::Duration.years(self) end alias :year :years end diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index 809dfd4e07..2e6c70d418 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -19,7 +19,7 @@ class Numeric # # equivalent to Time.current.advance(months: 4, years: 5) # (4.months + 5.years).from_now def seconds - ActiveSupport::Duration.new(self, [[:seconds, self]]) + ActiveSupport::Duration.seconds(self) end alias :second :seconds @@ -27,7 +27,7 @@ class Numeric # # 2.minutes # => 2 minutes def minutes - ActiveSupport::Duration.new(self * 60, [[:minutes, self]]) + ActiveSupport::Duration.minutes(self) end alias :minute :minutes @@ -35,7 +35,7 @@ class Numeric # # 2.hours # => 2 hours def hours - ActiveSupport::Duration.new(self * 3600, [[:hours, self]]) + ActiveSupport::Duration.hours(self) end alias :hour :hours @@ -43,7 +43,7 @@ class Numeric # # 2.days # => 2 days def days - ActiveSupport::Duration.new(self * 24.hours, [[:days, self]]) + ActiveSupport::Duration.days(self) end alias :day :days @@ -51,7 +51,7 @@ class Numeric # # 2.weeks # => 2 weeks def weeks - ActiveSupport::Duration.new(self * 7.days, [[:weeks, self]]) + ActiveSupport::Duration.weeks(self) end alias :week :weeks @@ -59,7 +59,7 @@ class Numeric # # 2.fortnights # => 4 weeks def fortnights - ActiveSupport::Duration.new(self * 2.weeks, [[:weeks, self * 2]]) + ActiveSupport::Duration.weeks(self * 2) end alias :fortnight :fortnights diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index c9e8c8fdc4..003f6203ef 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -7,13 +7,82 @@ module ActiveSupport # # 1.month.ago # equivalent to Time.now.advance(months: -1) class Duration - EPOCH = ::Time.utc(2000) + SECONDS_PER_MINUTE = 60 + SECONDS_PER_HOUR = 3600 + SECONDS_PER_DAY = 86400 + SECONDS_PER_WEEK = 604800 + SECONDS_PER_MONTH = 2629746 # 1/12 of a gregorian year + SECONDS_PER_YEAR = 31556952 # length of a gregorian year (365.2425 days) + + PARTS_IN_SECONDS = { + seconds: 1, + minutes: SECONDS_PER_MINUTE, + hours: SECONDS_PER_HOUR, + days: SECONDS_PER_DAY, + weeks: SECONDS_PER_WEEK, + months: SECONDS_PER_MONTH, + years: SECONDS_PER_YEAR + }.freeze attr_accessor :value, :parts autoload :ISO8601Parser, "active_support/duration/iso8601_parser" autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer" + class << self + # Creates a new Duration from string formatted according to ISO 8601 Duration. + # + # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. + # This method allows negative parts to be present in pattern. + # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+. + def parse(iso8601duration) + parts = ISO8601Parser.new(iso8601duration).parse! + new(calculate_total_seconds(parts), parts) + end + + def ===(other) #:nodoc: + other.is_a?(Duration) + rescue ::NoMethodError + false + end + + def seconds(value) #:nodoc: + new(value, [[:seconds, value]]) + end + + def minutes(value) #:nodoc: + new(value * SECONDS_PER_MINUTE, [[:minutes, value]]) + end + + def hours(value) #:nodoc: + new(value * SECONDS_PER_HOUR, [[:hours, value]]) + end + + def days(value) #:nodoc: + new(value * SECONDS_PER_DAY, [[:days, value]]) + end + + def weeks(value) #:nodoc: + new(value * SECONDS_PER_WEEK, [[:weeks, value]]) + end + + def months(value) #:nodoc: + new(value * SECONDS_PER_MONTH, [[:months, value]]) + end + + def years(value) #:nodoc: + new(value * SECONDS_PER_YEAR, [[:years, value]]) + end + + private + + def calculate_total_seconds(parts) + parts.inject(0) do |total, (part, value)| + total + value * PARTS_IN_SECONDS[part] + end + end + end + def initialize(value, parts) #:nodoc: @value, @parts = value, parts.to_h @parts.default = 0 @@ -78,14 +147,14 @@ module ActiveSupport # 1.day.to_i # => 86400 # # Note that this conversion makes some assumptions about the - # duration of some periods, e.g. months are always 30 days - # and years are 365.25 days: + # duration of some periods, e.g. months are always 1/12 of year + # and years are 365.2425 days: # - # # equivalent to 30.days.to_i - # 1.month.to_i # => 2592000 + # # equivalent to (1.year / 12).to_i + # 1.month.to_i # => 2629746 # - # # equivalent to 365.25.days.to_i - # 1.year.to_i # => 31557600 + # # equivalent to 365.2425.days.to_i + # 1.year.to_i # => 31556952 # # In such cases, Ruby's core # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and @@ -105,12 +174,6 @@ module ActiveSupport @value.hash end - def self.===(other) #:nodoc: - other.is_a?(Duration) - rescue ::NoMethodError - false - end - # Calculates a new Time or Date that is as far in the future # as this Duration represents. def since(time = ::Time.current) @@ -141,16 +204,6 @@ module ActiveSupport @value.respond_to?(method, include_private) end - # Creates a new Duration from string formatted according to ISO 8601 Duration. - # - # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. - # This method allows negative parts to be present in pattern. - # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+. - def self.parse(iso8601duration) - parts = ISO8601Parser.new(iso8601duration).parse! - new(EPOCH.advance(parts) - EPOCH, parts) - end - # Build ISO 8601 Duration string for this duration. # The +precision+ parameter can be used to limit seconds' precision of duration. def iso8601(precision: nil) diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb index 3384d12d5b..ca88e7876b 100644 --- a/activesupport/lib/active_support/execution_wrapper.rb +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -19,14 +19,14 @@ module ActiveSupport set_callback(:complete, *args, &block) end - class RunHook < Struct.new(:hook) # :nodoc: + RunHook = Struct.new(:hook) do # :nodoc: def before(target) hook_state = target.send(:hook_state) hook_state[hook] = hook.run end end - class CompleteHook < Struct.new(:hook) # :nodoc: + CompleteHook = Struct.new(:hook) do # :nodoc: def before(target) hook_state = target.send(:hook_state) if hook_state.key?(hook) diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb index 09e1cbb28d..90eac89c9e 100644 --- a/activesupport/lib/active_support/string_inquirer.rb +++ b/activesupport/lib/active_support/string_inquirer.rb @@ -18,7 +18,7 @@ module ActiveSupport private def respond_to_missing?(method_name, include_private = false) - method_name[-1] == "?" + (method_name[-1] == "?") || super end def method_missing(method_name, *arguments) diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb index e2f008b4b7..07c9be0604 100644 --- a/activesupport/lib/active_support/testing/time_helpers.rb +++ b/activesupport/lib/active_support/testing/time_helpers.rb @@ -10,7 +10,7 @@ module ActiveSupport @stubs = Concurrent::Map.new { |h, k| h[k] = {} } end - def stub_object(object, method_name, return_value) + def stub_object(object, method_name, &block) if stub = stubbing(object, method_name) unstub_object(stub) end @@ -20,7 +20,7 @@ module ActiveSupport @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name) object.singleton_class.send :alias_method, new_name, method_name - object.define_singleton_method(method_name) { return_value } + object.define_singleton_method(method_name, &block) end def unstub_all! @@ -134,9 +134,9 @@ module ActiveSupport now = date_or_time.to_time.change(usec: 0) end - simple_stubs.stub_object(Time, :now, now) - simple_stubs.stub_object(Date, :today, now.to_date) - simple_stubs.stub_object(DateTime, :now, now.to_datetime) + simple_stubs.stub_object(Time, :now) { at(now.to_i) } + simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) } + simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) } if block_given? begin |