# 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 CoreExtensions module Extensions # Register extension class << self # @private def registered(app) app.define_hook :initialized app.define_hook :after_configuration app.define_hook :before_configuration app.define_hook :build_config app.define_hook :development_config 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.send :include, InstanceMethods app.delegate :configure, :to => :"self.class" end alias :included :registered end # Class methods module ClassMethods # Add a callback to run in a specific environment # # @param [String, Symbol] env The environment to run in # @return [void] def configure(env, &block) send("#{env}_config", &block) end # Register a new extension # # @param [Module] extension Extension modules to register # @param [Hash] options Per-extension options hash # @return [void] def register(extension, options={}, &block) extend extension if extension.respond_to?(:registered) if extension.method(:registered).arity === 1 extension.registered(self, &block) else extension.registered(self, options, &block) end end extension end end # Instance methods module InstanceMethods # This method is available in the project's `config.rb`. # It takes a underscore-separated symbol, finds the appropriate # feature module and includes it. # # activate :lorem # # @param [Symbol, Module] ext Which extension to activate # @return [void] def activate(ext, options={}, &block) ext_module = if ext.is_a?(Module) ext else ::Middleman::Extensions.load(ext) end if ext_module.nil? logger.error "== Unknown Extension: #{ext}" else logger.debug "== Activating: #{ext}" if ext_module.instance_of? Module extensions[ext] = self.class.register(ext_module, options, &block) elsif ext_module.instance_of?(Class) && ext_module.ancestors.include?(::Middleman::Extension) if ext_module.supports_multiple_instances? extensions[ext] ||= {} key = "instance_#{extensions[ext].keys.length}" extensions[ext][key] = ext_module.new(self.class, options, &block) else if extensions[ext] logger.error "== #{ext} already activated." else extensions[ext] = ext_module.new(self.class, options, &block) end end end end end # Access activated extensions # # @return [Hash] def extensions @extensions ||= {} end # Load features before starting server def initialize super self.class.inst = self run_hook :before_configuration # Search the root of the project for required files $LOAD_PATH.unshift(root) if config[:autoload_sprockets] begin require "middleman-sprockets" activate(:sprockets) rescue LoadError end end # Check for and evaluate local configuration local_config = File.join(root, "config.rb") if File.exists? local_config logger.debug "== Reading: Local config" instance_eval File.read(local_config), local_config, 1 end run_hook :build_config if build? run_hook :development_config if development? run_hook :initialized run_hook :after_configuration logger.debug "Loaded extensions:" self.extensions.each do |ext,_| if ext.is_a?(Hash) ext.each do |k,_| logger.debug "== Extension: #{k}" end else logger.debug "== Extension: #{ext}" end end end end end end end