Turn routing into an extension
This commit is contained in:
parent
213c672969
commit
bf8f02d563
|
@ -1,10 +1,5 @@
|
||||||
require 'middleman-core/core_extensions/routing'
|
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
class ConfigContext
|
class ConfigContext
|
||||||
# page routing
|
|
||||||
include Middleman::CoreExtensions::Routing
|
|
||||||
|
|
||||||
attr_reader :app
|
attr_reader :app
|
||||||
|
|
||||||
# Whitelist methods that can reach out.
|
# Whitelist methods that can reach out.
|
||||||
|
|
|
@ -45,6 +45,12 @@ Middleman::Extensions.register :lorem, auto_activate: :before_configuration do
|
||||||
Middleman::Extensions::Lorem
|
Middleman::Extensions::Lorem
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Middleman::Extensions.register :routing, auto_activate: :before_configuration do
|
||||||
|
require 'middleman-core/core_extensions/routing'
|
||||||
|
Middleman::CoreExtensions::Routing
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Setup Optional Extensions
|
# Setup Optional Extensions
|
||||||
###
|
###
|
||||||
|
|
|
@ -105,6 +105,9 @@ module Middleman
|
||||||
|
|
||||||
run_hook :before_configuration
|
run_hook :before_configuration
|
||||||
|
|
||||||
|
# Evaluate a passed block if given
|
||||||
|
config_context.instance_exec(&block) if block_given?
|
||||||
|
|
||||||
# Check for and evaluate local configuration in `config.rb`
|
# Check for and evaluate local configuration in `config.rb`
|
||||||
local_config = File.join(root, 'config.rb')
|
local_config = File.join(root, 'config.rb')
|
||||||
if File.exist? local_config
|
if File.exist? local_config
|
||||||
|
|
|
@ -1,16 +1,55 @@
|
||||||
# Routing extension
|
# Routing extension
|
||||||
module Middleman
|
module Middleman
|
||||||
module CoreExtensions
|
module CoreExtensions
|
||||||
module Routing
|
class Routing < Extension
|
||||||
# The page method allows the layout to be set on a specific path
|
# This should always run late, but not as late as :directory_indexes,
|
||||||
|
# so it can add metadata to any pages generated by other extensions
|
||||||
|
self.resource_list_manipulator_priority = 90
|
||||||
|
|
||||||
|
def initialize(app, options_hash={}, &block)
|
||||||
|
super
|
||||||
|
|
||||||
|
@page_configs = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def before_configuration
|
||||||
|
app.add_to_config_context :page, &method(:page)
|
||||||
|
end
|
||||||
|
|
||||||
|
def manipulate_resource_list(resources)
|
||||||
|
resources.each do |resource|
|
||||||
|
@page_configs.each do |matcher, metadata|
|
||||||
|
case matcher
|
||||||
|
when Regexp
|
||||||
|
next unless resource.path =~ matcher
|
||||||
|
when String
|
||||||
|
next unless File.fnmatch('/' + Util.strip_leading_slash(matcher), "/#{resource.path}")
|
||||||
|
end
|
||||||
|
|
||||||
|
resource.add_metadata metadata
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# The page method allows options to be set for a given source path, regex, or glob.
|
||||||
|
# Options that may be set include layout, locals, proxy, andx ignore.
|
||||||
#
|
#
|
||||||
# page "/about.html", layout: false
|
# @example
|
||||||
# page "/", layout: :homepage_layout
|
# page '/about.html', layout: false
|
||||||
|
# @example
|
||||||
|
# page '/index.html', layout: :homepage_layout
|
||||||
|
# @example
|
||||||
|
# page '/foo.html', locals: { foo: 'bar' }
|
||||||
#
|
#
|
||||||
# @param [String] url
|
# @param [String, Regexp] path A source path, or a Regexp/glob that can match multiple resources.
|
||||||
# @param [Hash] opts
|
# @params [Hash] opts Options to apply to all matching resources. Undocumented options are passed on as page metadata to be used by extensions.
|
||||||
|
# @option opts [Symbol, Boolean, String] layout The layout name to use (e.g. `:article`) or `false` to disable layout.
|
||||||
|
# @option opts [Boolean] directory_indexes Whether or not the `:directory_indexes` extension applies to these paths.
|
||||||
|
# @option opts [Hash] locals Local variables for the template. These will be available when the template renders.
|
||||||
|
# @option opts [String] proxy The source path for a template to proxy this path to. Only valid when a single path is provided. Prefer using the `proxy` method to do this.
|
||||||
|
# @option opts [Boolean] ignore Set to `true` to ignore the provided path(s). Only valid when a single path is provided. Prefer using the `ignore` method to do this.
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def page(url, opts={})
|
def page(path, opts={})
|
||||||
options = opts.dup
|
options = opts.dup
|
||||||
|
|
||||||
# Default layout
|
# Default layout
|
||||||
|
@ -19,30 +58,26 @@ module Middleman
|
||||||
# TODO: You can set options and locals, but not data
|
# TODO: You can set options and locals, but not data
|
||||||
metadata = { options: options, locals: options.delete(:locals) || {} }
|
metadata = { options: options, locals: options.delete(:locals) || {} }
|
||||||
|
|
||||||
# If the url is a regexp
|
# If the path is a regexp
|
||||||
unless url.is_a?(Regexp) || url.include?('*')
|
unless path.is_a?(Regexp) || path.include?('*')
|
||||||
# Normalized path
|
# Normalized path
|
||||||
url = '/' + Middleman::Util.normalize_path(url)
|
path = '/' + Middleman::Util.normalize_path(path)
|
||||||
if url.end_with?('/') || File.directory?(File.join(@app.source_dir, url))
|
if path.end_with?('/') || File.directory?(File.join(@app.source_dir, path))
|
||||||
url = File.join(url, @app.config[:index_file])
|
path = File.join(path, @app.config[:index_file])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Setup proxy
|
# Setup proxy
|
||||||
if target = options.delete(:proxy)
|
if target = options.delete(:proxy)
|
||||||
# TODO: deprecate proxy through page?
|
# TODO: deprecate proxy through page?
|
||||||
@app.proxy(url, target, opts.dup)
|
@app.proxy(path, target, opts.dup)
|
||||||
return
|
return
|
||||||
elsif options.delete(:ignore)
|
elsif options.delete(:ignore)
|
||||||
# TODO: deprecate ignore through page?
|
# TODO: deprecate ignore through page?
|
||||||
@app.ignore(url)
|
@app.ignore(path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Setup a metadata matcher for rendering those options
|
@page_configs << [path, metadata]
|
||||||
# TODO: How to get rid of this? Perhaps a separate extension that manipulates
|
|
||||||
# in this sort of data?
|
|
||||||
# This is harder because sitemap isn't available.
|
|
||||||
@app.sitemap.provides_metadata_for_path(url) { |_| metadata }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
module Middleman
|
|
||||||
module Sitemap
|
|
||||||
module Extensions
|
|
||||||
|
|
||||||
# Add metadata to Resources based on path matchers. This exists
|
|
||||||
# entirely to support the "page" method in config.rb.
|
|
||||||
|
|
||||||
# TODO: This requires the concept of priority for sitemap manipulators
|
|
||||||
# in order for it to always run after all other manipulators.
|
|
||||||
class MetadataForPath
|
|
||||||
def initialize(sitemap)
|
|
||||||
@app = sitemap.app
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -53,7 +53,7 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
def render(*)
|
def render(*)
|
||||||
url = ::Middleman::Util.url_for(store.app, @request_path,
|
url = ::Middleman::Util.url_for(@store.app, @request_path,
|
||||||
relative: false,
|
relative: false,
|
||||||
find_resource: true
|
find_resource: true
|
||||||
)
|
)
|
||||||
|
@ -83,10 +83,6 @@ module Middleman
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def metadata
|
|
||||||
@local_metadata.dup
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_source_file
|
def get_source_file
|
||||||
''
|
''
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,8 +71,8 @@ module Middleman
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def metadata
|
def get_source_file
|
||||||
@local_metadata.dup
|
''
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,7 +42,7 @@ module Middleman
|
||||||
# Locals are local variables for rendering this resource's template
|
# Locals are local variables for rendering this resource's template
|
||||||
# Page are data that is exposed through this resource's data member.
|
# Page are data that is exposed through this resource's data member.
|
||||||
# Note: It is named 'page' for backwards compatibility with older MM.
|
# Note: It is named 'page' for backwards compatibility with older MM.
|
||||||
@local_metadata = { options: {}, locals: {}, page: {} }
|
@metadata = { options: {}, locals: {}, page: {} }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Whether this resource has a template file
|
# Whether this resource has a template file
|
||||||
|
@ -59,15 +59,12 @@ module Middleman
|
||||||
# Page are data that is exposed through this resource's data member.
|
# Page are data that is exposed through this resource's data member.
|
||||||
# Note: It is named 'page' for backwards compatibility with older MM.
|
# Note: It is named 'page' for backwards compatibility with older MM.
|
||||||
def add_metadata(meta={})
|
def add_metadata(meta={})
|
||||||
@local_metadata.deep_merge!(meta)
|
@metadata.deep_merge!(meta)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the metadata for both the current source_file and the current path
|
# The metadata for this resource
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def metadata
|
attr_reader :metadata
|
||||||
# TODO: The only reason we call metadata_for_page is to power the "page" DSL
|
|
||||||
@store.metadata_for_path(path).deep_merge @local_metadata
|
|
||||||
end
|
|
||||||
|
|
||||||
# Data about this resource, populated from frontmatter or extensions.
|
# Data about this resource, populated from frontmatter or extensions.
|
||||||
# @return [HashWithIndifferentAccess]
|
# @return [HashWithIndifferentAccess]
|
||||||
|
|
|
@ -27,11 +27,9 @@ module Middleman
|
||||||
def initialize(app)
|
def initialize(app)
|
||||||
@app = app
|
@app = app
|
||||||
@resources = []
|
@resources = []
|
||||||
@_cached_metadata = {}
|
|
||||||
# TODO: Should this be a set or hash?
|
# TODO: Should this be a set or hash?
|
||||||
@resource_list_manipulators = []
|
@resource_list_manipulators = []
|
||||||
@needs_sitemap_rebuild = true
|
@needs_sitemap_rebuild = true
|
||||||
@provides_metadata_for_path = Set.new
|
|
||||||
|
|
||||||
@lock = Monitor.new
|
@lock = Monitor.new
|
||||||
reset_lookup_cache!
|
reset_lookup_cache!
|
||||||
|
@ -130,40 +128,6 @@ module Middleman
|
||||||
@resources_not_ignored = nil
|
@resources_not_ignored = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Register a handler to provide metadata on a url path
|
|
||||||
# Extensions authors should prefer adding metadata to Resources via a
|
|
||||||
# sitemap manipulator and Resource#add_metadata.
|
|
||||||
#
|
|
||||||
# @param [Regexp, String] matcher or glob string
|
|
||||||
def provides_metadata_for_path(matcher=nil, &block)
|
|
||||||
if block_given?
|
|
||||||
@provides_metadata_for_path << [block, matcher]
|
|
||||||
@_cached_metadata = {}
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the metadata for a specific source path
|
|
||||||
# @param [String] path Source path of a resource
|
|
||||||
# @return [Hash]
|
|
||||||
def metadata_for_path(path)
|
|
||||||
return @_cached_metadata[path] if @_cached_metadata.has_key?(path)
|
|
||||||
|
|
||||||
blank_metadata = { options: {}, locals: {}, page: {} }
|
|
||||||
|
|
||||||
@_cached_metadata[path] = @provides_metadata_for_path.inject(blank_metadata) do |result, (callback, matcher)|
|
|
||||||
case matcher
|
|
||||||
when Regexp
|
|
||||||
next result unless path =~ matcher
|
|
||||||
when String
|
|
||||||
next result unless File.fnmatch('/' + Util.strip_leading_slash(matcher), "/#{path}")
|
|
||||||
end
|
|
||||||
|
|
||||||
metadata = callback.call(path)
|
|
||||||
result.deep_merge(metadata)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the URL path for an on-disk file
|
# Get the URL path for an on-disk file
|
||||||
# @param [String] file
|
# @param [String] file
|
||||||
# @return [String]
|
# @return [String]
|
||||||
|
|
Loading…
Reference in a new issue