From 220603ee70d1655cf97a1e9f09fbc5d019c99856 Mon Sep 17 00:00:00 2001 From: wycats Date: Fri, 4 Jun 2010 09:48:03 -0700 Subject: Eliminate the need to check for superclass changes to the callback stack each time through the callbacks --- activesupport/lib/active_support/callbacks.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 933667c909..ba15043bde 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -390,9 +390,12 @@ module ActiveSupport undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks") class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def _run_#{symbol}_callbacks(key = nil, &blk) - if self.class.send("_update_#{symbol}_superclass_callbacks") - self.class.__define_runner(#{symbol.inspect}) - return _run_#{symbol}_callbacks(key, &blk) + @_initialized_#{symbol}_callbacks ||= begin + if self.class.send("_update_#{symbol}_superclass_callbacks") + self.class.__define_runner(#{symbol.inspect}) + return _run_#{symbol}_callbacks(key, &blk) + end + true end if key -- cgit v1.2.3 From 8b05c5207dd5757d55d0c384740db289e6bd5415 Mon Sep 17 00:00:00 2001 From: wycats Date: Fri, 4 Jun 2010 09:48:57 -0700 Subject: Improve performance of MessageVerifier while keeping it constant time --- activesupport/lib/active_support/message_verifier.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index 6c46b68eaf..1031662293 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -47,11 +47,11 @@ module ActiveSupport def secure_compare(a, b) return false unless a.bytesize == b.bytesize - l = a.unpack "C#{a.bytesize}" + l = a.unpack "C*" - res = 0 - b.each_byte { |byte| res |= byte ^ l.shift } - res == 0 + res = true + b.each_byte { |byte| res = (byte == l.shift) && res } + res end def generate_digest(data) -- cgit v1.2.3 From 16ee4b4d1b125bd3edb5c191d58c7afdf6d3232e Mon Sep 17 00:00:00 2001 From: wycats Date: Fri, 4 Jun 2010 11:50:34 -0700 Subject: Small optimization of 1.9 unescape. We should make sure that inbound ASCII always means UTF-8. It seems so based on a quick survey of common browsers, but let's be sure --- activesupport/lib/active_support/core_ext/uri.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb index 28eabd2111..b7fe0a6209 100644 --- a/activesupport/lib/active_support/core_ext/uri.rb +++ b/activesupport/lib/active_support/core_ext/uri.rb @@ -6,11 +6,15 @@ if RUBY_VERSION >= '1.9' str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. parser = URI::Parser.new + unless str == parser.unescape(parser.escape(str)) URI::Parser.class_eval do remove_method :unescape - def unescape(str, escaped = @regexp[:ESCAPED]) - enc = (str.encoding == Encoding::US_ASCII) ? Encoding::UTF_8 : str.encoding + def unescape(str, escaped = /%[a-fA-F\d]{2}/) + # TODO: Are we actually sure that ASCII == UTF-8? + # YK: My initial experiments say yes, but let's be sure please + enc = str.encoding + enc = Encoding::UTF_8 if enc == Encoding::US_ASCII str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(enc) end end -- cgit v1.2.3 From a6b39428431abeaa0251bbf4b6582e578f81783f Mon Sep 17 00:00:00 2001 From: wycats Date: Fri, 4 Jun 2010 17:28:04 -0700 Subject: Optimize LookupContext --- activesupport/lib/active_support/dependencies.rb | 23 +++++++++++++++++++++++ activesupport/test/dependencies_test.rb | 15 +++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index e14e225596..e0d2b70306 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -47,6 +47,9 @@ module ActiveSupport #:nodoc: mattr_accessor :autoloaded_constants self.autoloaded_constants = [] + mattr_accessor :references + self.references = {} + # An array of constant names that need to be unloaded on every request. Used # to allow arbitrary constants to be marked for unloading. mattr_accessor :explicitly_unloadable_constants @@ -476,9 +479,28 @@ module ActiveSupport #:nodoc: def remove_unloadable_constants! autoloaded_constants.each { |const| remove_constant const } autoloaded_constants.clear + references.each {|k,v| v.clear! } explicitly_unloadable_constants.each { |const| remove_constant const } end + class Reference + def initialize(constant, name) + @constant, @name = constant, name + end + + def get + @constant ||= Inflector.constantize(@name) + end + + def clear! + @constant = nil + end + end + + def ref(name) + references[name] ||= Reference.new(Inflector.constantize(name), name) + end + # Determine if the given constant has been automatically loaded. def autoloaded?(desc) # No name => anonymous module. @@ -572,6 +594,7 @@ module ActiveSupport #:nodoc: log "removing constant #{const}" parent.instance_eval { remove_const to_remove } + return true end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 75ff88505d..15543e07c3 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -431,6 +431,21 @@ class DependenciesTest < Test::Unit::TestCase end end + def test_references_should_work + with_loading 'dependencies' do + root = ActiveSupport::Dependencies.load_paths.first + c = ActiveSupport::Dependencies.ref("ServiceOne") + service_one_first = ServiceOne + assert_equal service_one_first, c.get + ActiveSupport::Dependencies.clear + assert ! defined?(ServiceOne) + + service_one_second = ServiceOne + assert_not_equal service_one_first, c.get + assert_equal service_one_second, c.get + end + end + def test_nested_load_error_isnt_rescued with_loading 'dependencies' do assert_raise(MissingSourceFile) do -- cgit v1.2.3 From fd1a5041362f5e65b813b7938d477143bd82de40 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 5 Jun 2010 20:33:53 -0700 Subject: ActiveSupport::Dependencies.constantize shortcut for caching named constant lookups --- .../lib/active_support/core_ext/string/conversions.rb | 11 +++++++++++ .../lib/active_support/core_ext/string/inflections.rb | 11 ----------- activesupport/lib/active_support/dependencies.rb | 12 +++++++++--- activesupport/test/dependencies_test.rb | 6 ++++++ 4 files changed, 26 insertions(+), 14 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index 6a243fe982..cd7a42ed2b 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -47,4 +47,15 @@ class String d[5] += d.pop ::DateTime.civil(*d) end + + # +constantize+ tries to find a declared constant with the name specified + # in the string. It raises a NameError when the name is not in CamelCase + # or is not initialized. + # + # Examples + # "Module".constantize # => Module + # "Class".constantize # => Class + def constantize + ActiveSupport::Inflector.constantize(self) + end end diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 48b028bb64..ef479d559e 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -146,15 +146,4 @@ class String def foreign_key(separate_class_name_and_id_with_underscore = true) ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore) end - - # +constantize+ tries to find a declared constant with the name specified - # in the string. It raises a NameError when the name is not in CamelCase - # or is not initialized. - # - # Examples - # "Module".constantize # => Module - # "Class".constantize # => Class - def constantize - ActiveSupport::Inflector.constantize(self) - end end diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index e0d2b70306..5091abc3a4 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -484,8 +484,10 @@ module ActiveSupport #:nodoc: end class Reference - def initialize(constant, name) - @constant, @name = constant, name + attr_reader :name + + def initialize(name, constant = nil) + @name, @constant = name, constant end def get @@ -498,7 +500,11 @@ module ActiveSupport #:nodoc: end def ref(name) - references[name] ||= Reference.new(Inflector.constantize(name), name) + references[name] ||= Reference.new(name) + end + + def constantize(name) + ref(name).get end # Determine if the given constant has been automatically loaded. diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 15543e07c3..5422c75f5f 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -446,6 +446,12 @@ class DependenciesTest < Test::Unit::TestCase end end + def test_constantize_shortcut_for_cached_constant_lookups + with_loading 'dependencies' do + assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne") + end + end + def test_nested_load_error_isnt_rescued with_loading 'dependencies' do assert_raise(MissingSourceFile) do -- cgit v1.2.3 From 9d0d6f7d261a14def6afd17568b8c8aa7c33d0b3 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 5 Jun 2010 22:02:49 -0700 Subject: Clear const references all at once --- activesupport/lib/active_support/dependencies.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 5091abc3a4..16c3bc1142 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -479,23 +479,26 @@ module ActiveSupport #:nodoc: def remove_unloadable_constants! autoloaded_constants.each { |const| remove_constant const } autoloaded_constants.clear - references.each {|k,v| v.clear! } + Reference.clear! explicitly_unloadable_constants.each { |const| remove_constant const } end class Reference + @@constants = Hash.new { |h, k| h[k] = Inflector.constantize(k) } + attr_reader :name - def initialize(name, constant = nil) - @name, @constant = name, constant + def initialize(name) + @name = name.to_s + @@constants[@name] = name if name.respond_to?(:name) end def get - @constant ||= Inflector.constantize(@name) + @@constants[@name] end - def clear! - @constant = nil + def self.clear! + @@constants.clear end end -- cgit v1.2.3 From d96efe63681cdf63e7c1a1448387a39af736bab9 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 6 Jun 2010 18:42:21 +0200 Subject: the order in which we apply deltas in Date#advance matters, add test coverage for that --- activesupport/test/core_ext/date_ext_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'activesupport') diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index a3a2f13436..55cd566738 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -198,6 +198,16 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(:years => 1) #leap day plus one year end + def test_advance_does_first_years_and_then_days + assert_equal Date.new(2012, 2, 29), Date.new(2011, 2, 28).advance(:years => 1, :days => 1) + # If day was done first we would jump to 2012-03-01 instead. + end + + def test_advance_does_first_months_and_then_days + assert_equal Date.new(2010, 3, 28), Date.new(2010, 2, 28).advance(:months => 1, :day => 1) + # If day was done first we would jump to 2010-04-01 instead. + end + def test_advance_in_calendar_reform assert_equal Date.new(1582,10,15), Date.new(1582,10,4).advance(:days => 1) assert_equal Date.new(1582,10,4), Date.new(1582,10,15).advance(:days => -1) -- cgit v1.2.3 From 8c7730db02b8a26c318caf98e726ee6e9f39df24 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 7 Jun 2010 07:27:51 +0200 Subject: oops, two cancelling errors made a previous test pass, fixing it --- activesupport/test/core_ext/date_ext_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport') diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index 55cd566738..3e003b3ed4 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -204,7 +204,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_advance_does_first_months_and_then_days - assert_equal Date.new(2010, 3, 28), Date.new(2010, 2, 28).advance(:months => 1, :day => 1) + assert_equal Date.new(2010, 3, 29), Date.new(2010, 2, 28).advance(:months => 1, :days => 1) # If day was done first we would jump to 2010-04-01 instead. end -- cgit v1.2.3