Merge pull request #861 from bhollis/extensions

A bunch of extensions and config meta pages work
This commit is contained in:
Ben Hollis 2013-04-13 16:38:17 -07:00
commit a2f0cc263a
10 changed files with 126 additions and 98 deletions

View file

@ -165,16 +165,12 @@ module Middleman
# mode and no new settings may be defined. # mode and no new settings may be defined.
def finalize! def finalize!
@finalized = true @finalized = true
self
end end
# Deep duplicate of the configuration manager # Deep duplicate of the configuration manager
def dup def dup
copy = ConfigurationManager.new ConfigurationManager.new.tap {|c| c.load_settings(self.all_settings) }
@settings.each do |key, setting|
copy_setting = copy.define_setting(setting.key, setting.default, setting.description)
copy_setting.value = setting.value if setting.value_set?
end
copy
end end
# Load in a list of settings # Load in a list of settings

View file

@ -62,22 +62,12 @@ module Middleman
send("#{env}_config", &block) send("#{env}_config", &block)
end end
# Alias `extensions` to access registered extensions
#
# @return [Array<Module>]
def extensions
@extensions ||= []
end
# Register a new extension # Register a new extension
# #
# @param [Module] extension Extension modules to register # @param [Module] extension Extension modules to register
# @param [Hash] options Per-extension options hash # @param [Hash] options Per-extension options hash
# @return [void] # @return [void]
def register(extension, options={}, &block) def register(extension, options={}, &block)
@extensions ||= []
@extensions += [extension]
if extension.instance_of? Module if extension.instance_of? Module
extend extension extend extension
if extension.respond_to?(:registered) if extension.respond_to?(:registered)
@ -87,6 +77,7 @@ module Middleman
extension.registered(self, options, &block) extension.registered(self, options, &block)
end end
end end
extension
elsif extension.instance_of?(Class) && extension.ancestors.include?(::Middleman::Extension) elsif extension.instance_of?(Class) && extension.ancestors.include?(::Middleman::Extension)
extension.new(self, options, &block) extension.new(self, options, &block)
end end
@ -107,17 +98,24 @@ module Middleman
ext_module = if ext.is_a?(Module) ext_module = if ext.is_a?(Module)
ext ext
else else
::Middleman::Extensions.load(ext.to_sym) ::Middleman::Extensions.load(ext)
end end
if ext_module.nil? if ext_module.nil?
logger.error "== Unknown Extension: #{ext}" logger.error "== Unknown Extension: #{ext}"
else else
logger.debug "== Activating: #{ext}" logger.debug "== Activating: #{ext}"
self.class.register(ext_module, options, &block) extensions[ext] = self.class.register(ext_module, options, &block)
end end
end end
# Access activated extensions
#
# @return [Hash<Symbol,Middleman::Extension|Module>]
def extensions
@extensions ||= {}
end
# Load features before starting server # Load features before starting server
def initialize def initialize
super super
@ -149,7 +147,7 @@ module Middleman
run_hook :after_configuration run_hook :after_configuration
logger.debug "Loaded extensions:" logger.debug "Loaded extensions:"
self.class.extensions.each do |ext| self.extensions.each do |ext,_|
logger.debug "== Extension: #{ext}" logger.debug "== Extension: #{ext}"
end end
end end

View file

@ -37,15 +37,7 @@ module Middleman
# #
# @private # @private
def reset! def reset!
@app = nil @rack_app = nil
end
# The shared Rack instance being build
#
# @private
# @return [Rack::Builder]
def app
@app ||= ::Rack::Builder.new
end end
# Get the static instance # Get the static instance
@ -74,21 +66,23 @@ module Middleman
# @private # @private
# @return [Rack::Builder] # @return [Rack::Builder]
def to_rack_app(&block) def to_rack_app(&block)
inner_app = inst(&block) @rack_app ||= begin
app = ::Rack::Builder.new
app.use Rack::Lint
app.use Rack::Lint Array(@middleware).each do |klass, options, blockm|
app.use(klass, *options, &block)
end
(@middleware || []).each do |m| inner_app = inst(&block)
app.use(m[0], *m[1], &m[2]) app.map("/") { run inner_app }
Array(@mappings).each do |path, block|
app.map(path, &block)
end
app
end end
app.map("/") { run inner_app }
(@mappings || []).each do |m|
app.map(m[0], &m[1])
end
app
end end
# Prototype app. Used in config.ru # Prototype app. Used in config.ru

View file

@ -114,15 +114,15 @@ module Middleman
attr_accessor :app, :options attr_accessor :app, :options
def initialize(klass, options_hash={}, &block) def initialize(klass, options_hash={})
@options = ::Middleman::Configuration::ConfigurationManager.new @options = self.class.config.dup
@options.load_settings(self.class.config.all_settings) @options.finalize!
options_hash.each do |k, v| options_hash.each do |k, v|
@options[k] = v @options[k] = v
end end
block.call(@options) if block_given? yield @options if block_given?
ext = self ext = self
klass.after_configuration do klass.after_configuration do
@ -132,7 +132,6 @@ module Middleman
end end
def after_configuration def after_configuration
nil nil
end end
end end

View file

@ -45,7 +45,7 @@ module Middleman
# Inspect the sitemap # Inspect the sitemap
def sitemap(env) def sitemap(env)
resources = @middleman.sitemap.resources(true) resources = @middleman.inst.sitemap.resources(true)
sitemap_tree = SitemapTree.new sitemap_tree = SitemapTree.new
@ -58,7 +58,8 @@ module Middleman
# Inspect configuration # Inspect configuration
def config(env) def config(env)
template('config.html.erb', :config => @middleman.config)
template('config.html.erb', :config => @middleman.inst.config, :extensions => @middleman.inst.extensions, :registered_extensions => Middleman::Extensions.registered.dup)
end end
private private

View file

@ -10,10 +10,11 @@
<h1>Middleman Config</h1> <h1>Middleman Config</h1>
<a href="../">More meta pages</a> <a href="../">More meta pages</a>
<h2>Core Configuration</h2>
<ul> <ul>
<% config.all_settings.each do |setting| %> <% config.all_settings.each do |setting| %>
<li> <li>
<b><%= setting.key %></b>: <b><%= setting.key.inspect %></b>:
<%= setting.value.inspect %> <%= setting.value.inspect %>
<% if setting.value_set? %> <% if setting.value_set? %>
<br> <br>
@ -26,6 +27,44 @@
</li> </li>
<% end %> <% end %>
</ul> </ul>
<h2>Extensions</h2>
<ul>
<% extensions.each do |ext_name, extension| %>
<li>
<% registered_extensions.delete(ext_name) %>
<b><%= ext_name.inspect %></b> (Active)
<% if extension.is_a?(::Middleman::Extension) && !extension.options.all_settings.empty? %>
<br>
<b>Options:</b>
<br>
<ul>
<% extension.options.all_settings.each do |setting| %>
<li>
<b><%= setting.key.inspect %></b>:
<%= setting.value.inspect %>
<% if setting.value_set? %>
<br>
Default: <%= setting.default.inspect %>
<% else %>
(Default)
<% end %>
<br>
<i><%= setting.description %></i>
</li>
<% end %>
</ul>
<% end %>
</li>
<% end %>
<% registered_extensions.keys.each do |ext_name| %>
<li><b><%= ext_name.inspect %></b> (Inactive)</li>
<% end %>
</ul>
</body> </body>
</html> </html>

View file

@ -19,6 +19,7 @@ module Middleman
mount_instance mount_instance
logger.info "== The Middleman is standing watch at http://#{host}:#{port}" logger.info "== The Middleman is standing watch at http://#{host}:#{port}"
logger.info "== Inspect your site configuration at http://#{host}:#{port}/__middleman/"
@initialized ||= false @initialized ||= false
unless @initialized unless @initialized
@ -77,7 +78,15 @@ module Middleman
private private
def new_app def new_app
opts = @options opts = @options
@app =::Middleman::Application.server.inst do server = ::Middleman::Application.server
# Add in the meta pages application
meta_app = Middleman::MetaPages::Application.new(server)
server.map '/__middleman' do
run meta_app
end
@app = server.inst do
if opts[:environment] if opts[:environment]
config[:environment] = opts[:environment].to_sym config[:environment] = opts[:environment].to_sym
end end
@ -166,13 +175,6 @@ module Middleman
start_file_watcher start_file_watcher
rack_app = app.class.to_rack_app rack_app = app.class.to_rack_app
# Add in the meta pages application
meta_app = Middleman::MetaPages::Application.new(app.class.inst)
rack_app.map '/__middleman' do
run meta_app
end
@webrick.mount "/", ::Rack::Handler::WEBrick, rack_app @webrick.mount "/", ::Rack::Handler::WEBrick, rack_app
end end

View file

@ -2,42 +2,39 @@
require "middleman-core" require "middleman-core"
# Extension namespace # Extension namespace
module MyExtension module MyExtension < Middleman::Extension
class << self option :my_option, "default", "An example option"
# Called when user `activate`s your extension def initialize(app, options_hash={})
def registered(app, options={}) # Call super to build options from the options_hash
# Include class methods super
# app.extend ClassMethods
# Include instance methods # Require libraries only when activated
# app.send :include, InstanceMethods # require 'necessary/library'
app.after_configuration do # Include helpers or instance methods for the Middleman app
# Do something # app.send :include, Helpers
end
end # set up your extension
alias :included :registered # puts options.my_option
end end
# module ClassMethods def after_configuration
# def a_class_method # Do something
# end end
# end
# module InstanceMethods # module Helpers
# def an_instance_method # def a_helper
# end # end
# end # end
end end
# Register extensions which can be activated # Register extensions which can be activated
# Make sure we have the version of Middleman we expect # Make sure we have the version of Middleman we expect
# ::Middleman::Extensions.register(:extension_name) do # ::Middleman::Extensions.register(:extension_name) do
# #
# # Return the extension module # # Return the extension class
# ::MyExtension # ::MyExtension
# #
# end # end

View file

@ -83,7 +83,7 @@ module Middleman
# to avoid browser caches failing to update to your new content. # to avoid browser caches failing to update to your new content.
Middleman::Extensions.register(:asset_hash) do Middleman::Extensions.register(:asset_hash) do
require "middleman-more/extensions/asset_hash" require "middleman-more/extensions/asset_hash"
Middleman::Extensions::AssetHash Middleman::Extensions::AssetHash::Extension
end end
# AssetHost allows you to setup multiple domains to host your static # AssetHost allows you to setup multiple domains to host your static

View file

@ -1,27 +1,29 @@
module Middleman module Middleman
module Extensions module Extensions
module AssetHash module AssetHash
class << self class Extension < ::Middleman::Extension
def registered(app, options={}) option :exts, %w(.jpg .jpeg .png .gif .js .css .otf .woff .eot .ttf .svg), "List of extensions that get asset hashes appended to them."
option :ignore, [], "Regexes of filenames to skip adding asset hashes to"
def initialize(app, options_hash={})
super
require 'digest/sha1' require 'digest/sha1'
require 'rack/test' require 'rack/test'
require 'uri' require 'uri'
exts = options[:exts] || %w(.jpg .jpeg .png .gif .js .css .otf .woff .eot .ttf .svg)
# Allow specifying regexes to ignore, plus always ignore apple touch icons
ignore = Array(options[:ignore]) << /^apple-touch-icon/
app.ready do
sitemap.register_resource_list_manipulator(
:asset_hash,
AssetHashManager.new(self, exts, ignore)
)
use Middleware, :exts => exts, :middleman_app => self, :ignore => ignore
end
end end
alias :included :registered
def after_configuration
# Allow specifying regexes to ignore, plus always ignore apple touch icons
ignore = Array(options.ignore) + [/^apple-touch-icon/]
app.sitemap.register_resource_list_manipulator(
:asset_hash,
AssetHashManager.new(app, options.exts, ignore)
)
app.use Middleware, :exts => options.exts, :middleman_app => app, :ignore => ignore
end
end end
# Central class for managing asset_hash extension # Central class for managing asset_hash extension
@ -38,6 +40,7 @@ module Middleman
# Process resources in order: binary images and fonts, then SVG, then JS/CSS. # Process resources in order: binary images and fonts, then SVG, then JS/CSS.
# This is so by the time we get around to the text files (which may reference # This is so by the time we get around to the text files (which may reference
# images and fonts) the static assets' hashes are already calculated. # images and fonts) the static assets' hashes are already calculated.
rack_client = ::Rack::Test::Session.new(@app.class.to_rack_app)
resources.sort_by do |a| resources.sort_by do |a|
if %w(.svg).include? a.ext if %w(.svg).include? a.ext
0 0
@ -51,7 +54,6 @@ module Middleman
next if @ignore.any? { |ignore| Middleman::Util.path_match(ignore, resource.destination_path) } next if @ignore.any? { |ignore| Middleman::Util.path_match(ignore, resource.destination_path) }
# Render through the Rack interface so middleware and mounted apps get a shot # Render through the Rack interface so middleware and mounted apps get a shot
rack_client = ::Rack::Test::Session.new(@app.class)
response = rack_client.get(URI.escape(resource.destination_path), {}, { "bypass_asset_hash" => "true" }) response = rack_client.get(URI.escape(resource.destination_path), {}, { "bypass_asset_hash" => "true" })
raise "#{resource.path} should be in the sitemap!" unless response.status == 200 raise "#{resource.path} should be in the sitemap!" unless response.status == 200