Pull mixin for extension activation into a real class
This commit is contained in:
parent
09c31b848b
commit
c0a6d8ac4c
|
@ -18,6 +18,8 @@ require 'middleman-core/logger'
|
||||||
require 'middleman-core/sitemap/store'
|
require 'middleman-core/sitemap/store'
|
||||||
|
|
||||||
require 'middleman-core/configuration'
|
require 'middleman-core/configuration'
|
||||||
|
|
||||||
|
require 'middleman-core/extension_manager'
|
||||||
require 'middleman-core/core_extensions'
|
require 'middleman-core/core_extensions'
|
||||||
|
|
||||||
require 'middleman-core/config_context'
|
require 'middleman-core/config_context'
|
||||||
|
@ -27,9 +29,6 @@ require 'middleman-core/template_renderer'
|
||||||
# Rack Request
|
# Rack Request
|
||||||
require 'middleman-core/core_extensions/request'
|
require 'middleman-core/core_extensions/request'
|
||||||
|
|
||||||
# Custom Extension API and config.rb handling
|
|
||||||
require 'middleman-core/core_extensions/extensions'
|
|
||||||
|
|
||||||
# Core Middleman Class
|
# Core Middleman Class
|
||||||
module Middleman
|
module Middleman
|
||||||
class Application
|
class Application
|
||||||
|
@ -156,8 +155,13 @@ module Middleman
|
||||||
}
|
}
|
||||||
}, 'Callbacks that can exclude paths from the sitemap'
|
}, 'Callbacks that can exclude paths from the sitemap'
|
||||||
|
|
||||||
# Activate custom features and extensions
|
define_hook :initialized
|
||||||
include Middleman::CoreExtensions::Extensions
|
define_hook :instance_available
|
||||||
|
define_hook :after_configuration
|
||||||
|
define_hook :before_configuration
|
||||||
|
|
||||||
|
config.define_setting :autoload_sprockets, true, 'Automatically load sprockets at startup?'
|
||||||
|
config[:autoload_sprockets] = (ENV['AUTOLOAD_SPROCKETS'] == 'true') if ENV['AUTOLOAD_SPROCKETS']
|
||||||
|
|
||||||
# Basic Rack Request Handling
|
# Basic Rack Request Handling
|
||||||
include Middleman::CoreExtensions::Request
|
include Middleman::CoreExtensions::Request
|
||||||
|
@ -166,9 +170,7 @@ module Middleman
|
||||||
include Middleman::CoreExtensions::Rendering
|
include Middleman::CoreExtensions::Rendering
|
||||||
|
|
||||||
# Reference to Logger singleton
|
# Reference to Logger singleton
|
||||||
def logger
|
def_delegator :"::Middleman::Logger", :singleton, :logger
|
||||||
::Middleman::Logger.singleton
|
|
||||||
end
|
|
||||||
|
|
||||||
# New container for config.rb commands
|
# New container for config.rb commands
|
||||||
attr_reader :config_context
|
attr_reader :config_context
|
||||||
|
@ -181,11 +183,19 @@ module Middleman
|
||||||
|
|
||||||
attr_reader :template_context_class
|
attr_reader :template_context_class
|
||||||
|
|
||||||
|
# Hack to get a sandboxed copy of these helpers for overriding similar methods inside Markdown renderers.
|
||||||
attr_reader :generic_template_context
|
attr_reader :generic_template_context
|
||||||
def_delegators :@generic_template_context, :link_to, :image_tag, :asset_path
|
def_delegators :@generic_template_context, :link_to, :image_tag, :asset_path
|
||||||
|
|
||||||
|
attr_reader :extensions
|
||||||
|
|
||||||
# Initialize the Middleman project
|
# Initialize the Middleman project
|
||||||
def initialize
|
def initialize(&block)
|
||||||
|
self.class.inst = self
|
||||||
|
|
||||||
|
# Search the root of the project for required files
|
||||||
|
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
||||||
|
|
||||||
@template_context_class = Class.new(Middleman::TemplateContext)
|
@template_context_class = Class.new(Middleman::TemplateContext)
|
||||||
@generic_template_context = @template_context_class.new(self)
|
@generic_template_context = @template_context_class.new(self)
|
||||||
@config_context = ConfigContext.new(self, @template_context_class)
|
@config_context = ConfigContext.new(self, @template_context_class)
|
||||||
|
@ -196,7 +206,8 @@ module Middleman
|
||||||
# Setup the default values from calls to set before initialization
|
# Setup the default values from calls to set before initialization
|
||||||
self.class.config.load_settings(self.class.superclass.config.all_settings)
|
self.class.config.load_settings(self.class.superclass.config.all_settings)
|
||||||
|
|
||||||
::Middleman::Extensions.auto_activate(:before_sitemap, self)
|
@extensions = ::Middleman::ExtensionManager.new(self)
|
||||||
|
@extensions.auto_activate(:before_sitemap)
|
||||||
|
|
||||||
# Initialize the Sitemap
|
# Initialize the Sitemap
|
||||||
@sitemap = ::Middleman::Sitemap::Store.new(self)
|
@sitemap = ::Middleman::Sitemap::Store.new(self)
|
||||||
|
@ -208,7 +219,60 @@ module Middleman
|
||||||
|
|
||||||
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
|
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
|
||||||
|
|
||||||
super
|
::Middleman::Extension.clear_after_extension_callbacks
|
||||||
|
|
||||||
|
@extensions.auto_activate(:before_configuration)
|
||||||
|
|
||||||
|
if config[:autoload_sprockets]
|
||||||
|
begin
|
||||||
|
require 'middleman-sprockets'
|
||||||
|
activate :sprockets
|
||||||
|
rescue LoadError
|
||||||
|
# It's OK if somebody is using middleman-core without middleman-sprockets
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
run_hook :initialized
|
||||||
|
|
||||||
|
run_hook :before_configuration
|
||||||
|
|
||||||
|
evaluate_configuration(&block)
|
||||||
|
|
||||||
|
run_hook :instance_available
|
||||||
|
|
||||||
|
# This is for making the tests work - since the tests
|
||||||
|
# don't completely reload middleman, I18n.load_path can get
|
||||||
|
# polluted with paths from other test app directories that don't
|
||||||
|
# exist anymore.
|
||||||
|
if ENV['TEST']
|
||||||
|
::I18n.load_path.delete_if { |path| path =~ %r{tmp/aruba} }
|
||||||
|
::I18n.reload!
|
||||||
|
end
|
||||||
|
|
||||||
|
run_hook :after_configuration
|
||||||
|
config_context.execute_after_configuration_callbacks
|
||||||
|
|
||||||
|
@extensions.activate_all
|
||||||
|
end
|
||||||
|
|
||||||
|
def evaluate_configuration(&block)
|
||||||
|
# Evaluate a passed block if given
|
||||||
|
config_context.instance_exec(&block) if block_given?
|
||||||
|
|
||||||
|
# Check for and evaluate local configuration in `config.rb`
|
||||||
|
local_config = File.join(root, 'config.rb')
|
||||||
|
if File.exist? local_config
|
||||||
|
logger.debug '== Reading: Local config'
|
||||||
|
config_context.instance_eval File.read(local_config), local_config, 1
|
||||||
|
end
|
||||||
|
|
||||||
|
env_config = File.join(root, 'environments', "#{config[:environment]}.rb")
|
||||||
|
if File.exist? env_config
|
||||||
|
logger.debug "== Reading: #{config[:environment]} config"
|
||||||
|
config_context.instance_eval File.read(env_config), env_config, 1
|
||||||
|
end
|
||||||
|
|
||||||
|
config_context.execute_configure_callbacks(config[:environment])
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_to_instance(name, &func)
|
def add_to_instance(name, &func)
|
||||||
|
|
|
@ -5,7 +5,8 @@ module Middleman
|
||||||
attr_reader :app
|
attr_reader :app
|
||||||
|
|
||||||
# Whitelist methods that can reach out.
|
# Whitelist methods that can reach out.
|
||||||
def_delegators :@app, :config, :logger, :activate, :use, :map, :mime_type, :data, :files, :root
|
def_delegators :@app, :config, :logger, :use, :map, :mime_type, :data, :files, :root
|
||||||
|
def_delegator :"@app.extensions", :activate
|
||||||
|
|
||||||
def initialize(app, template_context_class)
|
def initialize(app, template_context_class)
|
||||||
@app = app
|
@app = app
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
module Middleman
|
|
||||||
module CoreExtensions
|
|
||||||
# The Extensions core module provides basic configurability to Middleman projects:
|
|
||||||
#
|
|
||||||
# * It loads and evaluates `config.rb`.
|
|
||||||
# * It defines lifecycle hooks for extensions and `config.rb` to use.
|
|
||||||
# * It provides the {#activate} method for use in `config.rb`.
|
|
||||||
module Extensions
|
|
||||||
def self.included(app)
|
|
||||||
app.define_hook :initialized
|
|
||||||
app.define_hook :instance_available
|
|
||||||
app.define_hook :after_configuration
|
|
||||||
app.define_hook :before_configuration
|
|
||||||
|
|
||||||
app.config.define_setting :autoload_sprockets, true, 'Automatically load sprockets at startup?'
|
|
||||||
app.config[:autoload_sprockets] = (ENV['AUTOLOAD_SPROCKETS'] == 'true') if ENV['AUTOLOAD_SPROCKETS']
|
|
||||||
|
|
||||||
app.extend ClassMethods
|
|
||||||
app.def_delegator :"self.class", :configure
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
# Register a block to run only in a specific environment.
|
|
||||||
#
|
|
||||||
# @example
|
|
||||||
# # Only minify when building
|
|
||||||
# configure :production do
|
|
||||||
# activate :minify_javascript
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# @param [String, Symbol] env The environment to run in
|
|
||||||
# @return [void]
|
|
||||||
def configure(env, &block)
|
|
||||||
send("#{env}_config", &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Activate an extension, optionally passing in options.
|
|
||||||
# This method is typically used from a project's `config.rb`.
|
|
||||||
#
|
|
||||||
# @example Activate an extension with no options
|
|
||||||
# activate :lorem
|
|
||||||
#
|
|
||||||
# @example Activate an extension, with options
|
|
||||||
# activate :minify_javascript, inline: true
|
|
||||||
#
|
|
||||||
# @example Use a block to configure extension options
|
|
||||||
# activate :minify_javascript do |opts|
|
|
||||||
# opts.ignore += ['*-test.js']
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# @param [Symbol] ext_name The name of thed extension to activate
|
|
||||||
# @param [Hash] options Options to pass to the extension
|
|
||||||
# @yield [Middleman::Configuration::ConfigurationManager] Extension options that can be modified before the extension is initialized.
|
|
||||||
# @return [void]
|
|
||||||
def activate(ext_name, options={}, &block)
|
|
||||||
extension = ::Middleman::Extensions.load(ext_name)
|
|
||||||
logger.debug "== Activating: #{ext_name}"
|
|
||||||
|
|
||||||
if extension.supports_multiple_instances?
|
|
||||||
extensions[ext_name] ||= {}
|
|
||||||
key = "instance_#{extensions[ext_name].keys.length}"
|
|
||||||
extensions[ext_name][key] = extension.new(self.class, options, &block)
|
|
||||||
elsif extensions.key?(ext_name)
|
|
||||||
raise "#{ext_name} has already been activated and cannot be re-activated."
|
|
||||||
else
|
|
||||||
extensions[ext_name] = extension.new(self.class, options, &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# A hash of all activated extensions, indexed by their name. If an extension supports multiple
|
|
||||||
# instances, it will be stored as a hash of instances instead of just the instance.
|
|
||||||
#
|
|
||||||
# @return [Hash{Symbol => Middleman::Extension, Hash{String => Middleman::Extension}}]
|
|
||||||
def extensions
|
|
||||||
@extensions ||= {}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Override application initialization to load `config.rb` and to call lifecycle hooks.
|
|
||||||
def initialize(&block)
|
|
||||||
self.class.inst = self
|
|
||||||
|
|
||||||
# Search the root of the project for required files
|
|
||||||
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
|
||||||
|
|
||||||
super
|
|
||||||
|
|
||||||
::Middleman::Extension.clear_after_extension_callbacks
|
|
||||||
|
|
||||||
::Middleman::Extensions.auto_activate(:before_configuration, self)
|
|
||||||
|
|
||||||
if config[:autoload_sprockets]
|
|
||||||
begin
|
|
||||||
require 'middleman-sprockets'
|
|
||||||
activate :sprockets
|
|
||||||
rescue LoadError
|
|
||||||
# It's OK if somebody is using middleman-core without middleman-sprockets
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
run_hook :initialized
|
|
||||||
|
|
||||||
run_hook :before_configuration
|
|
||||||
|
|
||||||
# Evaluate a passed block if given
|
|
||||||
config_context.instance_exec(&block) if block_given?
|
|
||||||
|
|
||||||
# Check for and evaluate local configuration in `config.rb`
|
|
||||||
local_config = File.join(root, 'config.rb')
|
|
||||||
if File.exist? local_config
|
|
||||||
logger.debug '== Reading: Local config'
|
|
||||||
config_context.instance_eval File.read(local_config), local_config, 1
|
|
||||||
end
|
|
||||||
|
|
||||||
env_config = File.join(root, 'environments', "#{config[:environment]}.rb")
|
|
||||||
if File.exist? env_config
|
|
||||||
logger.debug "== Reading: #{config[:environment]} config"
|
|
||||||
config_context.instance_eval File.read(env_config), env_config, 1
|
|
||||||
end
|
|
||||||
|
|
||||||
config_context.execute_configure_callbacks(config[:environment])
|
|
||||||
|
|
||||||
run_hook :instance_available
|
|
||||||
|
|
||||||
# This is for making the tests work - since the tests
|
|
||||||
# don't completely reload middleman, I18n.load_path can get
|
|
||||||
# polluted with paths from other test app directories that don't
|
|
||||||
# exist anymore.
|
|
||||||
if ENV['TEST']
|
|
||||||
::I18n.load_path.delete_if { |path| path =~ %r{tmp/aruba} }
|
|
||||||
::I18n.reload!
|
|
||||||
end
|
|
||||||
|
|
||||||
run_hook :after_configuration
|
|
||||||
config_context.execute_after_configuration_callbacks
|
|
||||||
|
|
||||||
extension_instances = []
|
|
||||||
logger.debug 'Loaded extensions:'
|
|
||||||
extensions.each do |ext_name, ext|
|
|
||||||
if ext.is_a?(Hash)
|
|
||||||
ext.each do |instance_key, instance|
|
|
||||||
logger.debug "== Extension: #{ext_name} #{instance_key}"
|
|
||||||
extension_instances << instance
|
|
||||||
end
|
|
||||||
else
|
|
||||||
logger.debug "== Extension: #{ext_name}"
|
|
||||||
extension_instances << ext
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
extension_instances.each do |ext|
|
|
||||||
# Forward Extension helpers to TemplateContext
|
|
||||||
Array(ext.class.defined_helpers).each do |m|
|
|
||||||
@template_context_class.send(:include, m)
|
|
||||||
end
|
|
||||||
|
|
||||||
::Middleman::Extension.activated_extension(ext)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
73
middleman-core/lib/middleman-core/extension_manager.rb
Normal file
73
middleman-core/lib/middleman-core/extension_manager.rb
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
module Middleman
|
||||||
|
class ExtensionManager
|
||||||
|
extend Forwardable
|
||||||
|
def_delegator :"::Middleman::Logger", :singleton, :logger
|
||||||
|
def_delegators :@activated, :[]
|
||||||
|
|
||||||
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
@activated = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def auto_activate(key)
|
||||||
|
::Middleman::Extensions.auto_activate(key, @app)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Activate an extension, optionally passing in options.
|
||||||
|
# This method is typically used from a project's `config.rb`.
|
||||||
|
#
|
||||||
|
# @example Activate an extension with no options
|
||||||
|
# activate :lorem
|
||||||
|
#
|
||||||
|
# @example Activate an extension, with options
|
||||||
|
# activate :minify_javascript, inline: true
|
||||||
|
#
|
||||||
|
# @example Use a block to configure extension options
|
||||||
|
# activate :minify_javascript do |opts|
|
||||||
|
# opts.ignore += ['*-test.js']
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @param [Symbol] ext_name The name of thed extension to activate
|
||||||
|
# @param [Hash] options Options to pass to the extension
|
||||||
|
# @yield [Middleman::Configuration::ConfigurationManager] Extension options that can be modified before the extension is initialized.
|
||||||
|
# @return [void]
|
||||||
|
def activate(ext_name, options={}, &block)
|
||||||
|
extension = ::Middleman::Extensions.load(ext_name)
|
||||||
|
logger.debug "== Activating: #{ext_name}"
|
||||||
|
|
||||||
|
if extension.supports_multiple_instances?
|
||||||
|
@activated[ext_name] ||= {}
|
||||||
|
key = "instance_#{@activated[ext_name].keys.length}"
|
||||||
|
@activated[ext_name][key] = extension.new(@app.class, options, &block)
|
||||||
|
elsif @activated.key?(ext_name)
|
||||||
|
raise "#{ext_name} has already been activated and cannot be re-activated."
|
||||||
|
else
|
||||||
|
@activated[ext_name] = extension.new(@app.class, options, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def activate_all
|
||||||
|
logger.debug 'Loaded extensions:'
|
||||||
|
instances = @activated.each_with_object([]) do |(ext_name, ext), sum|
|
||||||
|
if ext.is_a?(Hash)
|
||||||
|
ext.each do |instance_key, instance|
|
||||||
|
logger.debug "== Extension: #{ext_name} #{instance_key}"
|
||||||
|
sum << instance
|
||||||
|
end
|
||||||
|
else
|
||||||
|
logger.debug "== Extension: #{ext_name}"
|
||||||
|
sum << ext
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
instances.each do |ext|
|
||||||
|
# Forward Extension helpers to TemplateContext
|
||||||
|
Array(ext.class.defined_helpers).each do |m|
|
||||||
|
@app.template_context_class.send(:include, m)
|
||||||
|
end
|
||||||
|
|
||||||
|
::Middleman::Extension.activated_extension(ext)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -116,7 +116,7 @@ module Middleman
|
||||||
@auto_activate[group].each do |descriptor|
|
@auto_activate[group].each do |descriptor|
|
||||||
next unless descriptor[:modes] == :all || descriptor[:modes].include?(app.config[:mode])
|
next unless descriptor[:modes] == :all || descriptor[:modes].include?(app.config[:mode])
|
||||||
|
|
||||||
app.activate descriptor[:name]
|
app.extensions.activate descriptor[:name]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue