Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Optimize LookupContext
  • Loading branch information
wycats committed Jun 5, 2010
1 parent 16ee4b4 commit a6b3942
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 14 deletions.
13 changes: 10 additions & 3 deletions actionpack/lib/action_dispatch/routing/route_set.rb
Expand Up @@ -12,6 +12,7 @@ class Dispatcher #:nodoc:
def initialize(options={})
@defaults = options[:defaults]
@glob_param = options.delete(:glob)
@controllers = {}
end

def call(env)
Expand All @@ -32,9 +33,15 @@ def prepare_params!(params)
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
Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_view/base.rb
Expand Up @@ -201,6 +201,7 @@ def self.xss_safe? #:nodoc:
end

def self.process_view_paths(value)
return value.dup if value.is_a?(PathSet)
ActionView::PathSet.new(Array.wrap(value))
end

Expand Down
35 changes: 25 additions & 10 deletions actionpack/lib/action_view/lookup_context.rb
Expand Up @@ -13,8 +13,12 @@ class LookupContext #:nodoc:
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}
Expand Down Expand Up @@ -60,7 +64,7 @@ def initialize(view_paths, details = {})
@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
Expand Down Expand Up @@ -116,11 +120,11 @@ def normalize_name(name, prefix) #:nodoc:
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

Expand All @@ -141,10 +145,13 @@ def freeze_formats(formats, unless_frozen=false) #:nodoc:
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.
Expand All @@ -170,14 +177,22 @@ def locale=(value)
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?
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_view/template/handlers.rb
Expand Up @@ -19,7 +19,7 @@ def self.extended(base)
@@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
Expand Down
23 changes: 23 additions & 0 deletions activesupport/lib/active_support/dependencies.rb
Expand Up @@ -47,6 +47,9 @@ module Dependencies #: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
Expand Down Expand Up @@ -476,9 +479,28 @@ def load_missing_constant(from_mod, const_name)
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.
Expand Down Expand Up @@ -572,6 +594,7 @@ def remove_constant(const) #:nodoc:

log "removing constant #{const}"
parent.instance_eval { remove_const to_remove }

return true
end

Expand Down
15 changes: 15 additions & 0 deletions activesupport/test/dependencies_test.rb
Expand Up @@ -431,6 +431,21 @@ def test_removal_from_tree_should_be_detected
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
Expand Down

0 comments on commit a6b3942

Please sign in to comment.