diff options
Diffstat (limited to 'activesupport')
19 files changed, 150 insertions, 112 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 3b6a29f7d6..6e8cce0d27 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -4,6 +4,10 @@ * Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White] +*Rails 3.0.2 (unreleased)* + +* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White] + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 84f6f29572..18182bbb40 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/file/atomic' require 'active_support/core_ext/string/conversions' +require 'rack/utils' module ActiveSupport module Cache @@ -11,8 +12,6 @@ module ActiveSupport attr_reader :cache_path DIR_FORMATTER = "%03X" - ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i - UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/ def initialize(cache_path, options = nil) super(options) @@ -136,7 +135,7 @@ module ActiveSupport # Translate a key into a file path. def key_file_path(key) - fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"} + fname = Rack::Utils.escape(key) hash = Zlib.adler32(fname) hash, dir_1 = hash.divmod(0x1000) dir_2 = hash.modulo(0x1000) @@ -156,7 +155,7 @@ module ActiveSupport # Translate a file path into a key. def file_path_key(path) fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last - fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)} + Rack::Utils.unescape(fname) end # Delete empty directories in the cache. diff --git a/activesupport/lib/active_support/core_ext/cgi.rb b/activesupport/lib/active_support/core_ext/cgi.rb deleted file mode 100644 index 7279a3d4da..0000000000 --- a/activesupport/lib/active_support/core_ext/cgi.rb +++ /dev/null @@ -1 +0,0 @@ -require 'active_support/core_ext/cgi/escape_skipping_slashes' diff --git a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb b/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb deleted file mode 100644 index d3c3575748..0000000000 --- a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'cgi' - -class CGI #:nodoc: - if RUBY_VERSION >= '1.9' - def self.escape_skipping_slashes(str) - str = str.join('/') if str.respond_to? :join - str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do - "%#{$1.unpack('H2' * $1.bytesize).join('%').upcase}" - end.tr(' ', '+') - end - else - def self.escape_skipping_slashes(str) - str = str.join('/') if str.respond_to? :join - str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do - "%#{$1.unpack('H2').first.upcase}" - end.tr(' ', '+') - end - end -end diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb index 501483498d..fd1cda991e 100644 --- a/activesupport/lib/active_support/core_ext/hash.rb +++ b/activesupport/lib/active_support/core_ext/hash.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/hash/conversions' require 'active_support/core_ext/hash/deep_merge' +require 'active_support/core_ext/hash/deep_dup' require 'active_support/core_ext/hash/diff' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/indifferent_access' diff --git a/activesupport/lib/active_support/core_ext/hash/deep_dup.rb b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb new file mode 100644 index 0000000000..447142605c --- /dev/null +++ b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb @@ -0,0 +1,11 @@ +class Hash + # Returns a deep copy of hash. + def deep_dup + duplicate = self.dup + duplicate.each_pair do |k,v| + tv = duplicate[k] + duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v + end + duplicate + end +end diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb index 77a3cfc21d..eda9694614 100644 --- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb +++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb @@ -30,35 +30,4 @@ class Object else alias_method :instance_variable_names, :instance_variables end - - # Copies the instance variables of +object+ into +self+. - # - # Instance variable names in the +exclude+ array are ignored. If +object+ - # responds to <tt>protected_instance_variables</tt> the ones returned are - # also ignored. For example, Rails controllers implement that method. - # - # In both cases strings and symbols are understood, and they have to include - # the at sign. - # - # class C - # def initialize(x, y, z) - # @x, @y, @z = x, y, z - # end - # - # def protected_instance_variables - # %w(@z) - # end - # end - # - # a = C.new(0, 1, 2) - # b = C.new(3, 4, 5) - # - # a.copy_instance_variables_from(b, [:@y]) - # # a is now: @x = 3, @y = 1, @z = 2 - def copy_instance_variables_from(object, exclude = []) #:nodoc: - exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables - - vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s) - vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) } - end end diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index 48e9d04787..4d742b9ed2 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -8,6 +8,8 @@ class Object # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass. # + # If try is called without a method to call, it will yield any given block with the object. + # # ==== Examples # # Without try @@ -21,10 +23,20 @@ class Object # +try+ also accepts arguments and/or a block, for the method it is trying # Person.try(:find, 1) # @people.try(:collect) {|p| p.name} + # + # Without a method argument try will yield to the block unless the reciever is nil. + # @person.try { |p| "#{p.first_name} #{p.last_name}" } #-- # +try+ behaves like +Object#send+, unless called on +NilClass+. - alias_method :try, :__send__ + def try(*a, &b) + if a.empty? && block_given? + yield self + else + __send__(*a, &b) + end + end + end class NilClass #:nodoc: diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index c406dd3c2e..320f5c1c92 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -28,7 +28,7 @@ module ActiveSupport end def self.new_from_hash_copying_default(hash) - ActiveSupport::HashWithIndifferentAccess.new(hash).tap do |new_hash| + new(hash).tap do |new_hash| new_hash.default = hash.default end end @@ -97,7 +97,9 @@ module ActiveSupport # Returns an exact copy of the hash. def dup - HashWithIndifferentAccess.new(self) + self.class.new(self).tap do |new_hash| + new_hash.default = default + end end # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash @@ -142,7 +144,7 @@ module ActiveSupport when Hash self.class.new_from_hash_copying_default(value) when Array - value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e } + value.dup.replace(value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e }) else value end diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 7f148dc853..8e157d3af4 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -137,6 +137,8 @@ module ActiveSupport alias_method :each_pair, :each + alias_method :select, :find_all + def clear super @keys.clear diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 93f5d5a0cc..6a7da8266c 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -73,7 +73,7 @@ module ActiveSupport # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your system's <tt>ENV['TZ']</tt> zone def localtime - utc.getlocal + utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal end alias_method :getlocal, :localtime diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index b6a8cf3caf..cddfcddb57 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -126,9 +126,11 @@ module ActiveSupport end def rename_key(key, options = {}) - camelize = options.has_key?(:camelize) && options[:camelize] + camelize = options[:camelize] dasherize = !options.has_key?(:dasherize) || options[:dasherize] - key = key.camelize if camelize + if camelize + key = true == camelize ? key.camelize : key.camelize(camelize) + end key = _dasherize(key) if dasherize key end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 28ef695a4b..579d5dad24 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -356,9 +356,13 @@ module CacheDeleteMatchedBehavior def test_delete_matched @cache.write("foo", "bar") @cache.write("fu", "baz") + @cache.write("foo/bar", "baz") + @cache.write("fu/baz", "bar") @cache.delete_matched(/oo/) assert_equal false, @cache.exist?("foo") assert_equal true, @cache.exist?("fu") + assert_equal false, @cache.exist?("foo/bar") + assert_equal true, @cache.exist?("fu/baz") end end @@ -509,6 +513,11 @@ class FileStoreTest < ActiveSupport::TestCase assert_nil old_cache.read('foo') end end + + def test_key_transformation + key = @cache.send(:key_file_path, "views/index?id=1") + assert_equal "views/index?id=1", @cache.send(:file_path_key, key) + end end class MemoryStoreTest < ActiveSupport::TestCase diff --git a/activesupport/test/core_ext/cgi_ext_test.rb b/activesupport/test/core_ext/cgi_ext_test.rb deleted file mode 100644 index c80362e382..0000000000 --- a/activesupport/test/core_ext/cgi_ext_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'abstract_unit' -require 'active_support/core_ext/cgi' - -class EscapeSkippingSlashesTest < Test::Unit::TestCase - def test_array - assert_equal 'hello/world', CGI.escape_skipping_slashes(%w(hello world)) - assert_equal 'hello+world/how/are/you', CGI.escape_skipping_slashes(['hello world', 'how', 'are', 'you']) - end - - def test_typical - assert_equal 'hi', CGI.escape_skipping_slashes('hi') - assert_equal 'hi/world', CGI.escape_skipping_slashes('hi/world') - assert_equal 'hi/world+you+funky+thing', CGI.escape_skipping_slashes('hi/world you funky thing') - end -end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 545fed2684..370f26b0d7 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -6,6 +6,12 @@ require 'active_support/ordered_hash' require 'active_support/core_ext/object/conversions' class HashExtTest < Test::Unit::TestCase + class IndifferentHash < HashWithIndifferentAccess + end + + class SubclassingArray < Array + end + def setup @strings = { 'a' => 1, 'b' => 2 } @symbols = { :a => 1, :b => 2 } @@ -248,6 +254,20 @@ class HashExtTest < Test::Unit::TestCase hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access assert_equal "1", hash[:urls][:url].first[:address] end + + def test_should_preserve_array_subclass_when_value_is_array + array = SubclassingArray.new + array << { "address" => "1" } + hash = { "urls" => { "url" => array }}.with_indifferent_access + assert_equal SubclassingArray, hash[:urls][:url].class + end + + def test_should_preserve_array_class_when_hash_value_is_frozen_array + array = SubclassingArray.new + array << { "address" => "1" } + hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access + assert_equal SubclassingArray, hash[:urls][:url].class + end def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash h = HashWithIndifferentAccess.new @@ -267,7 +287,6 @@ class HashExtTest < Test::Unit::TestCase assert_equal 1, h['first'] end - def test_indifferent_subhashes h = {'user' => {'id' => 5}}.with_indifferent_access ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} @@ -276,6 +295,17 @@ class HashExtTest < Test::Unit::TestCase ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} end + def test_indifferent_duplication + # Should preserve default value + h = HashWithIndifferentAccess.new + h.default = '1234' + assert_equal h.default, h.dup.default + + # Should preserve class for subclasses + h = IndifferentHash.new + assert_equal h.class, h.dup.class + end + def test_assert_valid_keys assert_nothing_raised do { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) @@ -316,6 +346,21 @@ class HashExtTest < Test::Unit::TestCase assert_equal expected, hash_1 end + def test_deep_dup + hash = { :a => { :b => 'b' } } + dup = hash.deep_dup + dup[:a][:c] = 'c' + assert_equal nil, hash[:a][:c] + assert_equal 'c', dup[:a][:c] + end + + def test_deep_dup_initialize + zero_hash = Hash.new 0 + hash = { :a => zero_hash } + dup = hash.deep_dup + assert_equal 0, dup[:a][44] + end + def test_store_on_indifferent_access hash = HashWithIndifferentAccess.new hash.store(:test1, 1) @@ -486,7 +531,7 @@ class HashExtToParamTests < Test::Unit::TestCase def test_to_param_hash_escapes_its_keys_and_values assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param end - + def test_to_param_orders_by_key_in_ascending_order assert_equal 'a=2&b=1&c=0', ActiveSupport::OrderedHash[*%w(b 1 c 0 a 2)].to_param end @@ -525,6 +570,13 @@ class HashToXmlTest < Test::Unit::TestCase assert xml.include?(%(<Name>David</Name>)) end + def test_one_level_camelize_lower + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => :lower)) + assert_equal "<person>", xml.first(8) + assert xml.include?(%(<streetName>Paulina</streetName>)) + assert xml.include?(%(<name>David</name>)) + end + def test_one_level_with_types xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) 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 3ccf18f473..398e6ca9b2 100644 --- a/activesupport/test/core_ext/object_and_class_ext_test.rb +++ b/activesupport/test/core_ext/object_and_class_ext_test.rb @@ -82,37 +82,6 @@ class ObjectInstanceVariableTest < Test::Unit::TestCase assert_equal %w(@bar @baz), @source.instance_variable_names.sort end - def test_copy_instance_variables_from_without_explicit_excludes - assert_equal [], @dest.instance_variables - @dest.copy_instance_variables_from(@source) - - assert_equal %w(@bar @baz), @dest.instance_variables.sort.map(&:to_s) - %w(@bar @baz).each do |name| - assert_equal @source.instance_variable_get(name).object_id, - @dest.instance_variable_get(name).object_id - end - end - - def test_copy_instance_variables_from_with_explicit_excludes - @dest.copy_instance_variables_from(@source, ['@baz']) - assert !@dest.instance_variable_defined?('@baz') - assert_equal 'bar', @dest.instance_variable_get('@bar') - end - - def test_copy_instance_variables_automatically_excludes_protected_instance_variables - @source.instance_variable_set(:@quux, 'quux') - class << @source - def protected_instance_variables - ['@bar', :@quux] - end - end - - @dest.copy_instance_variables_from(@source) - assert !@dest.instance_variable_defined?('@bar') - assert !@dest.instance_variable_defined?('@quux') - assert_equal 'baz', @dest.instance_variable_get('@baz') - end - def test_instance_values object = Object.new object.instance_variable_set :@a, 1 @@ -165,4 +134,14 @@ class ObjectTryTest < Test::Unit::TestCase def test_false_try assert_equal 'false', false.try(:to_s) end + + def test_try_only_block + assert_equal @string.reverse, @string.try { |s| s.reverse } + end + + def test_try_only_block_nil + ran = false + nil.try { ran = true } + assert_equal false, ran + end end diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 0bb2c4a39e..5579c27215 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -36,6 +36,10 @@ class TimeWithZoneTest < Test::Unit::TestCase assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id end + def test_localtime + assert_equal @twz.localtime, @twz.utc.getlocal + end + def test_utc? assert_equal false, @twz.utc? assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc? @@ -763,6 +767,13 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase end end + def test_localtime + Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal + ensure + Time.zone_default = nil + end + def test_use_zone Time.zone = 'Alaska' Time.use_zone 'Hawaii' do diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index 50778b5864..72088854fc 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -109,6 +109,14 @@ class OrderedHashTest < Test::Unit::TestCase assert_equal @keys, keys end + def test_find_all + assert_equal @keys, @ordered_hash.find_all { true }.map(&:first) + end + + def test_select + assert_equal @keys, @ordered_hash.select { true }.map(&:first) + end + def test_delete_if copy = @ordered_hash.dup copy.delete('pink') diff --git a/activesupport/test/test_xml_mini.rb b/activesupport/test/test_xml_mini.rb index 585eb15c6e..309fa234bf 100644 --- a/activesupport/test/test_xml_mini.rb +++ b/activesupport/test/test_xml_mini.rb @@ -14,14 +14,26 @@ class XmlMiniTest < Test::Unit::TestCase assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false) end - def test_rename_key_camelizes_with_camelize_true - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) + def test_rename_key_camelizes_with_camelize_false + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => false) + end + + def test_rename_key_camelizes_with_camelize_nil + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => nil) end def test_rename_key_camelizes_with_camelize_true assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) end + def test_rename_key_lower_camelizes_with_camelize_lower + assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower) + end + + def test_rename_key_lower_camelizes_with_camelize_upper + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :upper) + end + def test_rename_key_does_not_dasherize_leading_underscores assert_equal "_id", ActiveSupport::XmlMini.rename_key("_id") end |