From 220603ee70d1655cf97a1e9f09fbc5d019c99856 Mon Sep 17 00:00:00 2001
From: wycats <wycats@gmail.com>
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 <wycats@gmail.com>
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 <wycats@gmail.com>
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 <wycats@gmail.com>
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 <jeremy@bitsweat.net>
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 <jeremy@bitsweat.net>
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 <fxn@hashref.com>
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 <fxn@hashref.com>
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