diff options
Diffstat (limited to 'activesupport/lib/active_support')
8 files changed, 103 insertions, 52 deletions
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 2c1ad60d44..8e265ad863 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/marshal' require 'active_support/core_ext/file/atomic' require 'active_support/core_ext/string/conversions' require 'uri/common' diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 17450fe4d0..712db2c75a 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -6,6 +6,7 @@ rescue LoadError => e end require 'digest/md5' +require 'active_support/core_ext/marshal' module ActiveSupport module Cache diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index 0c6437b02b..f77d444479 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -32,6 +32,15 @@ class DateTime sec + (min * 60) + (hour * 3600) end + # Returns the number of seconds until 23:59:59. + # + # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399 + # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103 + # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0 + def seconds_until_end_of_day + end_of_day.to_i - to_i + end + # Returns a new DateTime where one or more of the elements have been changed # according to the +options+ parameter. The time options (<tt>:hour</tt>, # <tt>:minute</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb new file mode 100644 index 0000000000..fec3051c0c --- /dev/null +++ b/activesupport/lib/active_support/core_ext/marshal.rb @@ -0,0 +1,21 @@ +module Marshal + class << self + def load_with_autoloading(source) + begin + load_without_autoloading(source) + rescue ArgumentError, NameError => exc + if exc.message.match(%r|undefined class/module (.+)|) + # try loading the class/module + $1.constantize + # if it is a IO we need to go back to read the object + source.rewind if source.respond_to?(:rewind) + retry + else + raise exc + end + end + end + + alias_method_chain :load, :autoloading + end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb index 4e7824ad74..a124202936 100644 --- a/activesupport/lib/active_support/core_ext/string/multibyte.rb +++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb @@ -6,7 +6,7 @@ class String # # +mb_chars+ is a multibyte safe proxy for string methods. # - # In Ruby 1.8 and older it creates and returns an instance of the ActiveSupport::Multibyte::Chars class which + # It creates and returns an instance of the ActiveSupport::Multibyte::Chars class which # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string. # @@ -17,9 +17,6 @@ class String # name.mb_chars.reverse.to_s # => "rellüM sualC" # name.mb_chars.length # => 12 # - # In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that - # it becomes easy to run one version of your code on multiple Ruby versions. - # # == Method chaining # # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows @@ -36,11 +33,7 @@ class String # For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For # information about how to change the default Multibyte behavior see ActiveSupport::Multibyte. def mb_chars - if ActiveSupport::Multibyte.proxy_class.consumes?(self) - ActiveSupport::Multibyte.proxy_class.new(self) - else - self - end + ActiveSupport::Multibyte.proxy_class.new(self) end def is_utf8? diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 931851d40e..46c9f05c15 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -62,6 +62,15 @@ class Time to_i - change(:hour => 0).to_i + (usec / 1.0e+6) end + # Returns the number of seconds until 23:59:59. + # + # Time.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399 + # Time.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103 + # Time.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0 + def seconds_until_end_of_day + end_of_day.to_i - to_i + end + # Returns a new Time where one or more of the elements have been changed according # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>, # <tt>:sec</tt>, <tt>:usec</tt>) reset cascadingly, so if only the hour is passed, diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index c75fb46263..b816ecae5a 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -644,46 +644,58 @@ module ActiveSupport #:nodoc: normalized = const.to_s.sub(/\A::/, '') normalized.sub!(/\A(Object::)+/, '') - constants = normalized.split('::') - to_remove = constants.pop - parent_name = constants.empty? ? 'Object' : constants.join('::') + constants = normalized.split('::') + to_remove = constants.pop - if parent = safe_constantize(parent_name) - log "removing constant #{const}" - - # In an autoloaded user.rb like this - # - # autoload :Foo, 'foo' - # - # class User < ActiveRecord::Base - # end - # - # we correctly register "Foo" as being autoloaded. But if the app does - # not use the "Foo" constant we need to be careful not to trigger - # loading "foo.rb" ourselves. While #const_defined? and #const_get? do - # require the file, #autoload? and #remove_const don't. + if constants.empty? + parent = Object + else + # This method is robust to non-reachable constants. # - # We are going to remove the constant nonetheless ---which exists as - # far as Ruby is concerned--- because if the user removes the macro - # call from a class or module that were not autoloaded, as in the - # example above with Object, accessing to that constant must err. - unless parent.autoload?(to_remove) - begin - constantized = parent.const_get(to_remove, false) - rescue NameError - log "the constant #{const} is not reachable anymore, skipping" - return - else - constantized.before_remove_const if constantized.respond_to?(:before_remove_const) - end - end + # Non-reachable constants may be passed if some of the parents were + # autoloaded and already removed. It is easier to do a sanity check + # here than require the caller to be clever. We check the parent + # rather than the very const argument because we do not want to + # trigger Kernel#autoloads, see the comment below. + parent_name = constants.join('::') + return unless qualified_const_defined?(parent_name) + parent = constantize(parent_name) + end + log "removing constant #{const}" + + # In an autoloaded user.rb like this + # + # autoload :Foo, 'foo' + # + # class User < ActiveRecord::Base + # end + # + # we correctly register "Foo" as being autoloaded. But if the app does + # not use the "Foo" constant we need to be careful not to trigger + # loading "foo.rb" ourselves. While #const_defined? and #const_get? do + # require the file, #autoload? and #remove_const don't. + # + # We are going to remove the constant nonetheless ---which exists as + # far as Ruby is concerned--- because if the user removes the macro + # call from a class or module that were not autoloaded, as in the + # example above with Object, accessing to that constant must err. + unless parent.autoload?(to_remove) begin - parent.instance_eval { remove_const to_remove } + constantized = parent.const_get(to_remove, false) rescue NameError log "the constant #{const} is not reachable anymore, skipping" + return + else + constantized.before_remove_const if constantized.respond_to?(:before_remove_const) end end + + begin + parent.instance_eval { remove_const to_remove } + rescue NameError + log "the constant #{const} is not reachable anymore, skipping" + end end protected diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 0207f53238..1a37d6f2a4 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -278,18 +278,23 @@ module ActiveSupport # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00 # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00 def parse(str, now=now) - date_parts = Date._parse(str) - return if date_parts.empty? - time = Time.parse(str, now) rescue DateTime.parse(str) - - if date_parts[:offset].nil? - if date_parts[:hour] && time.hour != date_parts[:hour] - time = DateTime.parse(str) - end - - ActiveSupport::TimeWithZone.new(nil, self, time) + 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, now.day), + parts.fetch(:hour, now.hour), + parts.fetch(:min, now.min), + parts.fetch(:sec, now.sec) + parts.fetch(:sec_fraction, 0), + parts.fetch(:offset, 0) + ) + + if parts[:offset] + TimeWithZone.new(time.utc, self) else - time.in_time_zone(self) + TimeWithZone.new(nil, self, time) end end |