diff options
Diffstat (limited to 'activesupport/lib')
59 files changed, 476 insertions, 238 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 290920dbf8..9af3f8b447 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -59,6 +59,7 @@ module ActiveSupport autoload :StringInquirer autoload :TaggedLogging autoload :XmlMini + autoload :ArrayInquirer end autoload :Rescuable diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb new file mode 100644 index 0000000000..0ae534da00 --- /dev/null +++ b/activesupport/lib/active_support/array_inquirer.rb @@ -0,0 +1,38 @@ +module ActiveSupport + # Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check + # its string-like contents: + # + # variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet]) + # + # variants.phone? # => true + # variants.tablet? # => true + # variants.desktop? # => false + # + # variants.any?(:phone, :tablet) # => true + # variants.any?(:phone, :desktop) # => true + # variants.any?(:desktop, :watch) # => false + class ArrayInquirer < Array + def any?(*candidates, &block) + if candidates.none? + super + else + candidates.any? do |candidate| + include?(candidate) || include?(candidate.to_sym) + end + end + end + + private + def respond_to_missing?(name, include_private = false) + name[-1] == '?' + end + + def method_missing(name, *args) + if name[-1] == '?' + any?(name[0..-2]) + else + super + end + end + end +end diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 3a1e1ac3a1..837974bc85 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -325,19 +325,22 @@ module ActiveSupport def read_multi(*names) options = names.extract_options! options = merged_options(options) - results = {} - names.each do |name| - key = namespaced_key(name, options) - entry = read_entry(key, options) - if entry - if entry.expired? - delete_entry(key, options) - else - results[name] = entry.value + + instrument_multi(:read, names, options) do |payload| + results = {} + names.each do |name| + key = namespaced_key(name, options) + entry = read_entry(key, options) + if entry + if entry.expired? + delete_entry(key, options) + else + results[name] = entry.value + end end end + results end - results end # Fetches data from the cache, using the given keys. If there is data in @@ -350,8 +353,11 @@ module ActiveSupport # Returns a hash with the data for each of the names. For example: # # cache.write("bim", "bam") - # cache.fetch_multi("bim", "boom") { |key| key * 2 } - # # => { "bam" => "bam", "boom" => "boomboom" } + # cache.fetch_multi("bim", "unknown_key") do |key| + # "Fallback value for key: #{key}" + # end + # # => { "bim" => "bam", + # # "unknown_key" => "Fallback value for key: unknown_key" } # def fetch_multi(*names) options = names.extract_options! @@ -527,16 +533,27 @@ module ActiveSupport end def instrument(operation, key, options = nil) - log(operation, key, options) + log { "Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}" } payload = { :key => key } payload.merge!(options) if options.is_a?(Hash) ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) } end - def log(operation, key, options = nil) + def instrument_multi(operation, keys, options = nil) + log do + formatted_keys = keys.map { |k| "- #{k}" }.join("\n") + "Caches multi #{operation}:\n#{formatted_keys}#{options.blank? ? "" : " (#{options.inspect})"}" + end + + payload = { key: keys } + payload.merge!(options) if options.is_a?(Hash) + ActiveSupport::Notifications.instrument("cache_#{operation}_multi.active_support", payload) { yield(payload) } + end + + def log return unless logger && logger.debug? && !silence? - logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}") + logger.debug(yield) end def find_cached_entry(key, name, options) @@ -549,9 +566,9 @@ module ActiveSupport def handle_expired_entry(entry, key, options) if entry && entry.expired? race_ttl = options[:race_condition_ttl].to_i - if race_ttl && (Time.now.to_f - entry.expires_at <= race_ttl) - # When an entry has :race_condition_ttl defined, put the stale entry back into the cache - # for a brief period while the entry is begin recalculated. + if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl) + # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache + # for a brief period while the entry is being recalculated. entry.expires_at = Time.now + race_ttl write_entry(key, entry, :expires_in => race_ttl * 2) else diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 61b4f0b8b0..73ae3acea5 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -66,14 +66,17 @@ module ActiveSupport def read_multi(*names) options = names.extract_options! options = merged_options(options) - keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}] - raw_values = @data.get_multi(keys_to_names.keys, :raw => true) - values = {} - raw_values.each do |key, value| - entry = deserialize_entry(value) - values[keys_to_names[key]] = entry.value unless entry.expired? + + instrument_multi(:read, names, options) do + keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}] + raw_values = @data.get_multi(keys_to_names.keys, :raw => true) + values = {} + raw_values.each do |key, value| + entry = deserialize_entry(value) + values[keys_to_names[key]] = entry.value unless entry.expired? + end + values end - values end # Increment a cached value. This method uses the memcached incr atomic diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index 73c6b3cb88..a913736fc3 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -39,7 +39,7 @@ module ActiveSupport @data = {} end - # Don't allow synchronizing since it isn't thread safe, + # Don't allow synchronizing since it isn't thread safe. def synchronize # :nodoc: yield end diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0f1de8b076..9cf09ab266 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -5,6 +5,7 @@ require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/kernel/singleton_class' require 'active_support/core_ext/string/filters' +require 'active_support/deprecation' require 'thread' module ActiveSupport @@ -291,13 +292,11 @@ module ActiveSupport if !halted && user_conditions.all? { |c| c.call(target, value) } user_callback.call(target, value) { - env = run.call env - env.value + run.call.value } - env else - run.call env + run.call end end end @@ -309,11 +308,10 @@ module ActiveSupport value = env.value if env.halted - run.call env + run.call else user_callback.call(target, value) { - env = run.call env - env.value + run.call.value } env end @@ -328,12 +326,11 @@ module ActiveSupport if user_conditions.all? { |c| c.call(target, value) } user_callback.call(target, value) { - env = run.call env - env.value + run.call.value } env else - run.call env + run.call end end end @@ -342,8 +339,7 @@ module ActiveSupport def self.simple(callback_sequence, user_callback) callback_sequence.around do |env, &run| user_callback.call(env.target, env.value) { - env = run.call env - env.value + run.call.value } env end @@ -373,14 +369,14 @@ module ActiveSupport def filter; @key; end def raw_filter; @filter; end - def merge(chain, new_options) + def merge_conditional_options(chain, if_option:, unless_option:) options = { :if => @if.dup, :unless => @unless.dup } - options[:if].concat Array(new_options.fetch(:unless, [])) - options[:unless].concat Array(new_options.fetch(:if, [])) + options[:if].concat Array(unless_option) + options[:unless].concat Array(if_option) self.class.build chain, @filter, @kind, options end @@ -495,17 +491,17 @@ module ActiveSupport end def around(&around) - CallbackSequence.new do |*args| - around.call(*args) { - self.call(*args) + CallbackSequence.new do |arg| + around.call(arg) { + self.call(arg) } end end - def call(*args) - @before.each { |b| b.call(*args) } - value = @call.call(*args) - @after.each { |a| a.call(*args) } + def call(arg) + @before.each { |b| b.call(arg) } + value = @call.call(arg) + @after.each { |a| a.call(arg) } value end end @@ -667,10 +663,12 @@ module ActiveSupport # # ===== Options # - # * <tt>:if</tt> - A symbol naming an instance method or a proc; the - # callback will be called only when it returns a +true+ value. - # * <tt>:unless</tt> - A symbol naming an instance method or a proc; the - # callback will be called only when it returns a +false+ value. + # * <tt>:if</tt> - A symbol, a string or an array of symbols and strings, + # each naming an instance method or a proc; the callback will be called + # only when they all return a true value. + # * <tt>:unless</tt> - A symbol, a string or an array of symbols and + # strings, each naming an instance method or a proc; the callback will + # be called only when they all return a false value. # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the # existing chain rather than appended. def set_callback(name, *filter_list, &block) @@ -701,7 +699,7 @@ module ActiveSupport filter = chain.find {|c| c.matches?(type, filter) } if filter && options.any? - new_filter = filter.merge(chain, options) + new_filter = filter.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless]) chain.insert(chain.index(filter), new_filter) end @@ -746,8 +744,8 @@ module ActiveSupport # # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after # callbacks should be terminated by the <tt>:terminator</tt> option. By - # default after callbacks executed no matter if callback chain was - # terminated or not. Option makes sense only when <tt>:terminator</tt> + # default after callbacks are executed no matter if callback chain was + # terminated or not. This option makes sense only when <tt>:terminator</tt> # option is specified. # # * <tt>:scope</tt> - Indicates which methods should be executed when an diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb index 342d3a9d52..4082d2d464 100644 --- a/activesupport/lib/active_support/concern.rb +++ b/activesupport/lib/active_support/concern.rb @@ -114,7 +114,7 @@ module ActiveSupport return false else return false if base < self - @_dependencies.each { |dep| base.send(:include, dep) } + @_dependencies.each { |dep| base.include(dep) } super base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods) base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block) diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb index 3dd44e32d8..8256c325af 100644 --- a/activesupport/lib/active_support/configurable.rb +++ b/activesupport/lib/active_support/configurable.rb @@ -122,6 +122,7 @@ module ActiveSupport send("#{name}=", yield) if block_given? end end + private :config_accessor end # Reads and writes attributes from a configuration <tt>OrderedHash</tt>. diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index 7d0c1e4c8d..7551551bd7 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -4,3 +4,4 @@ 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/prepend_and_append' +require 'active_support/core_ext/array/inquiry' diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index ca66d806ef..3177d8498e 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -27,6 +27,18 @@ class Array end end + # Returns a copy of the Array without the specified elements. + # + # people = ["David", "Rafael", "Aaron", "Todd"] + # people.without "Aaron", "Todd" + # => ["David", "Rafael"] + # + # Note: This is an optimization of `Enumerable#without` that uses `Array#-` + # instead of `Array#reject` for performance reasons. + def without(*elements) + self - elements + end + # Equal to <tt>self[1]</tt>. # # %w( a b c d e ).second # => "b" diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 080e3b5ef7..d80df21e7d 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -74,7 +74,7 @@ class Array when 0 '' when 1 - self[0].to_s.dup + "#{self[0]}" when 2 "#{self[0]}#{options[:two_words_connector]}#{self[1]}" else diff --git a/activesupport/lib/active_support/core_ext/array/inquiry.rb b/activesupport/lib/active_support/core_ext/array/inquiry.rb new file mode 100644 index 0000000000..de623c466c --- /dev/null +++ b/activesupport/lib/active_support/core_ext/array/inquiry.rb @@ -0,0 +1,15 @@ +class Array + # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way + # to check its string-like contents. + # + # pets = [:cat, :dog].inquiry + # + # pets.cat? # => true + # pets.ferret? # => false + # + # pets.any?(:cat, :ferret) # => true + # pets.any?(:ferret, :alligator) # => false + def inquiry + ActiveSupport::ArrayInquirer.new(self) + end +end diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 1343beb87a..7a893292b3 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -60,6 +60,17 @@ module Enumerable def exclude?(object) !include?(object) end + + # Returns a copy of the enumerable without the specified elements. + # + # ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd" + # => ["David", "Rafael"] + # + # {foo: 1, bar: 2, baz: 3}.without :bar + # => {foo: 1, baz: 3} + def without(*elements) + reject { |element| elements.include?(element) } + end end class Range #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb index 38374af388..fad6fa8d9d 100644 --- a/activesupport/lib/active_support/core_ext/file/atomic.rb +++ b/activesupport/lib/active_support/core_ext/file/atomic.rb @@ -20,7 +20,7 @@ class File temp_file = Tempfile.new(basename(file_name), temp_dir) temp_file.binmode - yield temp_file + return_val = yield temp_file temp_file.close if File.exist?(file_name) @@ -40,6 +40,9 @@ class File chown(old_stat.uid, old_stat.gid, file_name) # This operation will affect filesystem ACL's chmod(old_stat.mode, file_name) + + # Make sure we return the result of the yielded block + return_val rescue Errno::EPERM, Errno::EACCES # Changing file ownership failed, moving on. end diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 9297a59c46..c30044b9ff 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -14,7 +14,7 @@ class Hash result end - # Destructively convert all keys using the block operations. + # Destructively converts all keys using the block operations. # Same as transform_keys but modifies +self+. def transform_keys! return enum_for(:transform_keys!) unless block_given? @@ -34,7 +34,7 @@ class Hash transform_keys(&:to_s) end - # Destructively convert all keys to strings. Same as + # Destructively converts all keys to strings. Same as # +stringify_keys+, but modifies +self+. def stringify_keys! transform_keys!(&:to_s) @@ -52,14 +52,14 @@ class Hash end alias_method :to_options, :symbolize_keys - # Destructively convert all keys to symbols, as long as they respond + # Destructively converts all keys to symbols, as long as they respond # to +to_sym+. Same as +symbolize_keys+, but modifies +self+. def symbolize_keys! transform_keys!{ |key| key.to_sym rescue key } end alias_method :to_options!, :symbolize_keys! - # Validate all keys in a hash match <tt>*valid_keys</tt>, raising + # Validates all keys in a hash match <tt>*valid_keys</tt>, raising # ArgumentError on a mismatch. # # Note that keys are treated differently than HashWithIndifferentAccess, @@ -89,7 +89,7 @@ class Hash _deep_transform_keys_in_object(self, &block) end - # Destructively convert all keys by using the block operation. + # Destructively converts all keys by using the block operation. # This includes the keys from the root hash and from all # nested hashes and arrays. def deep_transform_keys!(&block) @@ -108,7 +108,7 @@ class Hash deep_transform_keys(&:to_s) end - # Destructively convert all keys to strings. + # Destructively converts all keys to strings. # This includes the keys from the root hash and from all # nested hashes and arrays. def deep_stringify_keys! @@ -127,7 +127,7 @@ class Hash deep_transform_keys{ |key| key.to_sym rescue key } end - # Destructively convert all keys to symbols, as long as they respond + # Destructively converts all keys to symbols, as long as they respond # to +to_sym+. This includes the keys from the root hash and from all # nested hashes and arrays. def deep_symbolize_keys! diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 41b2279013..1d5f38231a 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -1,5 +1,5 @@ class Hash - # Slice a hash to include only the given keys. Returns a hash containing + # Slices a hash to include only the given keys. Returns a hash containing # the given keys. # # { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b) diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb index 82080ffe51..f0b7382ef3 100644 --- a/activesupport/lib/active_support/core_ext/integer/time.rb +++ b/activesupport/lib/active_support/core_ext/integer/time.rb @@ -17,21 +17,6 @@ class Integer # # # equivalent to Time.now.advance(months: 4, years: 5) # (4.months + 5.years).from_now - # - # While these methods provide precise calculation when used as in the examples - # above, care should be taken to note that this is not true if the result of - # +months+, +years+, etc is converted before use: - # - # # equivalent to 30.days.to_i.from_now - # 1.month.to_i.from_now - # - # # equivalent to 365.25.days.to_f.from_now - # 1.year.to_f.from_now - # - # In such cases, Ruby's core - # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and - # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision - # date and time arithmetic. def months ActiveSupport::Duration.new(self * 30.days, [[:months, self]]) end diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb index 56c79c04bd..20a0856e71 100644 --- a/activesupport/lib/active_support/core_ext/marshal.rb +++ b/activesupport/lib/active_support/core_ext/marshal.rb @@ -1,9 +1,7 @@ -require 'active_support/core_ext/module/aliasing' - -module Marshal - class << self - def load_with_autoloading(source) - load_without_autoloading(source) +module ActiveSupport + module MarshalWithAutoloading # :nodoc: + def load(source) + super(source) rescue ArgumentError, NameError => exc if exc.message.match(%r|undefined class/module (.+)|) # try loading the class/module @@ -15,7 +13,7 @@ module Marshal raise exc end end - - alias_method_chain :load, :autoloading end end + +Marshal.singleton_class.prepend(ActiveSupport::MarshalWithAutoloading) diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index 0a6fadf928..a4c40b25ff 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -21,6 +21,8 @@ class Module # # so you can safely chain foo, foo?, foo! and/or foo= with the same feature. def alias_method_chain(target, feature) + ActiveSupport::Deprecation.warn("alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super.") + # Strip out punctuation on predicates, bang or writer methods since # e.g. target?_without_feature is not a valid method name. aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 @@ -43,7 +45,7 @@ class Module end # Allows you to make aliases for attributes, which includes - # getter, setter, and query methods. + # getter, setter, and a predicate. # # class Content < ActiveRecord::Base # # has a title attribute diff --git a/activesupport/lib/active_support/core_ext/module/anonymous.rb b/activesupport/lib/active_support/core_ext/module/anonymous.rb index b0c7b021db..0ecc67a855 100644 --- a/activesupport/lib/active_support/core_ext/module/anonymous.rb +++ b/activesupport/lib/active_support/core_ext/module/anonymous.rb @@ -7,6 +7,13 @@ class Module # m = Module.new # m.name # => nil # + # +anonymous?+ method returns true if module does not have a name: + # + # Module.new.anonymous? # => true + # + # module M; end + # M.anonymous? # => false + # # 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: # diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 24df83800b..9b7a429db9 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -167,7 +167,7 @@ class Module '' end - file, line = caller.first.split(':', 2) + file, line = caller(1, 1).first.split(':', 2) line = line.to_i to = to.to_s @@ -185,19 +185,31 @@ class Module # On the other hand it could be that the target has side-effects, # whereas conceptually, from the user point of view, the delegator should # be doing one call. - - exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") - - method_def = [ - "def #{method_prefix}#{method}(#{definition})", - " _ = #{to}", - " if !_.nil? || nil.respond_to?(:#{method})", - " _.#{method}(#{definition})", - " else", - " #{exception unless allow_nil}", - " end", + if allow_nil + method_def = [ + "def #{method_prefix}#{method}(#{definition})", + "_ = #{to}", + "if !_.nil? || nil.respond_to?(:#{method})", + " _.#{method}(#{definition})", + "end", "end" - ].join ';' + ].join ';' + else + exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") + + method_def = [ + "def #{method_prefix}#{method}(#{definition})", + " _ = #{to}", + " _.#{method}(#{definition})", + "rescue NoMethodError => e", + " if _.nil? && e.name == :#{method}", + " #{exception}", + " else", + " raise", + " end", + "end" + ].join ';' + end module_eval(method_def, file, line) end diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb index 8a2569a7d0..52632d2c6b 100644 --- a/activesupport/lib/active_support/core_ext/module/remove_method.rb +++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb @@ -1,13 +1,13 @@ class Module - # Remove the named method, if it exists. + # Removes the named method, if it exists. def remove_possible_method(method) if method_defined?(method) || private_method_defined?(method) undef_method(method) end end - # Replace the existing method definition, if there is one, with the contents - # of the block. + # Replaces the existing method definition, if there is one, with the passed + # block as its body. def redefine_method(method, &block) remove_possible_method(method) define_method(method, &block) diff --git a/activesupport/lib/active_support/core_ext/name_error.rb b/activesupport/lib/active_support/core_ext/name_error.rb index b82148e4e5..6b447d772b 100644 --- a/activesupport/lib/active_support/core_ext/name_error.rb +++ b/activesupport/lib/active_support/core_ext/name_error.rb @@ -23,8 +23,7 @@ class NameError # # => true def missing_name?(name) if name.is_a? Symbol - last_name = (missing_name || '').split('::').last - last_name == name.to_s + self.name == name else missing_name == name.to_s end diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index 98716383f4..6c4a975495 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -18,21 +18,6 @@ class Numeric # # # equivalent to Time.current.advance(months: 4, years: 5) # (4.months + 5.years).from_now - # - # While these methods provide precise calculation when used as in the examples above, care - # should be taken to note that this is not true if the result of `months', `years', etc is - # converted before use: - # - # # equivalent to 30.days.to_i.from_now - # 1.month.to_i.from_now - # - # # equivalent to 365.25.days.to_f.from_now - # 1.year.to_f.from_now - # - # In such cases, Ruby's core - # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and - # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision - # date and time arithmetic. def seconds ActiveSupport::Duration.new(self, [[:seconds, self]]) end diff --git a/activesupport/lib/active_support/core_ext/object/json.rb b/activesupport/lib/active_support/core_ext/object/json.rb index 698b2d1920..0db787010c 100644 --- a/activesupport/lib/active_support/core_ext/object/json.rb +++ b/activesupport/lib/active_support/core_ext/object/json.rb @@ -9,7 +9,6 @@ require 'time' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/date_time/conversions' require 'active_support/core_ext/date/conversions' -require 'active_support/core_ext/module/aliasing' # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting # their default behavior. That said, we need to define the basic to_json method in all of them, @@ -26,22 +25,25 @@ require 'active_support/core_ext/module/aliasing' # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump} # should give exactly the same results with or without active support. -[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].each do |klass| - klass.class_eval do - def to_json_with_active_support_encoder(options = nil) + +module ActiveSupport + module ToJsonWithActiveSupportEncoder # :nodoc: + def to_json(options = nil) if options.is_a?(::JSON::State) # Called from JSON.{generate,dump}, forward it to JSON gem's to_json - self.to_json_without_active_support_encoder(options) + super(options) else # to_json is being invoked directly, use ActiveSupport's encoder ActiveSupport::JSON.encode(self, options) end end - - alias_method_chain :to_json, :active_support_encoder end end +[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass| + klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder) +end + class Object def as_json(options = nil) #:nodoc: if respond_to?(:to_hash) diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb index b1a12781f3..83eced50bf 100644 --- a/activesupport/lib/active_support/core_ext/range/conversions.rb +++ b/activesupport/lib/active_support/core_ext/range/conversions.rb @@ -3,9 +3,24 @@ class Range :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } } - # Gives a human readable format of the range. + # Convert range to a formatted string. See RANGE_FORMATS for predefined formats. # - # (1..100).to_formatted_s # => "1..100" + # This method is aliased to <tt>to_s</tt>. + # + # range = (1..100) # => 1..100 + # + # range.to_formatted_s # => "1..100" + # range.to_s # => "1..100" + # + # range.to_formatted_s(:db) # => "BETWEEN '1' AND '100'" + # range.to_s(:db) # => "BETWEEN '1' AND '100'" + # + # == Adding your own range formats to to_formatted_s + # You can add your own formats to the Range::RANGE_FORMATS hash. + # Use the format name as the hash key and a Proc instance. + # + # # config/initializers/range_formats.rb + # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" } def to_formatted_s(format = :default) if formatter = RANGE_FORMATS[format] formatter.call(first, last) diff --git a/activesupport/lib/active_support/core_ext/range/each.rb b/activesupport/lib/active_support/core_ext/range/each.rb index ecef78f55f..f666480fe6 100644 --- a/activesupport/lib/active_support/core_ext/range/each.rb +++ b/activesupport/lib/active_support/core_ext/range/each.rb @@ -1,18 +1,22 @@ -require 'active_support/core_ext/module/aliasing' - class Range #:nodoc: def each_with_time_with_zone(&block) ensure_iteration_allowed each_without_time_with_zone(&block) end - alias_method_chain :each, :time_with_zone + # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2: + # https://bugs.ruby-lang.org/issues/10847 + alias_method :each_without_time_with_zone, :each + alias_method :each, :each_with_time_with_zone def step_with_time_with_zone(n = 1, &block) ensure_iteration_allowed step_without_time_with_zone(n, &block) end - alias_method_chain :step, :time_with_zone + # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2: + # https://bugs.ruby-lang.org/issues/10847 + alias_method :step_without_time_with_zone, :step + alias_method :step, :step_with_time_with_zone private def ensure_iteration_allowed 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 3a07401c8a..9d20920dd0 100644 --- a/activesupport/lib/active_support/core_ext/range/include_range.rb +++ b/activesupport/lib/active_support/core_ext/range/include_range.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/module/aliasing' - class Range # Extends the default Range#include? to support range comparisons. # (1..5).include?(1..5) # => true @@ -18,6 +16,8 @@ class Range include_without_range?(value) end end - - alias_method_chain :include?, :range + # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2: + # https://bugs.ruby-lang.org/issues/10847 + alias_method :include_without_range?, :include? + alias_method :include?, :include_with_range? end diff --git a/activesupport/lib/active_support/core_ext/string/behavior.rb b/activesupport/lib/active_support/core_ext/string/behavior.rb index 4aa960039b..710f1f4670 100644 --- a/activesupport/lib/active_support/core_ext/string/behavior.rb +++ b/activesupport/lib/active_support/core_ext/string/behavior.rb @@ -1,5 +1,5 @@ class String - # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>. + # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>. def acts_like_string? true end diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb index 096292dc58..7461d03acc 100644 --- a/activesupport/lib/active_support/core_ext/string/filters.rb +++ b/activesupport/lib/active_support/core_ext/string/filters.rb @@ -26,6 +26,7 @@ class String # Returns a new string with all occurrences of the patterns removed. # str = "foo bar test" # str.remove(" test") # => "foo bar" + # str.remove(" test", /bar/) # => "foo " # str # => "foo bar test" def remove(*patterns) dup.remove!(*patterns) @@ -33,8 +34,8 @@ class String # Alters the string by removing all occurrences of the patterns. # str = "foo bar test" - # str.remove!(" test") # => "foo bar" - # str # => "foo bar" + # str.remove!(" test", /bar/) # => "foo " + # str # => "foo " def remove!(*patterns) patterns.each do |pattern| gsub! pattern, "" @@ -93,7 +94,7 @@ class String def truncate_words(words_count, options = {}) sep = options[:separator] || /\s+/ sep = Regexp.escape(sep.to_s) unless Regexp === sep - if self =~ /\A((?:.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m + if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m $1 + (options[:omission] || '...') else dup diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 38d567c014..97f9720b2b 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -178,7 +178,7 @@ class String ActiveSupport::Inflector.tableize(self) end - # Create a class name from a plural table name like Rails does for table names to models. + # Creates a class name from a plural table name like Rails does for table names to models. # Note that this returns a string and not a class. (To convert to an actual class # follow +classify+ with +constantize+.) # diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb index a124202936..7055f7f699 100644 --- a/activesupport/lib/active_support/core_ext/string/multibyte.rb +++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb @@ -1,4 +1,3 @@ -# encoding: utf-8 require 'active_support/multibyte' class String @@ -36,6 +35,13 @@ class String ActiveSupport::Multibyte.proxy_class.new(self) end + # Returns +true+ if string has utf_8 encoding. + # + # utf_8_str = "some string".encode "UTF-8" + # iso_str = "some string".encode "ISO-8859-1" + # + # utf_8_str.is_utf8? # => true + # iso_str.is_utf8? # => false def is_utf8? case encoding when Encoding::UTF_8 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 ba8d4acd6d..c676b26b06 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -13,7 +13,7 @@ class ERB # This method is also aliased as <tt>h</tt>. # # In your ERB templates, use this method to escape any unsafe content. For example: - # <%=h @person.name %> + # <%= h @person.name %> # # puts html_escape('is a > 0 & a < 10?') # # => is a > 0 & a < 10? @@ -85,6 +85,11 @@ class ERB # automatically flag the result as HTML safe, since the raw value is unsafe to # use inside HTML attributes. # + # If your JSON is being used downstream for insertion into the DOM, be aware of + # whether or not it is being inserted via +html()+. Most JQuery plugins do this. + # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated + # content returned by your JSON. + # # If you need to output JSON elsewhere in your HTML, you can just do something # like this, as any unsafe characters (including quotation marks) will be # automatically escaped for you: @@ -217,7 +222,7 @@ module ActiveSupport #:nodoc: end def encode_with(coder) - coder.represent_scalar nil, to_str + coder.represent_object nil, to_str end UNSAFE_STRING_METHODS.each do |unsafe_method| diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 649dc52865..1ce68ea7c7 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -48,7 +48,11 @@ class Time alias_method :at, :at_with_coercion end - # Seconds since midnight: Time.now.seconds_since_midnight + # Returns the number of seconds since 00:00:00. + # + # Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0 + # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296 + # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399 def seconds_since_midnight to_i - change(:hour => 0).to_i + (usec / 1.0e+6) end @@ -69,7 +73,7 @@ class Time # and minute is passed, then sec, usec and nsec is set to 0. The +options+ # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt> - # <tt>:nsec</tt>. Path either <tt>:usec</tt> or <tt>:nsec</tt>, not both. + # <tt>:nsec</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both. # # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0) # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0) @@ -242,8 +246,10 @@ class Time # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances # can be chronologically compared with a Time def compare_with_coercion(other) - # we're avoiding Time#to_datetime cause it's expensive - if other.is_a?(Time) + # we're avoiding Time#to_datetime and Time#to_time because they're expensive + if other.class == Time + compare_without_coercion(other) + elsif other.is_a?(Time) compare_without_coercion(other.to_time) else to_datetime <=> other diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 0668eadb1e..d683e7c777 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -26,7 +26,7 @@ class Time # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone: # # class ApplicationController < ActionController::Base - # around_filter :set_time_zone + # around_action :set_time_zone # # def set_time_zone # if logged_in? diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index e03e7c30d8..664cc15a29 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -373,7 +373,7 @@ module ActiveSupport #:nodoc: # Is the provided constant path defined? def qualified_const_defined?(path) - Object.qualified_const_defined?(path.sub(/^::/, ''), false) + Object.const_defined?(path, false) end # Given +path+, a filesystem path to a ruby file, return an array of @@ -607,7 +607,7 @@ module ActiveSupport #:nodoc: def autoloaded?(desc) return false if desc.is_a?(Module) && desc.anonymous? name = to_constant_name desc - return false unless qualified_const_defined? name + return false unless qualified_const_defined?(name) return autoloaded_constants.include?(name) end diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb index cab8a1b14d..c74e9c40ac 100644 --- a/activesupport/lib/active_support/deprecation/method_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb @@ -31,12 +31,14 @@ module ActiveSupport method_names += options.keys method_names.each do |method_name| - target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation| - target_module.send(:define_method, "#{target}_with_deprecation#{punctuation}") do |*args, &block| + mod = Module.new do + define_method(method_name) do |*args, &block| deprecator.deprecation_warning(method_name, options[method_name]) - send(:"#{target}_without_deprecation#{punctuation}", *args, &block) + super(*args, &block) end end + + target_module.prepend(mod) end end end diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index 5a64fc52cc..4c0d1197fe 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -56,6 +56,30 @@ module ActiveSupport @value.to_s end + # Returns the number of seconds that this Duration represents. + # + # 1.minute.to_i # => 60 + # 1.hour.to_i # => 3600 + # 1.day.to_i # => 86400 + # + # Note that this conversion makes some assumptions about the + # duration of some periods, e.g. months are always 30 days + # and years are 365.25 days: + # + # # equivalent to 30.days.to_i + # 1.month.to_i # => 2592000 + # + # # equivalent to 365.25.days.to_i + # 1.year.to_i # => 31557600 + # + # In such cases, Ruby's core + # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and + # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision + # date and time arithmetic. + def to_i + @value.to_i + end + # Returns +true+ if +other+ is also a Duration instance, which has the # same parts as this one. def eql?(other) diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb index 9e742b1917..95f3f6255a 100644 --- a/activesupport/lib/active_support/i18n_railtie.rb +++ b/activesupport/lib/active_support/i18n_railtie.rb @@ -68,7 +68,7 @@ module I18n end def self.include_fallbacks_module - I18n.backend.class.send(:include, I18n::Backend::Fallbacks) + I18n.backend.class.include(I18n::Backend::Fallbacks) end def self.init_fallbacks(fallbacks) diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index fe8a2ac9ba..a08c655d69 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -73,7 +73,7 @@ module ActiveSupport string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase } end string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" } - string.gsub!(/\//, '::') + string.gsub!('/'.freeze, '::'.freeze) string end @@ -90,7 +90,7 @@ module ActiveSupport # camelize(underscore('SSLError')) # => "SslError" def underscore(camel_cased_word) return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/ - word = camel_cased_word.to_s.gsub(/::/, '/') + word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze) word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'}#{$2.downcase}" } word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2') word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 34439ee8be..258d9b34e1 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -94,9 +94,9 @@ module ActiveSupport # * <tt>:locale</tt> - Sets the locale to be used for formatting # (defaults to current locale). # * <tt>:precision</tt> - Sets the precision of the number - # (defaults to 3). - # * <tt>:significant</tt> - If +true+, precision will be the # - # of significant_digits. If +false+, the # of fractional + # (defaults to 3). Keeps the number's precision if nil. + # * <tt>:significant</tt> - If +true+, precision will be the number + # of significant_digits. If +false+, the number of fractional # digits (defaults to +false+). # * <tt>:separator</tt> - Sets the separator between the # fractional and integer digits (defaults to "."). @@ -116,6 +116,7 @@ module ActiveSupport # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000% # number_to_percentage(302.24398923423, precision: 5) # => 302.24399% # number_to_percentage(1000, locale: :fr) # => 1 000,000% + # number_to_percentage:(1000, precision: nil) # => 1000% # number_to_percentage('98a') # => 98a% # number_to_percentage(100, format: '%n %') # => 100 % def number_to_percentage(number, options = {}) @@ -161,9 +162,9 @@ module ActiveSupport # * <tt>:locale</tt> - Sets the locale to be used for formatting # (defaults to current locale). # * <tt>:precision</tt> - Sets the precision of the number - # (defaults to 3). - # * <tt>:significant</tt> - If +true+, precision will be the # - # of significant_digits. If +false+, the # of fractional + # (defaults to 3). Keeps the number's precision if nil. + # * <tt>:significant</tt> - If +true+, precision will be the number + # of significant_digits. If +false+, the number of fractional # digits (defaults to +false+). # * <tt>:separator</tt> - Sets the separator between the # fractional and integer digits (defaults to "."). @@ -182,6 +183,7 @@ module ActiveSupport # number_to_rounded(111.2345, significant: true) # => 111 # number_to_rounded(111.2345, precision: 1, significant: true) # => 100 # number_to_rounded(13, precision: 5, significant: true) # => 13.000 + # number_to_rounded(13, precision: nil) # => 13 # number_to_rounded(111.234, locale: :fr) # => 111,234 # # number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true) @@ -208,8 +210,8 @@ module ActiveSupport # (defaults to current locale). # * <tt>:precision</tt> - Sets the precision of the number # (defaults to 3). - # * <tt>:significant</tt> - If +true+, precision will be the # - # of significant_digits. If +false+, the # of fractional + # * <tt>:significant</tt> - If +true+, precision will be the number + # of significant_digits. If +false+, the number of fractional # digits (defaults to +true+) # * <tt>:separator</tt> - Sets the separator between the # fractional and integer digits (defaults to "."). @@ -258,8 +260,8 @@ module ActiveSupport # (defaults to current locale). # * <tt>:precision</tt> - Sets the precision of the number # (defaults to 3). - # * <tt>:significant</tt> - If +true+, precision will be the # - # of significant_digits. If +false+, the # of fractional + # * <tt>:significant</tt> - If +true+, precision will be the number + # of significant_digits. If +false+, the number of fractional # digits (defaults to +true+) # * <tt>:separator</tt> - Sets the separator between the # fractional and integer digits (defaults to "."). diff --git a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb index fb5adb574a..cd5a2b3cbb 100644 --- a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb @@ -13,7 +13,7 @@ module ActiveSupport end rounded_number = NumberToRoundedConverter.convert(number, options) - format.gsub(/%n/, rounded_number).gsub(/%u/, options[:unit]) + format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, options[:unit]) end private @@ -29,14 +29,14 @@ module ActiveSupport def options @options ||= begin defaults = default_format_options.merge(i18n_opts) - # Override negative format if format options is given + # Override negative format if format options are given defaults[:negative_format] = "-#{opts[:format]}" if opts[:format] defaults.merge!(opts) end end def i18n_opts - # Set International negative format if not exists + # Set International negative format if it does not exist i18n = i18n_format_options i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format] i18n diff --git a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb index 6940beb318..5c6fe2df83 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb @@ -23,7 +23,7 @@ module ActiveSupport unit = determine_unit(units, exponent) rounded_number = NumberToRoundedConverter.convert(number, options) - format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip + format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, unit).strip end private diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb index 78d2c9ae6e..ac0d20b454 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb @@ -20,7 +20,7 @@ module ActiveSupport human_size = number / (base ** exponent) number_to_format = NumberToRoundedConverter.convert(human_size, options) end - conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit) + conversion_format.gsub('%n'.freeze, number_to_format).gsub('%u'.freeze, unit) end private diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb index 1af294a03e..4c04d40c19 100644 --- a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb @@ -5,7 +5,7 @@ module ActiveSupport def convert rounded_number = NumberToRoundedConverter.convert(number, options) - options[:format].gsub(/%n/, rounded_number) + options[:format].gsub('%n'.freeze, rounded_number) end end end diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb index dcf9a567e8..981c562551 100644 --- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb @@ -6,36 +6,39 @@ module ActiveSupport def convert precision = options.delete :precision - significant = options.delete :significant - case number - when Float, String - @number = BigDecimal(number.to_s) - when Rational - @number = BigDecimal(number, digit_count(number.to_i) + precision) - else - @number = number.to_d - end - - if significant && precision > 0 - digits, rounded_number = digits_and_rounded_number(precision) - precision -= digits - precision = 0 if precision < 0 # don't let it be negative - else - rounded_number = number.round(precision) - rounded_number = rounded_number.to_i if precision == 0 - rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros - end + if precision + case number + when Float, String + @number = BigDecimal(number.to_s) + when Rational + @number = BigDecimal(number, digit_count(number.to_i) + precision) + else + @number = number.to_d + end - formatted_string = - if BigDecimal === rounded_number && rounded_number.finite? - s = rounded_number.to_s('F') + '0'*precision - a, b = s.split('.', 2) - a + '.' + b[0, precision] + if options.delete(:significant) && precision > 0 + digits, rounded_number = digits_and_rounded_number(precision) + precision -= digits + precision = 0 if precision < 0 # don't let it be negative else - "%00.#{precision}f" % rounded_number + rounded_number = number.round(precision) + rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite? + rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros end + formatted_string = + if BigDecimal === rounded_number && rounded_number.finite? + s = rounded_number.to_s('F') + '0'*precision + a, b = s.split('.', 2) + a + '.' + b[0, precision] + else + "%00.#{precision}f" % rounded_number + end + else + formatted_string = number + end + delimited_number = NumberToDelimitedConverter.convert(formatted_string, options) format_number(delimited_number) end diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 6eba24b569..ef22433491 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -23,6 +23,11 @@ module ActiveSupport # Sets the default value for Time.zone # If assigned value cannot be matched to a TimeZone, an exception will be raised. initializer "active_support.initialize_time_zone" do |app| + begin + TZInfo::DataSource.get + rescue TZInfo::DataSourceNotFound => e + raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install" + end require 'active_support/core_ext/time/zones' zone_default = Time.find_zone!(app.config.time_zone) diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 1a02acd5b1..67aac32742 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -100,7 +100,7 @@ module ActiveSupport # a string, otherwise a NameError will be raised by the interpreter # itself when rescue_from CONSTANT is executed. klass = self.class.const_get(klass_name) rescue nil - klass ||= klass_name.constantize rescue nil + klass ||= (klass_name.constantize rescue nil) klass === exception if klass end diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb index 45271c9163..bc673150d0 100644 --- a/activesupport/lib/active_support/string_inquirer.rb +++ b/activesupport/lib/active_support/string_inquirer.rb @@ -1,7 +1,7 @@ module ActiveSupport # Wrapping a string in this class gives you a prettier way to test # for equality. The value returned by <tt>Rails.env</tt> is wrapped - # in a StringInquirer object so instead of calling this: + # in a StringInquirer object, so instead of calling this: # # Rails.env == 'production' # diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb index 98be78b41b..8db423f0e9 100644 --- a/activesupport/lib/active_support/subscriber.rb +++ b/activesupport/lib/active_support/subscriber.rb @@ -10,19 +10,14 @@ module ActiveSupport # # module ActiveRecord # class StatsSubscriber < ActiveSupport::Subscriber + # attach_to :active_record + # # def sql(event) # Statsd.timing("sql.#{event.payload[:name]}", event.duration) # end # end # end # - # And it's finally registered as: - # - # ActiveRecord::StatsSubscriber.attach_to :active_record - # - # Since we need to know all instance methods before attaching the log - # subscriber, the line above should be called after your subscriber definition. - # # After configured, whenever a "sql.active_record" notification is published, # it will properly dispatch the event (ActiveSupport::Notifications::Event) to # the +sql+ method. @@ -96,7 +91,7 @@ module ActiveSupport event.end = finished event.payload.merge!(payload) - method = name.split('.').first + method = name.split('.'.freeze).first send(method, event) end diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb index 9086a959aa..bcd7bf74c0 100644 --- a/activesupport/lib/active_support/tagged_logging.rb +++ b/activesupport/lib/active_support/tagged_logging.rb @@ -43,7 +43,7 @@ module ActiveSupport end def current_tags - # We use our object ID here to void conflicting with other instances + # We use our object ID here to avoid conflicting with other instances thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}".freeze Thread.current[thread_key] ||= [] end diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index c7d6c62129..24b8f4b9f9 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -8,6 +8,7 @@ require 'active_support/testing/declarative' require 'active_support/testing/isolation' require 'active_support/testing/constant_lookup' require 'active_support/testing/time_helpers' +require 'active_support/testing/file_fixtures' require 'active_support/core_ext/kernel/reporting' module ActiveSupport @@ -44,8 +45,6 @@ module ActiveSupport test_order end - - alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent! end alias_method :method_name, :name @@ -55,6 +54,7 @@ module ActiveSupport include ActiveSupport::Testing::Assertions include ActiveSupport::Testing::Deprecation include ActiveSupport::Testing::TimeHelpers + include ActiveSupport::Testing::FileFixtures extend ActiveSupport::Testing::Declarative # test/unit backwards compatibility methods @@ -73,7 +73,7 @@ module ActiveSupport alias :assert_not_respond_to :refute_respond_to alias :assert_not_same :refute_same - # Fails if the block raises an exception. + # Reveals the intention that the block should not raise any exception. # # assert_nothing_raised do # ... diff --git a/activesupport/lib/active_support/testing/file_fixtures.rb b/activesupport/lib/active_support/testing/file_fixtures.rb new file mode 100644 index 0000000000..4c6a0801b8 --- /dev/null +++ b/activesupport/lib/active_support/testing/file_fixtures.rb @@ -0,0 +1,34 @@ +module ActiveSupport + module Testing + # Adds simple access to sample files called file fixtures. + # File fixtures are normal files stored in + # <tt>ActiveSupport::TestCase.file_fixture_path</tt>. + # + # File fixtures are represented as +Pathname+ objects. + # This makes it easy to extract specific information: + # + # file_fixture("example.txt").read # get the file's content + # file_fixture("example.mp3").size # get the file size + module FileFixtures + extend ActiveSupport::Concern + + included do + class_attribute :file_fixture_path, instance_writer: false + end + + # Returns a +Pathname+ to the fixture file named +fixture_name+. + # + # Raises ArgumentError if +fixture_name+ can't be found. + def file_fixture(fixture_name) + path = Pathname.new(File.join(file_fixture_path, fixture_name)) + + if path.exist? + path + else + msg = "the directory '%s' does not contain a file named '%s'" + raise ArgumentError, msg % [file_fixture_path, fixture_name] + end + end + end + end +end diff --git a/activesupport/lib/active_support/testing/stream.rb b/activesupport/lib/active_support/testing/stream.rb new file mode 100644 index 0000000000..895192ad05 --- /dev/null +++ b/activesupport/lib/active_support/testing/stream.rb @@ -0,0 +1,42 @@ +module ActiveSupport + module Testing + module Stream #:nodoc: + private + + def silence_stream(stream) + old_stream = stream.dup + stream.reopen(IO::NULL) + stream.sync = true + yield + ensure + stream.reopen(old_stream) + old_stream.close + end + + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end + end + end + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end + end + end +end diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb index 8c63815660..3478b09423 100644 --- a/activesupport/lib/active_support/testing/time_helpers.rb +++ b/activesupport/lib/active_support/testing/time_helpers.rb @@ -39,15 +39,16 @@ module ActiveSupport end end - # Containing helpers that helps you test passage of time. + # Contain helpers that help you test passage of time. module TimeHelpers # Changes current time to the time in the future or in the past by a given time difference by - # stubbing +Time.now+ and +Date.today+. + # stubbing +Time.now+, +Date.today+, and +DateTime.now+. # - # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 + # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 # travel 1.day - # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00 - # Date.current # => Sun, 10 Nov 2013 + # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00 + # Date.current # => Sun, 10 Nov 2013 + # DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500 # # This method also accepts a block, which will return the current time back to its original # state at the end of the block: @@ -61,13 +62,14 @@ module ActiveSupport travel_to Time.now + duration, &block end - # Changes current time to the given time by stubbing +Time.now+ and - # +Date.today+ to return the time or date passed into this method. + # Changes current time to the given time by stubbing +Time.now+, + # +Date.today+, and +DateTime.now+ to return the time or date passed into this method. # - # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 + # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 # travel_to Time.new(2004, 11, 24, 01, 04, 44) - # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 - # Date.current # => Wed, 24 Nov 2004 + # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 + # Date.current # => Wed, 24 Nov 2004 + # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500 # # Dates are taken as their timestamp at the beginning of the day in the # application time zone. <tt>Time.current</tt> returns said timestamp, @@ -99,6 +101,7 @@ module ActiveSupport simple_stubs.stub_object(Time, :now, now) simple_stubs.stub_object(Date, :today, now.to_date) + simple_stubs.stub_object(DateTime, :now, now.to_datetime) if block_given? begin diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 8ddf233b3e..c28de4e21c 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -252,7 +252,7 @@ module ActiveSupport utc.hash end - # Adds an interval of time to the current object's time and return that + # Adds an interval of time to the current object's time and returns that # value as a new TimeWithZone object. # # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)' diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 728b53849d..da39f0d245 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -224,13 +224,6 @@ module ActiveSupport @zones ||= zones_map.values.sort end - def zones_map - @zones_map ||= begin - MAPPING.each_key {|place| self[place]} # load all the zones - @lazy_zones_map - end - end - # Locate a specific time zone object. If the argument is a string, it # is interpreted to mean the name of the timezone to locate. If it is a # numeric value it is either the hour offset, or the second offset, of the @@ -257,6 +250,14 @@ module ActiveSupport def us_zones @us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ } end + + private + def zones_map + @zones_map ||= begin + MAPPING.each_key {|place| self[place]} # load all the zones + @lazy_zones_map + end + end end include Comparable diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb index 47a2824186..bb0ea9c582 100644 --- a/activesupport/lib/active_support/xml_mini/libxml.rb +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -75,5 +75,5 @@ module LibXML #:nodoc: end end -LibXML::XML::Document.send(:include, LibXML::Conversions::Document) -LibXML::XML::Node.send(:include, LibXML::Conversions::Node) +LibXML::XML::Document.include(LibXML::Conversions::Document) +LibXML::XML::Node.include(LibXML::Conversions::Node) diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb index 7398d4fa82..619cc7522d 100644 --- a/activesupport/lib/active_support/xml_mini/nokogiri.rb +++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb @@ -77,7 +77,7 @@ module ActiveSupport end end - Nokogiri::XML::Document.send(:include, Conversions::Document) - Nokogiri::XML::Node.send(:include, Conversions::Node) + Nokogiri::XML::Document.include(Conversions::Document) + Nokogiri::XML::Node.include(Conversions::Node) end end |