From a6b39428431abeaa0251bbf4b6582e578f81783f Mon Sep 17 00:00:00 2001 From: wycats Date: Fri, 4 Jun 2010 17:28:04 -0700 Subject: [PATCH] Optimize LookupContext --- .../lib/action_dispatch/routing/route_set.rb | 13 +++++-- actionpack/lib/action_view/base.rb | 1 + actionpack/lib/action_view/lookup_context.rb | 35 +++++++++++++------ .../lib/action_view/template/handlers.rb | 2 +- .../lib/active_support/dependencies.rb | 23 ++++++++++++ activesupport/test/dependencies_test.rb | 15 ++++++++ 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 5c4c96d9fc..750912b251 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -12,6 +12,7 @@ module ActionDispatch def initialize(options={}) @defaults = options[:defaults] @glob_param = options.delete(:glob) + @controllers = {} end def call(env) @@ -32,9 +33,15 @@ module ActionDispatch end def controller(params, raise_error=true) - if params && params.has_key?(:controller) - controller = "#{params[:controller].camelize}Controller" - ActiveSupport::Inflector.constantize(controller) + if params && params.key?(:controller) + controller_param = params[:controller] + unless controller = @controllers[controller_param] + controller_name = "#{controller_param.camelize}Controller" + controller = @controllers[controller_param] = + ActiveSupport::Dependencies.ref(controller_name) + end + + controller.get end rescue NameError => e raise ActionController::RoutingError, e.message, e.backtrace if raise_error diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index f4af763afe..16d7d25279 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -201,6 +201,7 @@ module ActionView #:nodoc: end def self.process_view_paths(value) + return value.dup if value.is_a?(PathSet) ActionView::PathSet.new(Array.wrap(value)) end diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 7021342b4a..801b08b19d 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -13,8 +13,12 @@ module ActionView mattr_accessor :registered_details self.registered_details = [] + mattr_accessor :registered_detail_setters + self.registered_detail_setters = [] + def self.register_detail(name, options = {}, &block) self.registered_details << name + self.registered_detail_setters << [name, "#{name}="] Accessors.send :define_method, :"_#{name}_defaults", &block Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{name} @@ -60,7 +64,7 @@ module ActionView @details, @details_key = { :handlers => default_handlers }, nil @frozen_formats, @skip_default_locale = false, false self.view_paths = view_paths - self.update_details(details, true) + self.initialize_details(details) end module ViewPaths @@ -116,11 +120,11 @@ module ActionView end def default_handlers #:nodoc: - @default_handlers ||= Template::Handlers.extensions + @@default_handlers ||= Template::Handlers.extensions end def handlers_regexp #:nodoc: - @handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/ + @@handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/ end end @@ -141,10 +145,13 @@ module ActionView end # Overload formats= to reject [:"*/*"] values. - def formats=(value) - value = nil if value == [:"*/*"] - value << :html if value == [:js] - super(value) + def formats=(values) + if values && values.size == 1 + value = values.first + values = nil if value == :"*/*" + values << :html if value == :js + end + super(values) end # Do not use the default locale on template lookup. @@ -170,14 +177,22 @@ module ActionView super(@skip_default_locale ? I18n.locale : _locale_defaults) end + def initialize_details(details) + details = details.dup + + registered_detail_setters.each do |key, setter| + send(setter, details[key]) + end + end + # Update the details keys by merging the given hash into the current # details hash. If a block is given, the details are modified just during # the execution of the block and reverted to the previous value after. - def update_details(new_details, force=false) + def update_details(new_details) old_details = @details.dup - registered_details.each do |key| - send(:"#{key}=", new_details[key]) if force || new_details.key?(key) + registered_detail_setters.each do |key, setter| + send(setter, new_details[key]) if new_details.key?(key) end if block_given? diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 35488c0391..6228d7ac39 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -19,7 +19,7 @@ module ActionView #:nodoc: @@default_template_handlers = nil def self.extensions - @@template_handlers.keys + @@template_extensions ||= @@template_handlers.keys end # Register a class that knows how to handle template files with the given 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