diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2008-09-03 17:44:58 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2008-09-03 17:44:58 +0100 |
commit | 2933f4481f8b70b3b809fab6e818d80c2af1b919 (patch) | |
tree | c83d1308545cc82215b90ab37208cc81b4712276 /activesupport | |
parent | 36ee17d458b86c5f3f371810160e8839d318bbf1 (diff) | |
parent | 10fe6a6d8940300dd6698ec38e9c9573404e687d (diff) | |
download | rails-2933f4481f8b70b3b809fab6e818d80c2af1b919.tar.gz rails-2933f4481f8b70b3b809fab6e818d80c2af1b919.tar.bz2 rails-2933f4481f8b70b3b809fab6e818d80c2af1b919.zip |
Merge commit 'mainstream/master'
Conflicts:
actionpack/lib/action_controller/resources.rb
Diffstat (limited to 'activesupport')
23 files changed, 457 insertions, 210 deletions
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb index 8724a492bf..e6143a274b 100644 --- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb @@ -91,14 +91,14 @@ class Class # :nodoc: def inheritable_attributes @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES end - + def write_inheritable_attribute(key, value) if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES) @inheritable_attributes = {} end inheritable_attributes[key] = value end - + def write_inheritable_array(key, elements) write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil? write_inheritable_attribute(key, read_inheritable_attribute(key) + elements) @@ -112,7 +112,7 @@ class Class # :nodoc: def read_inheritable_attribute(key) inheritable_attributes[key] end - + def reset_inheritable_attributes @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES end @@ -123,7 +123,7 @@ class Class # :nodoc: def inherited_with_inheritable_attributes(child) inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes) - + if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES) new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES else @@ -131,7 +131,7 @@ class Class # :nodoc: memo.update(key => value.duplicable? ? value.dup : value) end end - + child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes) end diff --git a/activesupport/lib/active_support/core_ext/date/behavior.rb b/activesupport/lib/active_support/core_ext/date/behavior.rb index 6f8f7c6a82..bd378eb375 100644 --- a/activesupport/lib/active_support/core_ext/date/behavior.rb +++ b/activesupport/lib/active_support/core_ext/date/behavior.rb @@ -1,3 +1,5 @@ +require 'date' + module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Date #:nodoc: @@ -10,18 +12,29 @@ module ActiveSupport #:nodoc: # 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 freezing. - def freeze #:nodoc: - self.class.private_instance_methods(false).each do |m| - if m.to_s =~ /\A__\d+__\Z/ - instance_variable_set(:"@#{m}", [send(m)]) + # instance variable is uninitialized. + # + # Work around by eagerly memoizing before freezing. + # + # Ruby 1.9 uses a preinitialized instance variable so it's unaffected. + # This hack is as close as we can get to feature detection: + begin + ::Date.today.freeze.jd + rescue => frozen_object_error + if frozen_object_error.message =~ /frozen/ + def freeze #:nodoc: + self.class.private_instance_methods(false).each do |m| + if m.to_s =~ /\A__\d+__\Z/ + instance_variable_set(:"@#{m}", [send(m)]) + end + end + + super end end - - super end end end diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index e451e9933a..fd94bc051f 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -64,8 +64,28 @@ 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, &block) + returning memo do |memo| + each do |element| + block.call(element, memo) + end + end + end unless [].respond_to?(:each_with_object) + # Convert an enumerable to a hash. Examples: - # + # # people.index_by(&:login) # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...} # people.index_by { |person| "#{person.first_name} #{person.last_name}" } diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb index 34fcbd124b..da8d28ec13 100644 --- a/activesupport/lib/active_support/core_ext/module.rb +++ b/activesupport/lib/active_support/core_ext/module.rb @@ -7,7 +7,17 @@ require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/module/loading' require 'active_support/core_ext/module/aliasing' require 'active_support/core_ext/module/model_naming' +require 'active_support/core_ext/module/synchronization' + +module ActiveSupport + module CoreExtensions + # Various extensions for the Ruby core Module class. + module Module + # Nothing here. Only defined for API documentation purposes. + end + end +end class Module - include ActiveSupport::CoreExt::Module::ModelNaming + include ActiveSupport::CoreExtensions::Module end diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index 1894e3b0a2..e640f64520 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -1,70 +1,74 @@ -class Module - # Encapsulates the common pattern of: - # - # alias_method :foo_without_feature, :foo - # alias_method :foo, :foo_with_feature - # - # With this, you simply do: - # - # alias_method_chain :foo, :feature - # - # And both aliases are set up for you. - # - # Query and bang methods (foo?, foo!) keep the same punctuation: - # - # alias_method_chain :foo?, :feature - # - # is equivalent to - # - # alias_method :foo_without_feature?, :foo? - # alias_method :foo?, :foo_with_feature? - # - # so you can safely chain foo, foo?, and foo! with the same feature. - def alias_method_chain(target, feature) - # Strip out punctuation on predicates or bang methods since - # e.g. target?_without_feature is not a valid method name. - aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 - yield(aliased_target, punctuation) if block_given? - - with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" - - alias_method without_method, target - alias_method target, with_method - - case - when public_method_defined?(without_method) - public target - when protected_method_defined?(without_method) - protected target - when private_method_defined?(without_method) - private target - end - end +module ActiveSupport + module CoreExtensions + module Module + # Encapsulates the common pattern of: + # + # alias_method :foo_without_feature, :foo + # alias_method :foo, :foo_with_feature + # + # With this, you simply do: + # + # alias_method_chain :foo, :feature + # + # And both aliases are set up for you. + # + # Query and bang methods (foo?, foo!) keep the same punctuation: + # + # alias_method_chain :foo?, :feature + # + # is equivalent to + # + # alias_method :foo_without_feature?, :foo? + # alias_method :foo?, :foo_with_feature? + # + # so you can safely chain foo, foo?, and foo! with the same feature. + def alias_method_chain(target, feature) + # Strip out punctuation on predicates or bang methods since + # e.g. target?_without_feature is not a valid method name. + aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 + yield(aliased_target, punctuation) if block_given? + + with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" - # Allows you to make aliases for attributes, which includes - # getter, setter, and query methods. - # - # Example: - # - # class Content < ActiveRecord::Base - # # has a title attribute - # end - # - # class Email < Content - # alias_attribute :subject, :title - # end - # - # e = Email.find(1) - # e.title # => "Superstars" - # e.subject # => "Superstars" - # e.subject? # => true - # e.subject = "Megastars" - # e.title # => "Megastars" - def alias_attribute(new_name, old_name) - module_eval <<-STR, __FILE__, __LINE__+1 - def #{new_name}; self.#{old_name}; end - def #{new_name}?; self.#{old_name}?; end - def #{new_name}=(v); self.#{old_name} = v; end - STR + alias_method without_method, target + alias_method target, with_method + + case + when public_method_defined?(without_method) + public target + when protected_method_defined?(without_method) + protected target + when private_method_defined?(without_method) + private target + end + end + + # Allows you to make aliases for attributes, which includes + # getter, setter, and query methods. + # + # Example: + # + # class Content < ActiveRecord::Base + # # has a title attribute + # end + # + # class Email < Content + # alias_attribute :subject, :title + # end + # + # e = Email.find(1) + # e.title # => "Superstars" + # e.subject # => "Superstars" + # e.subject? # => true + # e.subject = "Megastars" + # e.title # => "Megastars" + def alias_attribute(new_name, old_name) + module_eval <<-STR, __FILE__, __LINE__+1 + def #{new_name}; self.#{old_name}; end + def #{new_name}?; self.#{old_name}?; end + def #{new_name}=(v); self.#{old_name} = v; end + STR + end + end 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 45f3e4bf5c..8beaff4b82 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -1,86 +1,90 @@ -class Module - # Returns the name of the module containing this one. - # - # p M::N.parent_name # => "M" - def parent_name - unless defined? @parent_name - @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil - end - @parent_name - end +module ActiveSupport + module CoreExtensions + module Module + # Returns the name of the module containing this one. + # + # p M::N.parent_name # => "M" + def parent_name + unless defined? @parent_name + @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil + end + @parent_name + end - # Returns the module which contains this one according to its name. - # - # module M - # module N - # end - # end - # X = M::N - # - # p M::N.parent # => M - # p X.parent # => M - # - # The parent of top-level and anonymous modules is Object. - # - # p M.parent # => Object - # p Module.new.parent # => Object - # - def parent - parent_name ? parent_name.constantize : Object - end + # Returns the module which contains this one according to its name. + # + # module M + # module N + # end + # end + # X = M::N + # + # p M::N.parent # => M + # p X.parent # => M + # + # The parent of top-level and anonymous modules is Object. + # + # p M.parent # => Object + # p Module.new.parent # => Object + # + def parent + parent_name ? parent_name.constantize : Object + end - # Returns all the parents of this module according to its name, ordered from - # nested outwards. The receiver is not contained within the result. - # - # module M - # module N - # end - # end - # X = M::N - # - # p M.parents # => [Object] - # p M::N.parents # => [M, Object] - # p X.parents # => [M, Object] - # - def parents - parents = [] - if parent_name - parts = parent_name.split('::') - until parts.empty? - parents << (parts * '::').constantize - parts.pop + # Returns all the parents of this module according to its name, ordered from + # nested outwards. The receiver is not contained within the result. + # + # module M + # module N + # end + # end + # X = M::N + # + # p M.parents # => [Object] + # p M::N.parents # => [M, Object] + # p X.parents # => [M, Object] + # + def parents + parents = [] + if parent_name + parts = parent_name.split('::') + until parts.empty? + parents << (parts * '::').constantize + parts.pop + end + end + parents << Object unless parents.include? Object + parents end - end - parents << Object unless parents.include? Object - 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 = {} + 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 - ancestors.each do |anc| - next if anc == self - anc.constants.each { |const| inherited[const] = anc.const_get(const) } + 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 end - constants.select do |const| - !inherited.key?(const) || inherited[const].object_id != const_get(const).object_id + # Returns the names of the constants defined locally rather than the + # constants themselves. See <tt>local_constants</tt>. + def local_constant_names + local_constants.map { |c| c.to_s } end end - else - def local_constants #:nodoc: - constants(false) - end - end - - # Returns the names of the constants defined locally rather than the - # constants themselves. See <tt>local_constants</tt>. - def local_constant_names - local_constants.map { |c| c.to_s } end end diff --git a/activesupport/lib/active_support/core_ext/module/model_naming.rb b/activesupport/lib/active_support/core_ext/module/model_naming.rb index 5518f5417b..3ec4f3ba11 100644 --- a/activesupport/lib/active_support/core_ext/module/model_naming.rb +++ b/activesupport/lib/active_support/core_ext/module/model_naming.rb @@ -11,12 +11,12 @@ module ActiveSupport end end - module CoreExt + module CoreExtensions module Module - module ModelNaming - def model_name - @model_name ||= ModelName.new(name) - end + # Returns an ActiveSupport::ModelName object for module. It can be + # used to retrieve all kinds of naming-related information. + def model_name + @model_name ||= ModelName.new(name) end end end diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb new file mode 100644 index 0000000000..6253594dfa --- /dev/null +++ b/activesupport/lib/active_support/core_ext/module/synchronization.rb @@ -0,0 +1,36 @@ +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.flatten.each do |method| + aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1 + if instance_methods.include?("#{aliased_method}_without_synchronization#{punctuation}") + raise ArgumentError, "#{method} is already synchronized. Double synchronization is not currently supported." + end + module_eval(<<-EOS, __FILE__, __LINE__) + def #{aliased_method}_with_synchronization#{punctuation}(*args, &block) + #{with}.synchronize do + #{aliased_method}_without_synchronization#{punctuation}(*args, &block) + end + end + EOS + alias_method_chain method, :synchronization + end + end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/object/misc.rb b/activesupport/lib/active_support/core_ext/object/misc.rb index 8384a12327..06a7d05702 100644 --- a/activesupport/lib/active_support/core_ext/object/misc.rb +++ b/activesupport/lib/active_support/core_ext/object/misc.rb @@ -1,9 +1,4 @@ class Object - unless respond_to?(:send!) - # Anticipating Ruby 1.9 neutering send - alias send! send - end - # A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman. # # def foo 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 39dac85636..6fa1eb5bee 100644 --- a/activesupport/lib/active_support/core_ext/range/blockless_step.rb +++ b/activesupport/lib/active_support/core_ext/range/blockless_step.rb @@ -8,7 +8,7 @@ module ActiveSupport #:nodoc: end if RUBY_VERSION < '1.9' - def step_with_blockless(value, &block) + def step_with_blockless(value = 1, &block) if block_given? step_without_blockless(value, &block) else @@ -18,7 +18,7 @@ module ActiveSupport #:nodoc: end end else - def step_with_blockless(value, &block) + def step_with_blockless(value = 1, &block) if block_given? step_without_blockless(value, &block) else diff --git a/activesupport/lib/active_support/core_ext/rexml.rb b/activesupport/lib/active_support/core_ext/rexml.rb new file mode 100644 index 0000000000..af8ce3af47 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/rexml.rb @@ -0,0 +1,35 @@ +require 'rexml/document' +require 'rexml/entity' + +# 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 + +unless REXML::VERSION > "3.1.7.2" + module REXML + class Entity < Child + 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 + @@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 diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 079ecdd48e..9d8eb73908 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -78,7 +78,7 @@ module ActiveSupport #:nodoc: # # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00 def in_time_zone(zone = ::Time.zone) - ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.send!(:get_zone, zone)) + ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.__send__(:get_zone, zone)) end end end diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 01eb5df593..950bca60a6 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -109,7 +109,7 @@ module ActiveSupport end def deprecation_horizon - '2.0' + '2.3' end end @@ -162,6 +162,22 @@ module ActiveSupport end end + class DeprecatedObjectProxy < DeprecationProxy + def initialize(object, message) + @object = object + @message = message + end + + private + def target + @object + end + + def warn(callstack, called, args) + ActiveSupport::Deprecation.warn(@message, callstack) + end + end + # Stand-in for <tt>@request</tt>, <tt>@attributes</tt>, <tt>@params</tt>, etc. # which emits deprecation warnings on any method call (except +inspect+). class DeprecatedInstanceVariableProxy < DeprecationProxy #:nodoc: diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb index c77bca1ac9..b563b093ed 100644 --- a/activesupport/lib/active_support/option_merger.rb +++ b/activesupport/lib/active_support/option_merger.rb @@ -11,7 +11,7 @@ module ActiveSupport private def method_missing(method, *arguments, &block) arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup) - @context.send!(method, *arguments, &block) + @context.__send__(method, *arguments, &block) end end end diff --git a/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb b/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb index 70a44eab8c..63d1ba6507 100644 --- a/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb +++ b/activesupport/lib/active_support/testing/core_ext/test/unit/assertions.rb @@ -36,7 +36,11 @@ module Test # post :delete, :id => ... # end def assert_difference(expressions, difference = 1, message = nil, &block) - expression_evaluations = Array(expressions).collect{ |expression| lambda { eval(expression, block.send!(:binding)) } } + expression_evaluations = Array(expressions).map do |expression| + lambda do + eval(expression, block.__send__(:binding)) + end + end original_values = expression_evaluations.inject([]) { |memo, expression| memo << expression.call } yield diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 4866fa0dc8..75591b7c34 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -275,7 +275,7 @@ module ActiveSupport end def marshal_load(variables) - initialize(variables[0].utc, ::Time.send!(:get_zone, variables[1]), variables[2].utc) + initialize(variables[0].utc, ::Time.__send__(:get_zone, variables[1]), variables[2].utc) end # Ensure proxy class responds to all methods that underlying time instance responds to. diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 2e966a51be..da89b30c54 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -3,6 +3,9 @@ require 'strscan' module I18n module Backend class Simple + INTERPOLATION_RESERVED_KEYS = %w(scope default) + MATCH = /(\\\\)?\{\{([^\}]+)\}\}/ + # Accepts a list of paths to translation files. Loads translations from # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml # for details. @@ -114,29 +117,29 @@ module I18n # the <tt>{{...}}</tt> key in a string (once for the string and once for the # interpolation). def interpolate(locale, string, values = {}) - return string if !string.is_a?(String) + return string unless string.is_a?(String) string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}') + if string.respond_to?(:force_encoding) - original_encoding = string.encoding - string.force_encoding(Encoding::BINARY) - end - s = StringScanner.new(string) - - while s.skip_until(/\{\{/) - s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' - start_pos = s.pos - 2 - key = s.scan_until(/\}\}/)[0..-3] - end_pos = s.pos - 1 + original_encoding = string.encoding + string.force_encoding(Encoding::BINARY) + end - raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) - raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + result = string.gsub(MATCH) do + escaped, pattern, key = $1, $2, $2.to_sym - s.string[start_pos..end_pos] = values[key.to_sym].to_s - s.unscan + if escaped + pattern + elsif INTERPOLATION_RESERVED_KEYS.include?(pattern) + raise ReservedInterpolationKey.new(pattern, string) + elsif !values.include?(key) + raise MissingInterpolationArgument.new(pattern, string) + else + values[key].to_s + end end - - result = s.string + result.force_encoding(original_encoding) if original_encoding result end diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb index 6319c09210..28dd34334f 100644 --- a/activesupport/test/buffered_logger_test.rb +++ b/activesupport/test/buffered_logger_test.rb @@ -134,6 +134,7 @@ class BufferedLoggerTest < Test::Unit::TestCase a.join b.join - assert_equal "a\nb\nc\nx\ny\nz\n", @output.string + assert @output.string.include?("a\nb\nc\n") + assert @output.string.include?("x\ny\nz\n") end end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 2315d8f3db..deb9b7544d 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -58,6 +58,11 @@ class EnumerableTests < Test::Unit::TestCase assert_equal Payment.new(0), [].sum(Payment.new(0)) end + def test_each_with_object + result = %w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } + assert_equal({'foo' => 'FOO', 'bar' => 'BAR'}, result) + end + def test_index_by payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ] assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] }, diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index fc8ed45358..7a414e946f 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -62,7 +62,7 @@ class HashExtTest < Test::Unit::TestCase @symbols = @symbols.with_indifferent_access @mixed = @mixed.with_indifferent_access - assert_equal 'a', @strings.send!(:convert_key, :a) + assert_equal 'a', @strings.__send__(:convert_key, :a) assert_equal 1, @strings.fetch('a') assert_equal 1, @strings.fetch(:a.to_s) @@ -75,9 +75,9 @@ class HashExtTest < Test::Unit::TestCase hashes.each do |name, hash| method_map.sort_by { |m| m.to_s }.each do |meth, expected| - assert_equal(expected, hash.send!(meth, 'a'), + assert_equal(expected, hash.__send__(meth, 'a'), "Calling #{name}.#{meth} 'a'") - assert_equal(expected, hash.send!(meth, :a), + assert_equal(expected, hash.__send__(meth, :a), "Calling #{name}.#{meth} :a") end end @@ -733,7 +733,7 @@ class HashToXmlTest < Test::Unit::TestCase def test_empty_string_works_for_typecast_xml_value assert_nothing_raised do - Hash.send!(:typecast_xml_value, "") + Hash.__send__(:typecast_xml_value, "") end end @@ -839,6 +839,27 @@ class QueryTest < Test::Unit::TestCase :person => {:id => [20, 10]} end + def test_expansion_count_is_limited + assert_raises RuntimeError do + attack_xml = <<-EOT + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE member [ + <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> + <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> + <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;"> + <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;"> + <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;"> + <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;"> + <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"> + ]> + <member> + &a; + </member> + EOT + Hash.from_xml(attack_xml) + end + end + private def assert_query_equal(expected, actual, message = nil) assert_equal expected.split('&'), actual.to_query.split('&') diff --git a/activesupport/test/core_ext/module/synchronization_test.rb b/activesupport/test/core_ext/module/synchronization_test.rb new file mode 100644 index 0000000000..b1d4bc5e06 --- /dev/null +++ b/activesupport/test/core_ext/module/synchronization_test.rb @@ -0,0 +1,85 @@ +require 'abstract_unit' + +class SynchronizationTest < Test::Unit::TestCase + def setup + @target = Class.new + @target.cattr_accessor :mutex, :instance_writer => false + @target.mutex = Mutex.new + @instance = @target.new + end + + def test_synchronize_aliases_method_chain_with_synchronize + @target.module_eval do + attr_accessor :value + synchronize :value, :with => :mutex + end + assert @instance.respond_to?(:value_with_synchronization) + assert @instance.respond_to?(:value_without_synchronization) + end + + def test_synchronize_does_not_change_behavior + @target.module_eval do + attr_accessor :value + synchronize :value, :with => :mutex + end + expected = "some state" + @instance.value = expected + assert_equal expected, @instance.value + end + + def test_synchronize_with_no_mutex_raises_an_argument_error + assert_raises(ArgumentError) do + @target.synchronize :to_s + end + end + + def test_double_synchronize_raises_an_argument_error + @target.synchronize :to_s, :with => :mutex + assert_raises(ArgumentError) do + @target.synchronize :to_s, :with => :mutex + end + end + + def dummy_sync + dummy = Object.new + def dummy.synchronize + @sync_count ||= 0 + @sync_count += 1 + yield + end + def dummy.sync_count; @sync_count; end + dummy + end + + def test_mutex_is_entered_during_method_call + @target.mutex = dummy_sync + @target.synchronize :to_s, :with => :mutex + @instance.to_s + @instance.to_s + assert_equal 2, @target.mutex.sync_count + end + + def test_can_synchronize_method_with_punctuation + @target.module_eval do + def dangerous? + @dangerous + end + def dangerous! + @dangerous = true + end + end + @target.synchronize :dangerous?, :dangerous!, :with => :mutex + @instance.dangerous! + assert @instance.dangerous? + end + + def test_can_synchronize_singleton_methods + @target.mutex = dummy_sync + class << @target + synchronize :to_s, :with => :mutex + end + assert @target.respond_to?(:to_s_without_synchronization) + assert_nothing_raised { @target.to_s; @target.to_s } + assert_equal 2, @target.mutex.sync_count + end +end
\ No newline at end of file diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb index b0a746fdc7..e88dcb52d5 100644 --- a/activesupport/test/core_ext/object_and_class_ext_test.rb +++ b/activesupport/test/core_ext/object_and_class_ext_test.rb @@ -108,11 +108,6 @@ class ClassExtTest < Test::Unit::TestCase end class ObjectTests < Test::Unit::TestCase - def test_send_bang_aliases_send_before_19 - assert_respond_to 'a', :send! - assert_equal 1, 'a'.send!(:size) - end - def test_suppress_re_raises assert_raises(LoadError) { suppress(ArgumentError) {raise LoadError} } end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 39c9c74c94..18ad784837 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -146,42 +146,42 @@ class DependenciesTest < Test::Unit::TestCase def test_directories_manifest_as_modules_unless_const_defined with_loading 'autoloading_fixtures' do assert_kind_of Module, ModuleFolder - Object.send! :remove_const, :ModuleFolder + Object.__send__ :remove_const, :ModuleFolder end end def test_module_with_nested_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ModuleFolder::NestedClass - Object.send! :remove_const, :ModuleFolder + Object.__send__ :remove_const, :ModuleFolder end end def test_module_with_nested_inline_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ModuleFolder::InlineClass - Object.send! :remove_const, :ModuleFolder + Object.__send__ :remove_const, :ModuleFolder end end def test_directories_may_manifest_as_nested_classes with_loading 'autoloading_fixtures' do assert_kind_of Class, ClassFolder - Object.send! :remove_const, :ClassFolder + Object.__send__ :remove_const, :ClassFolder end end def test_class_with_nested_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ClassFolder::NestedClass - Object.send! :remove_const, :ClassFolder + Object.__send__ :remove_const, :ClassFolder end end def test_class_with_nested_inline_class with_loading 'autoloading_fixtures' do assert_kind_of Class, ClassFolder::InlineClass - Object.send! :remove_const, :ClassFolder + Object.__send__ :remove_const, :ClassFolder end end @@ -190,7 +190,7 @@ class DependenciesTest < Test::Unit::TestCase assert_kind_of Class, ClassFolder::ClassFolderSubclass assert_kind_of Class, ClassFolder assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder - Object.send! :remove_const, :ClassFolder + Object.__send__ :remove_const, :ClassFolder end end @@ -199,7 +199,7 @@ class DependenciesTest < Test::Unit::TestCase sibling = ModuleFolder::NestedClass.class_eval "NestedSibling" assert defined?(ModuleFolder::NestedSibling) assert_equal ModuleFolder::NestedSibling, sibling - Object.send! :remove_const, :ModuleFolder + Object.__send__ :remove_const, :ModuleFolder end end @@ -208,7 +208,7 @@ class DependenciesTest < Test::Unit::TestCase assert ! defined?(ModuleFolder) assert_raises(NameError) { ModuleFolder::Object } assert_raises(NameError) { ModuleFolder::NestedClass::Object } - Object.send! :remove_const, :ModuleFolder + Object.__send__ :remove_const, :ModuleFolder end end |