commit
5c75d26c86
|
@ -7,4 +7,5 @@ middleman-*/lib/**/*.rb
|
||||||
--exclude middleman-cli/lib/middleman-cli/templates/shared/
|
--exclude middleman-cli/lib/middleman-cli/templates/shared/
|
||||||
--exclude middleman-cli/lib/middleman-cli/templates/extension/
|
--exclude middleman-cli/lib/middleman-cli/templates/extension/
|
||||||
--no-private
|
--no-private
|
||||||
--hide-void-return
|
--hide-void-return
|
||||||
|
--markup=markdown
|
|
@ -5,4 +5,5 @@ lib/**/*.rb
|
||||||
--exclude lib/middleman-cli/templates/shared/
|
--exclude lib/middleman-cli/templates/shared/
|
||||||
--exclude lib/middleman-cli/templates/extension/
|
--exclude lib/middleman-cli/templates/extension/
|
||||||
--no-private
|
--no-private
|
||||||
--hide-void-return
|
--hide-void-return
|
||||||
|
--markup=markdown
|
|
@ -2,4 +2,5 @@ lib/**/*.rb
|
||||||
--exclude lib/vendored-middleman-deps/
|
--exclude lib/vendored-middleman-deps/
|
||||||
--exclude lib/middleman-core/step_definitions
|
--exclude lib/middleman-core/step_definitions
|
||||||
--no-private
|
--no-private
|
||||||
--hide-void-return
|
--hide-void-return
|
||||||
|
--markup=markdown
|
55
middleman-core/lib/middleman-core/auto_gem_extensions.rb
Normal file
55
middleman-core/lib/middleman-core/auto_gem_extensions.rb
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# Add module methods to the Middleman module that allow automatically loading
|
||||||
|
# extensions defined in gems based on the existance of a special file. This also
|
||||||
|
# adds a method for iterating over all the Gems on a system.
|
||||||
|
module Middleman
|
||||||
|
class << self
|
||||||
|
# Where to look in gems for extensions to auto-register. Since most extensions are
|
||||||
|
# called out in a Gemfile, this is really only useful for template extensions that get
|
||||||
|
# used by "middleman init".
|
||||||
|
EXTENSION_FILE = File.join('lib', 'middleman_extension.rb') unless const_defined?(:EXTENSION_FILE)
|
||||||
|
|
||||||
|
# Automatically load extensions from available RubyGems
|
||||||
|
# which contain the EXTENSION_FILE
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
def load_extensions_in_path
|
||||||
|
require 'rubygems'
|
||||||
|
|
||||||
|
extensions = rubygems_latest_specs.select do |spec|
|
||||||
|
spec_has_file?(spec, EXTENSION_FILE)
|
||||||
|
end
|
||||||
|
|
||||||
|
extensions.each do |spec|
|
||||||
|
require spec.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Backwards compatible means of finding all the latest gemspecs
|
||||||
|
# available on the system
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @return [Array] Array of latest Gem::Specification
|
||||||
|
def rubygems_latest_specs
|
||||||
|
# If newer Rubygems
|
||||||
|
if ::Gem::Specification.respond_to? :latest_specs
|
||||||
|
::Gem::Specification.latest_specs(true)
|
||||||
|
else
|
||||||
|
::Gem.source_index.latest_specs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Where a given Gem::Specification has a specific file. Used
|
||||||
|
# to discover extensions.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @param [Gem::Specification] spec
|
||||||
|
# @param [String] path Path to look for
|
||||||
|
# @return [Boolean] Whether the file exists
|
||||||
|
def spec_has_file?(spec, path)
|
||||||
|
full_path = File.join(spec.full_gem_path, path)
|
||||||
|
File.exist?(full_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -82,9 +82,11 @@ module Middleman
|
||||||
# Define a new setting, with optional default and user-friendly description.
|
# Define a new setting, with optional default and user-friendly description.
|
||||||
# Once the configuration manager is finalized, no new settings may be defined.
|
# Once the configuration manager is finalized, no new settings may be defined.
|
||||||
#
|
#
|
||||||
# @param [Symbol] key
|
# @example
|
||||||
# @param [Object] default
|
# config.define_setting :compress, false, 'Whether to compress the output'
|
||||||
# @param [String] description
|
# @param [Symbol] key The name of the option
|
||||||
|
# @param [Object] default The default value for the option
|
||||||
|
# @param [String] description A human-readable description of what the option does
|
||||||
# @return [ConfigSetting]
|
# @return [ConfigSetting]
|
||||||
def define_setting(key, default=nil, description=nil)
|
def define_setting(key, default=nil, description=nil)
|
||||||
raise "Setting #{key} doesn't exist" if @finalized
|
raise "Setting #{key} doesn't exist" if @finalized
|
||||||
|
|
|
@ -1,34 +1,3 @@
|
||||||
# Middleman provides an extension API which allows you to hook into the
|
|
||||||
# lifecycle of a page request, or static build, and manipulate the output.
|
|
||||||
# Internal to Middleman, these extensions are called "features," but we use
|
|
||||||
# the exact same API as is made available to the public.
|
|
||||||
#
|
|
||||||
# A Middleman extension looks like this:
|
|
||||||
#
|
|
||||||
# module MyExtension
|
|
||||||
# class << self
|
|
||||||
# def registered(app)
|
|
||||||
# # My Code
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# In your `config.rb`, you must load your extension (if it is not defined in
|
|
||||||
# that file) and call `activate`.
|
|
||||||
#
|
|
||||||
# require "my_extension"
|
|
||||||
# activate MyExtension
|
|
||||||
#
|
|
||||||
# This will call the `registered` method in your extension and provide you
|
|
||||||
# with the `app` parameter which is a Middleman::Application context. From here
|
|
||||||
# you can choose to respond to requests for certain paths or simply attach
|
|
||||||
# Rack middleware to the stack.
|
|
||||||
#
|
|
||||||
# The built-in features cover a wide range of functions. Some provide helper
|
|
||||||
# methods to use in your views. Some modify the output on-the-fly. And some
|
|
||||||
# apply computationally-intensive changes to your final build files.
|
|
||||||
|
|
||||||
# Namespace extensions module
|
|
||||||
module Middleman
|
module Middleman
|
||||||
module CoreExtensions
|
module CoreExtensions
|
||||||
module Extensions
|
module Extensions
|
||||||
|
@ -47,7 +16,6 @@ module Middleman
|
||||||
app.config[:autoload_sprockets] = (ENV['AUTOLOAD_SPROCKETS'] == 'true') if ENV['AUTOLOAD_SPROCKETS']
|
app.config[:autoload_sprockets] = (ENV['AUTOLOAD_SPROCKETS'] == 'true') if ENV['AUTOLOAD_SPROCKETS']
|
||||||
|
|
||||||
app.extend ClassMethods
|
app.extend ClassMethods
|
||||||
app.send :include, InstanceMethods
|
|
||||||
app.delegate :configure, to: :"self.class"
|
app.delegate :configure, to: :"self.class"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -56,121 +24,119 @@ module Middleman
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
# Add a callback to run in a specific environment
|
# Add a callback to run in a specific environment
|
||||||
#
|
#
|
||||||
# @param [String, Symbol] env The environment to run in
|
# @param [String, Symbol] env The environment to run in (:build, :development)
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def configure(env, &block)
|
def configure(env, &block)
|
||||||
send("#{env}_config", &block)
|
send("#{env}_config", &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Instance methods
|
# This method is available in the project's `config.rb`.
|
||||||
module InstanceMethods
|
# It takes a underscore-separated symbol, finds the appropriate
|
||||||
# This method is available in the project's `config.rb`.
|
# feature module and includes it.
|
||||||
# It takes a underscore-separated symbol, finds the appropriate
|
#
|
||||||
# feature module and includes it.
|
# activate :lorem
|
||||||
#
|
#
|
||||||
# activate :lorem
|
# @param [Symbol, Module] ext Which extension to activate
|
||||||
#
|
# @return [void]
|
||||||
# @param [Symbol, Module] ext Which extension to activate
|
# rubocop:disable BlockNesting
|
||||||
# @return [void]
|
def activate(ext, options={}, &block)
|
||||||
# rubocop:disable BlockNesting
|
extension = ::Middleman::Extensions.load(ext)
|
||||||
def activate(ext, options={}, &block)
|
logger.debug "== Activating: #{ext}"
|
||||||
extension = ::Middleman::Extensions.load(ext)
|
|
||||||
logger.debug "== Activating: #{ext}"
|
|
||||||
|
|
||||||
if extension.supports_multiple_instances?
|
if extension.supports_multiple_instances?
|
||||||
extensions[ext] ||= {}
|
extensions[ext] ||= {}
|
||||||
key = "instance_#{extensions[ext].keys.length}"
|
key = "instance_#{extensions[ext].keys.length}"
|
||||||
extensions[ext][key] = extension.new(self.class, options, &block)
|
extensions[ext][key] = extension.new(self.class, options, &block)
|
||||||
|
else
|
||||||
|
if extensions[ext]
|
||||||
|
raise "#{ext} has already been activated and cannot be re-activated."
|
||||||
else
|
else
|
||||||
if extensions[ext]
|
extensions[ext] = extension.new(self.class, options, &block)
|
||||||
raise "#{ext} has already been activated and cannot be re-activated."
|
end
|
||||||
else
|
end
|
||||||
extensions[ext] = extension.new(self.class, options, &block)
|
end
|
||||||
end
|
|
||||||
|
# Access activated extensions
|
||||||
|
#
|
||||||
|
# @return [Hash<Symbol,Middleman::Extension|Module>]
|
||||||
|
def extensions
|
||||||
|
@extensions ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Load features before starting server
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
|
||||||
|
self.class.inst = self
|
||||||
|
|
||||||
|
# Search the root of the project for required files
|
||||||
|
$LOAD_PATH.unshift(root)
|
||||||
|
|
||||||
|
::Middleman::Extension.clear_after_extension_callbacks
|
||||||
|
|
||||||
|
if config[:autoload_sprockets]
|
||||||
|
begin
|
||||||
|
require 'middleman-sprockets'
|
||||||
|
activate(:sprockets)
|
||||||
|
rescue LoadError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access activated extensions
|
run_hook :initialized
|
||||||
#
|
|
||||||
# @return [Hash<Symbol,Middleman::Extension|Module>]
|
run_hook :before_configuration
|
||||||
def extensions
|
|
||||||
@extensions ||= {}
|
# Check for and evaluate local configuration
|
||||||
|
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
|
end
|
||||||
|
|
||||||
# Load features before starting server
|
if build?
|
||||||
def initialize
|
run_hook :build_config
|
||||||
super
|
config_context.execute_configure_callbacks(:build)
|
||||||
|
end
|
||||||
|
|
||||||
self.class.inst = self
|
if development?
|
||||||
|
run_hook :development_config
|
||||||
|
config_context.execute_configure_callbacks(:development)
|
||||||
|
end
|
||||||
|
|
||||||
# Search the root of the project for required files
|
run_hook :instance_available
|
||||||
$LOAD_PATH.unshift(root)
|
|
||||||
|
|
||||||
::Middleman::Extension.clear_after_extension_callbacks
|
# 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
|
||||||
|
|
||||||
if config[:autoload_sprockets]
|
run_hook :after_configuration
|
||||||
begin
|
config_context.execute_after_configuration_callbacks
|
||||||
require 'middleman-sprockets'
|
|
||||||
activate(:sprockets)
|
logger.debug 'Loaded extensions:'
|
||||||
rescue LoadError
|
extensions.each do |ext, klass|
|
||||||
|
if ext.is_a?(Hash)
|
||||||
|
ext.each do |k, _|
|
||||||
|
logger.debug "== Extension: #{k}"
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
logger.debug "== Extension: #{ext}"
|
||||||
end
|
end
|
||||||
|
|
||||||
run_hook :initialized
|
if klass.is_a?(::Middleman::Extension)
|
||||||
|
# Forward Extension helpers to TemplateContext
|
||||||
run_hook :before_configuration
|
(klass.class.defined_helpers || []).each do |m|
|
||||||
|
@template_context_class.send(:include, m)
|
||||||
# Check for and evaluate local configuration
|
|
||||||
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
|
|
||||||
|
|
||||||
if build?
|
|
||||||
run_hook :build_config
|
|
||||||
config_context.execute_configure_callbacks(:build)
|
|
||||||
end
|
|
||||||
|
|
||||||
if development?
|
|
||||||
run_hook :development_config
|
|
||||||
config_context.execute_configure_callbacks(:development)
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
logger.debug 'Loaded extensions:'
|
|
||||||
extensions.each do |ext, klass|
|
|
||||||
if ext.is_a?(Hash)
|
|
||||||
ext.each do |k, _|
|
|
||||||
logger.debug "== Extension: #{k}"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
logger.debug "== Extension: #{ext}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if klass.is_a?(::Middleman::Extension)
|
::Middleman::Extension.activated_extension(klass)
|
||||||
# Forward Extension helpers to TemplateContext
|
|
||||||
(klass.class.defined_helpers || []).each do |m|
|
|
||||||
@template_context_class.send(:include, m)
|
|
||||||
end
|
|
||||||
|
|
||||||
::Middleman::Extension.activated_extension(klass)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,8 +56,6 @@ module Middleman
|
||||||
# Set the shared instance
|
# Set the shared instance
|
||||||
#
|
#
|
||||||
# @private
|
# @private
|
||||||
# @param [Middleman::Application] inst
|
|
||||||
# @return [void]
|
|
||||||
attr_writer :inst
|
attr_writer :inst
|
||||||
|
|
||||||
# Return built Rack app
|
# Return built Rack app
|
||||||
|
@ -188,7 +186,6 @@ module Middleman
|
||||||
# message.
|
# message.
|
||||||
#
|
#
|
||||||
# @param env
|
# @param env
|
||||||
# @param [Rack::Request] req
|
|
||||||
# @param [Rack::Response] res
|
# @param [Rack::Response] res
|
||||||
def process_request(env, _, res)
|
def process_request(env, _, res)
|
||||||
start_time = Time.now
|
start_time = Time.now
|
||||||
|
|
|
@ -2,64 +2,179 @@ require 'active_support/core_ext/module/delegation'
|
||||||
require 'active_support/core_ext/class/attribute'
|
require 'active_support/core_ext/class/attribute'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
|
# Middleman's Extension API provides the ability to add functionality to Middleman
|
||||||
|
# and to customize existing features. Internally, most features in Middleman are
|
||||||
|
# implemented as extensions. A good way to figure out how to write your own extension
|
||||||
|
# is to look at the source of the built-in extensions or popular extension gems like
|
||||||
|
# `middleman-blog` or `middleman-syntax`.
|
||||||
|
#
|
||||||
|
# The most basic extension looks like:
|
||||||
|
#
|
||||||
|
# class MyFeature < Middleman::Extension
|
||||||
|
# def initialize(app, options_hash={}, &block)
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# ::Middleman::Extensions.register(:my_feature, MyFeature)
|
||||||
|
#
|
||||||
|
# A more complicated example might look like:
|
||||||
|
#
|
||||||
|
# class MyFeature < Middleman::Extension
|
||||||
|
# option :my_option, 'cool', 'A very cool option'
|
||||||
|
#
|
||||||
|
# def initialize(app, options_hash={}, &block)
|
||||||
|
# super
|
||||||
|
# puts "My option is #{options.my_option}"
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def after_configuration
|
||||||
|
# puts "The project has been configured"
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def manipulate_resource_list(resources)
|
||||||
|
# resources.each do |resource|
|
||||||
|
# # Make all .jpg's get built or served with a .jpeg extension.
|
||||||
|
# if resource.ext == '.jpg'
|
||||||
|
# resource.destination_path = resource.destination_path.sub('.jpg', '.jpeg')
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# ::Middleman::Extensions.register :my_feature do
|
||||||
|
# MyFeature
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Extensions can add helpers (via {Extension.helpers}), add to the sitemap or change it (via {#manipulate_resource_list}), or run
|
||||||
|
# arbitrary code at different parts of the Middleman application's lifecycle. They can have options (defined via {Extension.option} and accessed via {#options}).
|
||||||
|
#
|
||||||
|
# Common lifecycle events can be handled by extensions simply by implementing an appropriately-named method:
|
||||||
|
#
|
||||||
|
# * {#after_configuration}
|
||||||
|
# * {#after_build}
|
||||||
|
# * {#before_build}
|
||||||
|
# * {#instance_available}
|
||||||
|
#
|
||||||
|
# There are also some less common hooks that can be listened to from within an extension's `initialize` method:
|
||||||
|
#
|
||||||
|
# * `app.before_render {|body, path, locs, template_class| ... }` - Manipulate template sources before they are rendered.
|
||||||
|
# * `app.after_render {|content, path, locs, template_class| ... }` - Manipulate output text after a template has been rendered. It is also common to install a Rack middleware to do this instead.
|
||||||
|
# * `app.ready { ... }` - Run code once Middleman is ready to serve or build files (after `after_configuration`).
|
||||||
|
# * `app.compass_config { |compass_config| ... }` - Manipulate the Compass configuration after it has been set up.
|
||||||
|
#
|
||||||
|
# @see http://middlemanapp.com/advanced/custom/ Middleman Custom Extensions Documentation
|
||||||
class Extension
|
class Extension
|
||||||
|
# @!attribute supports_multiple_instances
|
||||||
|
# @!scope class
|
||||||
|
# @return [Boolean] whether or not an extension can be activated multiple times, generating multiple instances of the extension.
|
||||||
|
# By default extensions can only be activated once in a project. This is an advanced option.
|
||||||
class_attribute :supports_multiple_instances, instance_reader: false, instance_writer: false
|
class_attribute :supports_multiple_instances, instance_reader: false, instance_writer: false
|
||||||
|
|
||||||
|
# @!attribute defined_helpers
|
||||||
|
# @!scope class
|
||||||
|
# @api private
|
||||||
|
# @return [Array<Module>] a list of all the helper modules this extension provides. Set these using {#helpers}.
|
||||||
class_attribute :defined_helpers, instance_reader: false, instance_writer: false
|
class_attribute :defined_helpers, instance_reader: false, instance_writer: false
|
||||||
|
|
||||||
|
# @!attribute ext_name
|
||||||
|
# @!scope class
|
||||||
|
# @return [Symbol] the name this extension is registered under. This is the symbol used to activate the extension.
|
||||||
class_attribute :ext_name, instance_reader: false, instance_writer: false
|
class_attribute :ext_name, instance_reader: false, instance_writer: false
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
# @api private
|
||||||
|
# @return [Middleman::Configuration::ConfigurationManager] The defined options for this extension.
|
||||||
def config
|
def config
|
||||||
@_config ||= ::Middleman::Configuration::ConfigurationManager.new
|
@_config ||= ::Middleman::Configuration::ConfigurationManager.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Add an option to this extension.
|
||||||
|
# @see Middleman::Configuration::ConfigurationManager#define_setting
|
||||||
|
# @example
|
||||||
|
# option :compress, false, 'Whether to compress the output'
|
||||||
|
# @param [Symbol] key The name of the option
|
||||||
|
# @param [Object] default The default value for the option
|
||||||
|
# @param [String] description A human-readable description of what the option does
|
||||||
def option(key, default=nil, description=nil)
|
def option(key, default=nil, description=nil)
|
||||||
config.define_setting(key, default, description)
|
config.define_setting(key, default, description)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add helpers to the global Middleman application.
|
# Declare helpers to be added the global Middleman application.
|
||||||
# This accepts either a list of modules to add on behalf
|
# This accepts either a list of modules to add on behalf
|
||||||
# of this extension, or a block whose contents will all
|
# of this extension, or a block whose contents will all
|
||||||
# be used as helpers in a new module.
|
# be used as helpers in a new module.
|
||||||
def helpers(*m, &block)
|
# @example With a block:
|
||||||
|
# helpers do
|
||||||
|
# def my_helper
|
||||||
|
# "I helped!"
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# @example With modules:
|
||||||
|
# helpers FancyHelpers, PlainHelpers
|
||||||
|
# @param [Array<Module>] modules An optional list of modules to add as helpers
|
||||||
|
# @param [Proc] block A block which will be evaluated to create a new helper module
|
||||||
|
# @return [void]
|
||||||
|
def helpers(*modules, &block)
|
||||||
self.defined_helpers ||= []
|
self.defined_helpers ||= []
|
||||||
|
|
||||||
if block_given?
|
if block_given?
|
||||||
mod = Module.new
|
mod = Module.new
|
||||||
mod.module_eval(&block)
|
mod.module_eval(&block)
|
||||||
m = [mod]
|
modules = [mod]
|
||||||
end
|
end
|
||||||
|
|
||||||
self.defined_helpers += m
|
self.defined_helpers += modules
|
||||||
end
|
|
||||||
|
|
||||||
def activate
|
|
||||||
new(::Middleman::Application)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reset all {Extension.after_extension_activated} callbacks.
|
||||||
|
# @api private
|
||||||
|
# @return [void]
|
||||||
def clear_after_extension_callbacks
|
def clear_after_extension_callbacks
|
||||||
@_extension_activation_callbacks = {}
|
@_extension_activation_callbacks = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Register to run a block after a named extension is activated.
|
||||||
|
# @param [Symbol] name The name the extension was registered under
|
||||||
|
# @param [Proc] block A callback to run when the named extension is activated
|
||||||
|
# @return [void]
|
||||||
def after_extension_activated(name, &block)
|
def after_extension_activated(name, &block)
|
||||||
@_extension_activation_callbacks ||= {}
|
@_extension_activation_callbacks ||= {}
|
||||||
@_extension_activation_callbacks[name] ||= []
|
@_extension_activation_callbacks[name] ||= []
|
||||||
@_extension_activation_callbacks[name] << block if block_given?
|
@_extension_activation_callbacks[name] << block if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Notify that a particular extension has been activated and run all
|
||||||
|
# registered {Extension.after_extension_activated} callbacks.
|
||||||
|
# @api private
|
||||||
|
# @param [Middleman::Extension] instance Activated extension instance
|
||||||
|
# @return [void]
|
||||||
def activated_extension(instance)
|
def activated_extension(instance)
|
||||||
name = instance.class.ext_name
|
name = instance.class.ext_name
|
||||||
return unless @_extension_activation_callbacks && @_extension_activation_callbacks[name]
|
return unless @_extension_activation_callbacks && @_extension_activation_callbacks.has_key?(name)
|
||||||
@_extension_activation_callbacks[name].each do |block|
|
@_extension_activation_callbacks[name].each do |block|
|
||||||
block.arity == 1 ? block.call(instance) : block.call
|
block.arity == 1 ? block.call(instance) : block.call
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_accessor :options
|
# @return [Middleman::Configuration::ConfigurationManager] options for this extension instance.
|
||||||
|
attr_reader :options
|
||||||
|
|
||||||
|
# @return [Middleman::Application] the Middleman application instance.
|
||||||
attr_reader :app
|
attr_reader :app
|
||||||
|
|
||||||
|
# @!method after_extension_activated(name, &block)
|
||||||
|
# Register to run a block after a named extension is activated.
|
||||||
|
# @param [Symbol] name The name the extension was registered under
|
||||||
|
# @param [Proc] block A callback to run when the named extension is activated
|
||||||
|
# @return [void]
|
||||||
delegate :after_extension_activated, to: :"::Middleman::Extension"
|
delegate :after_extension_activated, to: :"::Middleman::Extension"
|
||||||
|
|
||||||
|
# Extensions are instantiated when they are activated.
|
||||||
|
# @param [Class] klass The Middleman::Application class
|
||||||
|
# @param [Hash] options_hash The raw options hash. Subclasses should not manipulate this directly - it will be turned into {#options}.
|
||||||
|
# @yield An optional block that can be used to customize options before the extension is activated.
|
||||||
|
# @yieldparam [Middleman::Configuration::ConfigurationManager] options Extension options
|
||||||
def initialize(klass, options_hash={}, &block)
|
def initialize(klass, options_hash={}, &block)
|
||||||
@_helpers = []
|
@_helpers = []
|
||||||
@klass = klass
|
@klass = klass
|
||||||
|
@ -74,6 +189,39 @@ module Middleman
|
||||||
bind_after_build
|
bind_after_build
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @!method before_configuration
|
||||||
|
# Respond to the `before_configuration` event.
|
||||||
|
# If a `before_configuration` method is implemented, that method will be run before `config.rb` is run.
|
||||||
|
# @note Because most extensions are activated from within `config.rb`, they *will not run* any `before_configuration` hook.
|
||||||
|
|
||||||
|
# @!method after_configuration
|
||||||
|
# Respond to the `after_configuration` event.
|
||||||
|
# If an `after_configuration` method is implemented, that method will be run before `config.rb` is run.
|
||||||
|
|
||||||
|
# @!method before_build
|
||||||
|
# Respond to the `before_build` event.
|
||||||
|
# If an `before_build` method is implemented, that method will be run before the builder runs.
|
||||||
|
|
||||||
|
# @!method after_build
|
||||||
|
# Respond to the `after_build` event.
|
||||||
|
# If an `after_build` method is implemented, that method will be run after the builder runs.
|
||||||
|
|
||||||
|
# @!method instance_available
|
||||||
|
# Respond to the `instance_available` event.
|
||||||
|
# If an `instance_available` method is implemented, that method will be run after `config.rb` is run and after environment-specific config blocks have been run, but before any `after_configuration` callbacks.
|
||||||
|
|
||||||
|
# @!method manipulate_resource_list(resources)
|
||||||
|
# Manipulate the resource list by transforming or adding {Sitemap::Resource}s.
|
||||||
|
# Sitemap manipulation is a powerful way of interacting with a project, since it can modify each {Sitemap::Resource} or generate new {Sitemap::Resources}. This method is used in a pipeline where each sitemap manipulator is run in turn, with each one being fed the output of the previous manipulator. See the source of built-in Middleman extensions like {Middleman::Extensions::DirectoryIndexes} and {Middleman::Extensions::AssetHash} for examples of how to use this.
|
||||||
|
# @note This method *must* return the full set of resources, because its return value will be used as the new sitemap.
|
||||||
|
# @see http://middlemanapp.com/advanced/sitemap/ Sitemap Documentation
|
||||||
|
# @see Sitemap::Store
|
||||||
|
# @see Sitemap::Resource
|
||||||
|
# @param [Array<Sitemap::Resource>] resources A list of all the resources known to the sitemap.
|
||||||
|
# @return [Array<Sitemap::Resource>] The transformed list of resources.
|
||||||
|
|
||||||
|
# Assign the app instance. Used internally.
|
||||||
|
# @api private
|
||||||
def app=(app)
|
def app=(app)
|
||||||
@app = app
|
@app = app
|
||||||
|
|
||||||
|
@ -85,8 +233,10 @@ module Middleman
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
private
|
||||||
|
|
||||||
|
# @yield An optional block that can be used to customize options before the extension is activated.
|
||||||
|
# @yieldparam Middleman::Configuration::ConfigurationManager] options Extension options
|
||||||
def setup_options(options_hash)
|
def setup_options(options_hash)
|
||||||
@options = self.class.config.dup
|
@options = self.class.config.dup
|
||||||
@options.finalize!
|
@options.finalize!
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
|
require 'middleman-core/extension'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
|
# The Extensions module is used to handle global registration and loading of Middleman Extensions.
|
||||||
|
#
|
||||||
|
# The application-facing extension API (activate, etc) is in Middleman::CoreExtensions::Extensions in
|
||||||
|
# middleman-core/core_extensions/extensions.rb.
|
||||||
module Extensions
|
module Extensions
|
||||||
class << self
|
class << self
|
||||||
def registered
|
def registered
|
||||||
|
@ -66,55 +72,4 @@ module Middleman
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Where to look in gems for extensions to auto-register. Since most extensions are
|
|
||||||
# called out in a Gemfile, this is really only useful for template extensions that get
|
|
||||||
# used by "middleman init".
|
|
||||||
EXTENSION_FILE = File.join('lib', 'middleman_extension.rb') unless const_defined?(:EXTENSION_FILE)
|
|
||||||
|
|
||||||
class << self
|
|
||||||
# Automatically load extensions from available RubyGems
|
|
||||||
# which contain the EXTENSION_FILE
|
|
||||||
#
|
|
||||||
# @private
|
|
||||||
def load_extensions_in_path
|
|
||||||
require 'rubygems'
|
|
||||||
|
|
||||||
extensions = rubygems_latest_specs.select do |spec|
|
|
||||||
spec_has_file?(spec, EXTENSION_FILE)
|
|
||||||
end
|
|
||||||
|
|
||||||
extensions.each do |spec|
|
|
||||||
require spec.name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Backwards compatible means of finding all the latest gemspecs
|
|
||||||
# available on the system
|
|
||||||
#
|
|
||||||
# @private
|
|
||||||
# @return [Array] Array of latest Gem::Specification
|
|
||||||
def rubygems_latest_specs
|
|
||||||
# If newer Rubygems
|
|
||||||
if ::Gem::Specification.respond_to? :latest_specs
|
|
||||||
::Gem::Specification.latest_specs(true)
|
|
||||||
else
|
|
||||||
::Gem.source_index.latest_specs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Where a given Gem::Specification has a specific file. Used
|
|
||||||
# to discover extensions.
|
|
||||||
#
|
|
||||||
# @private
|
|
||||||
# @param [Gem::Specification] spec
|
|
||||||
# @param [String] path Path to look for
|
|
||||||
# @return [Boolean] Whether the file exists
|
|
||||||
def spec_has_file?(spec, path)
|
|
||||||
full_path = File.join(spec.full_gem_path, path)
|
|
||||||
File.exist?(full_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'middleman-core/extension'
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Core Pathname library used for traversal
|
# Core Pathname library used for traversal
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
require 'middleman-core/auto_gem_extensions'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
class << self
|
class << self
|
||||||
|
|
|
@ -57,21 +57,20 @@ module Middleman
|
||||||
app.config_context.class.send :delegate, :sitemap, to: :app
|
app.config_context.class.send :delegate, :sitemap, to: :app
|
||||||
end
|
end
|
||||||
|
|
||||||
# Register a klass which can manipulate the main site map list. Best to register
|
# Register an object which can transform the sitemap resource list. Best to register
|
||||||
# these in a before_configuration or after_configuration hook.
|
# these in a `before_configuration` or `after_configuration` hook.
|
||||||
#
|
#
|
||||||
# @param [Symbol] name Name of the manipulator for debugging
|
# @param [Symbol] name Name of the manipulator for debugging
|
||||||
# @param [Class, Module] inst Abstract namespace which can update the resource list
|
# @param [#manipulate_resource_list] manipulator Resource list manipulator
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def register_resource_list_manipulator(name, inst, *)
|
def register_resource_list_manipulator(name, manipulator, *)
|
||||||
@resource_list_manipulators << [name, inst]
|
@resource_list_manipulators << [name, manipulator]
|
||||||
rebuild_resource_list!(:registered_new)
|
rebuild_resource_list!(:registered_new)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rebuild the list of resources from scratch, using registed manipulators
|
# Rebuild the list of resources from scratch, using registed manipulators
|
||||||
# rubocop:disable UnusedMethodArgument
|
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def rebuild_resource_list!(reason=nil)
|
def rebuild_resource_list!(_=nil)
|
||||||
@lock.synchronize do
|
@lock.synchronize do
|
||||||
@needs_sitemap_rebuild = true
|
@needs_sitemap_rebuild = true
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,7 +60,6 @@ module Middleman
|
||||||
# Sinatra/Padrino compatible render method signature referenced by some view
|
# Sinatra/Padrino compatible render method signature referenced by some view
|
||||||
# helpers. Especially partials.
|
# helpers. Especially partials.
|
||||||
#
|
#
|
||||||
# @param [String, Symbol] engine
|
|
||||||
# @param [String, Symbol] data
|
# @param [String, Symbol] data
|
||||||
# @param [Hash] options
|
# @param [Hash] options
|
||||||
# @return [String]
|
# @return [String]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
lib/**/*.rb
|
lib/**/*.rb
|
||||||
--exclude lib/middleman-templates
|
--exclude lib/middleman-templates
|
||||||
--no-private
|
--no-private
|
||||||
--hide-void-return
|
--hide-void-return
|
||||||
|
--markup=markdown
|
Loading…
Reference in a new issue