Add the ability for plugins to set default configuration settings.

This commit is contained in:
Carl Lerche 2009-12-15 22:07:12 -08:00
parent f0bbc647c2
commit 1b27f5c4f7
7 changed files with 142 additions and 18 deletions

@ -3,9 +3,11 @@
require 'active_support'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/logger'
require 'action_dispatch'
require 'rails/initializable'
require 'rails/application'
require 'rails/plugin'
require 'rails/railties_path'
require 'rails/version'
require 'rails/rack'
@ -14,7 +16,6 @@
require 'rails/configuration'
require 'rails/deprecation'
require 'rails/initializer'
require 'rails/plugin'
require 'rails/ruby_version_check'
# For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
@ -29,4 +30,4 @@
Encoding.default_external = Encoding::UTF_8
end
RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV)
RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV)

@ -13,7 +13,11 @@ def new
end
def config
@config ||= Configuration.new
@config ||= begin
config = Configuration.new
Plugin.plugins.each { |p| config.merge(p.config) }
config
end
end
# TODO: change the plugin loader to use config
@ -104,6 +108,8 @@ def initializers
def plugins
@plugins ||= begin
plugin_names = config.plugins || [:all]
Plugin.plugins.select { |p| plugin_names.include?(p.plugin_name) } +
Plugin::Vendored.all(config.plugins || [:all], config.paths.vendor.plugins)
end
end

@ -1,10 +1,54 @@
require 'active_support/ordered_options'
module Rails
class Configuration
attr_accessor :action_controller, :action_mailer, :action_view,
:active_record, :active_resource, :active_support,
:after_initialize_blocks, :cache_classes,
# Temporarily separate the plugin configuration class from the main
# configuration class while this bit is being cleaned up.
class Plugin::Configuration
def initialize
@options = Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new }
end
def middleware
@middleware ||= ActionDispatch::MiddlewareStack.new
end
def respond_to?(name)
super || name.to_s =~ config_key_regexp
end
def merge(config)
@options = config.options.merge(@options)
end
protected
attr_reader :options
private
def method_missing(name, *args, &blk)
if name.to_s =~ config_key_regexp
return $2 == '=' ? @options[$1] = args.first : @options[$1]
end
super
end
def config_key_regexp
bits = config_keys.map { |n| Regexp.escape(n.to_s) }.join('|')
/^(#{bits})(?:=)?$/
end
def config_keys
([ :active_support, :active_record, :action_controller,
:action_view, :action_mailer, :active_resource ] +
Plugin.plugin_names).map { |n| n.to_s }.uniq
end
end
class Configuration < Plugin::Configuration
attr_accessor :after_initialize_blocks, :cache_classes,
:consider_all_requests_local, :dependency_loading, :gems,
:load_once_paths, :logger, :metals, :plugins,
:preload_frameworks, :reload_plugins, :serve_static_assets,
@ -17,15 +61,11 @@ class Configuration
:view_path
def initialize
super
@load_once_paths = []
@after_initialize_blocks = []
@dependency_loading = true
@serve_static_assets = true
for framework in frameworks
self.send("#{framework}=", ActiveSupport::OrderedOptions.new)
end
self.active_support = ActiveSupport::OrderedOptions.new
end
def after_initialize(&blk)
@ -84,7 +124,10 @@ def threadsafe!
self.preload_frameworks = true
self.cache_classes = true
self.dependency_loading = false
self.action_controller.allow_concurrency = true
if respond_to?(:action_controller)
action_controller.allow_concurrency = true
end
self
end
@ -103,11 +146,6 @@ def framework_root_path
defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root}/vendor/rails"
end
def middleware
require 'action_dispatch'
@middleware ||= ActionDispatch::MiddlewareStack.new
end
# Loads and returns the contents of the #database_configuration_file. The
# contents of the file are processed via ERB before being sent through
# YAML::load.

@ -2,6 +2,27 @@ module Rails
class Plugin
include Initializable
def self.plugin_name
@plugin_name || name.demodulize.underscore
end
def self.inherited(klass)
@plugins ||= []
@plugins << klass unless klass == Vendored
end
def self.plugins
@plugins
end
def self.plugin_names
plugins.map { |p| p.plugin_name }
end
def self.config
@config ||= Configuration.new
end
class Vendored < Plugin
def self.all(list, paths)
plugins = []

@ -53,5 +53,26 @@ def setup
assert_raises(NoMethodError) { 1.day }
end
end
test "marking the application as threadsafe sets the correct config variables" do
add_to_config <<-RUBY
config.threadsafe!
RUBY
require "#{app_path}/config/application"
assert AppTemplate.configuration.action_controller.allow_concurrency
end
test "the application can be marked as threadsafe when there are no frameworks" do
FileUtils.rm_rf("#{app_path}/config/environments")
add_to_config <<-RUBY
config.frameworks = []
config.threadsafe!
RUBY
assert_nothing_raised do
require "#{app_path}/config/application"
end
end
end
end

@ -6,6 +6,7 @@ class InitializerTest < Test::Unit::TestCase
def setup
build_app
FileUtils.rm_rf("#{app_path}/config/environments")
boot_rails
require "rails"
end

@ -0,0 +1,36 @@
require "isolation/abstract_unit"
module PluginsTest
class ConfigurationTest < Test::Unit::TestCase
def setup
build_app
boot_rails
require "rails"
end
test "config is available to plugins" do
class Foo < Rails::Plugin ; end
assert_nil Foo.config.action_controller.foo
end
test "a config name is available for the plugin" do
class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end
assert_equal "hello", Foo.config.foo.greetings
end
test "plugin configurations are available in the application" do
class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end
require "#{app_path}/config/application"
assert_equal "hello", AppTemplate.config.foo.greetings
end
test "plugin config merges are deep" do
class Foo < Rails::Plugin ; config.foo.greetings = 'hello' ; end
class MyApp < Rails::Application
config.foo.bar = "bar"
end
assert_equal "hello", MyApp.config.foo.greetings
assert_equal "bar", MyApp.config.foo.bar
end
end
end