diff options
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/CHANGELOG | 7 | ||||
-rw-r--r-- | activesupport/lib/active_support/configurable.rb | 37 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/kernel/reporting.rb | 3 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/uri.rb | 3 | ||||
-rw-r--r-- | activesupport/lib/active_support/hash_with_indifferent_access.rb | 6 | ||||
-rw-r--r-- | activesupport/lib/active_support/json/encoding.rb | 24 | ||||
-rw-r--r-- | activesupport/lib/active_support/multibyte/chars.rb | 4 | ||||
-rw-r--r-- | activesupport/lib/active_support/notifications/fanout.rb | 20 | ||||
-rw-r--r-- | activesupport/lib/active_support/testing/isolation.rb | 3 | ||||
-rw-r--r-- | activesupport/test/configurable_test.rb | 42 | ||||
-rw-r--r-- | activesupport/test/core_ext/hash_ext_test.rb | 41 | ||||
-rw-r--r-- | activesupport/test/core_ext/uri_ext_test.rb | 2 | ||||
-rw-r--r-- | activesupport/test/json/encoding_test.rb | 21 | ||||
-rw-r--r-- | activesupport/test/multibyte_chars_test.rb | 2 | ||||
-rw-r--r-- | activesupport/test/notifications_test.rb | 22 |
15 files changed, 197 insertions, 40 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index da370303c6..c47839b001 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,12 @@ +*Rails 3.0.0 [beta 4/release candidate] (unreleased)* + +* JSON: encode objects that don't have a native JSON representation using to_hash, if available, instead of instance_values (the old fallback) or to_s (other encoders' default). Encode BigDecimal and Regexp encode as strings to conform with other encoders. Try to transcode non-UTF-8 strings. [Jeremy Kemper] + + *Rails 3.0.0 [beta 3] (April 13th, 2010)* +* HashWithIndifferentAccess: remove inherited symbolize_keys! since its keys are always strings. [Santiago Pastorino] + * Improve transliteration quality. #4374 [Norman Clarke] * Speed up and add Ruby 1.9 support for ActiveSupport::Multibyte::Chars#tidy_bytes. #4350 [Norman Clarke] diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb index 890f465ce1..f562e17c75 100644 --- a/activesupport/lib/active_support/configurable.rb +++ b/activesupport/lib/active_support/configurable.rb @@ -1,35 +1,36 @@ -require "active_support/concern" +require 'active_support/concern' +require 'active_support/ordered_options' +require 'active_support/core_ext/kernel/singleton_class' +require 'active_support/core_ext/module/delegation' module ActiveSupport module Configurable extend ActiveSupport::Concern module ClassMethods - def get_config - module_parts = name.split("::") - modules = [Object] - module_parts.each {|name| modules.push modules.last.const_get(name) } - modules.reverse_each do |mod| - return mod.const_get(:DEFAULT_CONFIG) if const_defined?(:DEFAULT_CONFIG) - end - {} - end - def config - self.config = get_config unless @config - @config + @config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {}) end - def config=(hash) - @config = ActiveSupport::OrderedOptions.new - hash.each do |key, value| - @config[key] = value + def configure + yield config + end + + def config_accessor(*names) + names.each do |name| + code, line = <<-RUBY, __LINE__ + 1 + def #{name}; config.#{name}; end + def #{name}=(value); config.#{name} = value; end + RUBY + + singleton_class.class_eval code, __FILE__, line + class_eval code, __FILE__, line end end end def config - self.class.config + @config ||= ActiveSupport::InheritableOptions.new(self.class.config) end end end
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb index ac35db6ab6..7c455f66d5 100644 --- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb +++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb @@ -1,3 +1,4 @@ +require 'rbconfig' module Kernel # Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards. # @@ -37,7 +38,7 @@ module Kernel # puts 'But this will' def silence_stream(stream) old_stream = stream.dup - stream.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') + stream.reopen(Config::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') stream.sync = true yield ensure diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb index ca1be8b7e9..28eabd2111 100644 --- a/activesupport/lib/active_support/core_ext/uri.rb +++ b/activesupport/lib/active_support/core_ext/uri.rb @@ -1,8 +1,9 @@ +# encoding: utf-8 + if RUBY_VERSION >= '1.9' require 'uri' str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. - str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding) parser = URI::Parser.new unless str == parser.unescape(parser.escape(str)) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 8241b69c8b..f64f0f44cc 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/hash/keys' + # This class has dubious semantics and we only have it so that # people can write params[:key] instead of params['key'] # and they get the same value for both keys. @@ -112,7 +114,9 @@ module ActiveSupport end def stringify_keys!; self end - def symbolize_keys!; self end + def stringify_keys; dup end + undef :symbolize_keys! + def symbolize_keys; to_hash.symbolize_keys end def to_options!; self end # Convert to a Hash with String keys. diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 8ba45f7ea2..0f38fd0e89 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -1,4 +1,5 @@ # encoding: utf-8 +require 'bigdecimal' require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/slice' @@ -102,7 +103,9 @@ module ActiveSupport end def escape(string) - string = string.dup.force_encoding(::Encoding::BINARY) if string.respond_to?(:force_encoding) + if string.respond_to?(:force_encoding) + string = string.encode(::Encoding::UTF_8, undef: :replace).force_encoding(::Encoding::BINARY) + end json = string. gsub(escape_regex) { |s| ESCAPED_CHARS[s] }. gsub(/([\xC0-\xDF][\x80-\xBF]| @@ -110,7 +113,9 @@ module ActiveSupport [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&') } - %("#{json}") + json = %("#{json}") + json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding) + json end end @@ -128,7 +133,13 @@ class Object ActiveSupport::JSON.encode(self, options) end - def as_json(options = nil) instance_values end #:nodoc: + def as_json(options = nil) #:nodoc: + if respond_to?(:to_hash) + to_hash + else + instance_values + end + end end # A string that returns itself as its JSON-encoded form. @@ -166,9 +177,12 @@ class Numeric def encode_json(encoder) to_s end #:nodoc: end +class BigDecimal + def as_json(options = nil) to_s end #:nodoc: +end + class Regexp - def as_json(options = nil) self end #:nodoc: - def encode_json(encoder) inspect end #:nodoc: + def as_json(options = nil) to_s end #:nodoc: end module Enumerable diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 38007fd4e7..4ade1158fd 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -72,8 +72,8 @@ module ActiveSupport #:nodoc: def self.codepoints_to_pattern(array_of_codepoints) #:nodoc: array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|') end - UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/ - UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/ + UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/u + UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/u UTF8_PAT = ActiveSupport::Multibyte::VALID_CHARACTER['UTF-8'] diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index a3ddc7705a..300ec842a9 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -19,8 +19,8 @@ module ActiveSupport end def unsubscribe(subscriber) - @subscribers.delete(subscriber) @listeners_for.clear + @subscribers.reject! {|s| s.matches?(subscriber)} end def publish(name, *args) @@ -60,7 +60,7 @@ module ActiveSupport end def publish(*args) - return unless matches?(args.first) + return unless subscribed_to?(args.first) push(*args) true end @@ -69,10 +69,20 @@ module ActiveSupport true end - private - def matches?(name) - !@pattern || @pattern =~ name.to_s + def subscribed_to?(name) + !@pattern || @pattern =~ name.to_s + end + + def matches?(subscriber_or_name) + case subscriber_or_name + when String + @pattern && @pattern =~ subscriber_or_name + when self + true end + end + + private def push(*args) @block.call(*args) diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index 9507dbf473..69df399cde 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -1,3 +1,4 @@ +require 'rbconfig' module ActiveSupport module Testing class RemoteError < StandardError @@ -33,7 +34,7 @@ module ActiveSupport module Isolation def self.forking_env? - !ENV["NO_FORK"] && RUBY_PLATFORM !~ /mswin|mingw|java/ + !ENV["NO_FORK"] && ((Config::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/)) end def self.included(base) diff --git a/activesupport/test/configurable_test.rb b/activesupport/test/configurable_test.rb new file mode 100644 index 0000000000..cef67e3cf9 --- /dev/null +++ b/activesupport/test/configurable_test.rb @@ -0,0 +1,42 @@ +require 'abstract_unit' +require 'active_support/configurable' + +class ConfigurableActiveSupport < ActiveSupport::TestCase + class Parent + include ActiveSupport::Configurable + config_accessor :foo + end + + class Child < Parent + end + + setup do + Parent.config.clear + Parent.config.foo = :bar + + Child.config.clear + end + + test "adds a configuration hash" do + assert_equal({ :foo => :bar }, Parent.config) + end + + test "configuration hash is inheritable" do + assert_equal :bar, Child.config.foo + assert_equal :bar, Parent.config.foo + + Child.config.foo = :baz + assert_equal :baz, Child.config.foo + assert_equal :bar, Parent.config.foo + end + + test "configuration hash is available on instance" do + instance = Parent.new + assert_equal :bar, instance.config.foo + assert_equal :bar, Parent.config.foo + + instance.config.foo = :baz + assert_equal :baz, instance.config.foo + assert_equal :bar, Parent.config.foo + end +end
\ No newline at end of file diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 86272a28c1..b2a9731578 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -60,6 +60,43 @@ class HashExtTest < Test::Unit::TestCase assert_equal @strings, @mixed.dup.stringify_keys! end + def test_symbolize_keys_for_hash_with_indifferent_access + assert_instance_of Hash, @symbols.with_indifferent_access.symbolize_keys + assert_equal @symbols, @symbols.with_indifferent_access.symbolize_keys + assert_equal @symbols, @strings.with_indifferent_access.symbolize_keys + assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys + end + + def test_symbolize_keys_bang_for_hash_with_indifferent_access + assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! } + assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! } + assert_raise(NoMethodError) { @mixed.with_indifferent_access.dup.symbolize_keys! } + end + + def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access + assert_equal @illegal_symbols, @illegal_symbols.with_indifferent_access.symbolize_keys + assert_raise(NoMethodError) { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! } + end + + def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access + assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys + assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! } + end + + def test_stringify_keys_for_hash_with_indifferent_access + assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.stringify_keys + assert_equal @strings, @symbols.with_indifferent_access.stringify_keys + assert_equal @strings, @strings.with_indifferent_access.stringify_keys + assert_equal @strings, @mixed.with_indifferent_access.stringify_keys + end + + def test_stringify_keys_bang_for_hash_with_indifferent_access + assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.dup.stringify_keys! + assert_equal @strings, @symbols.with_indifferent_access.dup.stringify_keys! + assert_equal @strings, @strings.with_indifferent_access.dup.stringify_keys! + assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys! + end + def test_indifferent_assorted @strings = @strings.with_indifferent_access @symbols = @symbols.with_indifferent_access @@ -213,11 +250,11 @@ class HashExtTest < Test::Unit::TestCase def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash h = HashWithIndifferentAccess.new h[:first] = 1 - h.stringify_keys! + h = h.stringify_keys assert_equal 1, h['first'] h = HashWithIndifferentAccess.new h['first'] = 1 - h.symbolize_keys! + h = h.symbolize_keys assert_equal 1, h[:first] end diff --git a/activesupport/test/core_ext/uri_ext_test.rb b/activesupport/test/core_ext/uri_ext_test.rb index e4a242abc4..d988837603 100644 --- a/activesupport/test/core_ext/uri_ext_test.rb +++ b/activesupport/test/core_ext/uri_ext_test.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 require 'abstract_unit' require 'uri' require 'active_support/core_ext/uri' @@ -5,7 +6,6 @@ require 'active_support/core_ext/uri' class URIExtTest < Test::Unit::TestCase def test_uri_decode_handle_multibyte str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. - str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding) if URI.const_defined?(:Parser) parser = URI::Parser.new diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 188b799f3f..ff95c0ca18 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -9,6 +9,12 @@ class TestJSONEncoding < Test::Unit::TestCase end end + class Hashlike + def to_hash + { :a => 1 } + end + end + class Custom def as_json(options) 'custom' @@ -19,7 +25,8 @@ class TestJSONEncoding < Test::Unit::TestCase FalseTests = [[ false, %(false) ]] NilTests = [[ nil, %(null) ]] NumericTests = [[ 1, %(1) ], - [ 2.5, %(2.5) ]] + [ 2.5, %(2.5) ], + [ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s}") ]] StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")], [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], @@ -35,11 +42,12 @@ class TestJSONEncoding < Test::Unit::TestCase [ :"a b", %("a b") ]] ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]] + HashlikeTests = [[ Hashlike.new, %({\"a\":1}) ]] CustomTests = [[ Custom.new, '"custom"' ]] VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'], [ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']] - RegexpTests = [[ /^a/, '/^a/' ], [/^\w{1,2}[a-z]+/ix, '/^\\w{1,2}[a-z]+/ix']] + RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']] DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]] TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]] @@ -91,6 +99,15 @@ class TestJSONEncoding < Test::Unit::TestCase end end + if '1.9'.respond_to?(:force_encoding) + def test_non_utf8_string_transcodes + s = '二'.encode('Shift_JIS') + result = ActiveSupport::JSON.encode(s) + assert_equal '"\\u4e8c"', result + assert_equal Encoding::UTF_8, result.encoding + end + end + def test_exception_raised_when_encoding_circular_reference a = [1] a << a diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 1b8d13c024..caf50aa1c9 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -105,7 +105,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase @whitespace = "\n\t#{[32, 8195].pack('U*')}" else # Ruby 1.9 only supports basic whitespace - @whitespace = "\n\t ".force_encoding(Encoding::UTF_8) + @whitespace = "\n\t " end @byte_order_mark = [65279].pack('U') diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 92fbe5b92f..c2e1c588f0 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -6,7 +6,9 @@ module Notifications ActiveSupport::Notifications.notifier = nil @notifier = ActiveSupport::Notifications.notifier @events = [] + @named_events = [] @subscription = @notifier.subscribe { |*args| @events << event(*args) } + @named_subscription = @notifier.subscribe("named.subscription") { |*args| @named_events << event(*args) } end private @@ -30,6 +32,26 @@ module Notifications assert_equal [[:foo]], @events end + def test_unsubscribing_by_name_removes_a_subscription + @notifier.publish "named.subscription", :foo + @notifier.wait + assert_equal [["named.subscription", :foo]], @named_events + @notifier.unsubscribe("named.subscription") + @notifier.publish "named.subscription", :foo + @notifier.wait + assert_equal [["named.subscription", :foo]], @named_events + end + + def test_unsubscribing_by_name_leaves_the_other_subscriptions + @notifier.publish "named.subscription", :foo + @notifier.wait + assert_equal [["named.subscription", :foo]], @events + @notifier.unsubscribe("named.subscription") + @notifier.publish "named.subscription", :foo + @notifier.wait + assert_equal [["named.subscription", :foo], ["named.subscription", :foo]], @events + end + private def event(*args) args |