mirror of
https://github.com/middleman/middleman.git
synced 2022-11-09 12:20:27 -05:00
Improve documentation for Middleman::Extension
This commit is contained in:
parent
6515f01800
commit
b79a74b35b
10 changed files with 179 additions and 55 deletions
|
@ -8,3 +8,4 @@ middleman-*/lib/**/*.rb
|
||||||
--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
|
|
@ -6,3 +6,4 @@ lib/**/*.rb
|
||||||
--exclude lib/middleman-cli/templates/extension/
|
--exclude lib/middleman-cli/templates/extension/
|
||||||
--no-private
|
--no-private
|
||||||
--hide-void-return
|
--hide-void-return
|
||||||
|
--markup=markdown
|
|
@ -3,3 +3,4 @@ lib/**/*.rb
|
||||||
--exclude lib/middleman-core/step_definitions
|
--exclude lib/middleman-core/step_definitions
|
||||||
--no-private
|
--no-private
|
||||||
--hide-void-return
|
--hide-void-return
|
||||||
|
--markup=markdown
|
|
@ -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
|
||||||
|
|
|
@ -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,60 +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
|
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
|
||||||
|
@ -70,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
|
||||||
|
|
||||||
|
@ -83,6 +235,8 @@ module Middleman
|
||||||
|
|
||||||
private
|
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!
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -2,3 +2,4 @@ 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