aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
authorDmitry Polushkin <dmitry.polushkin@gmail.com>2011-12-31 01:10:42 +0000
committerDmitry Polushkin <dmitry.polushkin@gmail.com>2011-12-31 01:10:42 +0000
commit04bc40ff501b1bf81bec7ce3937cb06c896ffc69 (patch)
tree88a33663195900df8a7307aefa2c9aaa561c3973 /activesupport/lib/active_support
parent84eece0a823e9c601ea99a8709f24605a19bcbfd (diff)
parented17983ec56dec689a0311c7f8fcbeba9874e5a4 (diff)
downloadrails-04bc40ff501b1bf81bec7ce3937cb06c896ffc69.tar.gz
rails-04bc40ff501b1bf81bec7ce3937cb06c896ffc69.tar.bz2
rails-04bc40ff501b1bf81bec7ce3937cb06c896ffc69.zip
Merge branch 'master' of git://github.com/rails/rails
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r--activesupport/lib/active_support/base64.rb38
-rw-r--r--activesupport/lib/active_support/basic_object.rb25
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb137
-rw-r--r--activesupport/lib/active_support/cache.rb155
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb9
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb6
-rw-r--r--activesupport/lib/active_support/cache/null_store.rb44
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb4
-rw-r--r--activesupport/lib/active_support/callbacks.rb104
-rw-r--r--activesupport/lib/active_support/concern.rb10
-rw-r--r--activesupport/lib/active_support/core_ext.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/array.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/array/grouping.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/random_access.rb30
-rw-r--r--activesupport/lib/active_support/core_ext/array/uniq_by.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb85
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/date/freeze.rb33
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb58
-rw-r--r--activesupport/lib/active_support/core_ext/exception.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/file.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/file/path.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/float.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/float/rounding.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/io.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/kernel/singleton_class.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/logger.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/module/anonymous.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/module/introspection.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/module/method_names.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/module/qualified_const.rb52
-rw-r--r--activesupport/lib/active_support/core_ext/module/synchronization.rb43
-rw-r--r--activesupport/lib/active_support/core_ext/object/blank.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/object/inclusion.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/object/instance_variables.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_json.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/process.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/process/daemon.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/range.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/range/blockless_step.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/range/cover.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_range.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/rexml.rb46
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb112
-rw-r--r--activesupport/lib/active_support/core_ext/string/conversions.rb30
-rw-r--r--activesupport/lib/active_support/core_ext/string/encoding.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb32
-rw-r--r--activesupport/lib/active_support/core_ext/string/multibyte.rb110
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb51
-rw-r--r--activesupport/lib/active_support/core_ext/time/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/time/marshal.rb27
-rw-r--r--activesupport/lib/active_support/core_ext/time/publicize_conversion_methods.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/uri.rb28
-rw-r--r--activesupport/lib/active_support/dependencies.rb87
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/file_update_checker.rb115
-rw-r--r--activesupport/lib/active_support/gzip.rb2
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb4
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb13
-rw-r--r--activesupport/lib/active_support/inflections.rb6
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb124
-rw-r--r--activesupport/lib/active_support/json/encoding.rb14
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb4
-rw-r--r--activesupport/lib/active_support/logger.rb18
-rw-r--r--activesupport/lib/active_support/memoizable.rb116
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb55
-rw-r--r--activesupport/lib/active_support/message_verifier.rb9
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb165
-rw-r--r--activesupport/lib/active_support/multibyte/utils.rb55
-rw-r--r--activesupport/lib/active_support/notifications.rb101
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb169
-rw-r--r--activesupport/lib/active_support/railtie.rb6
-rw-r--r--activesupport/lib/active_support/ruby/shim.rb8
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb63
-rw-r--r--activesupport/lib/active_support/testing/assertions.rb2
-rw-r--r--activesupport/lib/active_support/testing/performance.rb53
-rw-r--r--activesupport/lib/active_support/testing/performance/ruby.rb2
-rw-r--r--activesupport/lib/active_support/testing/performance/ruby/mri.rb57
-rw-r--r--activesupport/lib/active_support/testing/performance/ruby/yarv.rb29
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb65
-rw-r--r--activesupport/lib/active_support/time.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb7
-rw-r--r--activesupport/lib/active_support/version.rb4
-rw-r--r--activesupport/lib/active_support/whiny_nil.rb60
90 files changed, 985 insertions, 1998 deletions
diff --git a/activesupport/lib/active_support/base64.rb b/activesupport/lib/active_support/base64.rb
index 35014cb3d5..41a1a3469d 100644
--- a/activesupport/lib/active_support/base64.rb
+++ b/activesupport/lib/active_support/base64.rb
@@ -1,42 +1,18 @@
-begin
- require 'base64'
-rescue LoadError
-end
+require 'base64'
module ActiveSupport
- if defined? ::Base64
- Base64 = ::Base64
- else
- # Base64 provides utility methods for encoding and de-coding binary data
- # using a base 64 representation. A base 64 representation of binary data
- # consists entirely of printable US-ASCII characters. The Base64 module
- # is included in Ruby 1.8, but has been removed in Ruby 1.9.
- module Base64
- # Encodes a string to its base 64 representation. Each 60 characters of
- # output is separated by a newline character.
- #
- # ActiveSupport::Base64.encode64("Original unencoded string")
- # # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==\n"
- def self.encode64(data)
- [data].pack("m")
- end
-
- # Decodes a base 64 encoded string to its original representation.
- #
- # ActiveSupport::Base64.decode64("T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==")
- # # => "Original unencoded string"
- def self.decode64(data)
- data.unpack("m").first
- end
- end
- end
+ Base64 = ::Base64
+ # *DEPRECATED*: Use +Base64.strict_encode64+ instead.
+ #
# Encodes the value as base64 without the newline breaks. This makes the base64 encoding readily usable as URL parameters
# or memcache keys without further processing.
#
# ActiveSupport::Base64.encode64s("Original unencoded string")
# # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw=="
def Base64.encode64s(value)
- encode64(value).gsub(/\n/, '')
+ ActiveSupport::Deprecation.warn "encode64s " \
+ "is deprecated. Use Base64.strict_encode64 instead", caller
+ strict_encode64(value)
end
end
diff --git a/activesupport/lib/active_support/basic_object.rb b/activesupport/lib/active_support/basic_object.rb
index 3b5277c205..c3c7ab0112 100644
--- a/activesupport/lib/active_support/basic_object.rb
+++ b/activesupport/lib/active_support/basic_object.rb
@@ -1,21 +1,14 @@
module ActiveSupport
- if defined? ::BasicObject
- # A class with no predefined methods that behaves similarly to Builder's
- # BlankSlate. Used for proxy classes.
- class BasicObject < ::BasicObject
- undef_method :==
- undef_method :equal?
+ # A class with no predefined methods that behaves similarly to Builder's
+ # BlankSlate. Used for proxy classes.
+ class BasicObject < ::BasicObject
+ undef_method :==
+ undef_method :equal?
- # Let ActiveSupport::BasicObject at least raise exceptions.
- def raise(*args)
- ::Object.send(:raise, *args)
- end
- end
- else
- class BasicObject #:nodoc:
- instance_methods.each do |m|
- undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
- end
+ # Let ActiveSupport::BasicObject at least raise exceptions.
+ def raise(*args)
+ ::Object.send(:raise, *args)
end
end
+
end
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 26412cd7f4..36e29644c6 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -1,137 +1,10 @@
require 'thread'
require 'active_support/core_ext/class/attribute_accessors'
+require 'active_support/deprecation'
+require 'active_support/logger'
+require 'fileutils'
module ActiveSupport
- # Inspired by the buffered logger idea by Ezra
- class BufferedLogger
- module Severity
- DEBUG = 0
- INFO = 1
- WARN = 2
- ERROR = 3
- FATAL = 4
- UNKNOWN = 5
- end
- include Severity
-
- MAX_BUFFER_SIZE = 1000
-
- ##
- # :singleton-method:
- # Set to false to disable the silencer
- cattr_accessor :silencer
- self.silencer = true
-
- # Silences the logger for the duration of the block.
- def silence(temporary_level = ERROR)
- if silencer
- begin
- old_logger_level, self.level = level, temporary_level
- yield self
- ensure
- self.level = old_logger_level
- end
- else
- yield self
- end
- end
-
- attr_accessor :level
- attr_reader :auto_flushing
-
- def initialize(log, level = DEBUG)
- @level = level
- @buffer = Hash.new { |h,k| h[k] = [] }
- @auto_flushing = 1
- @guard = Mutex.new
-
- if log.respond_to?(:write)
- @log = log
- elsif File.exist?(log)
- @log = open_log(log, (File::WRONLY | File::APPEND))
- else
- FileUtils.mkdir_p(File.dirname(log))
- @log = open_log(log, (File::WRONLY | File::APPEND | File::CREAT))
- end
- end
-
- def open_log(log, mode)
- open(log, mode).tap do |open_log|
- open_log.set_encoding(Encoding::BINARY) if open_log.respond_to?(:set_encoding)
- open_log.sync = true
- end
- end
-
- def add(severity, message = nil, progname = nil, &block)
- return if @level > severity
- message = (message || (block && block.call) || progname).to_s
- # If a newline is necessary then create a new message ending with a newline.
- # Ensures that the original message is not mutated.
- message = "#{message}\n" unless message[-1] == ?\n
- buffer << message
- auto_flush
- message
- end
-
- # Dynamically add methods such as:
- # def info
- # def warn
- # def debug
- Severity.constants.each do |severity|
- class_eval <<-EOT, __FILE__, __LINE__ + 1
- def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
- add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
- end # end
-
- def #{severity.downcase}? # def debug?
- #{severity} >= @level # DEBUG >= @level
- end # end
- EOT
- end
-
- # Set the auto-flush period. Set to true to flush after every log message,
- # to an integer to flush every N messages, or to false, nil, or zero to
- # never auto-flush. If you turn auto-flushing off, be sure to regularly
- # flush the log yourself -- it will eat up memory until you do.
- def auto_flushing=(period)
- @auto_flushing =
- case period
- when true; 1
- when false, nil, 0; MAX_BUFFER_SIZE
- when Integer; period
- else raise ArgumentError, "Unrecognized auto_flushing period: #{period.inspect}"
- end
- end
-
- def flush
- @guard.synchronize do
- buffer.each do |content|
- @log.write(content)
- end
-
- # Important to do this even if buffer was empty or else @buffer will
- # accumulate empty arrays for each request where nothing was logged.
- clear_buffer
- end
- end
-
- def close
- flush
- @log.close if @log.respond_to?(:close)
- @log = nil
- end
-
- protected
- def auto_flush
- flush if buffer.size >= @auto_flushing
- end
-
- def buffer
- @buffer[Thread.current]
- end
-
- def clear_buffer
- @buffer.delete(Thread.current)
- end
- end
+ BufferedLogger = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
+ 'BufferedLogger', '::ActiveSupport::Logger')
end
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 95d936b32f..7d032ca984 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -16,8 +16,7 @@ module ActiveSupport
autoload :FileStore, 'active_support/cache/file_store'
autoload :MemoryStore, 'active_support/cache/memory_store'
autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
- autoload :SynchronizedMemoryStore, 'active_support/cache/synchronized_memory_store'
- autoload :CompressedMemCacheStore, 'active_support/cache/compressed_mem_cache_store'
+ autoload :NullStore, 'active_support/cache/null_store'
# These options mean something to all cache implementations. Individual cache
# implementations may support additional options.
@@ -27,75 +26,75 @@ module ActiveSupport
autoload :LocalCache, 'active_support/cache/strategy/local_cache'
end
- # Creates a new CacheStore object according to the given options.
- #
- # If no arguments are passed to this method, then a new
- # ActiveSupport::Cache::MemoryStore object will be returned.
- #
- # If you pass a Symbol as the first argument, then a corresponding cache
- # store class under the ActiveSupport::Cache namespace will be created.
- # For example:
- #
- # ActiveSupport::Cache.lookup_store(:memory_store)
- # # => returns a new ActiveSupport::Cache::MemoryStore object
- #
- # ActiveSupport::Cache.lookup_store(:mem_cache_store)
- # # => returns a new ActiveSupport::Cache::MemCacheStore object
- #
- # Any additional arguments will be passed to the corresponding cache store
- # class's constructor:
- #
- # ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
- # # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
- #
- # If the first argument is not a Symbol, then it will simply be returned:
- #
- # ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
- # # => returns MyOwnCacheStore.new
- def self.lookup_store(*store_option)
- store, *parameters = *Array.wrap(store_option).flatten
-
- case store
- when Symbol
- store_class_name = store.to_s.camelize
- store_class =
- begin
- require "active_support/cache/#{store}"
- rescue LoadError => e
- raise "Could not find cache store adapter for #{store} (#{e})"
- else
- ActiveSupport::Cache.const_get(store_class_name)
- end
- store_class.new(*parameters)
- when nil
- ActiveSupport::Cache::MemoryStore.new
- else
- store
+ class << self
+ # Creates a new CacheStore object according to the given options.
+ #
+ # If no arguments are passed to this method, then a new
+ # ActiveSupport::Cache::MemoryStore object will be returned.
+ #
+ # If you pass a Symbol as the first argument, then a corresponding cache
+ # store class under the ActiveSupport::Cache namespace will be created.
+ # For example:
+ #
+ # ActiveSupport::Cache.lookup_store(:memory_store)
+ # # => returns a new ActiveSupport::Cache::MemoryStore object
+ #
+ # ActiveSupport::Cache.lookup_store(:mem_cache_store)
+ # # => returns a new ActiveSupport::Cache::MemCacheStore object
+ #
+ # Any additional arguments will be passed to the corresponding cache store
+ # class's constructor:
+ #
+ # ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
+ # # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
+ #
+ # If the first argument is not a Symbol, then it will simply be returned:
+ #
+ # ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
+ # # => returns MyOwnCacheStore.new
+ def lookup_store(*store_option)
+ store, *parameters = *Array.wrap(store_option).flatten
+
+ case store
+ when Symbol
+ store_class_name = store.to_s.camelize
+ store_class =
+ begin
+ require "active_support/cache/#{store}"
+ rescue LoadError => e
+ raise "Could not find cache store adapter for #{store} (#{e})"
+ else
+ ActiveSupport::Cache.const_get(store_class_name)
+ end
+ store_class.new(*parameters)
+ when nil
+ ActiveSupport::Cache::MemoryStore.new
+ else
+ store
+ end
end
- end
- def self.expand_cache_key(key, namespace = nil)
- expanded_cache_key = namespace ? "#{namespace}/" : ""
+ def expand_cache_key(key, namespace = nil)
+ expanded_cache_key = namespace ? "#{namespace}/" : ""
+
+ prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
+ if prefix
+ expanded_cache_key << "#{prefix}/"
+ end
- prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
- if prefix
- expanded_cache_key << "#{prefix}/"
+ expanded_cache_key << retrieve_cache_key(key)
+ expanded_cache_key
end
- expanded_cache_key <<
- if key.respond_to?(:cache_key)
- key.cache_key
- elsif key.is_a?(Array)
- if key.size > 1
- key.collect { |element| expand_cache_key(element) }.to_param
- else
- key.first.to_param
- end
- elsif key
- key.to_param
- end.to_s
+ private
- expanded_cache_key
+ def retrieve_cache_key(key)
+ case
+ when key.respond_to?(:cache_key) then key.cache_key
+ when key.is_a?(Array) then ['Array', *key.map { |element| retrieve_cache_key(element) }].to_param
+ else key.to_param
+ end.to_s
+ end
end
# An abstract cache store class. There are multiple cache store
@@ -141,7 +140,7 @@ module ActiveSupport
# large enough to warrant compression. To turn on compression either pass
# <tt>:compress => true</tt> in the initializer or as an option to +fetch+
# or +write+. To specify the threshold at which to compress values, set the
- # <tt>:compress_threshold</tt> option. The default threshold is 32K.
+ # <tt>:compress_threshold</tt> option. The default threshold is 16K.
class Store
cattr_accessor :logger, :instance_writer => true
@@ -151,7 +150,7 @@ module ActiveSupport
# Create a new cache. The options will be passed to any write method calls except
# for :namespace which can be used to set the global namespace for the cache.
- def initialize (options = nil)
+ def initialize(options = nil)
@options = options ? options.dup : {}
end
@@ -232,7 +231,7 @@ module ActiveSupport
# <tt>:race_condition_ttl</tt> does not play any role.
#
# # Set all values to expire after one minute.
- # cache = ActiveSupport::Cache::MemoryCache.new(:expires_in => 1.minute)
+ # cache = ActiveSupport::Cache::MemoryStore.new(:expires_in => 1.minute)
#
# cache.write("foo", "original value")
# val_1 = nil
@@ -540,11 +539,11 @@ module ActiveSupport
# Create an entry with internal attributes set. This method is intended to be
# used by implementations that store cache entries in a native format instead
# of as serialized Ruby objects.
- def create (raw_value, created_at, options = {})
+ def create(raw_value, created_at, options = {})
entry = new(nil)
entry.instance_variable_set(:@value, raw_value)
entry.instance_variable_set(:@created_at, created_at.to_f)
- entry.instance_variable_set(:@compressed, !!options[:compressed])
+ entry.instance_variable_set(:@compressed, options[:compressed])
entry.instance_variable_set(:@expires_in, options[:expires_in])
entry
end
@@ -561,7 +560,7 @@ module ActiveSupport
@value = nil
else
@value = Marshal.dump(value)
- if should_compress?(value, options)
+ if should_compress?(@value, options)
@value = Zlib::Deflate.deflate(@value)
@compressed = true
end
@@ -575,6 +574,9 @@ module ActiveSupport
# Get the value stored in the cache.
def value
+ # If the original value was exactly false @value is still true because
+ # it is marshalled and eventually compressed. Both operations yield
+ # strings.
if @value
Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value)
end
@@ -615,13 +617,10 @@ module ActiveSupport
end
private
- def should_compress?(value, options)
- if options[:compress] && value
- unless value.is_a?(Numeric)
- compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
- serialized_value = value.is_a?(String) ? value : Marshal.dump(value)
- return true if serialized_value.size >= compress_threshold
- end
+ def should_compress?(serialized_value, options)
+ if options[:compress]
+ compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
+ return true if serialized_value.size >= compress_threshold
end
false
end
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index b431041b76..9460532af0 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -8,12 +8,13 @@ module ActiveSupport
# A cache store implementation which stores everything on the filesystem.
#
# FileStore implements the Strategy::LocalCache strategy which implements
- # an in memory cache inside of a block.
+ # an in-memory cache inside of a block.
class FileStore < Store
attr_reader :cache_path
DIR_FORMATTER = "%03X"
FILENAME_MAX_SIZE = 230 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
+ EXCLUDED_DIRS = ['.', '..'].freeze
def initialize(cache_path, options = nil)
super(options)
@@ -22,7 +23,7 @@ module ActiveSupport
end
def clear(options = nil)
- root_dirs = Dir.entries(cache_path).reject{|f| f.in?(['.', '..'])}
+ root_dirs = Dir.entries(cache_path).reject{|f| f.in?(EXCLUDED_DIRS)}
FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
end
@@ -149,7 +150,7 @@ module ActiveSupport
# Delete empty directories in the cache.
def delete_empty_directories(dir)
return if dir == cache_path
- if Dir.entries(dir).reject{|f| f.in?(['.', '..'])}.empty?
+ if Dir.entries(dir).reject{|f| f.in?(EXCLUDED_DIRS)}.empty?
File.delete(dir) rescue nil
delete_empty_directories(File.dirname(dir))
end
@@ -163,7 +164,7 @@ module ActiveSupport
def search_dir(dir, &callback)
return if !File.exist?(dir)
Dir.foreach(dir) do |d|
- next if d == "." || d == ".."
+ next if d.in?(EXCLUDED_DIRS)
name = File.join(dir, d)
if File.directory?(name)
search_dir(name, &callback)
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index e07294178b..e38a8387b4 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -11,7 +11,7 @@ require 'active_support/core_ext/string/encoding'
module ActiveSupport
module Cache
# A cache store implementation which stores data in Memcached:
- # http://www.danga.com/memcached/
+ # http://memcached.org/
#
# This is currently the most popular cache store for production websites.
#
@@ -21,7 +21,7 @@ module ActiveSupport
# server goes down, then MemCacheStore will ignore it until it comes back up.
#
# MemCacheStore implements the Strategy::LocalCache strategy which implements
- # an in memory cache inside of a block.
+ # an in-memory cache inside of a block.
class MemCacheStore < Store
module Response # :nodoc:
STORED = "STORED\r\n"
@@ -165,7 +165,7 @@ module ActiveSupport
# characters properly.
def escape_key(key)
key = key.to_s.dup
- key = key.force_encoding("BINARY") if key.encoding_aware?
+ key = key.force_encoding("BINARY")
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
key
diff --git a/activesupport/lib/active_support/cache/null_store.rb b/activesupport/lib/active_support/cache/null_store.rb
new file mode 100644
index 0000000000..4427eaafcd
--- /dev/null
+++ b/activesupport/lib/active_support/cache/null_store.rb
@@ -0,0 +1,44 @@
+module ActiveSupport
+ module Cache
+ # A cache store implementation which doesn't actually store anything. Useful in
+ # development and test environments where you don't want caching turned on but
+ # need to go through the caching interface.
+ #
+ # This cache does implement the local cache strategy, so values will actually
+ # be cached inside blocks that utilize this strategy. See
+ # ActiveSupport::Cache::Strategy::LocalCache for more details.
+ class NullStore < Store
+ def initialize(options = nil)
+ super(options)
+ extend Strategy::LocalCache
+ end
+
+ def clear(options = nil)
+ end
+
+ def cleanup(options = nil)
+ end
+
+ def increment(name, amount = 1, options = nil)
+ end
+
+ def decrement(name, amount = 1, options = nil)
+ end
+
+ def delete_matched(matcher, options = nil)
+ end
+
+ protected
+ def read_entry(key, options) # :nodoc:
+ end
+
+ def write_entry(key, entry, options) # :nodoc:
+ true
+ end
+
+ def delete_entry(key, options) # :nodoc:
+ false
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 0649a058aa..db5f228a70 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -4,9 +4,9 @@ require 'active_support/core_ext/string/inflections'
module ActiveSupport
module Cache
module Strategy
- # Caches that implement LocalCache will be backed by an in memory cache for the
+ # Caches that implement LocalCache will be backed by an in-memory cache for the
# duration of a block. Repeated calls to the cache for the same key will hit the
- # in memory cache for faster access.
+ # in-memory cache for faster access.
module LocalCache
# Simple memory backed cache. This cache is not thread safe and is intended only
# for serving as a temporary memory cache for a single thread.
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 656cba625c..df3aeb6b8a 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -77,8 +77,16 @@ module ActiveSupport
# save
# end
#
- def run_callbacks(kind, *args, &block)
- send("_run_#{kind}_callbacks", *args, &block)
+ def run_callbacks(kind, key = nil, &block)
+ self.class.__run_callbacks(key, kind, self, &block)
+ end
+
+ private
+
+ # A hook invoked everytime a before callback is halted.
+ # This can be overriden in AS::Callback implementors in order
+ # to provide better debugging/logging.
+ def halted_callback_hook(filter)
end
class Callback #:nodoc:#
@@ -153,7 +161,7 @@ module ActiveSupport
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def _one_time_conditions_valid_#{@callback_id}?
- true #{key_options[0]}
+ true if #{key_options}
end
RUBY_EVAL
end
@@ -171,18 +179,18 @@ module ActiveSupport
# if condition # before_save :filter_name, :if => :condition
# filter_name
# end
- filter = <<-RUBY_EVAL
- unless halted
- # This double assignment is to prevent warnings in 1.9.3. I would
- # remove the `result` variable, but apparently some other
- # generated code is depending on this variable being set sometimes
- # and sometimes not.
+ <<-RUBY_EVAL
+ if !halted && #{@compiled_options}
+ # This double assignment is to prevent warnings in 1.9.3 as
+ # the `result` variable is not always used except if the
+ # terminator code refers to it.
result = result = #{@filter}
halted = (#{chain.config[:terminator]})
+ if halted
+ halted_callback_hook(#{@raw_filter.inspect.inspect})
+ end
end
RUBY_EVAL
-
- [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
when :around
# Compile around filters with conditions into proxy methods
# that contain the conditions.
@@ -202,7 +210,7 @@ module ActiveSupport
name = "_conditional_callback_#{@kind}_#{next_id}"
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{name}(halted)
- #{@compiled_options[0] || "if true"} && !halted
+ if #{@compiled_options} && !halted
#{@filter} do
yield self
end
@@ -222,10 +230,12 @@ module ActiveSupport
case @kind
when :after
- # if condition # after_save :filter_name, :if => :condition
- # filter_name
- # end
- [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
+ # after_save :filter_name, :if => :condition
+ <<-RUBY_EVAL
+ if #{@compiled_options}
+ #{@filter}
+ end
+ RUBY_EVAL
when :around
<<-RUBY_EVAL
value
@@ -240,9 +250,7 @@ module ActiveSupport
# symbols, string, procs, and objects), so compile a conditional
# expression based on the options
def _compile_options(options)
- return [] if options[:if].empty? && options[:unless].empty?
-
- conditions = []
+ conditions = ["true"]
unless options[:if].empty?
conditions << Array.wrap(_compile_filter(options[:if]))
@@ -252,7 +260,7 @@ module ActiveSupport
conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
end
- ["if #{conditions.flatten.join(" && ")}", "end"]
+ conditions.flatten.join(" && ")
end
# Filters support:
@@ -368,45 +376,30 @@ module ActiveSupport
end
module ClassMethods
- # Generate the internal runner method called by +run_callbacks+.
- def __define_runner(symbol) #:nodoc:
- body = send("_#{symbol}_callbacks").compile
-
- silence_warnings do
- undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def _run_#{symbol}_callbacks(key = nil, &blk)
- if key
- name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
- unless respond_to?(name)
- self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
- end
-
- send(name, &blk)
- else
- #{body}
- end
- end
- private :_run_#{symbol}_callbacks
- RUBY_EVAL
- end
- end
-
- # This is called the first time a callback is called with a particular
- # key. It creates a new callback method for the key, calculating
- # which callbacks can be omitted because of per_key conditions.
+ # This method calls the callback method for the given key.
+ # If this called first time it creates a new callback method for the key,
+ # calculating which callbacks can be omitted because of per_key conditions.
#
- def __create_keyed_callback(name, kind, object, &blk) #:nodoc:
- @_keyed_callbacks ||= {}
- @_keyed_callbacks[name] ||= begin
- str = send("_#{kind}_callbacks").compile(name, object)
+ def __run_callbacks(key, kind, object, &blk) #:nodoc:
+ name = __callback_runner_name(key, kind)
+ unless object.respond_to?(name)
+ str = send("_#{kind}_callbacks").compile(key, object)
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{name}() #{str} end
protected :#{name}
RUBY_EVAL
- true
end
+ object.send(name, &blk)
+ end
+
+ def __reset_runner(symbol)
+ name = __callback_runner_name(nil, symbol)
+ undef_method(name) if method_defined?(name)
+ end
+
+ def __callback_runner_name(key, kind)
+ "_run__#{self.name.hash.abs}__#{kind}__#{key.hash.abs}__callbacks"
end
# This is used internally to append, prepend and skip callbacks to the
@@ -420,7 +413,7 @@ module ActiveSupport
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
chain = target.send("_#{name}_callbacks")
yield target, chain.dup, type, filters, options
- target.__define_runner(name)
+ target.__reset_runner(name)
end
end
@@ -534,12 +527,12 @@ module ActiveSupport
chain = target.send("_#{symbol}_callbacks").dup
callbacks.each { |c| chain.delete(c) }
target.send("_#{symbol}_callbacks=", chain)
- target.__define_runner(symbol)
+ target.__reset_runner(symbol)
end
self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
- __define_runner(symbol)
+ __reset_runner(symbol)
end
# Define sets of events in the object lifecycle that support callbacks.
@@ -613,7 +606,6 @@ module ActiveSupport
callbacks.each do |callback|
class_attribute "_#{callback}_callbacks"
send("_#{callback}_callbacks=", CallbackChain.new(callback, config))
- __define_runner(callback)
end
end
end
diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb
index 81fb859334..c94a8d99f4 100644
--- a/activesupport/lib/active_support/concern.rb
+++ b/activesupport/lib/active_support/concern.rb
@@ -4,17 +4,12 @@ module ActiveSupport
# module M
# def self.included(base)
# base.extend ClassMethods
- # base.send(:include, InstanceMethods)
# scope :disabled, where(:disabled => true)
# end
#
# module ClassMethods
# ...
# end
- #
- # module InstanceMethods
- # ...
- # end
# end
#
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as:
@@ -31,10 +26,6 @@ module ActiveSupport
# module ClassMethods
# ...
# end
- #
- # module InstanceMethods
- # ...
- # end
# end
#
# Moreover, it gracefully handles module dependencies. Given a +Foo+ module and a +Bar+
@@ -118,7 +109,6 @@ module ActiveSupport
@_dependencies.each { |dep| base.send(:include, dep) }
super
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
- base.send :include, const_get("InstanceMethods") if const_defined?("InstanceMethods")
base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
end
end
diff --git a/activesupport/lib/active_support/core_ext.rb b/activesupport/lib/active_support/core_ext.rb
index 46a8609dd7..b48bdf08e8 100644
--- a/activesupport/lib/active_support/core_ext.rb
+++ b/activesupport/lib/active_support/core_ext.rb
@@ -1,3 +1,4 @@
Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].sort.each do |path|
+ next if File.basename(path, '.rb') == 'logger'
require "active_support/core_ext/#{File.basename(path, '.rb')}"
end
diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb
index 268c9bed4c..79ba79192a 100644
--- a/activesupport/lib/active_support/core_ext/array.rb
+++ b/activesupport/lib/active_support/core_ext/array.rb
@@ -4,5 +4,4 @@ require 'active_support/core_ext/array/uniq_by'
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/array/grouping'
-require 'active_support/core_ext/array/random_access'
require 'active_support/core_ext/array/prepend_and_append'
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 3b22e8b4f9..f3d06ecb2f 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -39,10 +39,10 @@ class Array
#
# Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
#
- # Adding in the <tt>:db</tt> argument as the format yields a prettier
- # output:
+ # Adding in the <tt>:db</tt> argument as the format yields a comma separated
+ # id list:
#
- # Blog.all.to_formatted_s(:db) # => "First Post,Second Post,Third Post"
+ # Blog.all.to_formatted_s(:db) # => "1,2,3"
def to_formatted_s(format = :default)
case format
when :db
diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb
index 4cd9bfadac..2b3f639cb1 100644
--- a/activesupport/lib/active_support/core_ext/array/grouping.rb
+++ b/activesupport/lib/active_support/core_ext/array/grouping.rb
@@ -1,5 +1,3 @@
-require 'enumerator'
-
class Array
# Splits or iterates over the array in groups of size +number+,
# padding any remaining slots with +fill_with+ unless it is +false+.
diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb
deleted file mode 100644
index bb1807a68a..0000000000
--- a/activesupport/lib/active_support/core_ext/array/random_access.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class Array
- # Backport of Array#sample based on Marc-Andre Lafortune's https://github.com/marcandre/backports/
- # Returns a random element or +n+ random elements from the array.
- # If the array is empty and +n+ is nil, returns <tt>nil</tt>.
- # If +n+ is passed and its value is less than 0, it raises an +ArgumentError+ exception.
- # If the value of +n+ is equal or greater than 0 it returns <tt>[]</tt>.
- #
- # [1,2,3,4,5,6].sample # => 4
- # [1,2,3,4,5,6].sample(3) # => [2, 4, 5]
- # [1,2,3,4,5,6].sample(-3) # => ArgumentError: negative array size
- # [].sample # => nil
- # [].sample(3) # => []
- def sample(n=nil)
- return self[Kernel.rand(size)] if n.nil?
- n = n.to_int
- rescue Exception => e
- raise TypeError, "Coercion error: #{n.inspect}.to_int => Integer failed:\n(#{e.message})"
- else
- raise TypeError, "Coercion error: obj.to_int did NOT return an Integer (was #{n.class})" unless n.kind_of? Integer
- raise ArgumentError, "negative array size" if n < 0
- n = size if n > size
- result = Array.new(self)
- n.times do |i|
- r = i + Kernel.rand(size - i)
- result[i], result[r] = result[r], result[i]
- end
- result[n..size] = []
- result
- end unless method_defined? :sample
-end
diff --git a/activesupport/lib/active_support/core_ext/array/uniq_by.rb b/activesupport/lib/active_support/core_ext/array/uniq_by.rb
index 9c5f97b0e9..ac3dedc0e3 100644
--- a/activesupport/lib/active_support/core_ext/array/uniq_by.rb
+++ b/activesupport/lib/active_support/core_ext/array/uniq_by.rb
@@ -1,16 +1,22 @@
class Array
- # Returns an unique array based on the criteria given as a +Proc+.
+ # *DEPRECATED*: Use +Array#uniq+ instead.
+ #
+ # Returns a unique array based on the criteria in the block.
#
# [1, 2, 3, 4].uniq_by { |i| i.odd? } # => [1, 2]
#
- def uniq_by
- hash, array = {}, []
- each { |i| hash[yield(i)] ||= (array << i) }
- array
+ def uniq_by(&block)
+ ActiveSupport::Deprecation.warn "uniq_by " \
+ "is deprecated. Use Array#uniq instead", caller
+ uniq(&block)
end
- # Same as uniq_by, but modifies self.
- def uniq_by!
- replace(uniq_by{ |i| yield(i) })
+ # *DEPRECATED*: Use +Array#uniq!+ instead.
+ #
+ # Same as +uniq_by+, but modifies +self+.
+ def uniq_by!(&block)
+ ActiveSupport::Deprecation.warn "uniq_by! " \
+ "is deprecated. Use Array#uniq! instead", caller
+ uniq!(&block)
end
end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 26a99658cc..af78226c21 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -7,24 +7,6 @@ require 'active_support/core_ext/time/zones'
class Date
DAYS_INTO_WEEK = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
- if RUBY_VERSION < '1.9'
- undef :>>
-
- # Backported from 1.9. The one in 1.8 leads to incorrect next_month and
- # friends for dates where the calendar reform is involved. It additionally
- # prevents an infinite loop fixed in r27013.
- def >>(n)
- y, m = (year * 12 + (mon - 1) + n).divmod(12)
- m, = (m + 1) .divmod(1)
- d = mday
- until jd2 = self.class.valid_civil?(y, m, d, start)
- d -= 1
- raise ArgumentError, 'invalid date' unless d > 0
- end
- self + (jd2 - jd)
- end
- end
-
class << self
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
def yesterday
@@ -154,51 +136,54 @@ class Date
advance(:years => years)
end
- # Shorthand for years_ago(1)
- def prev_year
- years_ago(1)
- end unless method_defined?(:prev_year)
-
- # Shorthand for years_since(1)
- def next_year
- years_since(1)
- end unless method_defined?(:next_year)
-
- # Shorthand for months_ago(1)
- def prev_month
- months_ago(1)
- end unless method_defined?(:prev_month)
-
- # Shorthand for months_since(1)
- def next_month
- months_since(1)
- end unless method_defined?(:next_month)
+ # Returns number of days to start of this week. Week is assumed to start on
+ # +start_day+, default is +:monday+.
+ def days_to_week_start(start_day = :monday)
+ start_day_number = DAYS_INTO_WEEK[start_day]
+ current_day_number = wday != 0 ? wday - 1 : 6
+ (current_day_number - start_day_number) % 7
+ end
- # Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00).
- def beginning_of_week
- days_to_monday = self.wday!=0 ? self.wday-1 : 6
- result = self - days_to_monday
- self.acts_like?(:time) ? result.midnight : result
+ # Returns a new +Date+/+DateTime+ representing the start of this week. Week is
+ # assumed to start on +start_day+, default is +:monday+. +DateTime+ objects
+ # have their time set to 0:00.
+ def beginning_of_week(start_day = :monday)
+ days_to_start = days_to_week_start(start_day)
+ result = self - days_to_start
+ acts_like?(:time) ? result.midnight : result
end
- alias :monday :beginning_of_week
alias :at_beginning_of_week :beginning_of_week
- # Returns a new Date/DateTime representing the end of this week (Sunday, DateTime objects will have time set to 23:59:59).
- def end_of_week
- days_to_sunday = self.wday!=0 ? 7-self.wday : 0
- result = self + days_to_sunday.days
+ # Returns a new +Date+/+DateTime+ representing the start of this week. Week is
+ # assumed to start on a Monday. +DateTime+ objects have their time set to 0:00.
+ def monday
+ beginning_of_week
+ end
+
+ # Returns a new +Date+/+DateTime+ representing the end of this week. Week is
+ # assumed to start on +start_day+, default is +:monday+. +DateTime+ objects
+ # have their time set to 23:59:59.
+ def end_of_week(start_day = :monday)
+ days_to_end = 6 - days_to_week_start(start_day)
+ result = self + days_to_end.days
self.acts_like?(:time) ? result.end_of_day : result
end
- alias :sunday :end_of_week
alias :at_end_of_week :end_of_week
- # Returns a new Date/DateTime representing the start of the given day in the previous week (default is Monday).
+ # Returns a new +Date+/+DateTime+ representing the end of this week. Week is
+ # assumed to start on a Monday. +DateTime+ objects have their time set to 23:59:59.
+ def sunday
+ end_of_week
+ end
+
+ # Returns a new +Date+/+DateTime+ representing the given +day+ in the previous
+ # week. Default is +:monday+. +DateTime+ objects have their time set to 0:00.
def prev_week(day = :monday)
result = (self - 7).beginning_of_week + DAYS_INTO_WEEK[day]
self.acts_like?(:time) ? result.change(:hour => 0) : result
end
- # Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).
+ # Returns a new Date/DateTime representing the start of the given day in next week (default is :monday).
def next_week(day = :monday)
result = (self + 7).beginning_of_week + DAYS_INTO_WEEK[day]
self.acts_like?(:time) ? result.change(:hour => 0) : result
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 338104fd05..3262c254f7 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -63,12 +63,6 @@ class Date
alias_method :default_inspect, :inspect
alias_method :inspect, :readable_inspect
- # A method to keep Time, Date and DateTime instances interchangeable on conversions.
- # In this case, it simply returns +self+.
- def to_date
- self
- end if RUBY_VERSION < '1.9'
-
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
# The timezone can be either :local or :utc (default :local).
#
@@ -83,23 +77,6 @@ class Date
::Time.send("#{form}_time", year, month, day)
end
- # Converts a Date instance to a DateTime, where the time is set to the beginning of the day
- # and UTC offset is set to 0.
- #
- # ==== Examples
- # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
- #
- # date.to_datetime # => Sat, 10 Nov 2007 00:00:00 0000
- def to_datetime
- ::DateTime.civil(year, month, day, 0, 0, 0, 0)
- end if RUBY_VERSION < '1.9'
-
- def iso8601
- strftime('%F')
- end if RUBY_VERSION < '1.9'
-
- alias_method :rfc3339, :iso8601 if RUBY_VERSION < '1.9'
-
def xmlschema
to_time_in_current_zone.xmlschema
end
diff --git a/activesupport/lib/active_support/core_ext/date/freeze.rb b/activesupport/lib/active_support/core_ext/date/freeze.rb
deleted file mode 100644
index a731f8345e..0000000000
--- a/activesupport/lib/active_support/core_ext/date/freeze.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# Date memoizes some instance methods using metaprogramming to wrap
-# the methods with one that caches the result in an instance variable.
-#
-# If a Date is frozen but the memoized method hasn't been called, the
-# first call will result in a frozen object error since the memo
-# instance variable is uninitialized.
-#
-# Work around by eagerly memoizing before the first freeze.
-#
-# Ruby 1.9 uses a preinitialized instance variable so it's unaffected.
-# This hack is as close as we can get to feature detection:
-if RUBY_VERSION < '1.9'
- require 'date'
- begin
- ::Date.today.freeze.jd
- rescue => frozen_object_error
- if frozen_object_error.message =~ /frozen/
- class Date #:nodoc:
- def freeze
- unless frozen?
- self.class.private_instance_methods(false).each do |m|
- if m.to_s =~ /\A__\d+__\Z/
- instance_variable_set(:"@#{m}", [send(m)])
- end
- end
- end
-
- super
- end
- end
- end
- end
-end
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 48cf1a435d..1a3cf66a1b 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -1,5 +1,3 @@
-require 'rational' unless RUBY_VERSION >= '1.9.2'
-
class DateTime
class << self
# DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index ca899c714c..d7b3ad7d8d 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -6,7 +6,7 @@ require 'active_support/values/time_zone'
class DateTime
# Ruby 1.9 has DateTime#to_time which internally relies on Time. We define our own #to_time which allows
# DateTimes outside the range of what can be created with Time.
- remove_method :to_time if instance_methods.include?(:to_time)
+ remove_method :to_time
# Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
#
@@ -66,7 +66,7 @@ class DateTime
# Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class.
# If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time.
def to_time
- self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec, sec_fraction * (RUBY_VERSION < '1.9' ? 86400000000 : 1000000)) : self
+ self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec, sec_fraction * 1000000) : self
end
# To be able to keep Times, Dates and DateTimes interchangeable on conversions.
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index 9343bb7106..77a5087981 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -1,41 +1,4 @@
-require 'active_support/ordered_hash'
-
module Enumerable
- # Ruby 1.8.7 introduces group_by, but the result isn't ordered. Override it.
- remove_method(:group_by) if [].respond_to?(:group_by) && RUBY_VERSION < '1.9'
-
- # Collect an enumerable into sets, grouped by the result of a block. Useful,
- # for example, for grouping records by date.
- #
- # Example:
- #
- # latest_transcripts.group_by(&:day).each do |day, transcripts|
- # p "#{day} -> #{transcripts.map(&:class).join(', ')}"
- # end
- # "2006-03-01 -> Transcript"
- # "2006-02-28 -> Transcript"
- # "2006-02-27 -> Transcript, Transcript"
- # "2006-02-26 -> Transcript, Transcript"
- # "2006-02-25 -> Transcript"
- # "2006-02-24 -> Transcript, Transcript"
- # "2006-02-23 -> Transcript"
- def group_by
- return to_enum :group_by unless block_given?
- assoc = ActiveSupport::OrderedHash.new
-
- each do |element|
- key = yield(element)
-
- if assoc.has_key?(key)
- assoc[key] << element
- else
- assoc[key] = [element]
- end
- end
-
- assoc
- end unless [].respond_to?(:group_by)
-
# Calculates a sum from the elements. Examples:
#
# payments.sum { |p| p.price * p.tax_rate }
@@ -63,27 +26,6 @@ module Enumerable
end
end
- # Iterates over a collection, passing the current element *and* the
- # +memo+ to the block. Handy for building up hashes or
- # reducing collections down to one object. Examples:
- #
- # %w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase }
- # # => {'foo' => 'FOO', 'bar' => 'BAR'}
- #
- # *Note* that you can't use immutable objects like numbers, true or false as
- # the memo. You would think the following returns 120, but since the memo is
- # never changed, it does not.
- #
- # (1..5).each_with_object(1) { |value, memo| memo *= value } # => 1
- #
- def each_with_object(memo)
- return to_enum :each_with_object, memo unless block_given?
- each do |element|
- yield element, memo
- end
- memo
- end unless [].respond_to?(:each_with_object)
-
# Convert an enumerable to a hash. Examples:
#
# people.index_by(&:login)
diff --git a/activesupport/lib/active_support/core_ext/exception.rb b/activesupport/lib/active_support/core_ext/exception.rb
index ef801e713d..ba7757ea07 100644
--- a/activesupport/lib/active_support/core_ext/exception.rb
+++ b/activesupport/lib/active_support/core_ext/exception.rb
@@ -1,3 +1,3 @@
module ActiveSupport
- FrozenObjectError = RUBY_VERSION < '1.9' ? TypeError : RuntimeError
+ FrozenObjectError = RuntimeError
end
diff --git a/activesupport/lib/active_support/core_ext/file.rb b/activesupport/lib/active_support/core_ext/file.rb
index a763447566..dc24afbe7f 100644
--- a/activesupport/lib/active_support/core_ext/file.rb
+++ b/activesupport/lib/active_support/core_ext/file.rb
@@ -1,2 +1 @@
require 'active_support/core_ext/file/atomic'
-require 'active_support/core_ext/file/path'
diff --git a/activesupport/lib/active_support/core_ext/file/path.rb b/activesupport/lib/active_support/core_ext/file/path.rb
deleted file mode 100644
index b5feab80ae..0000000000
--- a/activesupport/lib/active_support/core_ext/file/path.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class File
- unless File.allocate.respond_to?(:to_path)
- alias to_path path
- end
-end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/float.rb b/activesupport/lib/active_support/core_ext/float.rb
deleted file mode 100644
index 7570471b95..0000000000
--- a/activesupport/lib/active_support/core_ext/float.rb
+++ /dev/null
@@ -1 +0,0 @@
-require 'active_support/core_ext/float/rounding'
diff --git a/activesupport/lib/active_support/core_ext/float/rounding.rb b/activesupport/lib/active_support/core_ext/float/rounding.rb
deleted file mode 100644
index 0d4fb87665..0000000000
--- a/activesupport/lib/active_support/core_ext/float/rounding.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class Float
- alias precisionless_round round
- private :precisionless_round
-
- # Rounds the float with the specified precision.
- #
- # x = 1.337
- # x.round # => 1
- # x.round(1) # => 1.3
- # x.round(2) # => 1.34
- def round(precision = nil)
- if precision
- magnitude = 10.0 ** precision
- (self * magnitude).round / magnitude
- else
- precisionless_round
- end
- end
-end if RUBY_VERSION < '1.9'
diff --git a/activesupport/lib/active_support/core_ext/io.rb b/activesupport/lib/active_support/core_ext/io.rb
deleted file mode 100644
index 75f1055191..0000000000
--- a/activesupport/lib/active_support/core_ext/io.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-if RUBY_VERSION < '1.9.2'
-
-# :stopdoc:
-class IO
- def self.binread(name, length = nil, offset = nil)
- return File.read name unless length || offset
- File.open(name, 'rb') { |f|
- f.seek offset if offset
- f.read length
- }
- end
-end
-# :startdoc:
-
-end
diff --git a/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb b/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb
index 33612155fb..9bbf1bbd73 100644
--- a/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb
+++ b/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb
@@ -1,11 +1,4 @@
module Kernel
- # Returns the object's singleton class.
- def singleton_class
- class << self
- self
- end
- end unless respond_to?(:singleton_class) # exists in 1.9.2
-
# class_eval on an object acts like singleton_class.class_eval.
def class_eval(*args, &block)
singleton_class.class_eval(*args, &block)
diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb
index e63a0a9ed9..a51818d2b2 100644
--- a/activesupport/lib/active_support/core_ext/logger.rb
+++ b/activesupport/lib/active_support/core_ext/logger.rb
@@ -1,4 +1,7 @@
require 'active_support/core_ext/class/attribute_accessors'
+require 'active_support/deprecation'
+
+ActiveSupport::Deprecation.warn 'this file is deprecated and will be removed'
# Adds the 'around_level' method to Logger.
class Logger #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb
index 9fed346b7c..f2d4887df6 100644
--- a/activesupport/lib/active_support/core_ext/module.rb
+++ b/activesupport/lib/active_support/core_ext/module.rb
@@ -5,7 +5,6 @@ require 'active_support/core_ext/module/reachable'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
-require 'active_support/core_ext/module/synchronization'
require 'active_support/core_ext/module/deprecation'
require 'active_support/core_ext/module/remove_method'
-require 'active_support/core_ext/module/method_names' \ No newline at end of file
+require 'active_support/core_ext/module/qualified_const'
diff --git a/activesupport/lib/active_support/core_ext/module/anonymous.rb b/activesupport/lib/active_support/core_ext/module/anonymous.rb
index 3982c9c586..0a9e791030 100644
--- a/activesupport/lib/active_support/core_ext/module/anonymous.rb
+++ b/activesupport/lib/active_support/core_ext/module/anonymous.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/object/blank'
-
class Module
# A module may or may not have a name.
#
@@ -7,7 +5,7 @@ class Module
# M.name # => "M"
#
# m = Module.new
- # m.name # => ""
+ # m.name # => nil
#
# A module gets a name when it is first assigned to a constant. Either
# via the +module+ or +class+ keyword or by an explicit assignment:
@@ -17,8 +15,6 @@ class Module
# m.name # => "M"
#
def anonymous?
- # Uses blank? because the name of an anonymous class is an empty
- # string in 1.8, and nil in 1.9.
- name.blank?
+ name.nil?
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb
index c08ad251dd..1893a9cfa6 100644
--- a/activesupport/lib/active_support/core_ext/module/introspection.rb
+++ b/activesupport/lib/active_support/core_ext/module/introspection.rb
@@ -57,27 +57,8 @@ class Module
parents
end
- if RUBY_VERSION < '1.9'
- # Returns the constants that have been defined locally by this object and
- # not in an ancestor. This method is exact if running under Ruby 1.9. In
- # previous versions it may miss some constants if their definition in some
- # ancestor is identical to their definition in the receiver.
- def local_constants
- inherited = {}
-
- ancestors.each do |anc|
- next if anc == self
- anc.constants.each { |const| inherited[const] = anc.const_get(const) }
- end
-
- constants.select do |const|
- !inherited.key?(const) || inherited[const].object_id != const_get(const).object_id
- end
- end
- else
- def local_constants #:nodoc:
- constants(false)
- end
+ def local_constants #:nodoc:
+ constants(false)
end
# Returns the names of the constants defined locally rather than the
diff --git a/activesupport/lib/active_support/core_ext/module/method_names.rb b/activesupport/lib/active_support/core_ext/module/method_names.rb
deleted file mode 100644
index 2eb40a83ab..0000000000
--- a/activesupport/lib/active_support/core_ext/module/method_names.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class Module
- if instance_methods[0].is_a?(Symbol)
- def instance_method_names(*args)
- instance_methods(*args).map(&:to_s)
- end
-
- def method_names(*args)
- methods(*args).map(&:to_s)
- end
- else
- alias_method :instance_method_names, :instance_methods
- alias_method :method_names, :methods
- end
-end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/module/qualified_const.rb b/activesupport/lib/active_support/core_ext/module/qualified_const.rb
new file mode 100644
index 0000000000..8adf050b6b
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/qualified_const.rb
@@ -0,0 +1,52 @@
+require 'active_support/core_ext/string/inflections'
+
+#--
+# Allows code reuse in the methods below without polluting Module.
+#++
+module QualifiedConstUtils
+ def self.raise_if_absolute(path)
+ raise NameError, "wrong constant name #$&" if path =~ /\A::[^:]+/
+ end
+
+ def self.names(path)
+ path.split('::')
+ end
+end
+
+##
+# Extends the API for constants to be able to deal with qualified names. Arguments
+# are assumed to be relative to the receiver.
+#
+#--
+# Qualified names are required to be relative because we are extending existing
+# methods that expect constant names, ie, relative paths of length 1. For example,
+# Object.const_get("::String") raises NameError and so does qualified_const_get.
+#++
+class Module
+ def qualified_const_defined?(path, search_parents=true)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ return unless mod.const_defined?(name, search_parents)
+ mod.const_get(name)
+ end
+ return true
+ end
+
+ def qualified_const_get(path)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ mod.const_get(name)
+ end
+ end
+
+ def qualified_const_set(path, value)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ const_name = path.demodulize
+ mod_name = path.deconstantize
+ mod = mod_name.empty? ? self : qualified_const_get(mod_name)
+ mod.const_set(const_name, value)
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb
deleted file mode 100644
index ed16c2f71b..0000000000
--- a/activesupport/lib/active_support/core_ext/module/synchronization.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'thread'
-require 'active_support/core_ext/module/aliasing'
-require 'active_support/core_ext/array/extract_options'
-
-class Module
- # Synchronize access around a method, delegating synchronization to a
- # particular mutex. A mutex (either a Mutex, or any object that responds to
- # #synchronize and yields to a block) must be provided as a final :with option.
- # The :with option should be a symbol or string, and can represent a method,
- # constant, or instance or class variable.
- # Example:
- # class SharedCache
- # @@lock = Mutex.new
- # def expire
- # ...
- # end
- # synchronize :expire, :with => :@@lock
- # end
- def synchronize(*methods)
- options = methods.extract_options!
- unless options.is_a?(Hash) && with = options[:with]
- raise ArgumentError, "Synchronization needs a mutex. Supply an options hash with a :with key as the last argument (e.g. synchronize :hello, :with => :@mutex)."
- end
-
- methods.each do |method|
- aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
-
- if method_defined?("#{aliased_method}_without_synchronization#{punctuation}")
- raise ArgumentError, "#{method} is already synchronized. Double synchronization is not currently supported."
- end
-
- module_eval(<<-EOS, __FILE__, __LINE__ + 1)
- def #{aliased_method}_with_synchronization#{punctuation}(*args, &block) # def expire_with_synchronization(*args, &block)
- #{with}.synchronize do # @@lock.synchronize do
- #{aliased_method}_without_synchronization#{punctuation}(*args, &block) # expire_without_synchronization(*args, &block)
- end # end
- end # end
- EOS
-
- alias_method_chain method, :synchronization
- end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb
index fe27f45295..7271671908 100644
--- a/activesupport/lib/active_support/core_ext/object/blank.rb
+++ b/activesupport/lib/active_support/core_ext/object/blank.rb
@@ -89,9 +89,6 @@ class Hash
end
class String
- # 0x3000: fullwidth whitespace
- NON_WHITESPACE_REGEXP = %r![^\s#{[0x3000].pack("U")}]!
-
# A string is blank if it's empty or contains whitespaces only:
#
# "".blank? # => true
@@ -100,12 +97,7 @@ class String
# " something here ".blank? # => false
#
def blank?
- # 1.8 does not takes [:space:] properly
- if encoding_aware?
- self !~ /[^[:space:]]/
- else
- self !~ NON_WHITESPACE_REGEXP
- end
+ self !~ /[^[:space:]]/
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/inclusion.rb b/activesupport/lib/active_support/core_ext/object/inclusion.rb
index b5671f66d0..f611cdd606 100644
--- a/activesupport/lib/active_support/core_ext/object/inclusion.rb
+++ b/activesupport/lib/active_support/core_ext/object/inclusion.rb
@@ -1,15 +1,25 @@
class Object
- # Returns true if this object is included in the argument. Argument must be
- # any object which responds to +#include?+. Usage:
+ # Returns true if this object is included in the argument(s). Argument must be
+ # any object which responds to +#include?+ or optionally, multiple arguments can be passed in. Usage:
#
# characters = ["Konata", "Kagami", "Tsukasa"]
# "Konata".in?(characters) # => true
+ #
+ # character = "Konata"
+ # character.in?("Konata", "Kagami", "Tsukasa") # => true
#
- # This will throw an ArgumentError if the argument doesn't respond
+ # This will throw an ArgumentError if a single argument is passed in and it doesn't respond
# to +#include?+.
- def in?(another_object)
- another_object.include?(self)
- rescue NoMethodError
- raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
+ def in?(*args)
+ if args.length > 1
+ args.include? self
+ else
+ another_object = args.first
+ if another_object.respond_to? :include?
+ another_object.include? self
+ else
+ raise ArgumentError.new("The single parameter passed to #in? must respond to #include?")
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
index eda9694614..66caf9bec8 100644
--- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb
+++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -23,11 +23,7 @@ class Object
# end
#
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
- if RUBY_VERSION >= '1.9'
- def instance_variable_names
- instance_variables.map { |var| var.to_s }
- end
- else
- alias_method :instance_variable_names, :instance_variables
+ def instance_variable_names
+ instance_variables.map { |var| var.to_s }
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/to_json.rb b/activesupport/lib/active_support/core_ext/object/to_json.rb
index 14ef27340e..e7dc60a612 100644
--- a/activesupport/lib/active_support/core_ext/object/to_json.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_json.rb
@@ -10,10 +10,10 @@ end
# several cases (for instance, the JSON implementation for Hash does not work) with inheritance
# and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass|
- klass.class_eval <<-RUBY, __FILE__, __LINE__
+ klass.class_eval do
# Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
def to_json(options = nil)
ActiveSupport::JSON.encode(self, options)
end
- RUBY
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index 4797c93e63..e77a9da0ec 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -28,8 +28,6 @@ class Object
def try(*a, &b)
if a.empty? && block_given?
yield self
- elsif !a.empty? && !respond_to?(a.first)
- nil
else
__send__(*a, &b)
end
diff --git a/activesupport/lib/active_support/core_ext/process.rb b/activesupport/lib/active_support/core_ext/process.rb
deleted file mode 100644
index 0b0bc6dc69..0000000000
--- a/activesupport/lib/active_support/core_ext/process.rb
+++ /dev/null
@@ -1 +0,0 @@
-require 'active_support/core_ext/process/daemon'
diff --git a/activesupport/lib/active_support/core_ext/process/daemon.rb b/activesupport/lib/active_support/core_ext/process/daemon.rb
deleted file mode 100644
index f5202ddee4..0000000000
--- a/activesupport/lib/active_support/core_ext/process/daemon.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-module Process
- def self.daemon(nochdir = nil, noclose = nil)
- exit if fork # Parent exits, child continues.
- Process.setsid # Become session leader.
- exit if fork # Zap session leader. See [1].
-
- unless nochdir
- Dir.chdir "/" # Release old working directory.
- end
-
- File.umask 0000 # Ensure sensible umask. Adjust as needed.
-
- unless noclose
- STDIN.reopen "/dev/null" # Free file descriptors and
- STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
- STDERR.reopen '/dev/null', 'a'
- end
-
- trap("TERM") { exit }
-
- return 0
- end unless respond_to?(:daemon)
-end
diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb
index 2428a02242..c0736f3a44 100644
--- a/activesupport/lib/active_support/core_ext/range.rb
+++ b/activesupport/lib/active_support/core_ext/range.rb
@@ -2,4 +2,3 @@ require 'active_support/core_ext/range/blockless_step'
require 'active_support/core_ext/range/conversions'
require 'active_support/core_ext/range/include_range'
require 'active_support/core_ext/range/overlaps'
-require 'active_support/core_ext/range/cover'
diff --git a/activesupport/lib/active_support/core_ext/range/blockless_step.rb b/activesupport/lib/active_support/core_ext/range/blockless_step.rb
index db42ef5c47..f687287f0d 100644
--- a/activesupport/lib/active_support/core_ext/range/blockless_step.rb
+++ b/activesupport/lib/active_support/core_ext/range/blockless_step.rb
@@ -1,27 +1,11 @@
require 'active_support/core_ext/module/aliasing'
class Range
- begin
- (1..2).step
- # Range#step doesn't return an Enumerator
- rescue LocalJumpError
- # Return an array when step is called without a block.
- def step_with_blockless(*args, &block)
- if block_given?
- step_without_blockless(*args, &block)
- else
- array = []
- step_without_blockless(*args) { |step| array << step }
- array
- end
- end
- else
- def step_with_blockless(*args, &block) #:nodoc:
- if block_given?
- step_without_blockless(*args, &block)
- else
- step_without_blockless(*args).to_a
- end
+ def step_with_blockless(*args, &block) #:nodoc:
+ if block_given?
+ step_without_blockless(*args, &block)
+ else
+ step_without_blockless(*args).to_a
end
end
diff --git a/activesupport/lib/active_support/core_ext/range/cover.rb b/activesupport/lib/active_support/core_ext/range/cover.rb
deleted file mode 100644
index 3a182cddd2..0000000000
--- a/activesupport/lib/active_support/core_ext/range/cover.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class Range
- alias_method(:cover?, :include?) unless instance_methods.include?(:cover?)
-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 0246627467..684b7cbc4a 100644
--- a/activesupport/lib/active_support/core_ext/range/include_range.rb
+++ b/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -9,9 +9,9 @@ class Range
# (5..9).include?(11) # => false
def include_with_range?(value)
if value.is_a?(::Range)
- operator = exclude_end? ? :< : :<=
- end_value = value.exclude_end? ? last.succ : last
- include_without_range?(value.first) && (value.last <=> end_value).send(operator, 0)
+ # 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)
end
diff --git a/activesupport/lib/active_support/core_ext/rexml.rb b/activesupport/lib/active_support/core_ext/rexml.rb
deleted file mode 100644
index 0419ebc84b..0000000000
--- a/activesupport/lib/active_support/core_ext/rexml.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'active_support/core_ext/kernel/reporting'
-
-# Fixes the rexml vulnerability disclosed at:
-# http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/
-# This fix is identical to rexml-expansion-fix version 1.0.1.
-#
-# We still need to distribute this fix because albeit the REXML
-# in recent 1.8.7s is patched, it wasn't in early patchlevels.
-require 'rexml/rexml'
-
-# Earlier versions of rexml defined REXML::Version, newer ones REXML::VERSION
-unless (defined?(REXML::VERSION) ? REXML::VERSION : REXML::Version) > "3.1.7.2"
- silence_warnings { require 'rexml/document' }
-
- # REXML in 1.8.7 has the patch but early patchlevels didn't update Version from 3.1.7.2.
- unless REXML::Document.respond_to?(:entity_expansion_limit=)
- silence_warnings { require 'rexml/entity' }
-
- module REXML #:nodoc:
- class Entity < Child #:nodoc:
- undef_method :unnormalized
- def unnormalized
- document.record_entity_expansion! if document
- v = value()
- return nil if v.nil?
- @unnormalized = Text::unnormalize(v, parent)
- @unnormalized
- end
- end
- class Document < Element #:nodoc:
- @@entity_expansion_limit = 10_000
- def self.entity_expansion_limit= val
- @@entity_expansion_limit = val
- end
-
- def record_entity_expansion!
- @number_of_expansions ||= 0
- @number_of_expansions += 1
- if @number_of_expansions > @@entity_expansion_limit
- raise "Number of entity expansions exceeded, processing aborted."
- end
- end
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index c0d5cdf2d5..9b5266c58c 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -1,99 +1,35 @@
require "active_support/multibyte"
class String
- unless '1.9'.respond_to?(:force_encoding)
- # Returns the character at the +position+ treating the string as an array (where 0 is the first character).
- #
- # Examples:
- # "hello".at(0) # => "h"
- # "hello".at(4) # => "o"
- # "hello".at(10) # => ERROR if < 1.9, nil in 1.9
- def at(position)
- mb_chars[position, 1].to_s
- end
-
- # Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
- #
- # Examples:
- # "hello".from(0) # => "hello"
- # "hello".from(2) # => "llo"
- # "hello".from(10) # => "" if < 1.9, nil in 1.9
- def from(position)
- mb_chars[position..-1].to_s
- end
-
- # Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
- #
- # Examples:
- # "hello".to(0) # => "h"
- # "hello".to(2) # => "hel"
- # "hello".to(10) # => "hello"
- def to(position)
- mb_chars[0..position].to_s
- end
-
- # Returns the first character of the string or the first +limit+ characters.
- #
- # Examples:
- # "hello".first # => "h"
- # "hello".first(2) # => "he"
- # "hello".first(10) # => "hello"
- def first(limit = 1)
- if limit == 0
- ''
- elsif limit >= size
- self
- else
- mb_chars[0...limit].to_s
- end
- end
-
- # Returns the last character of the string or the last +limit+ characters.
- #
- # Examples:
- # "hello".last # => "o"
- # "hello".last(2) # => "lo"
- # "hello".last(10) # => "hello"
- def last(limit = 1)
- if limit == 0
- ''
- elsif limit >= size
- self
- else
- mb_chars[(-limit)..-1].to_s
- end
- end
- else
- def at(position)
- self[position]
- end
+ def at(position)
+ self[position]
+ end
- def from(position)
- self[position..-1]
- end
+ def from(position)
+ self[position..-1]
+ end
- def to(position)
- self[0..position]
- end
+ def to(position)
+ self[0..position]
+ end
- def first(limit = 1)
- if limit == 0
- ''
- elsif limit >= size
- self
- else
- to(limit - 1)
- end
+ def first(limit = 1)
+ if limit == 0
+ ''
+ elsif limit >= size
+ self
+ else
+ to(limit - 1)
end
+ end
- def last(limit = 1)
- if limit == 0
- ''
- elsif limit >= size
- self
- else
- from(-limit)
- end
+ def last(limit = 1)
+ if limit == 0
+ ''
+ elsif limit >= size
+ self
+ else
+ from(-limit)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb
index 0f8933b658..541f969faa 100644
--- a/activesupport/lib/active_support/core_ext/string/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/string/conversions.rb
@@ -1,37 +1,7 @@
-# encoding: utf-8
require 'date'
-require 'active_support/core_ext/time/publicize_conversion_methods'
require 'active_support/core_ext/time/calculations'
class String
- # Returns the codepoint of the first character of the string, assuming a
- # single-byte character encoding:
- #
- # "a".ord # => 97
- # "à".ord # => 224, in ISO-8859-1
- #
- # This method is defined in Ruby 1.8 for Ruby 1.9 forward compatibility on
- # these character encodings.
- #
- # <tt>ActiveSupport::Multibyte::Chars#ord</tt> is forward compatible with
- # Ruby 1.9 on UTF8 strings:
- #
- # "a".mb_chars.ord # => 97
- # "à".mb_chars.ord # => 224, in UTF8
- #
- # Note that the 224 is different in both examples. In ISO-8859-1 "à" is
- # represented as a single byte, 224. In UTF8 it is represented with two
- # bytes, namely 195 and 160, but its Unicode codepoint is 224. If we
- # call +ord+ on the UTF8 string "à" the return value will be 195. That is
- # not an error, because UTF8 is unsupported, the call itself would be
- # bogus.
- def ord
- self[0]
- end unless method_defined?(:ord)
-
- # +getbyte+ backport from Ruby 1.9
- alias_method :getbyte, :[] unless method_defined?(:getbyte)
-
# Form can be either :utc (default) or :local.
def to_time(form = :utc)
return nil if self.blank?
diff --git a/activesupport/lib/active_support/core_ext/string/encoding.rb b/activesupport/lib/active_support/core_ext/string/encoding.rb
index d4781bfe0c..dc635ed6a5 100644
--- a/activesupport/lib/active_support/core_ext/string/encoding.rb
+++ b/activesupport/lib/active_support/core_ext/string/encoding.rb
@@ -1,11 +1,8 @@
+require 'active_support/deprecation'
+
class String
- if defined?(Encoding) && "".respond_to?(:encode)
- def encoding_aware?
- true
- end
- else
- def encoding_aware?
- false
- end
+ def encoding_aware?
+ ActiveSupport::Deprecation.warn 'String#encoding_aware? is deprecated', caller
+ true
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index c7ceeb9de4..1e57b586d9 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -9,14 +9,25 @@ require 'active_support/inflector/transliterate'
class String
# Returns the plural form of the word in the string.
#
+ # If the optional parameter +count+ is specified,
+ # the singular form will be returned if <tt>count == 1</tt>.
+ # For any other value of +count+ the plural will be returned.
+ #
+ # ==== Examples
# "post".pluralize # => "posts"
# "octopus".pluralize # => "octopi"
# "sheep".pluralize # => "sheep"
# "words".pluralize # => "words"
# "the blue mailman".pluralize # => "the blue mailmen"
# "CamelOctopus".pluralize # => "CamelOctopi"
- def pluralize
- ActiveSupport::Inflector.pluralize(self)
+ # "apple".pluralize(1) # => "apple"
+ # "apple".pluralize(2) # => "apples"
+ def pluralize(count = nil)
+ if count == 1
+ self
+ else
+ ActiveSupport::Inflector.pluralize(self)
+ end
end
# The reverse of +pluralize+, returns the singular form of a word in a string.
@@ -42,7 +53,7 @@ class String
def constantize
ActiveSupport::Inflector.constantize(self)
end
-
+
# +safe_constantize+ tries to find a declared constant with the name specified
# in the string. It returns nil when the name is not in CamelCase
# or is not initialized. See ActiveSupport::Inflector.safe_constantize
@@ -106,10 +117,25 @@ class String
#
# "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
# "Inflections".demodulize # => "Inflections"
+ #
+ # See also +deconstantize+.
def demodulize
ActiveSupport::Inflector.demodulize(self)
end
+ # Removes the rightmost segment from the constant expression in the string.
+ #
+ # "Net::HTTP".deconstantize # => "Net"
+ # "::Net::HTTP".deconstantize # => "::Net"
+ # "String".deconstantize # => ""
+ # "::String".deconstantize # => ""
+ # "".deconstantize # => ""
+ #
+ # See also +demodulize+.
+ def deconstantize
+ ActiveSupport::Inflector.deconstantize(self)
+ end
+
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
#
# ==== Examples
diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb
index aae1cfccf2..4e7824ad74 100644
--- a/activesupport/lib/active_support/core_ext/string/multibyte.rb
+++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb
@@ -2,71 +2,55 @@
require 'active_support/multibyte'
class String
- if RUBY_VERSION >= "1.9"
- # == Multibyte proxy
- #
- # +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
- # 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.
- #
- # name = 'Claus Müller'
- # name.reverse # => "rell??M sualC"
- # name.length # => 13
- #
- # 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
- # method chaining on the result of any of these methods.
- #
- # name.mb_chars.reverse.length # => 12
- #
- # == Interoperability and configuration
- #
- # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
- # String and Char work like expected. The bang! methods change the internal string representation in the Chars
- # object. Interoperability problems can be resolved easily with a +to_s+ call.
- #
- # 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
- end
-
- def is_utf8? #:nodoc
- case encoding
- when Encoding::UTF_8
- valid_encoding?
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
- dup.force_encoding(Encoding::UTF_8).valid_encoding?
- else
- false
- end
- end
- else
- def mb_chars
- if ActiveSupport::Multibyte.proxy_class.wants?(self)
- ActiveSupport::Multibyte.proxy_class.new(self)
- else
- self
- end
+ # == Multibyte proxy
+ #
+ # +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
+ # 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.
+ #
+ # name = 'Claus Müller'
+ # name.reverse # => "rell??M sualC"
+ # name.length # => 13
+ #
+ # 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
+ # method chaining on the result of any of these methods.
+ #
+ # name.mb_chars.reverse.length # => 12
+ #
+ # == Interoperability and configuration
+ #
+ # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
+ # String and Char work like expected. The bang! methods change the internal string representation in the Chars
+ # object. Interoperability problems can be resolved easily with a +to_s+ call.
+ #
+ # 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
+ end
- # Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have
- # them), returns false otherwise.
- def is_utf8?
- ActiveSupport::Multibyte::Chars.consumes?(self)
+ def is_utf8?
+ case encoding
+ when Encoding::UTF_8
+ valid_encoding?
+ when Encoding::ASCII_8BIT, Encoding::US_ASCII
+ dup.force_encoding(Encoding::UTF_8).valid_encoding?
+ else
+ false
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 5d7f74bb65..6cb2ea68b3 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -20,7 +20,7 @@ class ERB
if s.html_safe?
s
else
- s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;").html_safe
+ s.encode(s.encoding, :xml => :attr)[1...-1].html_safe
end
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 372dd69212..f3235d11bb 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -161,27 +161,46 @@ class Time
months_since(1)
end
- # Returns a new Time representing the "start" of this week (Monday, 0:00)
- def beginning_of_week
- days_to_monday = wday!=0 ? wday-1 : 6
- (self - days_to_monday.days).midnight
+ # Returns number of days to start of this week, week starts on start_day (default is :monday).
+ def days_to_week_start(start_day = :monday)
+ start_day_number = DAYS_INTO_WEEK[start_day]
+ current_day_number = wday != 0 ? wday - 1 : 6
+ days_span = current_day_number - start_day_number
+ days_span >= 0 ? days_span : 7 + days_span
+ end
+
+ # Returns a new Time representing the "start" of this week, week starts on start_day (default is :monday, i.e. Monday, 0:00).
+ def beginning_of_week(start_day = :monday)
+ days_to_start = days_to_week_start(start_day)
+ (self - days_to_start.days).midnight
end
- alias :monday :beginning_of_week
alias :at_beginning_of_week :beginning_of_week
- # Returns a new Time representing the end of this week, (end of Sunday)
- def end_of_week
- days_to_sunday = wday!=0 ? 7-wday : 0
- (self + days_to_sunday.days).end_of_day
+ # Returns a new +Date+/+DateTime+ representing the start of this week. Week is
+ # assumed to start on a Monday. +DateTime+ objects have their time set to 0:00.
+ def monday
+ beginning_of_week
+ end
+
+ # Returns a new Time representing the end of this week, week starts on start_day (default is :monday, i.e. end of Sunday).
+ def end_of_week(start_day = :monday)
+ days_to_end = 6 - days_to_week_start(start_day)
+ (self + days_to_end.days).end_of_day
end
alias :at_end_of_week :end_of_week
- # Returns a new Time representing the start of the given day in the previous week (default is Monday).
+ # Returns a new +Date+/+DateTime+ representing the end of this week. Week is
+ # assumed to start on a Monday. +DateTime+ objects have their time set to 23:59:59.
+ def sunday
+ end_of_week
+ end
+
+ # Returns a new Time representing the start of the given day in the previous week (default is :monday).
def prev_week(day = :monday)
ago(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0)
end
- # Returns a new Time representing the start of the given day in next week (default is Monday).
+ # Returns a new Time representing the start of the given day in next week (default is :monday).
def next_week(day = :monday)
since(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0)
end
@@ -312,4 +331,14 @@ class Time
end
alias_method :compare_without_coercion, :<=>
alias_method :<=>, :compare_with_coercion
+
+ # Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
+ # can be eql? to an equivalent Time
+ def eql_with_coercion(other)
+ # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison
+ other = other.comparable_time if other.respond_to?(:comparable_time)
+ eql_without_coercion(other)
+ end
+ alias_method :eql_without_coercion, :eql?
+ alias_method :eql?, :eql_with_coercion
end
diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb
index 49ac18d245..5a17fc1afa 100644
--- a/activesupport/lib/active_support/core_ext/time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/time/conversions.rb
@@ -1,5 +1,4 @@
require 'active_support/inflector/methods'
-require 'active_support/core_ext/time/publicize_conversion_methods'
require 'active_support/values/time_zone'
class Time
diff --git a/activesupport/lib/active_support/core_ext/time/marshal.rb b/activesupport/lib/active_support/core_ext/time/marshal.rb
index 457d3f5b62..1bf622d6a6 100644
--- a/activesupport/lib/active_support/core_ext/time/marshal.rb
+++ b/activesupport/lib/active_support/core_ext/time/marshal.rb
@@ -1,30 +1,3 @@
-# Pre-1.9 versions of Ruby have a bug with marshaling Time instances, where utc instances are
-# unmarshalled in the local zone, instead of utc. We're layering behavior on the _dump and _load
-# methods so that utc instances can be flagged on dump, and coerced back to utc on load.
-if !Marshal.load(Marshal.dump(Time.now.utc)).utc?
- class Time
- class << self
- alias_method :_load_without_utc_flag, :_load
- def _load(marshaled_time)
- time = _load_without_utc_flag(marshaled_time)
- time.instance_eval do
- if defined?(@marshal_with_utc_coercion)
- val = remove_instance_variable("@marshal_with_utc_coercion")
- end
- val ? utc : self
- end
- end
- end
-
- alias_method :_dump_without_utc_flag, :_dump
- def _dump(*args)
- obj = dup
- obj.instance_variable_set('@marshal_with_utc_coercion', utc?)
- obj._dump_without_utc_flag(*args)
- end
- end
-end
-
# Ruby 1.9.2 adds utc_offset and zone to Time, but marshaling only
# preserves utc_offset. Preserve zone also, even though it may not
# work in some edge cases.
diff --git a/activesupport/lib/active_support/core_ext/time/publicize_conversion_methods.rb b/activesupport/lib/active_support/core_ext/time/publicize_conversion_methods.rb
deleted file mode 100644
index e1878d3c20..0000000000
--- a/activesupport/lib/active_support/core_ext/time/publicize_conversion_methods.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'date'
-
-class Time
- # Ruby 1.8-cvs and early 1.9 series define private Time#to_date
- %w(to_date to_datetime).each do |method|
- if private_instance_methods.include?(method) || private_instance_methods.include?(method.to_sym)
- public method
- end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb
index ee991e3439..0b219ce44a 100644
--- a/activesupport/lib/active_support/core_ext/uri.rb
+++ b/activesupport/lib/active_support/core_ext/uri.rb
@@ -1,22 +1,18 @@
# encoding: utf-8
-if RUBY_VERSION >= '1.9'
- require 'uri'
+require 'uri'
+str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
+parser = URI::Parser.new
- str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
-
- parser = URI::Parser.new
-
- unless str == parser.unescape(parser.escape(str))
- URI::Parser.class_eval do
- remove_method :unescape
- def unescape(str, escaped = /%[a-fA-F\d]{2}/)
- # TODO: Are we actually sure that ASCII == UTF-8?
- # YK: My initial experiments say yes, but let's be sure please
- enc = str.encoding
- enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
- str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(enc)
- end
+unless str == parser.unescape(parser.escape(str))
+ URI::Parser.class_eval do
+ remove_method :unescape
+ def unescape(str, escaped = /%[a-fA-F\d]{2}/)
+ # TODO: Are we actually sure that ASCII == UTF-8?
+ # YK: My initial experiments say yes, but let's be sure please
+ enc = str.encoding
+ enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
+ str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(enc)
end
end
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index c072a8e646..e121e452a3 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -5,6 +5,7 @@ require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/module/introspection'
require 'active_support/core_ext/module/anonymous'
+require 'active_support/core_ext/module/qualified_const'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/load_error'
require 'active_support/core_ext/name_error'
@@ -70,14 +71,24 @@ module ActiveSupport #:nodoc:
#
# This is handled by walking back up the watch stack and adding the constants
# found by child.rb to the list of original constants in parent.rb
- class WatchStack < Hash
+ class WatchStack
+ include Enumerable
+
# @watching is a stack of lists of constants being watched. For instance,
# if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb
# then requires namespace/child.rb, the stack will look like [[Object], [Namespace]].
def initialize
@watching = []
- super { |h,k| h[k] = [] }
+ @stack = Hash.new { |h,k| h[k] = [] }
+ end
+
+ def each(&block)
+ @stack.each(&block)
+ end
+
+ def watching?
+ !@watching.empty?
end
# return a list of new constants found since the last call to watch_namespaces
@@ -88,7 +99,7 @@ module ActiveSupport #:nodoc:
@watching.last.each do |namespace|
# Retrieve the constants that were present under the namespace when watch_namespaces
# was originally called
- original_constants = self[namespace].last
+ original_constants = @stack[namespace].last
mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
next unless mod.is_a?(Module)
@@ -101,7 +112,7 @@ module ActiveSupport #:nodoc:
# element of self[Object] will be an Array of the constants that were present
# before parent.rb was required. The second element will be an Array of the
# constants that were present before child.rb was required.
- self[namespace].each do |namespace_constants|
+ @stack[namespace].each do |namespace_constants|
namespace_constants.concat(new_constants)
end
@@ -125,13 +136,14 @@ module ActiveSupport #:nodoc:
Inflector.constantize(module_name).local_constant_names : []
watching << module_name
- self[module_name] << original_constants
+ @stack[module_name] << original_constants
end
@watching << watching
end
+ private
def pop_modules(modules)
- modules.each { |mod| self[mod].pop }
+ modules.each { |mod| @stack[mod].pop }
end
end
@@ -218,8 +230,8 @@ module ActiveSupport #:nodoc:
end
def load_dependency(file)
- if Dependencies.load?
- Dependencies.new_constants_in(Object) { yield }.presence
+ if Dependencies.load? && ActiveSupport::Dependencies.constant_watch_stack.watching?
+ Dependencies.new_constants_in(Object) { yield }
else
yield
end
@@ -228,13 +240,13 @@ module ActiveSupport #:nodoc:
raise
end
- def load(file, *)
+ def load(file, wrap = false)
result = false
load_dependency(file) { result = super }
result
end
- def require(file, *)
+ def require(file)
result = false
load_dependency(file) { result = super }
result
@@ -358,24 +370,11 @@ module ActiveSupport #:nodoc:
# Is the provided constant path defined?
def qualified_const_defined?(path)
- names = path.sub(/^::/, '').to_s.split('::')
-
- names.inject(Object) do |mod, name|
- return false unless local_const_defined?(mod, name)
- mod.const_get name
- end
+ Object.qualified_const_defined?(path.sub(/^::/, ''), false)
end
- if Module.method(:const_defined?).arity == 1
- # Does this module define this constant?
- # Wrapper to accommodate changing Module#const_defined? in Ruby 1.9
- def local_const_defined?(mod, const)
- mod.const_defined?(const)
- end
- else
- def local_const_defined?(mod, const) #:nodoc:
- mod.const_defined?(const, false)
- end
+ def local_const_defined?(mod, const) #:nodoc:
+ mod.const_defined?(const, false)
end
# Given +path+, a filesystem path to a ruby file, return an array of constant
@@ -426,7 +425,7 @@ module ActiveSupport #:nodoc:
end
# Attempt to autoload the provided module name by searching for a directory
- # matching the expect path suffix. If found, the module is created and assigned
+ # matching the expected path suffix. If found, the module is created and assigned
# to +into+'s constants with the name +const_name+. Provided that the directory
# was loaded from a reloadable base path, it is added to the set of constants
# that are to be unloaded.
@@ -525,7 +524,7 @@ module ActiveSupport #:nodoc:
class ClassCache
def initialize
- @store = Hash.new { |h, k| h[k] = Inflector.constantize(k) }
+ @store = Hash.new
end
def empty?
@@ -536,23 +535,24 @@ module ActiveSupport #:nodoc:
@store.key?(key)
end
- def []=(key, value)
- return unless key.respond_to?(:name)
-
- raise(ArgumentError, 'anonymous classes cannot be cached') if key.name.blank?
-
- @store[key.name] = value
+ def get(key)
+ key = key.name if key.respond_to?(:name)
+ @store[key] ||= Inflector.constantize(key)
end
+ alias :[] :get
- def [](key)
+ def safe_get(key)
key = key.name if key.respond_to?(:name)
-
- @store[key]
+ @store[key] || begin
+ klass = Inflector.safe_constantize(key)
+ @store[key] = klass
+ end
end
- alias :get :[]
- def store(name)
- self[name] = name
+ def store(klass)
+ return self unless klass.respond_to?(:name)
+ raise(ArgumentError, 'anonymous classes cannot be cached') if klass.name.empty?
+ @store[klass.name] = klass
self
end
@@ -569,10 +569,17 @@ module ActiveSupport #:nodoc:
end
# Get the reference for class named +name+.
+ # Raises an exception if referenced class does not exist.
def constantize(name)
Reference.get(name)
end
+ # Get the reference for class named +name+ if one exists.
+ # Otherwise returns nil.
+ def safe_constantize(name)
+ Reference.safe_get(name)
+ end
+
# Determine if the given constant has been automatically loaded.
def autoloaded?(desc)
# No name => anonymous module.
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 89b0923882..00c67a470d 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -10,7 +10,6 @@ module ActiveSupport
# 1.month.ago # equivalent to Time.now.advance(:months => -1)
class Duration < BasicObject
attr_accessor :value, :parts
- delegate :duplicable?, :to => :value # required when using ActiveSupport's BasicObject on 1.8
def initialize(value, parts) #:nodoc:
@value, @parts = value, parts
diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb
index f76ddff038..a4ad2da137 100644
--- a/activesupport/lib/active_support/file_update_checker.rb
+++ b/activesupport/lib/active_support/file_update_checker.rb
@@ -1,8 +1,28 @@
+require "active_support/core_ext/array/wrap"
+require "active_support/core_ext/array/extract_options"
+
module ActiveSupport
- # This class is responsible to track files and invoke the given block
- # whenever one of these files are changed. For example, this class
- # is used by Rails to reload the I18n framework whenever they are
- # changed upon a new request.
+ # \FileUpdateChecker specifies the API used by Rails to watch files
+ # and control reloading. The API depends on four methods:
+ #
+ # * +initialize+ which expects two parameters and one block as
+ # described below;
+ #
+ # * +updated?+ which returns a boolean if there were updates in
+ # the filesystem or not;
+ #
+ # * +execute+ which executes the given block on initialization
+ # and updates the counter to the latest timestamp;
+ #
+ # * +execute_if_updated+ which just executes the block if it was updated;
+ #
+ # After initialization, a call to +execute_if_updated+ must execute
+ # the block only if there was really a change in the filesystem.
+ #
+ # == Examples
+ #
+ # This class is used by Rails to reload the I18n framework whenever
+ # they are changed upon a new request.
#
# i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
# I18n.reload!
@@ -13,24 +33,89 @@ module ActiveSupport
# end
#
class FileUpdateChecker
- attr_reader :paths, :last_update_at
-
- def initialize(paths, calculate=false, &block)
- @paths = paths
+ # It accepts two parameters on initialization. The first is an array
+ # of files and the second is an optional hash of directories. The hash must
+ # have directories as keys and the value is an array of extensions to be
+ # watched under that directory.
+ #
+ # This method must also receive a block that will be called once a path changes.
+ #
+ # == Implementation details
+ #
+ # This particular implementation checks for added and updated files,
+ # but not removed files. Directories lookup are compiled to a glob for
+ # performance. Therefore, while someone can add new files to the +files+
+ # array after initialization (and parts of Rails do depend on this feature),
+ # adding new directories after initialization is not allowed.
+ #
+ # Notice that other objects that implements FileUpdateChecker API may
+ # not even allow new files to be added after initialization. If this
+ # is the case, we recommend freezing the +files+ after initialization to
+ # avoid changes that won't make effect.
+ def initialize(files, dirs={}, &block)
+ @files = files
+ @glob = compile_glob(dirs)
@block = block
- @last_update_at = calculate ? updated_at : nil
+ @updated_at = nil
+ @last_update_at = updated_at
+ end
+
+ # Check if any of the entries were updated. If so, the updated_at
+ # value is cached until the block is executed via +execute+ or +execute_if_updated+
+ def updated?
+ current_updated_at = updated_at
+ if @last_update_at < current_updated_at
+ @updated_at = updated_at
+ true
+ else
+ false
+ end
end
- def updated_at
- paths.map { |path| File.mtime(path) }.max
+ # Executes the given block and updates the counter to latest timestamp.
+ def execute
+ @last_update_at = updated_at
+ @block.call
+ ensure
+ @updated_at = nil
end
+ # Execute the block given if updated.
def execute_if_updated
- current_update_at = self.updated_at
- if @last_update_at != current_update_at
- @last_update_at = current_update_at
- @block.call
+ if updated?
+ execute
+ true
+ else
+ false
+ end
+ end
+
+ private
+
+ def updated_at #:nodoc:
+ @updated_at || begin
+ all = []
+ all.concat @files.select { |f| File.exists?(f) }
+ all.concat Dir[@glob] if @glob
+ all.map { |path| File.mtime(path) }.max || Time.at(0)
end
end
+
+ def compile_glob(hash) #:nodoc:
+ hash.freeze # Freeze so changes aren't accidently pushed
+ return if hash.empty?
+
+ globs = []
+ hash.each do |key, value|
+ globs << "#{key}/**/*#{compile_ext(value)}"
+ end
+ "{#{globs.join(",")}}"
+ end
+
+ def compile_ext(array) #:nodoc:
+ array = Array.wrap(array)
+ return if array.empty?
+ ".{#{array.join(",")}}"
+ end
end
end
diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb
index 9651f02c73..f7036315d6 100644
--- a/activesupport/lib/active_support/gzip.rb
+++ b/activesupport/lib/active_support/gzip.rb
@@ -8,7 +8,7 @@ module ActiveSupport
class Stream < StringIO
def initialize(*)
super
- set_encoding "BINARY" if "".encoding_aware?
+ set_encoding "BINARY"
end
def close; rewind; end
end
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 636f019cd5..674e4acfd6 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -16,6 +16,10 @@ module ActiveSupport
dup
end
+ def nested_under_indifferent_access
+ self
+ end
+
def initialize(constructor = {})
if constructor.is_a?(Hash)
super()
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index 4c59fe9ac9..bbeb8d82c6 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -10,14 +10,19 @@ module I18n
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
def self.reloader
- @reloader ||= ActiveSupport::FileUpdateChecker.new([]){ I18n.reload! }
+ @reloader ||= ActiveSupport::FileUpdateChecker.new(reloader_paths){ I18n.reload! }
+ end
+
+ def self.reloader_paths
+ @reloader_paths ||= []
end
# Add <tt>I18n::Railtie.reloader</tt> to ActionDispatch callbacks. Since, at this
# point, no path was added to the reloader, I18n.reload! is not triggered
# on to_prepare callbacks. This will only happen on the config.after_initialize
# callback below.
- initializer "i18n.callbacks" do
+ initializer "i18n.callbacks" do |app|
+ app.reloaders << I18n::Railtie.reloader
ActionDispatch::Reloader.to_prepare do
I18n::Railtie.reloader.execute_if_updated
end
@@ -58,8 +63,8 @@ module I18n
init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks)
- reloader.paths.concat I18n.load_path
- reloader.execute_if_updated
+ reloader_paths.concat I18n.load_path
+ reloader.execute
@i18n_inited = true
end
diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb
index daf2a1e1d9..527cce2594 100644
--- a/activesupport/lib/active_support/inflections.rb
+++ b/activesupport/lib/active_support/inflections.rb
@@ -16,8 +16,8 @@ module ActiveSupport
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
- inflect.plural(/([m|l])ouse$/i, '\1ice')
- inflect.plural(/([m|l])ice$/i, '\1ice')
+ inflect.plural(/(m|l)ouse$/i, '\1ice')
+ inflect.plural(/(m|l)ice$/i, '\1ice')
inflect.plural(/^(ox)$/i, '\1en')
inflect.plural(/^(oxen)$/i, '\1')
inflect.plural(/(quiz)$/i, '\1zes')
@@ -35,7 +35,7 @@ module ActiveSupport
inflect.singular(/(s)eries$/i, '\1eries')
inflect.singular(/(m)ovies$/i, '\1ovie')
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
- inflect.singular(/([m|l])ice$/i, '\1ouse')
+ inflect.singular(/(m|l)ice$/i, '\1ouse')
inflect.singular(/(bus)es$/i, '\1')
inflect.singular(/(o)es$/i, '\1')
inflect.singular(/(shoe)s$/i, '\1')
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 934529d496..7f325aee94 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -21,14 +21,7 @@ module ActiveSupport
# "words".pluralize # => "words"
# "CamelOctopus".pluralize # => "CamelOctopi"
def pluralize(word)
- result = word.to_s.dup
-
- if word.empty? || inflections.uncountables.include?(result.downcase)
- result
- else
- inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
- result
- end
+ apply_inflections(word, inflections.plurals)
end
# The reverse of +pluralize+, returns the singular form of a word in a string.
@@ -40,14 +33,7 @@ module ActiveSupport
# "word".singularize # => "word"
# "CamelOctopi".singularize # => "CamelOctopus"
def singularize(word)
- result = word.to_s.dup
-
- if inflections.uncountables.any? { |inflection| result =~ /\b(#{inflection})\Z/i }
- result
- else
- inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
- result
- end
+ apply_inflections(word, inflections.singulars)
end
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
@@ -160,13 +146,32 @@ module ActiveSupport
underscored_word.gsub(/_/, '-')
end
- # Removes the module part from the expression in the string.
+ # Removes the module part from the expression in the string:
#
- # Examples:
# "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
# "Inflections".demodulize # => "Inflections"
- def demodulize(class_name_in_module)
- class_name_in_module.to_s.gsub(/^.*::/, '')
+ #
+ # See also +deconstantize+.
+ def demodulize(path)
+ path = path.to_s
+ if i = path.rindex('::')
+ path[(i+2)..-1]
+ else
+ path
+ end
+ end
+
+ # Removes the rightmost segment from the constant expression in the string:
+ #
+ # "Net::HTTP".deconstantize # => "Net"
+ # "::Net::HTTP".deconstantize # => "::Net"
+ # "String".deconstantize # => ""
+ # "::String".deconstantize # => ""
+ # "".deconstantize # => ""
+ #
+ # See also +demodulize+.
+ def deconstantize(path)
+ path.to_s[0...(path.rindex('::') || 0)] # implementation based on the one in facets' Module#spacename
end
# Creates a foreign key name from a class name.
@@ -181,47 +186,32 @@ module ActiveSupport
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
end
- # Ruby 1.9 introduces an inherit argument for Module#const_get and
- # #const_defined? and changes their default behavior.
- if Module.method(:const_get).arity == 1
- # Tries to find a constant with the name specified in the argument string:
- #
- # "Module".constantize # => Module
- # "Test::Unit".constantize # => Test::Unit
- #
- # The name is assumed to be the one of a top-level constant, no matter whether
- # it starts with "::" or not. No lexical context is taken into account:
- #
- # C = 'outside'
- # module M
- # C = 'inside'
- # C # => 'inside'
- # "C".constantize # => 'outside', same as ::C
- # end
- #
- # NameError is raised when the name is not in CamelCase or the constant is
- # unknown.
- def constantize(camel_cased_word)
- names = camel_cased_word.split('::')
- names.shift if names.empty? || names.first.empty?
-
- constant = Object
- names.each do |name|
- constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
- end
- constant
- end
- else
- def constantize(camel_cased_word) #:nodoc:
- names = camel_cased_word.split('::')
- names.shift if names.empty? || names.first.empty?
+ # Tries to find a constant with the name specified in the argument string:
+ #
+ # "Module".constantize # => Module
+ # "Test::Unit".constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter whether
+ # it starts with "::" or not. No lexical context is taken into account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # "C".constantize # => 'outside', same as ::C
+ # end
+ #
+ # NameError is raised when the name is not in CamelCase or the constant is
+ # unknown.
+ def constantize(camel_cased_word) #:nodoc:
+ names = camel_cased_word.split('::')
+ names.shift if names.empty? || names.first.empty?
- constant = Object
- names.each do |name|
- constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
- end
- constant
+ constant = Object
+ names.each do |name|
+ constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
end
+ constant
end
# Tries to find a constant with the name specified in the argument string:
@@ -292,5 +282,21 @@ module ActiveSupport
part.empty? ? acc : "#{part}(::#{acc})?"
end
end
+
+ # Applies inflection rules for +singularize+ and +pluralize+.
+ #
+ # Examples:
+ # apply_inflections("post", inflections.plurals) # => "posts"
+ # apply_inflections("posts", inflections.singulars) # => "post"
+ def apply_inflections(word, rules)
+ result = word.to_s.dup
+
+ if word.empty? || inflections.uncountables.any? { |inflection| result =~ /\b#{inflection}\Z/i }
+ result
+ else
+ rules.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
+ result
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 469ae69258..d7181035d3 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -50,9 +50,9 @@ module ActiveSupport
end
# like encode, but only calls as_json, without encoding to string
- def as_json(value)
+ def as_json(value, use_options = true)
check_for_circular_references(value) do
- value.as_json(options_for(value))
+ use_options ? value.as_json(options_for(value)) : value.as_json
end
end
@@ -119,9 +119,7 @@ module ActiveSupport
end
def escape(string)
- if string.respond_to?(:force_encoding)
- string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
- end
+ string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
json = string.
gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
gsub(/([\xC0-\xDF][\x80-\xBF]|
@@ -130,7 +128,7 @@ module ActiveSupport
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
}
json = %("#{json}")
- json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
+ json.force_encoding(::Encoding::UTF_8)
json
end
end
@@ -212,7 +210,7 @@ class Array
def as_json(options = nil) #:nodoc:
# use encoder as a proxy to call as_json on all elements, to protect from circular references
encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
- map { |v| encoder.as_json(v) }
+ map { |v| encoder.as_json(v, options) }
end
def encode_json(encoder) #:nodoc:
@@ -239,7 +237,7 @@ class Hash
# use encoder as a proxy to call as_json on all values in the subset, to protect from circular references
encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
result = self.is_a?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash : Hash
- result[subset.map { |k, v| [k.to_s, encoder.as_json(v)] }]
+ result[subset.map { |k, v| [k.to_s, encoder.as_json(v, options)] }]
end
def encode_json(encoder)
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index dcfcf0b63c..7b7fc81e6c 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -50,7 +50,7 @@ module ActiveSupport
end
class MockLogger
- include ActiveSupport::BufferedLogger::Severity
+ include ActiveSupport::Logger::Severity
attr_reader :flush_count
attr_accessor :level
@@ -73,7 +73,7 @@ module ActiveSupport
@flush_count += 1
end
- ActiveSupport::BufferedLogger::Severity.constants.each do |severity|
+ ActiveSupport::Logger::Severity.constants.each do |severity|
class_eval <<-EOT, __FILE__, __LINE__ + 1
def #{severity.downcase}?
#{severity} >= @level
diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb
new file mode 100644
index 0000000000..66e8fcadb4
--- /dev/null
+++ b/activesupport/lib/active_support/logger.rb
@@ -0,0 +1,18 @@
+require 'logger'
+
+module ActiveSupport
+ class Logger < ::Logger
+ def initialize(*args)
+ super
+ @formatter = SimpleFormatter.new
+ end
+
+ # Simple formatter which only displays the message.
+ class SimpleFormatter < ::Logger::Formatter
+ # This method is invoked when a log event occurs
+ def call(severity, timestamp, progname, msg)
+ "#{String === msg ? msg : msg.inspect}\n"
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
deleted file mode 100644
index 4c67676ad5..0000000000
--- a/activesupport/lib/active_support/memoizable.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-require 'active_support/core_ext/kernel/singleton_class'
-require 'active_support/core_ext/module/aliasing'
-require 'active_support/deprecation'
-
-module ActiveSupport
- module Memoizable
- def self.extended(base)
- ActiveSupport::Deprecation.warn "ActiveSupport::Memoizable is deprecated and will be removed in future releases," \
- "simply use Ruby memoization pattern instead.", caller
- super
- end
-
- def self.memoized_ivar_for(symbol)
- "@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym
- end
-
- module InstanceMethods
- def self.included(base)
- base.class_eval do
- unless base.method_defined?(:freeze_without_memoizable)
- alias_method_chain :freeze, :memoizable
- end
- end
- end
-
- def freeze_with_memoizable
- memoize_all unless frozen?
- freeze_without_memoizable
- end
-
- def memoize_all
- prime_cache ".*"
- end
-
- def unmemoize_all
- flush_cache ".*"
- end
-
- def prime_cache(*syms)
- syms.each do |sym|
- methods.each do |m|
- if m.to_s =~ /^_unmemoized_(#{sym})/
- if method(m).arity == 0
- __send__($1)
- else
- ivar = ActiveSupport::Memoizable.memoized_ivar_for($1)
- instance_variable_set(ivar, {})
- end
- end
- end
- end
- end
-
- def flush_cache(*syms)
- syms.each do |sym|
- (methods + private_methods + protected_methods).each do |m|
- if m.to_s =~ /^_unmemoized_(#{sym.to_s.gsub(/\?\Z/, '\?')})/
- ivar = ActiveSupport::Memoizable.memoized_ivar_for($1)
- instance_variable_get(ivar).clear if instance_variable_defined?(ivar)
- end
- end
- end
- end
- end
-
- def memoize(*symbols)
- symbols.each do |symbol|
- original_method = :"_unmemoized_#{symbol}"
- memoized_ivar = ActiveSupport::Memoizable.memoized_ivar_for(symbol)
-
- class_eval <<-EOS, __FILE__, __LINE__ + 1
- include InstanceMethods # include InstanceMethods
- #
- if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
- raise "Already memoized #{symbol}" # raise "Already memoized mime_type"
- end # end
- alias #{original_method} #{symbol} # alias _unmemoized_mime_type mime_type
- #
- if instance_method(:#{symbol}).arity == 0 # if instance_method(:mime_type).arity == 0
- def #{symbol}(reload = false) # def mime_type(reload = false)
- if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? # if reload || !defined?(@_memoized_mime_type) || @_memoized_mime_type.empty?
- #{memoized_ivar} = [#{original_method}] # @_memoized_mime_type = [_unmemoized_mime_type]
- end # end
- #{memoized_ivar}[0] # @_memoized_mime_type[0]
- end # end
- else # else
- def #{symbol}(*args) # def mime_type(*args)
- #{memoized_ivar} ||= {} unless frozen? # @_memoized_mime_type ||= {} unless frozen?
- args_length = method(:#{original_method}).arity # args_length = method(:_unmemoized_mime_type).arity
- if args.length == args_length + 1 && # if args.length == args_length + 1 &&
- (args.last == true || args.last == :reload) # (args.last == true || args.last == :reload)
- reload = args.pop # reload = args.pop
- end # end
- #
- if defined?(#{memoized_ivar}) && #{memoized_ivar} # if defined?(@_memoized_mime_type) && @_memoized_mime_type
- if !reload && #{memoized_ivar}.has_key?(args) # if !reload && @_memoized_mime_type.has_key?(args)
- #{memoized_ivar}[args] # @_memoized_mime_type[args]
- elsif #{memoized_ivar} # elsif @_memoized_mime_type
- #{memoized_ivar}[args] = #{original_method}(*args) # @_memoized_mime_type[args] = _unmemoized_mime_type(*args)
- end # end
- else # else
- #{original_method}(*args) # _unmemoized_mime_type(*args)
- end # end
- end # end
- end # end
- #
- if private_method_defined?(#{original_method.inspect}) # if private_method_defined?(:_unmemoized_mime_type)
- private #{symbol.inspect} # private :mime_type
- elsif protected_method_defined?(#{original_method.inspect}) # elsif protected_method_defined?(:_unmemoized_mime_type)
- protected #{symbol.inspect} # protected :mime_type
- end # end
- EOS
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index e14386a85d..476ba0b3d1 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -10,21 +10,41 @@ module ActiveSupport
# This can be used in situations similar to the <tt>MessageVerifier</tt>, but where you don't
# want users to be able to determine the value of the payload.
class MessageEncryptor
+ module NullSerializer #:nodoc:
+ def self.load(value)
+ value
+ end
+
+ def self.dump(value)
+ value
+ end
+ end
+
class InvalidMessage < StandardError; end
OpenSSLCipherError = OpenSSL::Cipher.const_defined?(:CipherError) ? OpenSSL::Cipher::CipherError : OpenSSL::CipherError
def initialize(secret, options = {})
- unless options.is_a?(Hash)
- ActiveSupport::Deprecation.warn "The second parameter should be an options hash. Use :cipher => 'algorithm' to specify the cipher algorithm."
- options = { :cipher => options }
- end
-
@secret = secret
@cipher = options[:cipher] || 'aes-256-cbc'
+ @verifier = MessageVerifier.new(@secret, :serializer => NullSerializer)
@serializer = options[:serializer] || Marshal
end
- def encrypt(value)
+ # Encrypt and sign a message. We need to sign the message in order to avoid padding attacks.
+ # Reference: http://www.limited-entropy.com/padding-oracle-attacks
+ def encrypt_and_sign(value)
+ verifier.generate(_encrypt(value))
+ end
+
+ # Decrypt and verify a message. We need to verify the message in order to avoid padding attacks.
+ # Reference: http://www.limited-entropy.com/padding-oracle-attacks
+ def decrypt_and_verify(value)
+ _decrypt(verifier.verify(value))
+ end
+
+ private
+
+ def _encrypt(value)
cipher = new_cipher
# Rely on OpenSSL for the initialization vector
iv = cipher.random_iv
@@ -36,10 +56,10 @@ module ActiveSupport
encrypted_data = cipher.update(@serializer.dump(value))
encrypted_data << cipher.final
- [encrypted_data, iv].map {|v| ActiveSupport::Base64.encode64s(v)}.join("--")
+ [encrypted_data, iv].map {|v| ActiveSupport::Base64.strict_encode64(v)}.join("--")
end
- def decrypt(encrypted_message)
+ def _decrypt(encrypted_message)
cipher = new_cipher
encrypted_data, iv = encrypted_message.split("--").map {|v| ActiveSupport::Base64.decode64(v)}
@@ -55,23 +75,12 @@ module ActiveSupport
raise InvalidMessage
end
- def encrypt_and_sign(value)
- verifier.generate(encrypt(value))
+ def new_cipher
+ OpenSSL::Cipher::Cipher.new(@cipher)
end
- def decrypt_and_verify(value)
- decrypt(verifier.verify(value))
+ def verifier
+ @verifier
end
-
-
-
- private
- def new_cipher
- OpenSSL::Cipher::Cipher.new(@cipher)
- end
-
- def verifier
- MessageVerifier.new(@secret)
- end
end
end
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index 9d7c81142a..7cb5b1e82d 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -18,7 +18,7 @@ module ActiveSupport
# self.current_user = User.find(id)
# end
#
- # By default it uses Marshal to serialize the message. If you want to use another
+ # By default it uses Marshal to serialize the message. If you want to use another
# serialization method, you can set the serializer attribute to something that responds
# to dump and load, e.g.:
#
@@ -27,11 +27,6 @@ module ActiveSupport
class InvalidSignature < StandardError; end
def initialize(secret, options = {})
- unless options.is_a?(Hash)
- ActiveSupport::Deprecation.warn "The second parameter should be an options hash. Use :digest => 'algorithm' to specify the digest algorithm."
- options = { :digest => options }
- end
-
@secret = secret
@digest = options[:digest] || 'SHA1'
@serializer = options[:serializer] || Marshal
@@ -49,7 +44,7 @@ module ActiveSupport
end
def generate(value)
- data = ActiveSupport::Base64.encode64s(@serializer.dump(value))
+ data = ActiveSupport::Base64.strict_encode64(@serializer.dump(value))
"#{data}--#{generate_digest(data)}"
end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index b78d92f599..dcc176e93f 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -38,16 +38,10 @@ module ActiveSupport #:nodoc:
alias to_s wrapped_string
alias to_str wrapped_string
- if RUBY_VERSION >= "1.9"
- # Creates a new Chars instance by wrapping _string_.
- def initialize(string)
- @wrapped_string = string
- @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
- end
- else
- def initialize(string) #:nodoc:
- @wrapped_string = string
- end
+ # Creates a new Chars instance by wrapping _string_.
+ def initialize(string)
+ @wrapped_string = string
+ @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
end
# Forward all undefined methods to the wrapped string.
@@ -94,151 +88,8 @@ module ActiveSupport #:nodoc:
@wrapped_string <=> other.to_s
end
- if RUBY_VERSION < "1.9"
- # Returns +true+ if the Chars class can and should act as a proxy for the string _string_. Returns
- # +false+ otherwise.
- def self.wants?(string)
- $KCODE == 'UTF8' && consumes?(string)
- end
-
- # Returns a new Chars object containing the _other_ object concatenated to the string.
- #
- # Example:
- # ('Café'.mb_chars + ' périferôl').to_s # => "Café périferôl"
- def +(other)
- chars(@wrapped_string + other)
- end
-
- # Like <tt>String#=~</tt> only it returns the character offset (in codepoints) instead of the byte offset.
- #
- # Example:
- # 'Café périferôl'.mb_chars =~ /ô/ # => 12
- def =~(other)
- translate_offset(@wrapped_string =~ other)
- end
-
- # Inserts the passed string at specified codepoint offsets.
- #
- # Example:
- # 'Café'.mb_chars.insert(4, ' périferôl').to_s # => "Café périferôl"
- def insert(offset, fragment)
- unpacked = Unicode.u_unpack(@wrapped_string)
- unless offset > unpacked.length
- @wrapped_string.replace(
- Unicode.u_unpack(@wrapped_string).insert(offset, *Unicode.u_unpack(fragment)).pack('U*')
- )
- else
- raise IndexError, "index #{offset} out of string"
- end
- self
- end
-
- # Returns +true+ if contained string contains _other_. Returns +false+ otherwise.
- #
- # Example:
- # 'Café'.mb_chars.include?('é') # => true
- def include?(other)
- # We have to redefine this method because Enumerable defines it.
- @wrapped_string.include?(other)
- end
-
- # Returns the position _needle_ in the string, counting in codepoints. Returns +nil+ if _needle_ isn't found.
- #
- # Example:
- # 'Café périferôl'.mb_chars.index('ô') # => 12
- # 'Café périferôl'.mb_chars.index(/\w/u) # => 0
- def index(needle, offset=0)
- wrapped_offset = first(offset).wrapped_string.length
- index = @wrapped_string.index(needle, wrapped_offset)
- index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil
- end
-
- # Returns the position _needle_ in the string, counting in
- # codepoints, searching backward from _offset_ or the end of the
- # string. Returns +nil+ if _needle_ isn't found.
- #
- # Example:
- # 'Café périferôl'.mb_chars.rindex('é') # => 6
- # 'Café périferôl'.mb_chars.rindex(/\w/u) # => 13
- def rindex(needle, offset=nil)
- offset ||= length
- wrapped_offset = first(offset).wrapped_string.length
- index = @wrapped_string.rindex(needle, wrapped_offset)
- index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil
- end
-
- # Returns the number of codepoints in the string
- def size
- Unicode.u_unpack(@wrapped_string).size
- end
- alias_method :length, :size
-
- # Strips entire range of Unicode whitespace from the right of the string.
- def rstrip
- chars(@wrapped_string.gsub(Unicode::TRAILERS_PAT, ''))
- end
-
- # Strips entire range of Unicode whitespace from the left of the string.
- def lstrip
- chars(@wrapped_string.gsub(Unicode::LEADERS_PAT, ''))
- end
-
- # Strips entire range of Unicode whitespace from the right and left of the string.
- def strip
- rstrip.lstrip
- end
-
- # Returns the codepoint of the first character in the string.
- #
- # Example:
- # 'こんにちは'.mb_chars.ord # => 12371
- def ord
- Unicode.u_unpack(@wrapped_string)[0]
- end
-
- # Works just like <tt>String#rjust</tt>, only integer specifies characters instead of bytes.
- #
- # Example:
- #
- # "¾ cup".mb_chars.rjust(8).to_s
- # # => " ¾ cup"
- #
- # "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace
- # # => "   ¾ cup"
- def rjust(integer, padstr=' ')
- justify(integer, :right, padstr)
- end
-
- # Works just like <tt>String#ljust</tt>, only integer specifies characters instead of bytes.
- #
- # Example:
- #
- # "¾ cup".mb_chars.rjust(8).to_s
- # # => "¾ cup "
- #
- # "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace
- # # => "¾ cup   "
- def ljust(integer, padstr=' ')
- justify(integer, :left, padstr)
- end
-
- # Works just like <tt>String#center</tt>, only integer specifies characters instead of bytes.
- #
- # Example:
- #
- # "¾ cup".mb_chars.center(8).to_s
- # # => " ¾ cup "
- #
- # "¾ cup".mb_chars.center(8, " ").to_s # Use non-breaking whitespace
- # # => " ¾ cup  "
- def center(integer, padstr=' ')
- justify(integer, :center, padstr)
- end
-
- else
- def =~(other)
- @wrapped_string =~ other
- end
+ def =~(other)
+ @wrapped_string =~ other
end
# Works just like <tt>String#split</tt>, with the exception that the items in the resulting list are Chars
@@ -431,9 +282,7 @@ module ActiveSupport #:nodoc:
return nil if byte_offset.nil?
return 0 if @wrapped_string == ''
- if @wrapped_string.respond_to?(:force_encoding)
- @wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT)
- end
+ @wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT)
begin
@wrapped_string[0...byte_offset].unpack('U*').length
diff --git a/activesupport/lib/active_support/multibyte/utils.rb b/activesupport/lib/active_support/multibyte/utils.rb
index 94b393cee2..bd6d4bad41 100644
--- a/activesupport/lib/active_support/multibyte/utils.rb
+++ b/activesupport/lib/active_support/multibyte/utils.rb
@@ -2,36 +2,14 @@
module ActiveSupport #:nodoc:
module Multibyte #:nodoc:
- if Kernel.const_defined?(:Encoding)
- # Returns a regular expression that matches valid characters in the current encoding
- def self.valid_character
- VALID_CHARACTER[Encoding.default_external.to_s]
- end
- else
- def self.valid_character
- case $KCODE
- when 'UTF8'
- VALID_CHARACTER['UTF-8']
- when 'SJIS'
- VALID_CHARACTER['Shift_JIS']
- end
- end
+ # Returns a regular expression that matches valid characters in the current encoding
+ def self.valid_character
+ VALID_CHARACTER[Encoding.default_external.to_s]
end
- if 'string'.respond_to?(:valid_encoding?)
- # Verifies the encoding of a string
- def self.verify(string)
- string.valid_encoding?
- end
- else
- def self.verify(string)
- if expression = valid_character
- # Splits the string on character boundaries, which are determined based on $KCODE.
- string.split(//).all? { |c| expression =~ c }
- else
- true
- end
- end
+ # Verifies the encoding of a string
+ def self.verify(string)
+ string.valid_encoding?
end
# Verifies the encoding of the string and raises an exception when it's not valid
@@ -39,22 +17,11 @@ module ActiveSupport #:nodoc:
raise EncodingError.new("Found characters with invalid encoding") unless verify(string)
end
- if 'string'.respond_to?(:force_encoding)
- # Removes all invalid characters from the string.
- #
- # Note: this method is a no-op in Ruby 1.9
- def self.clean(string)
- string
- end
- else
- def self.clean(string)
- if expression = valid_character
- # Splits the string on character boundaries, which are determined based on $KCODE.
- string.split(//).grep(expression).join
- else
- string
- end
- end
+ # Removes all invalid characters from the string.
+ #
+ # Note: this method is a no-op in Ruby 1.9
+ def self.clean(string)
+ string
end
end
end
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index b5a70d5933..f549d2fff3 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -1,36 +1,102 @@
module ActiveSupport
- # Notifications provides an instrumentation API for Ruby. To instrument an
- # action in Ruby you just need to do:
+ # = Notifications
#
- # ActiveSupport::Notifications.instrument(:render, :extra => :information) do
+ # +ActiveSupport::Notifications+ provides an instrumentation API for Ruby.
+ #
+ # == Instrumenters
+ #
+ # To instrument an event you just need to do:
+ #
+ # ActiveSupport::Notifications.instrument("render", :extra => :information) do
# render :text => "Foo"
# end
#
+ # That executes the block first and notifies all subscribers once done.
+ #
+ # In the example above "render" is the name of the event, and the rest is called
+ # the _payload_. The payload is a mechanism that allows instrumenters to pass
+ # extra information to subscribers. Payloads consist of a hash whose contents
+ # are arbitrary and generally depend on the event.
+ #
+ # == Subscribers
+ #
# You can consume those events and the information they provide by registering
- # a log subscriber. For instance, let's store all instrumented events in an array:
+ # a subscriber. For instance, let's store all "render" events in an array:
#
- # @events = []
+ # events = []
#
- # ActiveSupport::Notifications.subscribe do |*args|
- # @events << ActiveSupport::Notifications::Event.new(*args)
+ # ActiveSupport::Notifications.subscribe("render") do |*args|
+ # events << ActiveSupport::Notifications::Event.new(*args)
# end
#
- # ActiveSupport::Notifications.instrument(:render, :extra => :information) do
+ # That code returns right away, you are just subscribing to "render" events.
+ # The block will be called asynchronously whenever someone instruments "render":
+ #
+ # ActiveSupport::Notifications.instrument("render", :extra => :information) do
# render :text => "Foo"
# end
#
- # event = @events.first
- # event.name # => :render
+ # event = events.first
+ # event.name # => "render"
# event.duration # => 10 (in milliseconds)
# event.payload # => { :extra => :information }
#
- # When subscribing to Notifications, you can pass a pattern, to only consume
- # events that match the pattern:
+ # The block in the +subscribe+ call gets the name of the event, start
+ # timestamp, end timestamp, a string with a unique identifier for that event
+ # (something like "535801666f04d0298cd6"), and a hash with the payload, in
+ # that order.
#
- # ActiveSupport::Notifications.subscribe(/render/) do |event|
- # @render_events << event
+ # If an exception happens during that particular instrumentation the payload will
+ # have a key +:exception+ with an array of two elements as value: a string with
+ # the name of the exception class, and the exception message.
+ #
+ # As the previous example depicts, the class +ActiveSupport::Notifications::Event+
+ # is able to take the arguments as they come and provide an object-oriented
+ # interface to that data.
+ #
+ # You can also subscribe to all events whose name matches a certain regexp:
+ #
+ # ActiveSupport::Notifications.subscribe(/render/) do |*args|
+ # ...
# end
#
+ # and even pass no argument to +subscribe+, in which case you are subscribing
+ # to all events.
+ #
+ # == Temporary Subscriptions
+ #
+ # Sometimes you do not want to subscribe to an event for the entire life of
+ # the application. There are two ways to unsubscribe.
+ #
+ # === Subscribe While a Block Runs
+ #
+ # You can subscribe to some event temporarily while some block runs. For
+ # example, in
+ #
+ # callback = lambda {|*args| ... }
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
+ # ...
+ # end
+ #
+ # the callback will be called for all "sql.active_record" events instrumented
+ # during the execution of the block. The callback is unsubscribed automatically
+ # after that.
+ #
+ # === Manual Unsubscription
+ #
+ # The +subscribe+ method returns a subscriber object:
+ #
+ # subscriber = ActiveSupport::Notifications.subscribe("render") do |*args|
+ # ...
+ # end
+ #
+ # To prevent that block from being called anymore, just unsubscribe passing
+ # that reference:
+ #
+ # ActiveSupport::Notifications.unsubscribe(subscriber)
+ #
+ # == Default Queue
+ #
# Notifications ships with a queue implementation that consumes and publish events
# to log subscribers in a thread. You can use any queue implementation you want.
#
@@ -62,6 +128,13 @@ module ActiveSupport
end
end
+ def subscribed(callback, *args, &block)
+ subscriber = subscribe(*args, &callback)
+ yield
+ ensure
+ unsubscribe(subscriber)
+ end
+
def unsubscribe(args)
notifier.unsubscribe(args)
@instrumenters.clear
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 0264133581..d4f309fbd7 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -20,7 +20,7 @@ module ActiveSupport
# oh.keys # => [:a, :b], this order is guaranteed
#
# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with other implementations.
- class OrderedHash < ::Hash #:nodoc:
+ class OrderedHash < ::Hash
def to_yaml_type
"!tag:yaml.org,2002:omap"
end
@@ -51,172 +51,5 @@ module ActiveSupport
def extractable_options?
true
end
-
- # Hash is ordered in Ruby 1.9!
- if RUBY_VERSION < '1.9'
-
- # In MRI the Hash class is core and written in C. In particular, methods are
- # programmed with explicit C function calls and polymorphism is not honored.
- #
- # For example, []= is crucial in this implementation to maintain the @keys
- # array but hash.c invokes rb_hash_aset() originally. This prevents method
- # reuse through inheritance and forces us to reimplement stuff.
- #
- # For instance, we cannot use the inherited #merge! because albeit the algorithm
- # itself would work, our []= is not being called at all by the C code.
-
- def initialize(*args, &block)
- super
- @keys = []
- end
-
- def self.[](*args)
- ordered_hash = new
-
- if (args.length == 1 && args.first.is_a?(Array))
- args.first.each do |key_value_pair|
- next unless (key_value_pair.is_a?(Array))
- ordered_hash[key_value_pair[0]] = key_value_pair[1]
- end
-
- return ordered_hash
- end
-
- unless (args.size % 2 == 0)
- raise ArgumentError.new("odd number of arguments for Hash")
- end
-
- args.each_with_index do |val, ind|
- next if (ind % 2 != 0)
- ordered_hash[val] = args[ind + 1]
- end
-
- ordered_hash
- end
-
- def initialize_copy(other)
- super
- # make a deep copy of keys
- @keys = other.keys
- end
-
- def []=(key, value)
- @keys << key unless has_key?(key)
- super
- end
-
- def delete(key)
- if has_key? key
- index = @keys.index(key)
- @keys.delete_at index
- end
- super
- end
-
- def delete_if
- super
- sync_keys!
- self
- end
-
- def reject!
- super
- sync_keys!
- self
- end
-
- def reject(&block)
- dup.reject!(&block)
- end
-
- def keys
- @keys.dup
- end
-
- def values
- @keys.collect { |key| self[key] }
- end
-
- def to_hash
- self
- end
-
- def to_a
- @keys.map { |key| [ key, self[key] ] }
- end
-
- def each_key
- return to_enum(:each_key) unless block_given?
- @keys.each { |key| yield key }
- self
- end
-
- def each_value
- return to_enum(:each_value) unless block_given?
- @keys.each { |key| yield self[key]}
- self
- end
-
- def each
- return to_enum(:each) unless block_given?
- @keys.each {|key| yield [key, self[key]]}
- self
- end
-
- def each_pair
- return to_enum(:each_pair) unless block_given?
- @keys.each {|key| yield key, self[key]}
- self
- end
-
- alias_method :select, :find_all
-
- def clear
- super
- @keys.clear
- self
- end
-
- def shift
- k = @keys.first
- v = delete(k)
- [k, v]
- end
-
- def merge!(other_hash)
- if block_given?
- other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
- else
- other_hash.each { |k, v| self[k] = v }
- end
- self
- end
-
- alias_method :update, :merge!
-
- def merge(other_hash, &block)
- dup.merge!(other_hash, &block)
- end
-
- # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
- def replace(other)
- super
- @keys = other.keys
- self
- end
-
- def invert
- OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
- end
-
- def inspect
- "#<OrderedHash #{super}>"
- end
-
- private
- def sync_keys!
- @keys.delete_if {|k| !has_key?(k)}
- end
- end
end
end
diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb
index 1638512af0..f696716cc8 100644
--- a/activesupport/lib/active_support/railtie.rb
+++ b/activesupport/lib/active_support/railtie.rb
@@ -5,12 +5,6 @@ module ActiveSupport
class Railtie < Rails::Railtie
config.active_support = ActiveSupport::OrderedOptions.new
- # Loads support for "whiny nil" (noisy warnings when methods are invoked
- # on +nil+ values) if Configuration#whiny_nils is true.
- initializer "active_support.initialize_whiny_nils" do |app|
- require 'active_support/whiny_nil' if app.config.whiny_nils
- end
-
initializer "active_support.deprecation_behavior" do |app|
if deprecation = app.config.active_support.deprecation
ActiveSupport::Deprecation.behavior = deprecation
diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb
index 608b3fe4b9..41fd866481 100644
--- a/activesupport/lib/active_support/ruby/shim.rb
+++ b/activesupport/lib/active_support/ruby/shim.rb
@@ -3,20 +3,14 @@
#
# Date next_year, next_month
# DateTime to_date, to_datetime, xmlschema
-# Enumerable group_by, each_with_object, none?
-# Process Process.daemon
-# REXML security fix
+# Enumerable group_by, none?
# String ord
# Time to_date, to_time, to_datetime
require 'active_support'
require 'active_support/core_ext/date/calculations'
require 'active_support/core_ext/date_time/conversions'
require 'active_support/core_ext/enumerable'
-require 'active_support/core_ext/process/daemon'
require 'active_support/core_ext/string/conversions'
require 'active_support/core_ext/string/interpolation'
require 'active_support/core_ext/string/encoding'
-require 'active_support/core_ext/rexml'
require 'active_support/core_ext/time/conversions'
-require 'active_support/core_ext/file/path'
-require 'active_support/core_ext/module/method_names' \ No newline at end of file
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
new file mode 100644
index 0000000000..8eae43188d
--- /dev/null
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -0,0 +1,63 @@
+require 'active_support/core_ext/object/blank'
+require 'logger'
+
+module ActiveSupport
+ # Wraps any standard Logger class to provide tagging capabilities. Examples:
+ #
+ # Logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
+ # Logger.tagged("BCX") { Logger.info "Stuff" } # Logs "[BCX] Stuff"
+ # Logger.tagged("BCX", "Jason") { Logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff"
+ # Logger.tagged("BCX") { Logger.tagged("Jason") { Logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
+ #
+ # This is used by the default Rails.logger as configured by Railties to make it easy to stamp log lines
+ # with subdomains, request ids, and anything else to aid debugging of multi-user production applications.
+ class TaggedLogging
+ def initialize(logger)
+ @logger = logger
+ @tags = Hash.new { |h,k| h[k] = [] }
+ end
+
+ def tagged(*new_tags)
+ tags = current_tags
+ new_tags = Array.wrap(new_tags).flatten.reject(&:blank?)
+ tags.concat new_tags
+ yield
+ ensure
+ new_tags.size.times { tags.pop }
+ end
+
+ def add(severity, message = nil, progname = nil, &block)
+ @logger.add(severity, "#{tags_text}#{message}", progname, &block)
+ end
+
+ %w( fatal error warn info debug unknown ).each do |severity|
+ eval <<-EOM, nil, __FILE__, __LINE__ + 1
+ def #{severity}(progname = nil, &block) # def warn(progname = nil, &block)
+ add(Logger::#{severity.upcase}, progname, &block) # add(Logger::WARN, progname, &block)
+ end # end
+ EOM
+ end
+
+ def flush
+ @tags.delete(Thread.current)
+ @logger.flush if @logger.respond_to?(:flush)
+ end
+
+ def method_missing(method, *args)
+ @logger.send(method, *args)
+ end
+
+ protected
+
+ def tags_text
+ tags = current_tags
+ if tags.any?
+ tags.collect { |tag| "[#{tag}]" }.join(" ") + " "
+ end
+ end
+
+ def current_tags
+ @tags[Thread.current]
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb
index f3629ada5b..4e1a58a801 100644
--- a/activesupport/lib/active_support/testing/assertions.rb
+++ b/activesupport/lib/active_support/testing/assertions.rb
@@ -87,7 +87,7 @@ module ActiveSupport
# Test if an expression is not blank. Passes if object.present? is true.
#
- # assert_present {:data => 'x' } # => true
+ # assert_present({:data => 'x' }) # => true
def assert_present(object, message=nil)
message ||= "#{object.inspect} is blank"
assert object.present?, message
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index dd23f8d82d..209bfac19f 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -13,12 +13,7 @@ module ActiveSupport
included do
superclass_delegating_accessor :profile_options
self.profile_options = {}
-
- if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions
- include ForMiniTest
- else
- include ForClassicTestUnit
- end
+ include ForMiniTest
end
# each implementation should define metrics and freeze the defaults
@@ -77,48 +72,6 @@ module ActiveSupport
end
end
- module ForClassicTestUnit
- def run(result)
- return if method_name =~ /^default_test$/
-
- yield(self.class::STARTED, name)
- @_result = result
-
- run_warmup
- if full_profile_options && metrics = full_profile_options[:metrics]
- metrics.each do |metric_name|
- if klass = Metrics[metric_name.to_sym]
- run_profile(klass.new)
- result.add_run
- else
- puts '%20s: unsupported' % metric_name
- end
- end
- end
-
- yield(self.class::FINISHED, name)
- end
-
- def run_test(metric, mode)
- run_callbacks :setup
- setup
- metric.send(mode) { __send__ @method_name }
- rescue ::Test::Unit::AssertionFailedError => e
- add_failure(e.message, e.backtrace)
- rescue StandardError, ScriptError => e
- add_error(e)
- ensure
- begin
- teardown
- run_callbacks :teardown, :enumerator => :reverse_each
- rescue ::Test::Unit::AssertionFailedError => e
- add_failure(e.message, e.backtrace)
- rescue StandardError, ScriptError => e
- add_error(e)
- end
- end
- end
-
protected
# overridden by each implementation
def run_gc; end
@@ -208,8 +161,7 @@ module ActiveSupport
end
end
- ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
- ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
+ ruby = "#{RUBY_ENGINE}-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
@env = [app, rails, ruby, RUBY_PLATFORM] * ','
end
@@ -306,7 +258,6 @@ module ActiveSupport
end
end
-RUBY_ENGINE = 'ruby' unless defined?(RUBY_ENGINE) # mri 1.8
case RUBY_ENGINE
when 'ruby' then require 'active_support/testing/performance/ruby'
when 'rbx' then require 'active_support/testing/performance/rubinius'
diff --git a/activesupport/lib/active_support/testing/performance/ruby.rb b/activesupport/lib/active_support/testing/performance/ruby.rb
index 7d6d047ef6..26731c6bd7 100644
--- a/activesupport/lib/active_support/testing/performance/ruby.rb
+++ b/activesupport/lib/active_support/testing/performance/ruby.rb
@@ -144,8 +144,6 @@ end
if RUBY_VERSION.between?('1.9.2', '2.0')
require 'active_support/testing/performance/ruby/yarv'
-elsif RUBY_VERSION.between?('1.8.6', '1.9')
- require 'active_support/testing/performance/ruby/mri'
else
$stderr.puts 'Update your ruby interpreter to be able to run benchmarks.'
exit
diff --git a/activesupport/lib/active_support/testing/performance/ruby/mri.rb b/activesupport/lib/active_support/testing/performance/ruby/mri.rb
deleted file mode 100644
index 142279dd6e..0000000000
--- a/activesupport/lib/active_support/testing/performance/ruby/mri.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-module ActiveSupport
- module Testing
- module Performance
- module Metrics
- class Base
- protected
- # Ruby 1.8 + ruby-prof wrapper (enable/disable stats for Benchmarker)
- if GC.respond_to?(:enable_stats)
- def with_gc_stats
- GC.enable_stats
- GC.start
- yield
- ensure
- GC.disable_stats
- end
- end
- end
-
- class Memory < DigitalInformationUnit
- # Ruby 1.8 + ruby-prof wrapper
- if RubyProf.respond_to?(:measure_memory)
- def measure
- RubyProf.measure_memory
- end
- end
- end
-
- class Objects < Amount
- # Ruby 1.8 + ruby-prof wrapper
- if RubyProf.respond_to?(:measure_allocations)
- def measure
- RubyProf.measure_allocations
- end
- end
- end
-
- class GcRuns < Amount
- # Ruby 1.8 + ruby-prof wrapper
- if RubyProf.respond_to?(:measure_gc_runs)
- def measure
- RubyProf.measure_gc_runs
- end
- end
- end
-
- class GcTime < Time
- # Ruby 1.8 + ruby-prof wrapper
- if RubyProf.respond_to?(:measure_gc_time)
- def measure
- RubyProf.measure_gc_time / 1000.0 / 1000.0
- end
- end
- end
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/testing/performance/ruby/yarv.rb b/activesupport/lib/active_support/testing/performance/ruby/yarv.rb
index 7873262331..c34d31bf10 100644
--- a/activesupport/lib/active_support/testing/performance/ruby/yarv.rb
+++ b/activesupport/lib/active_support/testing/performance/ruby/yarv.rb
@@ -4,15 +4,12 @@ module ActiveSupport
module Metrics
class Base
protected
- # Ruby 1.9 with GC::Profiler
- if defined?(GC::Profiler)
- def with_gc_stats
- GC::Profiler.enable
- GC.start
- yield
- ensure
- GC::Profiler.disable
- end
+ def with_gc_stats
+ GC::Profiler.enable
+ GC.start
+ yield
+ ensure
+ GC::Profiler.disable
end
end
@@ -35,20 +32,14 @@ module ActiveSupport
end
class GcRuns < Amount
- # Ruby 1.9
- if GC.respond_to?(:count)
- def measure
- GC.count
- end
+ def measure
+ GC.count
end
end
class GcTime < Time
- # Ruby 1.9 with GC::Profiler
- if defined?(GC::Profiler) && GC::Profiler.respond_to?(:total_time)
- def measure
- GC::Profiler.total_time
- end
+ def measure
+ GC::Profiler.total_time
end
end
end
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index 22e41fa905..40b781485e 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -10,11 +10,7 @@ module ActiveSupport
include ActiveSupport::Callbacks
define_callbacks :setup, :teardown
- if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions
- include ForMiniTest
- else
- include ForClassicTestUnit
- end
+ include ForMiniTest
end
module ClassMethods
@@ -47,65 +43,6 @@ module ActiveSupport
end
end
- module ForClassicTestUnit
- # For compatibility with Ruby < 1.8.6
- PASSTHROUGH_EXCEPTIONS = Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS rescue [NoMemoryError, SignalException, Interrupt, SystemExit]
-
- # This redefinition is unfortunate but test/unit shows us no alternative.
- # Doubly unfortunate: hax to support Mocha's hax.
- def run(result)
- return if @method_name.to_s == "default_test"
-
- mocha_counter = retrieve_mocha_counter(result)
- yield(Test::Unit::TestCase::STARTED, name)
- @_result = result
-
- begin
- begin
- run_callbacks :setup do
- setup
- __send__(@method_name)
- mocha_verify(mocha_counter) if mocha_counter
- end
- rescue Mocha::ExpectationError => e
- add_failure(e.message, e.backtrace)
- rescue Test::Unit::AssertionFailedError => e
- add_failure(e.message, e.backtrace)
- rescue Exception => e
- raise if PASSTHROUGH_EXCEPTIONS.include?(e.class)
- add_error(e)
- ensure
- begin
- teardown
- run_callbacks :teardown
- rescue Test::Unit::AssertionFailedError => e
- add_failure(e.message, e.backtrace)
- rescue Exception => e
- raise if PASSTHROUGH_EXCEPTIONS.include?(e.class)
- add_error(e)
- end
- end
- ensure
- mocha_teardown if mocha_counter
- end
-
- result.add_run
- yield(Test::Unit::TestCase::FINISHED, name)
- end
-
- protected
-
- def retrieve_mocha_counter(result) #:nodoc:
- if respond_to?(:mocha_verify) # using mocha
- if defined?(Mocha::TestCaseAdapter::AssertionCounter)
- Mocha::TestCaseAdapter::AssertionCounter.new(result)
- else
- Mocha::Integration::TestUnit::AssertionCounter.new(result)
- end
- end
- end
- end
-
end
end
end
diff --git a/activesupport/lib/active_support/time.rb b/activesupport/lib/active_support/time.rb
index 86f057d676..9634b52ecf 100644
--- a/activesupport/lib/active_support/time.rb
+++ b/activesupport/lib/active_support/time.rb
@@ -13,7 +13,6 @@ end
require 'date'
require 'time'
-require 'active_support/core_ext/time/publicize_conversion_methods'
require 'active_support/core_ext/time/marshal'
require 'active_support/core_ext/time/acts_like'
require 'active_support/core_ext/time/calculations'
@@ -21,7 +20,6 @@ require 'active_support/core_ext/time/conversions'
require 'active_support/core_ext/time/zones'
require 'active_support/core_ext/date/acts_like'
-require 'active_support/core_ext/date/freeze'
require 'active_support/core_ext/date/calculations'
require 'active_support/core_ext/date/conversions'
require 'active_support/core_ext/date/zones'
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 63279d0e6d..d3adf671a0 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -203,7 +203,11 @@ module ActiveSupport
end
def eql?(other)
- utc == other
+ utc.eql?(other)
+ end
+
+ def hash
+ utc.hash
end
def +(other)
@@ -277,7 +281,6 @@ module ActiveSupport
def to_i
utc.to_i
end
- alias_method :hash, :to_i
alias_method :tv_sec, :to_i
# A TimeWithZone acts like a Time, so just return +self+.
diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb
index bd8e7f907a..8a8f8f946d 100644
--- a/activesupport/lib/active_support/version.rb
+++ b/activesupport/lib/active_support/version.rb
@@ -1,7 +1,7 @@
module ActiveSupport
module VERSION #:nodoc:
- MAJOR = 3
- MINOR = 2
+ MAJOR = 4
+ MINOR = 0
TINY = 0
PRE = "beta"
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb
deleted file mode 100644
index 577db5018e..0000000000
--- a/activesupport/lib/active_support/whiny_nil.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# Extensions to +nil+ which allow for more helpful error messages for people who
-# are new to Rails.
-#
-# Ruby raises NoMethodError if you invoke a method on an object that does not
-# respond to it:
-#
-# $ ruby -e nil.destroy
-# -e:1: undefined method `destroy' for nil:NilClass (NoMethodError)
-#
-# With these extensions, if the method belongs to the public interface of the
-# classes in NilClass::WHINERS the error message suggests which could be the
-# actual intended class:
-#
-# $ rails runner nil.destroy
-# ...
-# You might have expected an instance of ActiveRecord::Base.
-# ...
-#
-# NilClass#id exists in Ruby 1.8 (though it is deprecated). Since +id+ is a fundamental
-# method of Active Record models NilClass#id is redefined as well to raise a RuntimeError
-# and warn the user. She probably wanted a model database identifier and the 4
-# returned by the original method could result in obscure bugs.
-#
-# The flag <tt>config.whiny_nils</tt> determines whether this feature is enabled.
-# By default it is on in development and test modes, and it is off in production
-# mode.
-class NilClass
- METHOD_CLASS_MAP = Hash.new
-
- def self.add_whiner(klass)
- methods = klass.public_instance_methods - public_instance_methods
- class_name = klass.name
- methods.each { |method| METHOD_CLASS_MAP[method.to_sym] = class_name }
- end
-
- add_whiner ::Array
-
- # Raises a RuntimeError when you attempt to call +id+ on +nil+.
- def id
- raise RuntimeError, "Called id for nil, which would mistakenly be #{object_id} -- if you really wanted the id of nil, use object_id", caller
- end
-
- private
- def method_missing(method, *args)
- if klass = METHOD_CLASS_MAP[method]
- raise_nil_warning_for klass, method, caller
- else
- super
- end
- end
-
- # Raises a NoMethodError when you attempt to call a method on +nil+.
- def raise_nil_warning_for(class_name = nil, selector = nil, with_caller = nil)
- message = "You have a nil object when you didn't expect it!"
- message << "\nYou might have expected an instance of #{class_name}." if class_name
- message << "\nThe error occurred while evaluating nil.#{selector}" if selector
-
- raise NoMethodError, message, with_caller || caller
- end
-end