1
0
Fork 0
mirror of https://github.com/middleman/middleman.git synced 2022-11-09 12:20:27 -05:00

build a config file jail

This commit is contained in:
Thomas Reynolds 2013-12-31 18:21:30 -08:00
parent 2e2415612a
commit c95c924d53
26 changed files with 553 additions and 613 deletions

View file

@ -1,12 +1,16 @@
set :layout, false
module ExtensionA
class << self
def registered(app, options={})
app.set :a_options, options
class ExtensionA < ::Middleman::Extension
helpers do
def get_option(key)
extensions[:extension_a].options[key]
end
alias :included :registered
end
option :hello, '', ''
option :hola, '', ''
end
activate ExtensionA, :hello => "world", :hola => "mundo"
ExtensionA.register
activate :extension_a, :hello => "world", :hola => "mundo"

View file

@ -1,3 +1,2 @@
<% a_options.each do |k, v| %>
<%= k %>: <%= v%>
<% end %>
hello: <%= get_option(:hello) %>
hola: <%= get_option(:hola) %>

View file

@ -1,9 +1,17 @@
class ExtensionOne < ::Middleman::Extension
helpers do
def extension_two_was_activated
extensions[:extension_one].extension_two_was_activated
end
end
attr_reader :extension_two_was_activated
def initialize(app, options_hash={})
super
after_extension_activated :extension_two do
app.set :extension_two_was_activated, true
@extension_two_was_activated = true
end
end
end
@ -11,11 +19,19 @@ end
ExtensionOne.register
class ExtensionTwo < ::Middleman::Extension
helpers do
def extension_one_was_activated
extensions[:extension_two].extension_one_was_activated
end
end
attr_reader :extension_one_was_activated
def initialize(app, options_hash={})
super
after_extension_activated :extension_one do
app.set :extension_one_was_activated, true
@extension_one_was_activated = true
end
end
end

View file

@ -20,10 +20,13 @@ require 'vendored-middleman-deps/hooks-0.2.0/lib/hooks'
require 'middleman-core/logger'
require 'middleman-core/sitemap'
require 'middleman-core/sitemap/store'
require 'middleman-core/configuration'
require 'middleman-core/core_extensions'
require 'middleman-core/config_context'
# Core Middleman Class
module Middleman
class Application
@ -150,48 +153,52 @@ module Middleman
# extensions see updated frontmatter!
register Middleman::CoreExtensions::FrontMatter
# Sitemap
# Sitemap Config options and public api
register Middleman::Sitemap
# Setup external helpers
register Middleman::CoreExtensions::ExternalHelpers
# with_layout and page routing
include Middleman::CoreExtensions::Routing
# Reference to Logger singleton
attr_reader :logger
# New container for config.rb commands
attr_reader :config_context
# Reference to Sitemap
attr_reader :sitemap
# Template cache
attr_reader :cache
# Initialize the Middleman project
def initialize(&block)
@cache = ::Tilt::Cache.new
@logger = ::Middleman::Logger.singleton
# Clear the static class cache
cache.clear
@config_context = ConfigContext.new(self)
# Setup the default values from calls to set before initialization
self.class.config.load_settings(self.class.superclass.config.all_settings)
# Initialize the Sitemap
@sitemap = ::Middleman::Sitemap::Store.new(self)
if Object.const_defined?(:Encoding)
Encoding.default_internal = config[:encoding]
Encoding.default_external = config[:encoding]
end
# Evaluate a passed block if given
instance_exec(&block) if block_given?
@config_context.instance_exec(&block) if block_given?
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
super
end
# Shared cache instance
#
# @private
# @return [Middleman::Util::Cache] The cache
def self.cache
@_cache ||= ::Tilt::Cache.new
def add_to_config_context(name, &func)
@config_context.define_singleton_method(name, &func)
end
delegate :cache, :to => :"self.class"
# Whether we're in development mode
# @return [Boolean] If we're in dev mode

View file

@ -68,6 +68,7 @@ module Middleman::Cli
action BuildAction.new(self, opts)
self.class.shared_instance.run_hook :after_build, self
self.class.shared_instance.config_context.execute_after_build_callbacks(self)
if self.had_errors && !self.debugging
msg = 'There were errors during this build'
@ -110,7 +111,7 @@ module Middleman::Cli
def initialize(base, config={})
@app = base.class.shared_instance
@source_dir = Pathname(@app.source_dir)
@build_dir = Pathname(@app.build_dir)
@build_dir = Pathname(@app.config[:build_dir])
@to_clean = Set.new
@logger = @app.logger
@ -190,7 +191,7 @@ module Middleman::Cli
logger.debug '== Checking for Compass sprites'
# Double-check for compass sprites
@app.files.find_new_files((@source_dir + @app.images_dir).relative_path_from(@app.root_path))
@app.files.find_new_files((@source_dir + @app.config[:images_dir]).relative_path_from(@app.root_path))
@app.sitemap.ensure_resource_list_updated!
# Sort paths to be built by the above order. This is primarily so Compass can

View file

@ -29,7 +29,7 @@ module Middleman::Cli
@app =::Middleman::Application.server.inst do
if opts[:environment]
set :environment, opts[:environment].to_sym
config[:environment] = opts[:environment].to_sym
end
logger(opts[:debug] ? 0 : 1, opts[:instrumenting] || false)

View file

@ -0,0 +1,66 @@
module Middleman
class ConfigContext
# with_layout and page routing
include Middleman::CoreExtensions::Routing
attr_reader :app
# Whitelist methods that can reach out.
delegate :config, :logger, :activate, :use, :map, :mime_type, :data, :helpers, :template_extensions, :root, :to => :app
def initialize(app)
@app = app
@ready_callbacks = []
@after_build_callbacks = []
@after_configuration_callbacks = []
@configure_callbacks = {}
end
def ready(&block)
@ready_callbacks << block
end
def execute_ready_callbacks
@ready_callbacks.each do |b|
instance_exec(&b)
end
end
def after_build(&block)
@after_build_callbacks << block
end
def execute_after_build_callbacks(*args)
@after_build_callbacks.each do |b|
instance_exec(*args, &b)
end
end
def after_configuration(&block)
@after_configuration_callbacks << block
end
def execute_after_configuration_callbacks
@after_configuration_callbacks.each do |b|
instance_exec(&b)
end
end
def configure(key, &block)
@configure_callbacks[key] ||= []
@configure_callbacks[key] << block
end
def execute_configure_callbacks(key)
@configure_callbacks[key] ||= []
@configure_callbacks[key].each do |b|
instance_exec(&b)
end
end
def set(key, default=nil, &block)
config.define_setting(key, default) unless config.defines_setting?(key)
@app.config[key] = block_given? ? block : default
end
end
end

View file

@ -5,6 +5,7 @@ module Middleman
module Global
def self.included(app)
app.send :extend, ClassMethods
app.send :delegate, :config, :to => :"self.class"
end
module ClassMethods
@ -13,75 +14,6 @@ module Middleman
def config
@_config ||= ConfigurationManager.new
end
# Set attributes (global variables)
#
# @deprecated Prefer accessing settings through "config".
#
# @param [Symbol] key Name of the attribue
# @param default Attribute value
# @return [void]
def set(key, default=nil, &block)
config.define_setting(key, default) unless config.defines_setting?(key)
@inst.set(key, default, &block) if @inst
end
# Access global settings as methods, to preserve compatibility with
# old Middleman.
#
# @deprecated Prefer accessing settings through "config".
def method_missing(method, *args)
if config.defines_setting? method
config[method]
else
super
end
end
# Needed so that method_missing makes sense
def respond_to?(method, include_private = false)
super || config.defines_setting?(method)
end
end
def config
self.class.config
end
# Backwards compatibilty with old Sinatra template interface
#
# @deprecated Prefer accessing settings through "config".
#
# @return [ConfigurationManager]
alias :settings :config
# Set attributes (global variables)
#
# @deprecated Prefer accessing settings through "config".
#
# @param [Symbol] key Name of the attribue
# @param value Attribute value
# @return [void]
def set(key, value=nil, &block)
value = block if block_given?
config[key] = value
end
# Access global settings as methods, to preserve compatibility with
# old Middleman.
#
# @deprecated Prefer accessing settings through "config".
def method_missing(method, *args)
if config.defines_setting? method
config[method]
else
super
end
end
# Needed so that method_missing makes sense
def respond_to?(method, include_private = false)
super || config.defines_setting?(method)
end
end

View file

@ -159,11 +159,18 @@ module Middleman
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
config_context.instance_eval File.read(local_config), local_config, 1
end
run_hook :build_config if build?
run_hook :development_config if development?
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
@ -177,6 +184,7 @@ module Middleman
end
run_hook :after_configuration
config_context.execute_after_configuration_callbacks
logger.debug 'Loaded extensions:'
self.extensions.each do |ext, klass|

View file

@ -51,6 +51,7 @@ module Middleman
@inst ||= begin
mm = new(&block)
mm.run_hook :ready
mm.config_context.execute_ready_callbacks
mm
end
end

View file

@ -2,69 +2,72 @@
module Middleman
module CoreExtensions
module Routing
# Takes a block which allows many pages to have the same layout
#
# with_layout :admin do
# page "/admin/"
# page "/admin/login.html"
# end
#
# @param [String, Symbol] layout_name
# @return [void]
def with_layout(layout_name, &block)
old_layout = config[:layout]
config[:layout] = layout_name
instance_exec(&block) if block_given?
ensure
config[:layout] = old_layout
# Sandboxed layout to implement temporary overriding of layout.
class LayoutBlock
attr_reader :scope
def initialize(scope, layout_name)
@scope = scope
@layout_name = layout_name
end
# The page method allows the layout to be set on a specific path
#
# page "/about.html", :layout => false
# page "/", :layout => :homepage_layout
#
# @param [String] url
# @param [Hash] opts
# @return [void]
def page(url, opts={}, &block)
blocks = Array(block)
opts[:layout] ||= @layout_name
@scope.page(url, opts, &block)
end
# Default layout
opts[:layout] = config[:layout] if opts[:layout].nil?
delegate :proxy, :to => :scope
end
# If the url is a regexp
if url.is_a?(Regexp) || url.include?('*')
# Takes a block which allows many pages to have the same layout
#
# with_layout :admin do
# page "/admin/"
# page "/admin/login.html"
# end
#
# @param [String, Symbol] layout_name
# @return [void]
def with_layout(layout_name, &block)
LayoutBlock.new(self, layout_name).instance_eval(&block)
end
# Use the metadata loop for matching against paths at runtime
sitemap.provides_metadata_for_path(url) do |_|
{ :options => opts, :blocks => blocks }
end
return
end
# The page method allows the layout to be set on a specific path
#
# page "/about.html", :layout => false
# page "/", :layout => :homepage_layout
#
# @param [String] url
# @param [Hash] opts
# @return [void]
def page(url, opts={}, &block)
# Default layout
opts[:layout] = @app.config[:layout] if opts[:layout].nil?
metadata = { :options => opts, :blocks => Array(block) }
# If the url is a regexp
unless url.is_a?(Regexp) || url.include?('*')
# Normalized path
url = '/' + Middleman::Util.normalize_path(url)
if url.end_with?('/') || File.directory?(File.join(source_dir, url))
url = File.join(url, config[:index_file])
if url.end_with?('/') || File.directory?(File.join(@app.source_dir, url))
url = File.join(url, @app.config[:index_file])
end
# Setup proxy
if target = opts.delete(:proxy)
# TODO: deprecate proxy through page?
proxy(url, target, opts, &block) and return
@app.proxy(url, target, opts, &block)
return
elsif opts.delete(:ignore)
# TODO: deprecate ignore through page?
ignore(url)
end
# Setup a metadata matcher for rendering those options
sitemap.provides_metadata_for_path(url) do |_|
{ :options => opts, :blocks => blocks }
@app.ignore(url)
end
end
# Setup a metadata matcher for rendering those options
@app.sitemap.provides_metadata_for_path(url) { |_| metadata }
end
end
end
end

View file

@ -12,8 +12,9 @@ module Middleman
# Once registered
def registered(app)
# Default less options
app.set :styl, {}
# Default stylus options
app.config.define_setting :styl, {}, 'Stylus config options'
app.before_configuration do
template_extensions :styl => :css

View file

@ -1,12 +1,3 @@
require 'middleman-core/sitemap/store'
require 'middleman-core/sitemap/resource'
require 'middleman-core/sitemap/extensions/on_disk'
require 'middleman-core/sitemap/extensions/redirects'
require 'middleman-core/sitemap/extensions/request_endpoints'
require 'middleman-core/sitemap/extensions/proxies'
require 'middleman-core/sitemap/extensions/ignores'
# Core Sitemap Extensions
module Middleman
@ -18,11 +9,6 @@ module Middleman
# Once registered
def registered(app)
app.register Middleman::Sitemap::Extensions::RequestEndpoints
app.register Middleman::Sitemap::Extensions::Proxies
app.register Middleman::Sitemap::Extensions::Ignores
app.register Middleman::Sitemap::Extensions::Redirects
# Set to automatically convert some characters into a directory
app.config.define_setting :automatic_directory_matcher, nil, 'Set to automatically convert some characters into a directory'
@ -46,11 +32,6 @@ module Middleman
# Include instance methods
app.send :include, InstanceMethods
# Initialize Sitemap
app.before_configuration do
sitemap
end
end
alias :included :registered
@ -59,12 +40,6 @@ module Middleman
# Sitemap instance methods
module InstanceMethods
# Get the sitemap class instance
# @return [Middleman::Sitemap::Store]
def sitemap
@_sitemap ||= Store.new(self)
end
# Get the resource object for the current path
# @return [Middleman::Sitemap::Resource]
def current_page

View file

@ -4,87 +4,61 @@ module Middleman
module Extensions
module Ignores
# Class to handle managing ignores
class Ignores
def initialize(sitemap)
@app = sitemap.app
@app.add_to_config_context :ignore, &method(:create_ignore)
@app.define_singleton_method(:ignore, &method(:create_ignore))
# Setup extension
class << self
# Array of callbacks which can ass ignored
@ignored_callbacks = []
# Once registered
def registered(app)
# Include methods
app.send :include, InstanceMethods
::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods
end
alias :included :registered
sitemap.define_singleton_method(:ignored?, &method(:ignored?))
::Middleman::Sitemap::Resource.send :include, IgnoreResourceInstanceMethods
end
# Helpers methods for Resources
module ResourceInstanceMethods
# Whether the Resource is ignored
# @return [Boolean]
def ignored?
@app.ignore_manager.ignored?(path) ||
(!proxy? &&
@app.ignore_manager.ignored?(source_file.sub("#{@app.source_dir}/", ''))
)
end
end
# Ignore-related instance methods
module InstanceMethods
def ignore_manager
@_ignore_manager ||= IgnoreManager.new(self)
end
# Ignore a path or add an ignore callback
# @param [String, Regexp] path Path glob expression, or path regex
# @return [void]
def ignore(path=nil, &block)
ignore_manager.ignore(path, &block)
end
end
# Class to handle managing ignores
class IgnoreManager
def initialize(app)
@app = app
# Array of callbacks which can ass ignored
@ignored_callbacks = []
end
# Ignore a path or add an ignore callback
# @param [String, Regexp] path Path glob expression, or path regex
# @return [void]
def ignore(path=nil, &block)
if path.is_a? Regexp
@ignored_callbacks << Proc.new {|p| p =~ path }
elsif path.is_a? String
path_clean = ::Middleman::Util.normalize_path(path)
if path_clean.include?('*') # It's a glob
@ignored_callbacks << Proc.new {|p| File.fnmatch(path_clean, p) }
else
# Add a specific-path ignore unless that path is already covered
return if ignored?(path_clean)
@ignored_callbacks << Proc.new {|p| p == path_clean }
end
elsif block_given?
@ignored_callbacks << block
end
@app.sitemap.invalidate_resources_not_ignored_cache!
end
# Whether a path is ignored
# @param [String] path
# @return [Boolean]
def ignored?(path)
# Ignore a path or add an ignore callback
# @param [String, Regexp] path Path glob expression, or path regex
# @return [void]
def create_ignore(path=nil, &block)
if path.is_a? Regexp
@ignored_callbacks << Proc.new {|p| p =~ path }
elsif path.is_a? String
path_clean = ::Middleman::Util.normalize_path(path)
@ignored_callbacks.any? { |b| b.call(path_clean) }
if path_clean.include?('*') # It's a glob
@ignored_callbacks << Proc.new {|p| File.fnmatch(path_clean, p) }
else
# Add a specific-path ignore unless that path is already covered
return if ignored?(path_clean)
@ignored_callbacks << Proc.new {|p| p == path_clean }
end
elsif block_given?
@ignored_callbacks << block
end
@app.sitemap.invalidate_resources_not_ignored_cache!
end
# Whether a path is ignored
# @param [String] path
# @return [Boolean]
def ignored?(path)
path_clean = ::Middleman::Util.normalize_path(path)
@ignored_callbacks.any? { |b| b.call(path_clean) }
end
end
# Helpers methods for Resources
module IgnoreResourceInstanceMethods
# Whether the Resource is ignored
# @return [Boolean]
def ignored?
@app.sitemap.ignored?(path) ||
(!proxy? &&
@app.sitemap.ignored?(source_file.sub("#{@app.source_dir}/", ''))
)
end
end
end

View file

@ -4,165 +4,143 @@ module Middleman
module Extensions
module Proxies
# Manages the list of proxy configurations and manipulates the sitemap
# to include new resources based on those configurations
class Proxies
def initialize(sitemap)
@app = sitemap.app
@app.add_to_config_context :proxy, &method(:create_proxy)
@app.define_singleton_method(:proxy, &method(:create_proxy))
# Setup extension
class << self
@proxy_configs = Set.new
# Once registered
def registered(app)
::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods
# Include methods
app.send :include, InstanceMethods
end
alias :included :registered
::Middleman::Sitemap::Resource.send :include, ProxyResourceInstanceMethods
end
module ResourceInstanceMethods
# Whether this page is a proxy
# @return [Boolean]
def proxy?
!!@proxied_to
# Setup a proxy from a path to a target
# @param [String] path
# @param [String] target
# @param [Hash] opts options to apply to the proxy, including things like
# :locals, :ignore to hide the proxy target, :layout, and :directory_indexes.
# @return [void]
def create_proxy(path, target, opts={}, &block)
metadata = { :options => {}, :locals => {}, :blocks => [] }
metadata[:blocks] << block if block_given?
metadata[:locals] = opts.delete(:locals) || {}
@app.ignore(target) if opts.delete(:ignore)
metadata[:options] = opts
@proxy_configs << ProxyConfiguration.new(:path => path, :target => target, :metadata => metadata)
@app.sitemap.rebuild_resource_list!(:added_proxy)
end
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
resources + @proxy_configs.map do |config|
p = ::Middleman::Sitemap::Resource.new(
@app.sitemap,
config.path
)
p.proxy_to(config.target)
p.add_metadata(config.metadata)
p
end
end
end
# Set this page to proxy to a target path
# @param [String] target
# @return [void]
def proxy_to(target)
target = ::Middleman::Util.normalize_path(target)
raise "You can't proxy #{path} to itself!" if target == path
@proxied_to = target
end
# Configuration for a proxy instance
class ProxyConfiguration
# The path that this proxy will appear at in the sitemap
attr_reader :path
def path=(p)
@path = ::Middleman::Util.normalize_path(p)
end
# The path of the page this page is proxied to, or nil if it's not proxied.
# @return [String]
def proxied_to
@proxied_to
end
# The existing sitemap path that this will proxy to
attr_reader :target
def target=(t)
@target = ::Middleman::Util.normalize_path(t)
end
# The resource for the page this page is proxied to. Throws an exception
# if there is no resource.
# @return [Sitemap::Resource]
def proxied_to_resource
proxy_resource = store.find_resource_by_path(proxied_to)
# Additional metadata like blocks and locals to apply to the proxy
attr_accessor :metadata
unless proxy_resource
raise "Path #{path} proxies to unknown file #{proxied_to}:#{store.resources.map(&:path)}"
end
if proxy_resource.proxy?
raise "You can't proxy #{path} to #{proxied_to} which is itself a proxy."
end
proxy_resource
end
def get_source_file
if proxy?
proxied_to_resource.source_file
else
super
end
end
def content_type
mime_type = super
return mime_type if mime_type
if proxy?
proxied_to_resource.content_type
else
nil
end
# Create a new proxy configuration from hash options
def initialize(options={})
options.each do |key, value|
send "#{key}=", value
end
end
module InstanceMethods
def proxy_manager
@_proxy_manager ||= ProxyManager.new(self)
# Two configurations are equal if they reference the same path
def eql?(other)
other.path == path
end
# Two configurations are equal if they reference the same path
def hash
path.hash
end
end
module ProxyResourceInstanceMethods
# Whether this page is a proxy
# @return [Boolean]
def proxy?
!!@proxied_to
end
# Set this page to proxy to a target path
# @param [String] target
# @return [void]
def proxy_to(target)
target = ::Middleman::Util.normalize_path(target)
raise "You can't proxy #{path} to itself!" if target == path
@proxied_to = target
end
# The path of the page this page is proxied to, or nil if it's not proxied.
# @return [String]
def proxied_to
@proxied_to
end
# The resource for the page this page is proxied to. Throws an exception
# if there is no resource.
# @return [Sitemap::Resource]
def proxied_to_resource
proxy_resource = store.find_resource_by_path(proxied_to)
unless proxy_resource
raise "Path #{path} proxies to unknown file #{proxied_to}:#{store.resources.map(&:path)}"
end
def proxy(*args, &block)
proxy_manager.proxy(*args, &block)
if proxy_resource.proxy?
raise "You can't proxy #{path} to #{proxied_to} which is itself a proxy."
end
proxy_resource
end
def get_source_file
if proxy?
proxied_to_resource.source_file
else
super
end
end
# Manages the list of proxy configurations and manipulates the sitemap
# to include new resources based on those configurations
class ProxyManager
def initialize(app)
@app = app
@proxy_configs = Set.new
end
def content_type
mime_type = super
return mime_type if mime_type
# Setup a proxy from a path to a target
# @param [String] path
# @param [String] target
# @param [Hash] opts options to apply to the proxy, including things like
# :locals, :ignore to hide the proxy target, :layout, and :directory_indexes.
# @return [void]
def proxy(path, target, opts={}, &block)
metadata = { :options => {}, :locals => {}, :blocks => [] }
metadata[:blocks] << block if block_given?
metadata[:locals] = opts.delete(:locals) || {}
@app.ignore(target) if opts.delete(:ignore)
metadata[:options] = opts
@proxy_configs << ProxyConfiguration.new(:path => path, :target => target, :metadata => metadata)
@app.sitemap.rebuild_resource_list!(:added_proxy)
end
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
resources + @proxy_configs.map do |config|
p = ::Middleman::Sitemap::Resource.new(
@app.sitemap,
config.path
)
p.proxy_to(config.target)
p.add_metadata(config.metadata)
p
end
end
end
# Configuration for a proxy instance
class ProxyConfiguration
# The path that this proxy will appear at in the sitemap
attr_reader :path
def path=(p)
@path = ::Middleman::Util.normalize_path(p)
end
# The existing sitemap path that this will proxy to
attr_reader :target
def target=(t)
@target = ::Middleman::Util.normalize_path(t)
end
# Additional metadata like blocks and locals to apply to the proxy
attr_accessor :metadata
# Create a new proxy configuration from hash options
def initialize(options={})
options.each do |key, value|
send "#{key}=", value
end
end
# Two configurations are equal if they reference the same path
def eql?(other)
other.path == path
end
# Two configurations are equal if they reference the same path
def hash
path.hash
if proxy?
proxied_to_resource.content_type
else
nil
end
end
end

View file

@ -1,126 +1,105 @@
require 'middleman-core/sitemap/resource'
module Middleman
module Sitemap
module Extensions
module Redirects
# Manages the list of proxy configurations and manipulates the sitemap
# to include new resources based on those configurations
class Redirects
def initialize(sitemap)
@app = sitemap.app
@app.add_to_config_context :redirect, &method(:create_redirect)
# Setup extension
class << self
# Once registered
def registered(app)
# Include methods
app.send :include, InstanceMethods
end
alias :included :registered
@redirects = {}
end
module InstanceMethods
def redirect_manager
@_redirect_manager ||= RedirectManager.new(self)
# Setup a redirect from a path to a target
# @param [String] path
# @param [Hash] opts The :to value gives a target path
def create_redirect(path, opts={}, &block)
if block_given?
opts[:template] = block
end
def redirect(*args, &block)
redirect_manager.create_redirect(*args, &block)
@redirects[path] = opts
@app.sitemap.rebuild_resource_list!(:added_redirect)
end
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
resources + @redirects.map do |path, opts|
r = RedirectResource.new(
@app.sitemap,
path,
opts[:to]
)
r.output = opts[:template] if opts[:template]
r
end
end
end
class RedirectResource < ::Middleman::Sitemap::Resource
attr_accessor :output
def initialize(store, path, target)
@request_path = target
super(store, path)
end
def template?
true
end
def render(*args, &block)
url = ::Middleman::Util.url_for(store.app, @request_path, {
:relative => false,
:find_resource => true
})
if output
output.call(path, url)
else
<<-END
<html>
<head>
<meta http-equiv=refresh content="0; url=#{url}" />
<meta name="robots" content="noindex,follow" />
<meta http-equiv="cache-control" content="no-cache" />
</head>
<body>
</body>
</html>
END
end
end
# Manages the list of proxy configurations and manipulates the sitemap
# to include new resources based on those configurations
class RedirectManager
def initialize(app)
@app = app
@redirects = {}
end
# def request_path
# @request_path
# end
# Setup a redirect from a path to a target
# @param [String] path
# @param [Hash] opts The :to value gives a target path
def create_redirect(path, opts={}, &block)
if block_given?
opts[:template] = block
end
@redirects[path] = opts
@app.sitemap.rebuild_resource_list!(:added_redirect)
end
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
resources + @redirects.map do |path, opts|
r = RedirectResource.new(
@app.sitemap,
path,
opts[:to]
)
r.output = opts[:template] if opts[:template]
r
end
end
def binary?
false
end
class RedirectResource < ::Middleman::Sitemap::Resource
attr_accessor :output
def initialize(store, path, target)
@request_path = target
super(store, path)
end
def template?
true
end
def render(*args, &block)
url = ::Middleman::Util.url_for(store.app, @request_path, {
:relative => false,
:find_resource => true
})
if output
output.call(path, url)
else
<<-END
<html>
<head>
<meta http-equiv=refresh content="0; url=#{url}" />
<meta name="robots" content="noindex,follow" />
<meta http-equiv="cache-control" content="no-cache" />
</head>
<body>
</body>
</html>
END
end
end
# def request_path
# @request_path
# end
def binary?
false
end
def raw_data
{}
end
def ignored?
false
end
def metadata
@local_metadata.dup
end
def raw_data
{}
end
def ignored?
false
end
def metadata
@local_metadata.dup
end
end
end
end

View file

@ -4,110 +4,87 @@ module Middleman
module Extensions
module RequestEndpoints
# Setup extension
class << self
# Once registered
def registered(app)
# Include methods
app.send :include, InstanceMethods
end
alias :included :registered
end
module InstanceMethods
def endpoint_manager
@_endpoint_manager ||= EndpointManager.new(self)
end
def endpoint(*args, &block)
endpoint_manager.create_endpoint(*args, &block)
end
end
class RequestEndpoints
# Manages the list of proxy configurations and manipulates the sitemap
# to include new resources based on those configurations
class EndpointManager
def initialize(app)
@app = app
@endpoints = {}
end
def initialize(sitemap)
@app = sitemap.app
@app.add_to_config_context :endpoint, &method(:create_endpoint)
# Setup a proxy from a path to a target
# @param [String] path
# @param [Hash] opts The :path value gives a request path if it
# differs from the output path
def create_endpoint(path, opts={}, &block)
endpoint = {
:request_path => path
}
if block_given?
endpoint[:output] = block
else
endpoint[:request_path] = opts[:path] if opts.has_key?(:path)
end
@endpoints[path] = endpoint
@app.sitemap.rebuild_resource_list!(:added_endpoint)
end
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
resources + @endpoints.map do |path, config|
r = EndpointResource.new(
@app.sitemap,
path,
config[:request_path]
)
r.output = config[:output] if config.has_key?(:output)
r
end
end
@endpoints = {}
end
class EndpointResource < ::Middleman::Sitemap::Resource
attr_accessor :output
# Setup a proxy from a path to a target
# @param [String] path
# @param [Hash] opts The :path value gives a request path if it
# differs from the output path
def create_endpoint(path, opts={}, &block)
endpoint = {
:request_path => path
}
def initialize(store, path, source_file)
@request_path = ::Middleman::Util.normalize_path(source_file)
super(store, path)
if block_given?
endpoint[:output] = block
else
endpoint[:request_path] = opts[:path] if opts.has_key?(:path)
end
def template?
true
end
@endpoints[path] = endpoint
def render(*args, &block)
return self.output.call if self.output
end
@app.sitemap.rebuild_resource_list!(:added_endpoint)
end
def request_path
@request_path
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
resources + @endpoints.map do |path, config|
r = EndpointResource.new(
@app.sitemap,
path,
config[:request_path]
)
r.output = config[:output] if config.has_key?(:output)
r
end
end
end
def binary?
false
end
class EndpointResource < ::Middleman::Sitemap::Resource
attr_accessor :output
def raw_data
{}
end
def initialize(store, path, source_file)
@request_path = ::Middleman::Util.normalize_path(source_file)
def ignored?
false
end
super(store, path)
end
def metadata
@local_metadata.dup
end
def template?
true
end
def render(*args, &block)
return self.output.call if self.output
end
def request_path
@request_path
end
def binary?
false
end
def raw_data
{}
end
def ignored?
false
end
def metadata
@local_metadata.dup
end
end
end

View file

@ -9,12 +9,12 @@ module Middleman
# @return [Middleman::Sitemap::Resource, nil]
def parent
parts = path.split('/')
parts.pop if path.include?(app.index_file)
parts.pop if path.include?(app.config[:index_file])
return nil if parts.length < 1
parts.pop
parts << app.index_file
parts << app.config[:index_file]
parent_path = '/' + parts.join('/')
@ -30,7 +30,7 @@ module Middleman
base_path = eponymous_directory_path
prefix = %r|^#{base_path.sub("/", "\\/")}|
else
base_path = path.sub("#{app.index_file}", '')
base_path = path.sub("#{app.config[:index_file]}", '')
prefix = %r|^#{base_path.sub("/", "\\/")}|
end
@ -43,7 +43,7 @@ module Middleman
if parts.length == 1
true
elsif parts.length == 2
parts.last == app.index_file
parts.last == app.config[:index_file]
else
false
end
@ -61,14 +61,14 @@ module Middleman
# Whether this resource either a directory index, or has the same name as an existing directory in the source
# @return [Boolean]
def directory_index?
path.include?(app.index_file) || path =~ /\/$/ || eponymous_directory?
path.include?(app.config[:index_file]) || path =~ /\/$/ || eponymous_directory?
end
# Whether the resource has the same name as a directory in the source
# (e.g., if the resource is named 'gallery.html' and a path exists named 'gallery/', this would return true)
# @return [Boolean]
def eponymous_directory?
if !path.end_with?("/#{app.index_file}") && destination_path.end_with?("/#{app.index_file}")
if !path.end_with?("/#{app.config[:index_file]}") && destination_path.end_with?("/#{app.config[:index_file]}")
return true
end
full_path = File.join(app.source_dir, eponymous_directory_path)

View file

@ -149,11 +149,11 @@ module Middleman
# @return [String]
def url
url_path = destination_path
if app.strip_index_file
url_path = url_path.sub(/(^|\/)#{Regexp.escape(app.index_file)}$/,
app.trailing_slash ? '/' : '')
if app.config[:strip_index_file]
url_path = url_path.sub(/(^|\/)#{Regexp.escape(app.config[:index_file])}$/,
app.config[:trailing_slash] ? '/' : '')
end
File.join(app.respond_to?(:http_prefix) ? app.http_prefix : '/', url_path)
File.join(app.config[:http_prefix], url_path)
end
# Whether the source file is binary.

View file

@ -3,6 +3,13 @@ require 'active_support/core_ext/hash/deep_merge'
require 'monitor'
require 'middleman-core/sitemap/queryable'
# Extensions
require 'middleman-core/sitemap/extensions/on_disk'
require 'middleman-core/sitemap/extensions/redirects'
require 'middleman-core/sitemap/extensions/request_endpoints'
require 'middleman-core/sitemap/extensions/proxies'
require 'middleman-core/sitemap/extensions/ignores'
module Middleman
# Sitemap namespace
@ -29,21 +36,31 @@ module Middleman
@_cached_metadata = {}
@resource_list_manipulators = []
@needs_sitemap_rebuild = true
@lock = Monitor.new
reset_lookup_cache!
# Register classes which can manipulate the main site map list
register_resource_list_manipulator(:on_disk, Middleman::Sitemap::Extensions::OnDisk.new(self))
# Handle ignore commands
Middleman::Sitemap::Extensions::Ignores.new(self)
# Request Endpoints
register_resource_list_manipulator(:request_endpoints, @app.endpoint_manager)
# Extensions
{
# Register classes which can manipulate the main site map list
on_disk: Middleman::Sitemap::Extensions::OnDisk,
# Proxies
register_resource_list_manipulator(:proxies, @app.proxy_manager)
# Request Endpoints
request_endpoints: Middleman::Sitemap::Extensions::RequestEndpoints,
# Redirects
register_resource_list_manipulator(:redirects, @app.redirect_manager)
# Proxies
proxies: Middleman::Sitemap::Extensions::Proxies,
# Redirects
redirects: Middleman::Sitemap::Extensions::Redirects
}.each do |k, m|
register_resource_list_manipulator(k, m.new(self))
end
app.config_context.class.send :delegate, :sitemap, :to => :app
end
# Register a klass which can manipulate the main site map list. Best to register

View file

@ -24,7 +24,9 @@ end
Given /^"([^\"]*)" is set to "([^\"]*)"$/ do |variable, value|
@initialize_commands ||= []
@initialize_commands << lambda { set(variable.to_sym, value) }
@initialize_commands << lambda {
config[variable.to_sym] = value
}
end
Given /^current environment is "([^\"]*)"$/ do |env|
@ -44,8 +46,8 @@ Given /^the Server is running$/ do
initialize_commands = @initialize_commands || []
initialize_commands.unshift lambda {
set :environment, @current_env || :development
set :show_exceptions, false
config[:environment] = @current_env || :development
config[:show_exceptions] = false
}
@server_inst = Middleman::Application.server.inst do

View file

@ -105,8 +105,8 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
def auto_tag(asset_ext, asset_dir=nil)
if asset_dir.nil?
asset_dir = case asset_ext
when :js then js_dir
when :css then css_dir
when :js then config[:js_dir]
when :css then config[:css_dir]
end
end
@ -153,10 +153,10 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
def asset_path(kind, source)
return source if source.to_s.include?('//') || source.to_s.start_with?('data:')
asset_folder = case kind
when :css then css_dir
when :js then js_dir
when :images then images_dir
when :fonts then fonts_dir
when :css then config[:css_dir]
when :js then config[:js_dir]
when :images then config[:images_dir]
when :fonts then config[:fonts_dir]
else kind.to_s
end
source = source.to_s.tr(' ', '')

View file

@ -20,7 +20,7 @@ class Middleman::Extensions::AutomaticImageSizes < ::Middleman::Extension
params[:alt] ||= ''
real_path = path
real_path = File.join(images_dir, real_path) unless real_path.start_with?('/')
real_path = File.join(config[:images_dir], real_path) unless real_path.start_with?('/')
full_path = File.join(source_dir, real_path)
if File.exists?(full_path)

View file

@ -8,7 +8,7 @@ class Middleman::Extensions::CacheBuster < ::Middleman::Extension
app.compass_config do |config|
config.asset_cache_buster do |path, real_path|
real_path = real_path.path if real_path.is_a? File
real_path = real_path.gsub(File.join(root, build_dir), source)
real_path = real_path.gsub(File.join(app.root, app.config[:build_dir]), app.config[:source])
if File.readable?(real_path)
File.mtime(real_path).strftime('%s')
else
@ -35,7 +35,7 @@ class Middleman::Extensions::CacheBuster < ::Middleman::Extension
real_path_static = File.join(prefix, path)
if build?
real_path_dynamic = File.join(build_dir, prefix, path)
real_path_dynamic = File.join(config[:build_dir], prefix, path)
real_path_dynamic = File.expand_path(real_path_dynamic, root)
http_path << '?' + File.mtime(real_path_dynamic).strftime('%s') if File.readable?(real_path_dynamic)
elsif resource = sitemap.find_resource_by_path(real_path_static)

View file

@ -3,7 +3,7 @@ class Middleman::Extensions::DirectoryIndexes < ::Middleman::Extension
# Update the main sitemap resource list
# @return [void]
def manipulate_resource_list(resources)
index_file = app.index_file
index_file = app.config[:index_file]
new_index_path = "/#{index_file}"
resources.each do |resource|

View file

@ -23,7 +23,7 @@ class Middleman::Extensions::Gzip < ::Middleman::Extension
def after_build(builder)
num_threads = 4
paths = ::Middleman::Util.all_files_under(app.build_dir)
paths = ::Middleman::Util.all_files_under(app.config[:build_dir])
total_savings = 0
# Fill a queue with inputs