Merge pull request #1288 from bhollis/data
@bhollis metadata rewrite/refactor
This commit is contained in:
commit
e7108a5656
23 changed files with 259 additions and 312 deletions
|
@ -1,14 +1,22 @@
|
|||
Feature: Custom layouts
|
||||
In order easily switch between relative and absolute paths
|
||||
|
||||
|
||||
Scenario: Using custom :layout attribute
|
||||
Given page "/custom-layout.html" has layout "custom"
|
||||
Given a fixture app "custom-layout-app2"
|
||||
And a file named "config.rb" with:
|
||||
"""
|
||||
page '/custom-layout.html', layout: :custom
|
||||
"""
|
||||
And the Server is running at "custom-layout-app2"
|
||||
When I go to "/custom-layout.html"
|
||||
Then I should see "Custom Layout"
|
||||
|
||||
|
||||
Scenario: Using custom :layout attribute with folders
|
||||
Given page "/custom-layout-dir/" has layout "custom"
|
||||
Given a fixture app "custom-layout-app2"
|
||||
And a file named "config.rb" with:
|
||||
"""
|
||||
page '/custom-layout-dir/', layout: :custom
|
||||
"""
|
||||
And the Server is running at "custom-layout-app2"
|
||||
When I go to "/custom-layout-dir"
|
||||
Then I should see "Custom Layout"
|
||||
|
@ -16,9 +24,13 @@ Feature: Custom layouts
|
|||
Then I should see "Custom Layout"
|
||||
When I go to "/custom-layout-dir/index.html"
|
||||
Then I should see "Custom Layout"
|
||||
|
||||
|
||||
Scenario: Using custom :layout attribute with folders
|
||||
Given page "/custom-layout-dir" has layout "custom"
|
||||
Given a fixture app "custom-layout-app2"
|
||||
And a file named "config.rb" with:
|
||||
"""
|
||||
page '/custom-layout-dir', layout: :custom
|
||||
"""
|
||||
And the Server is running at "custom-layout-app2"
|
||||
When I go to "/custom-layout-dir"
|
||||
Then I should see "Custom Layout"
|
||||
|
@ -26,9 +38,13 @@ Feature: Custom layouts
|
|||
Then I should see "Custom Layout"
|
||||
When I go to "/custom-layout-dir/index.html"
|
||||
Then I should see "Custom Layout"
|
||||
|
||||
|
||||
Scenario: Using custom :layout attribute with folders
|
||||
Given page "/custom-layout-dir/index.html" has layout "custom"
|
||||
Given a fixture app "custom-layout-app2"
|
||||
And a file named "config.rb" with:
|
||||
"""
|
||||
page '/custom-layout-dir/index.html', layout: :custom
|
||||
"""
|
||||
And the Server is running at "custom-layout-app2"
|
||||
When I go to "/custom-layout-dir"
|
||||
Then I should see "Custom Layout"
|
||||
|
@ -36,7 +52,7 @@ Feature: Custom layouts
|
|||
Then I should see "Custom Layout"
|
||||
When I go to "/custom-layout-dir/index.html"
|
||||
Then I should see "Custom Layout"
|
||||
|
||||
|
||||
Scenario: Setting layout inside a matching page block
|
||||
Given the Server is running at "page-helper-layout-block-app"
|
||||
When I go to "/index.html"
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Given /^page "([^\"]*)" has layout "([^\"]*)"$/ do |url, layout|
|
||||
@initialize_commands ||= []
|
||||
@initialize_commands << lambda {
|
||||
page(url, layout: layout.to_sym)
|
||||
}
|
||||
end
|
|
@ -1,10 +1,5 @@
|
|||
require 'middleman-core/core_extensions/routing'
|
||||
|
||||
module Middleman
|
||||
class ConfigContext
|
||||
# page routing
|
||||
include Middleman::CoreExtensions::Routing
|
||||
|
||||
attr_reader :app
|
||||
|
||||
# Whitelist methods that can reach out.
|
||||
|
|
|
@ -45,6 +45,11 @@ Middleman::Extensions.register :lorem, auto_activate: :before_configuration do
|
|||
Middleman::Extensions::Lorem
|
||||
end
|
||||
|
||||
Middleman::Extensions.register :routing, auto_activate: :before_configuration do
|
||||
require 'middleman-core/core_extensions/routing'
|
||||
Middleman::CoreExtensions::Routing
|
||||
end
|
||||
|
||||
###
|
||||
# Setup Optional Extensions
|
||||
###
|
||||
|
|
|
@ -83,9 +83,6 @@ module Middleman
|
|||
# Search the root of the project for required files
|
||||
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
||||
|
||||
# Evaluate a passed block if given
|
||||
config_context.instance_exec(&block) if block_given?
|
||||
|
||||
super
|
||||
|
||||
::Middleman::Extension.clear_after_extension_callbacks
|
||||
|
@ -105,6 +102,9 @@ module Middleman
|
|||
|
||||
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`
|
||||
local_config = File.join(root, 'config.rb')
|
||||
if File.exist? local_config
|
||||
|
|
|
@ -10,6 +10,9 @@ require 'active_support/json'
|
|||
# Extensions namespace
|
||||
module Middleman::CoreExtensions
|
||||
class FrontMatter < ::Middleman::Extension
|
||||
# Try to run after routing but before directory_indexes
|
||||
self.resource_list_manipulator_priority = 90
|
||||
|
||||
YAML_ERRORS = [StandardError]
|
||||
|
||||
# https://github.com/tenderlove/psych/issues/23
|
||||
|
@ -29,61 +32,34 @@ module Middleman::CoreExtensions
|
|||
app.files.deleted { |file| ext.clear_data(file) }
|
||||
end
|
||||
|
||||
def after_configuration
|
||||
app.ignore %r{\.frontmatter$}
|
||||
# Modify each resource to add data & options from frontmatter.
|
||||
def manipulate_resource_list(resources)
|
||||
resources.each do |resource|
|
||||
next if resource.source_file.blank?
|
||||
|
||||
::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods
|
||||
fmdata = data(resource.source_file).first.dup
|
||||
|
||||
app.sitemap.provides_metadata do |path|
|
||||
fmdata = data(path).first
|
||||
# Copy over special options
|
||||
# TODO: Should we make people put these under "options" instead of having
|
||||
# special known keys?
|
||||
opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type)
|
||||
opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options)
|
||||
|
||||
data = {}
|
||||
ignored = fmdata.delete(:ignored)
|
||||
|
||||
[:layout, :layout_engine].each do |opt|
|
||||
data[opt] = fmdata[opt] unless fmdata[opt].nil?
|
||||
end
|
||||
# TODO: Enhance data? NOOOO
|
||||
# TODO: stringify-keys? immutable/freeze?
|
||||
|
||||
if fmdata[:renderer_options]
|
||||
data[:renderer_options] = {}
|
||||
fmdata[:renderer_options].each do |k, v|
|
||||
data[:renderer_options][k.to_sym] = v
|
||||
end
|
||||
end
|
||||
resource.add_metadata options: opts, page: fmdata
|
||||
|
||||
{ options: data }
|
||||
resource.ignore! if ignored == true && !resource.proxy?
|
||||
|
||||
# TODO: Save new template here somewhere?
|
||||
end
|
||||
end
|
||||
|
||||
module ResourceInstanceMethods
|
||||
def ignored?
|
||||
if !proxy? && raw_data[:ignored] == true
|
||||
true
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# This page's frontmatter without being enhanced for access by either symbols or strings.
|
||||
# Used internally
|
||||
# @private
|
||||
# @return [Hash]
|
||||
def raw_data
|
||||
app.extensions[:front_matter].data(source_file).first
|
||||
end
|
||||
|
||||
# This page's frontmatter
|
||||
# @return [Hash]
|
||||
def data
|
||||
@enhanced_data ||= ::Middleman::Util.recursively_enhance(raw_data).freeze
|
||||
end
|
||||
|
||||
# Override Resource#content_type to take into account frontmatter
|
||||
def content_type
|
||||
# Allow setting content type in frontmatter too
|
||||
raw_data.fetch :content_type do
|
||||
super
|
||||
end
|
||||
end
|
||||
def after_configuration
|
||||
app.ignore %r{\.frontmatter$}
|
||||
end
|
||||
|
||||
# Get the template data from a path
|
||||
|
|
|
@ -27,9 +27,9 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
end
|
||||
|
||||
def after_configuration
|
||||
app.files.reload_path(app.config[:locals_dir] || options[:data])
|
||||
app.files.reload_path(app.config[:locales_dir] || options[:data])
|
||||
|
||||
@locales_glob = File.join(app.config[:locals_dir] || options[:data], '**', '*.{rb,yml,yaml}')
|
||||
@locales_glob = File.join(app.config[:locales_dir] || options[:data], '**', '*.{rb,yml,yaml}')
|
||||
@locales_regex = convert_glob_to_regex(@locales_glob)
|
||||
|
||||
@maps = {}
|
||||
|
@ -42,7 +42,6 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
# Don't output localizable files
|
||||
app.ignore File.join(options[:templates_dir], '**')
|
||||
|
||||
app.sitemap.provides_metadata_for_path(&method(:metadata_for_path))
|
||||
app.files.changed(&method(:on_file_changed))
|
||||
app.files.deleted(&method(:on_file_changed))
|
||||
end
|
||||
|
@ -56,14 +55,12 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
delegate :logger, to: :app
|
||||
|
||||
def langs
|
||||
@_langs ||= known_languages
|
||||
@langs ||= known_languages
|
||||
end
|
||||
|
||||
# Update the main sitemap resource list
|
||||
# @return [void]
|
||||
def manipulate_resource_list(resources)
|
||||
@_localization_data = {}
|
||||
|
||||
new_resources = []
|
||||
|
||||
resources.each do |resource|
|
||||
|
@ -81,6 +78,12 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
new_resources << build_resource(path, resource.path, page_id, lang)
|
||||
end
|
||||
end
|
||||
|
||||
# This is for backwards compatibility with the old provides_metadata-based code
|
||||
# that used to be in this extension, but I don't know how much sense it makes.
|
||||
unless resource.options[:lang]
|
||||
resource.add_metadata options: { lang: @mount_at_root }, locals: { lang: @mount_at_root }
|
||||
end
|
||||
end
|
||||
|
||||
resources + new_resources
|
||||
|
@ -90,7 +93,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
|
||||
def on_file_changed(file)
|
||||
if @locales_regex =~ file
|
||||
@_langs = nil # Clear langs cache
|
||||
@langs = nil # Clear langs cache
|
||||
::I18n.reload!
|
||||
end
|
||||
end
|
||||
|
@ -112,24 +115,6 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
end
|
||||
end
|
||||
|
||||
def metadata_for_path(url)
|
||||
if d = localization_data(url)
|
||||
lang, page_id = d
|
||||
else
|
||||
# Default to the @mount_at_root lang
|
||||
page_id = nil
|
||||
lang = @mount_at_root
|
||||
end
|
||||
|
||||
{
|
||||
locals: {
|
||||
lang: lang,
|
||||
page_id: page_id
|
||||
},
|
||||
options: { lang: lang }
|
||||
}
|
||||
end
|
||||
|
||||
def known_languages
|
||||
if options[:langs]
|
||||
Array(options[:langs]).map(&:to_sym)
|
||||
|
@ -144,11 +129,6 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
end
|
||||
end
|
||||
|
||||
def localization_data(path)
|
||||
@_localization_data ||= {}
|
||||
@_localization_data[path]
|
||||
end
|
||||
|
||||
# Parse locale extension filename
|
||||
# @return [lang, path, basename]
|
||||
# will return +nil+ if no locale extension
|
||||
|
@ -183,10 +163,9 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
|
||||
path = path.sub(options[:templates_dir] + '/', '')
|
||||
|
||||
@_localization_data[path] = [lang, path, localized_page_id]
|
||||
|
||||
p = ::Middleman::Sitemap::Resource.new(app.sitemap, path)
|
||||
p.proxy_to(source_path)
|
||||
p.add_metadata locals: { lang: lang, page_id: path }, options: { lang: lang }
|
||||
|
||||
::I18n.locale = old_locale
|
||||
p
|
||||
|
|
|
@ -48,7 +48,7 @@ module Middleman
|
|||
# Liquid Support
|
||||
begin
|
||||
require 'middleman-core/renderers/liquid'
|
||||
app.send :include, Middleman::Renderers::Liquid
|
||||
Middleman::Extensions.register :liquid, Middleman::Renderers::Liquid, auto_activate: :before_configuration
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
|
|
|
@ -1,43 +1,84 @@
|
|||
# Routing extension
|
||||
module Middleman
|
||||
module CoreExtensions
|
||||
module Routing
|
||||
# The page method allows the layout to be set on a specific path
|
||||
class Routing < Extension
|
||||
# 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 = 80
|
||||
|
||||
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
|
||||
# page "/", layout: :homepage_layout
|
||||
# @example
|
||||
# page '/about.html', layout: false
|
||||
# @example
|
||||
# page '/index.html', layout: :homepage_layout
|
||||
# @example
|
||||
# page '/foo.html', locals: { foo: 'bar' }
|
||||
#
|
||||
# @param [String] url
|
||||
# @param [Hash] opts
|
||||
# @param [String, Regexp] path A source path, or a Regexp/glob that can match multiple resources.
|
||||
# @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 [Hash] data Extra metadata to add to the page. This is the same as frontmatter, though frontmatter will take precedence over metadata defined here. Available via {Resource#data}.
|
||||
# @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]
|
||||
def page(url, opts={})
|
||||
def page(path, opts={})
|
||||
options = opts.dup
|
||||
|
||||
# Default layout
|
||||
# TODO: This seems wrong
|
||||
options[:layout] = @app.config[:layout] if options[:layout].nil?
|
||||
metadata = { options: options, locals: options.delete(:locals) || {} }
|
||||
# TODO: You can set options and locals, but not data
|
||||
metadata = { options: options, locals: options.delete(:locals) || {}, page: options.delete(:data) || {} }
|
||||
|
||||
# If the url is a regexp
|
||||
unless url.is_a?(Regexp) || url.include?('*')
|
||||
# If the path is a regexp
|
||||
unless path.is_a?(Regexp) || path.include?('*')
|
||||
# Normalized path
|
||||
url = '/' + Middleman::Util.normalize_path(url)
|
||||
if url.end_with?('/') || File.directory?(File.join(@app.source_dir, url))
|
||||
url = File.join(url, @app.config[:index_file])
|
||||
path = '/' + Middleman::Util.normalize_path(path)
|
||||
if path.end_with?('/') || File.directory?(File.join(@app.source_dir, path))
|
||||
path = File.join(path, @app.config[:index_file])
|
||||
end
|
||||
|
||||
# Setup proxy
|
||||
if target = options.delete(:proxy)
|
||||
# TODO: deprecate proxy through page?
|
||||
@app.proxy(url, target, opts.dup)
|
||||
@app.proxy(path, target, opts.dup)
|
||||
return
|
||||
elsif options.delete(:ignore)
|
||||
# TODO: deprecate ignore through page?
|
||||
@app.ignore(url)
|
||||
@app.ignore(path)
|
||||
end
|
||||
end
|
||||
|
||||
# Setup a metadata matcher for rendering those options
|
||||
@app.sitemap.provides_metadata_for_path(url) { |_| metadata }
|
||||
@page_configs << [path, metadata]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
require 'rack/showexceptions'
|
||||
|
||||
# Support rack/showexceptions during development
|
||||
module Middleman::CoreExtensions
|
||||
class ShowExceptions < ::Middleman::Extension
|
||||
def initialize(app, options_hash={}, &block)
|
||||
super
|
||||
|
||||
require 'rack/showexceptions'
|
||||
app.config.define_setting :show_exceptions, true, 'Whether to catch and display exceptions'
|
||||
end
|
||||
|
||||
def after_configuration
|
||||
app.use ::Rack::ShowExceptions
|
||||
app.use ::Rack::ShowExceptions if app.config[:show_exceptions]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,11 +16,8 @@ class Middleman::Extensions::DirectoryIndexes < ::Middleman::Extension
|
|||
resource.destination_path.end_with?(new_index_path) ||
|
||||
File.extname(index_file) != resource.ext
|
||||
|
||||
# Check if frontmatter turns directory_index off
|
||||
next if resource.raw_data[:directory_index] == false
|
||||
|
||||
# Check if file metadata (options set by "page" in config.rb) turns directory_index off
|
||||
next if resource.metadata[:options][:directory_index] == false
|
||||
# Check if file metadata (options set by "page" in config.rb or frontmatter) turns directory_index off
|
||||
next if resource.options[:directory_index] == false
|
||||
|
||||
resource.destination_path = resource.destination_path.chomp(File.extname(index_file)) + new_index_path
|
||||
end
|
||||
|
|
|
@ -44,11 +44,10 @@ module Middleman
|
|||
data = @resource.data
|
||||
props['Data'] = data.inspect unless data.empty?
|
||||
|
||||
meta = @resource.metadata
|
||||
options = meta[:options]
|
||||
options = @resource.options
|
||||
props['Options'] = options.inspect unless options.empty?
|
||||
|
||||
locals = meta[:locals].keys
|
||||
locals = @resource.locals.keys
|
||||
props['Locals'] = locals.join(', ') unless locals.empty?
|
||||
|
||||
props
|
||||
|
|
|
@ -4,23 +4,19 @@ require 'liquid'
|
|||
module Middleman
|
||||
module Renderers
|
||||
# Liquid Renderer
|
||||
module Liquid
|
||||
# Setup extension
|
||||
class << self
|
||||
# Once registerd
|
||||
def registered(app)
|
||||
# After config, setup liquid partial paths
|
||||
app.after_configuration do
|
||||
::Liquid::Template.file_system = ::Liquid::LocalFileSystem.new(source_dir)
|
||||
class Liquid < Middleman::Extension
|
||||
# After config, setup liquid partial paths
|
||||
def after_configuration
|
||||
::Liquid::Template.file_system = ::Liquid::LocalFileSystem.new(app.source_dir)
|
||||
end
|
||||
|
||||
# Convert data object into a hash for liquid
|
||||
sitemap.provides_metadata %r{\.liquid$} do
|
||||
{ locals: { data: data.to_h } }
|
||||
end
|
||||
def manipulate_resource_list(resources)
|
||||
resources.each do |resource|
|
||||
# Convert data object into a hash for liquid
|
||||
if resource.source_file =~ %r{\.liquid$}
|
||||
resource.add_metadata locals: { data: app.data.to_h }
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :included, :registered
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,8 +5,8 @@ module Middleman::Sitemap::Extensions
|
|||
module ContentType
|
||||
# The preferred MIME content type for this resource
|
||||
def content_type
|
||||
# Allow explcitly setting content type from page/proxy options
|
||||
meta_type = metadata[:options][:content_type]
|
||||
# Allow explcitly setting content type from page/proxy options or frontmatter
|
||||
meta_type = options[:content_type]
|
||||
return meta_type if meta_type
|
||||
|
||||
# Look up mime type based on extension
|
||||
|
|
|
@ -3,15 +3,15 @@ module Middleman
|
|||
module Extensions
|
||||
# Class to handle managing ignores
|
||||
class Ignores
|
||||
def initialize(sitemap)
|
||||
@app = sitemap.app
|
||||
def initialize(app, sitemap)
|
||||
@app = app
|
||||
@app.add_to_config_context :ignore, &method(:create_ignore)
|
||||
@app.define_singleton_method(:ignore, &method(:create_ignore))
|
||||
@app.define_singleton_method :ignore, &method(:create_ignore)
|
||||
|
||||
# Array of callbacks which can ass ignored
|
||||
@ignored_callbacks = []
|
||||
|
||||
sitemap.define_singleton_method(:ignored?, &method(:ignored?))
|
||||
sitemap.define_singleton_method :ignored?, &method(:ignored?)
|
||||
::Middleman::Sitemap::Resource.send :include, IgnoreResourceInstanceMethods
|
||||
end
|
||||
|
||||
|
@ -48,13 +48,20 @@ module Middleman
|
|||
|
||||
# Helpers methods for Resources
|
||||
module IgnoreResourceInstanceMethods
|
||||
# Ignore a resource directly, without going through the whole
|
||||
# ignore filter stuff.
|
||||
def ignore!
|
||||
@ignored = true
|
||||
end
|
||||
|
||||
# Whether the Resource is ignored
|
||||
# @return [Boolean]
|
||||
def ignored?
|
||||
@app.sitemap.ignored?(path) ||
|
||||
(!proxy? &&
|
||||
@app.sitemap.ignored?(source_file.sub("#{@app.source_dir}/", ''))
|
||||
)
|
||||
return true if @ignored
|
||||
# Ignore based on the source path (without template extensions)
|
||||
return true if @app.sitemap.ignored?(path)
|
||||
# This allows files to be ignored by their source file name (with template extensions)
|
||||
!proxy? && @app.sitemap.ignored?(source_file.sub("#{@app.source_dir}/", ''))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,22 +7,24 @@ module Middleman
|
|||
attr_accessor :sitemap
|
||||
attr_accessor :waiting_for_ready
|
||||
|
||||
def initialize(sitemap)
|
||||
def initialize(app, sitemap)
|
||||
@sitemap = sitemap
|
||||
@app = @sitemap.app
|
||||
@app = app
|
||||
@file_paths_on_disk = Set.new
|
||||
|
||||
scoped_self = self
|
||||
@waiting_for_ready = true
|
||||
|
||||
# Register file change callback
|
||||
@app.files.changed do |file|
|
||||
scoped_self.touch_file(file)
|
||||
end
|
||||
@app.before_configuration do
|
||||
# Register file change callback
|
||||
files.changed do |file|
|
||||
scoped_self.touch_file(file)
|
||||
end
|
||||
|
||||
# Register file delete callback
|
||||
@app.files.deleted do |file|
|
||||
scoped_self.remove_file(file)
|
||||
# Register file delete callback
|
||||
files.deleted do |file|
|
||||
scoped_self.remove_file(file)
|
||||
end
|
||||
end
|
||||
|
||||
@app.ready do
|
||||
|
|
|
@ -4,8 +4,8 @@ module Middleman
|
|||
# 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
|
||||
def initialize(app)
|
||||
@app = app
|
||||
@app.add_to_config_context :proxy, &method(:create_proxy)
|
||||
@app.define_singleton_method(:proxy, &method(:create_proxy))
|
||||
|
||||
|
@ -109,10 +109,10 @@ module Middleman
|
|||
# if there is no resource.
|
||||
# @return [Sitemap::Resource]
|
||||
def proxied_to_resource
|
||||
proxy_resource = store.find_resource_by_path(proxied_to)
|
||||
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)}"
|
||||
raise "Path #{path} proxies to unknown file #{proxied_to}:#{@store.resources.map(&:path)}"
|
||||
end
|
||||
|
||||
if proxy_resource.proxy?
|
||||
|
|
|
@ -6,8 +6,8 @@ module Middleman
|
|||
# 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
|
||||
def initialize(app)
|
||||
@app = app
|
||||
@app.add_to_config_context :redirect, &method(:create_redirect)
|
||||
|
||||
@redirects = {}
|
||||
|
@ -53,7 +53,7 @@ module Middleman
|
|||
end
|
||||
|
||||
def render(*)
|
||||
url = ::Middleman::Util.url_for(store.app, @request_path,
|
||||
url = ::Middleman::Util.url_for(@store.app, @request_path,
|
||||
relative: false,
|
||||
find_resource: true
|
||||
)
|
||||
|
@ -75,24 +75,17 @@ module Middleman
|
|||
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
|
||||
# rubocop:disable AccessorMethodName
|
||||
def get_source_file
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,8 +4,8 @@ module Middleman
|
|||
class RequestEndpoints
|
||||
# Manages the list of proxy configurations and manipulates the sitemap
|
||||
# to include new resources based on those configurations
|
||||
def initialize(sitemap)
|
||||
@app = sitemap.app
|
||||
def initialize(app)
|
||||
@app = app
|
||||
@app.add_to_config_context :endpoint, &method(:create_endpoint)
|
||||
|
||||
@endpoints = {}
|
||||
|
@ -49,12 +49,13 @@ module Middleman
|
|||
class EndpointResource < ::Middleman::Sitemap::Resource
|
||||
attr_accessor :output
|
||||
|
||||
def initialize(store, path, source_file)
|
||||
@request_path = ::Middleman::Util.normalize_path(source_file)
|
||||
|
||||
def initialize(store, path, request_path)
|
||||
super(store, path)
|
||||
@request_path = ::Middleman::Util.normalize_path(request_path)
|
||||
end
|
||||
|
||||
attr_reader :request_path
|
||||
|
||||
def template?
|
||||
true
|
||||
end
|
||||
|
@ -63,22 +64,17 @@ module Middleman
|
|||
return output.call if output
|
||||
end
|
||||
|
||||
attr_reader :request_path
|
||||
|
||||
def binary?
|
||||
false
|
||||
end
|
||||
|
||||
def raw_data
|
||||
{}
|
||||
end
|
||||
|
||||
def ignored?
|
||||
false
|
||||
end
|
||||
|
||||
def metadata
|
||||
@local_metadata.dup
|
||||
# rubocop:disable AccessorMethodName
|
||||
def get_source_file
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,13 +7,13 @@ module Middleman
|
|||
def parent
|
||||
parts = path.split('/')
|
||||
tail = parts.pop
|
||||
is_index = (tail == app.config[:index_file])
|
||||
is_index = (tail == @app.config[:index_file])
|
||||
|
||||
return nil if is_index && parts.length < 1
|
||||
|
||||
test_expr = parts.join('\\/')
|
||||
# eponymous reverse-lookup
|
||||
found = store.resources.find do |candidate|
|
||||
found = @store.resources.find do |candidate|
|
||||
candidate.path =~ %r!^#{test_expr}(?:\.[a-zA-Z0-9]+|\/)$!
|
||||
end
|
||||
|
||||
|
@ -21,7 +21,7 @@ module Middleman
|
|||
found
|
||||
else
|
||||
parts.pop if is_index
|
||||
store.find_resource_by_destination_path("#{parts.join('/')}/#{app.config[:index_file]}")
|
||||
@store.find_resource_by_destination_path("#{parts.join('/')}/#{@app.config[:index_file]}")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -34,11 +34,11 @@ module Middleman
|
|||
base_path = eponymous_directory_path
|
||||
prefix = %r{^#{base_path.sub("/", "\\/")}}
|
||||
else
|
||||
base_path = path.sub("#{app.config[:index_file]}", '')
|
||||
base_path = path.sub("#{@app.config[:index_file]}", '')
|
||||
prefix = %r{^#{base_path.sub("/", "\\/")}}
|
||||
end
|
||||
|
||||
store.resources.select do |sub_resource|
|
||||
@store.resources.select do |sub_resource|
|
||||
if sub_resource.path == path || sub_resource.path !~ prefix
|
||||
false
|
||||
else
|
||||
|
@ -47,7 +47,7 @@ module Middleman
|
|||
if parts.length == 1
|
||||
true
|
||||
elsif parts.length == 2
|
||||
parts.last == app.config[:index_file]
|
||||
parts.last == @app.config[:index_file]
|
||||
else
|
||||
false
|
||||
end
|
||||
|
@ -65,17 +65,17 @@ module Middleman
|
|||
# Whether this resource is either a directory index, or has the same name as an existing directory in the source
|
||||
# @return [Boolean]
|
||||
def directory_index?
|
||||
path.include?(app.config[: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.config[:index_file]}") && destination_path.end_with?("/#{app.config[: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)
|
||||
full_path = File.join(@app.source_dir, eponymous_directory_path)
|
||||
File.exist?(full_path) && File.directory?(full_path)
|
||||
end
|
||||
|
||||
|
|
|
@ -11,27 +11,24 @@ module Middleman
|
|||
include Middleman::Sitemap::Extensions::Traversal
|
||||
include Middleman::Sitemap::Extensions::ContentType
|
||||
|
||||
# @return [Middleman::Application]
|
||||
attr_reader :app
|
||||
delegate :logger, :instrument, to: :app
|
||||
|
||||
# @return [Middleman::Sitemap::Store]
|
||||
attr_reader :store
|
||||
|
||||
# The source path of this resource (relative to the source directory,
|
||||
# without template extensions)
|
||||
# @return [String]
|
||||
attr_reader :path
|
||||
|
||||
# The output path for this resource
|
||||
# The output path in the build directory for this resource
|
||||
# @return [String]
|
||||
attr_accessor :destination_path
|
||||
|
||||
# The path to use when requesting this resource. Normally it's
|
||||
# the same as {#destination_path} but it can be overridden in subclasses.
|
||||
# @return [String]
|
||||
alias_method :request_path, :destination_path
|
||||
|
||||
# Set the on-disk source file for this resource
|
||||
# @return [String]
|
||||
# attr_reader :source_file
|
||||
|
||||
def source_file
|
||||
# TODO: Make this work when get_source_file doesn't exist
|
||||
@source_file || get_source_file
|
||||
end
|
||||
|
||||
|
@ -46,7 +43,11 @@ module Middleman
|
|||
@source_file = source_file
|
||||
@destination_path = @path
|
||||
|
||||
@local_metadata = { options: {}, locals: {} }
|
||||
# Options are generally rendering/sitemap options
|
||||
# Locals are local variables for rendering this resource's template
|
||||
# Page are data that is exposed through this resource's data member.
|
||||
# Note: It is named 'page' for backwards compatibility with older MM.
|
||||
@metadata = { options: {}, locals: {}, page: {} }
|
||||
end
|
||||
|
||||
# Whether this resource has a template file
|
||||
|
@ -56,29 +57,39 @@ module Middleman
|
|||
!::Tilt[source_file].nil?
|
||||
end
|
||||
|
||||
# Get the metadata for both the current source_file and the current path
|
||||
# @return [Hash]
|
||||
def metadata
|
||||
result = store.metadata_for_path(path).dup
|
||||
|
||||
file_meta = store.metadata_for_file(source_file).dup
|
||||
result.deep_merge!(file_meta)
|
||||
|
||||
local_meta = @local_metadata.dup
|
||||
result.deep_merge!(local_meta)
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# Merge in new metadata specific to this resource.
|
||||
# @param [Hash] meta A metadata block like provides_metadata_for_path takes
|
||||
# @param [Hash] meta A metadata block with keys :options, :locals, :page.
|
||||
# Options are generally rendering/sitemap options
|
||||
# Locals are local variables for rendering this resource's template
|
||||
# Page are data that is exposed through this resource's data member.
|
||||
# Note: It is named 'page' for backwards compatibility with older MM.
|
||||
def add_metadata(meta={})
|
||||
@local_metadata.deep_merge!(meta.dup)
|
||||
@metadata.deep_merge!(meta)
|
||||
end
|
||||
|
||||
# The output/preview URL for this resource
|
||||
# @return [String]
|
||||
attr_accessor :destination_path
|
||||
# The metadata for this resource
|
||||
# @return [Hash]
|
||||
attr_reader :metadata
|
||||
|
||||
# Data about this resource, populated from frontmatter or extensions.
|
||||
# @return [HashWithIndifferentAccess]
|
||||
def data
|
||||
# TODO: Should this really be a HashWithIndifferentAccess?
|
||||
::Middleman::Util.recursively_enhance(metadata[:page]).freeze
|
||||
end
|
||||
|
||||
# Options about how this resource is rendered, such as its :layout,
|
||||
# :renderer_options, and whether or not to use :directory_indexes.
|
||||
# @return [Hash]
|
||||
def options
|
||||
metadata[:options]
|
||||
end
|
||||
|
||||
# Local variable mappings that are used when rendering the template for this resource.
|
||||
# @return [Hash]
|
||||
def locals
|
||||
metadata[:locals]
|
||||
end
|
||||
|
||||
# Extension of the path (i.e. '.js')
|
||||
# @return [String]
|
||||
|
@ -86,19 +97,15 @@ module Middleman
|
|||
File.extname(path)
|
||||
end
|
||||
|
||||
def request_path
|
||||
destination_path
|
||||
end
|
||||
|
||||
# Render this resource
|
||||
# @return [String]
|
||||
def render(opts={}, locs={})
|
||||
return ::Middleman::FileRenderer.new(@app, source_file).template_data_for_file unless template?
|
||||
|
||||
relative_source = Pathname(source_file).relative_path_from(Pathname(app.root))
|
||||
relative_source = Pathname(source_file).relative_path_from(Pathname(@app.root))
|
||||
|
||||
instrument 'render.resource', path: relative_source, destination_path: destination_path do
|
||||
md = metadata.dup
|
||||
@app.instrument 'render.resource', path: relative_source, destination_path: destination_path do
|
||||
md = metadata
|
||||
opts = md[:options].deep_merge(opts)
|
||||
locs = md[:locals].deep_merge(locs)
|
||||
locs[:current_path] ||= destination_path
|
||||
|
@ -118,11 +125,11 @@ module Middleman
|
|||
# @return [String]
|
||||
def url
|
||||
url_path = destination_path
|
||||
if app.config[:strip_index_file]
|
||||
url_path = url_path.sub(/(^|\/)#{Regexp.escape(app.config[:index_file])}$/,
|
||||
app.config[: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.config[:http_prefix], url_path)
|
||||
File.join(@app.config[:http_prefix], url_path)
|
||||
end
|
||||
|
||||
# Whether the source file is binary.
|
||||
|
|
|
@ -20,14 +20,14 @@ module Middleman
|
|||
# extensions. All "path" parameters used in this class are source paths.
|
||||
class Store
|
||||
# @return [Middleman::Application]
|
||||
attr_accessor :app
|
||||
attr_reader :app
|
||||
|
||||
# Initialize with parent app
|
||||
# @param [Middleman::Application] app
|
||||
def initialize(app)
|
||||
@app = app
|
||||
@resources = []
|
||||
@_cached_metadata = {}
|
||||
# TODO: Should this be a set or hash?
|
||||
@resource_list_manipulators = []
|
||||
@needs_sitemap_rebuild = true
|
||||
|
||||
|
@ -35,26 +35,26 @@ module Middleman
|
|||
reset_lookup_cache!
|
||||
|
||||
# Handle ignore commands
|
||||
Middleman::Sitemap::Extensions::Ignores.new(self)
|
||||
Middleman::Sitemap::Extensions::Ignores.new(@app, self)
|
||||
|
||||
# Extensions
|
||||
{
|
||||
# Register classes which can manipulate the main site map list
|
||||
on_disk: Middleman::Sitemap::Extensions::OnDisk,
|
||||
on_disk: Middleman::Sitemap::Extensions::OnDisk.new(@app, self),
|
||||
|
||||
# Request Endpoints
|
||||
request_endpoints: Middleman::Sitemap::Extensions::RequestEndpoints,
|
||||
request_endpoints: Middleman::Sitemap::Extensions::RequestEndpoints.new(@app),
|
||||
|
||||
# Proxies
|
||||
proxies: Middleman::Sitemap::Extensions::Proxies,
|
||||
proxies: Middleman::Sitemap::Extensions::Proxies.new(@app),
|
||||
|
||||
# Redirects
|
||||
redirects: Middleman::Sitemap::Extensions::Redirects
|
||||
redirects: Middleman::Sitemap::Extensions::Redirects.new(@app)
|
||||
}.each do |k, m|
|
||||
register_resource_list_manipulator(k, m.new(self))
|
||||
register_resource_list_manipulator(k, m)
|
||||
end
|
||||
|
||||
app.config_context.class.send :delegate, :sitemap, to: :app
|
||||
@app.config_context.class.send :delegate, :sitemap, to: :app
|
||||
end
|
||||
|
||||
# Register an object which can transform the sitemap resource list. Best to register
|
||||
|
@ -128,63 +128,6 @@ module Middleman
|
|||
@resources_not_ignored = nil
|
||||
end
|
||||
|
||||
# Register a handler to provide metadata on a file path
|
||||
# @param [Regexp] matcher
|
||||
# @return [Array<Array<Proc, Regexp>>]
|
||||
def provides_metadata(matcher=nil, &block)
|
||||
@_provides_metadata ||= []
|
||||
@_provides_metadata << [block, matcher] if block_given?
|
||||
@_provides_metadata
|
||||
end
|
||||
|
||||
# Get the metadata for a specific file
|
||||
# @param [String] source_file
|
||||
# @return [Hash]
|
||||
def metadata_for_file(source_file)
|
||||
blank_metadata = { options: {}, locals: {} }
|
||||
|
||||
provides_metadata.reduce(blank_metadata) do |result, (callback, matcher)|
|
||||
next result if matcher && !source_file.match(matcher)
|
||||
|
||||
metadata = callback.call(source_file).dup
|
||||
result.deep_merge(metadata)
|
||||
end
|
||||
end
|
||||
|
||||
# Register a handler to provide metadata on a url path
|
||||
# @param [Regexp] matcher
|
||||
# @return [Array<Array<Proc, Regexp>>]
|
||||
def provides_metadata_for_path(matcher=nil, &block)
|
||||
@_provides_metadata_for_path ||= []
|
||||
if block_given?
|
||||
@_provides_metadata_for_path << [block, matcher]
|
||||
@_cached_metadata = {}
|
||||
end
|
||||
@_provides_metadata_for_path
|
||||
end
|
||||
|
||||
# Get the metadata for a specific URL
|
||||
# @param [String] request_path
|
||||
# @return [Hash]
|
||||
def metadata_for_path(request_path)
|
||||
return @_cached_metadata[request_path] if @_cached_metadata[request_path]
|
||||
|
||||
blank_metadata = { options: {}, locals: {} }
|
||||
|
||||
@_cached_metadata[request_path] = provides_metadata_for_path.reduce(blank_metadata) do |result, (callback, matcher)|
|
||||
case matcher
|
||||
when Regexp
|
||||
next result unless request_path =~ matcher
|
||||
when String
|
||||
next result unless File.fnmatch('/' + Util.strip_leading_slash(matcher), "/#{request_path}")
|
||||
end
|
||||
|
||||
metadata = callback.call(request_path).dup
|
||||
|
||||
result.deep_merge(metadata)
|
||||
end
|
||||
end
|
||||
|
||||
# Get the URL path for an on-disk file
|
||||
# @param [String] file
|
||||
# @return [String]
|
||||
|
|
|
@ -41,12 +41,11 @@ Given /^the Server is running$/ do
|
|||
ENV['MM_ROOT'] = root_dir
|
||||
|
||||
initialize_commands = @initialize_commands || []
|
||||
initialize_commands.unshift lambda { config[:show_exceptions] = false }
|
||||
|
||||
@server_inst = Middleman::Application.server.inst do
|
||||
app.initialized do
|
||||
initialize_commands.each do |p|
|
||||
config_context.instance_exec(&p)
|
||||
end
|
||||
initialize_commands.each do |p|
|
||||
instance_exec(&p)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue