Name things :)
This commit is contained in:
parent
08b75f06ef
commit
6ccab8e071
|
@ -15,6 +15,8 @@ require 'hooks'
|
||||||
# Our custom logger
|
# Our custom logger
|
||||||
require 'middleman-core/logger'
|
require 'middleman-core/logger'
|
||||||
|
|
||||||
|
require 'middleman-core/contracts'
|
||||||
|
|
||||||
require 'middleman-core/sitemap/store'
|
require 'middleman-core/sitemap/store'
|
||||||
|
|
||||||
require 'middleman-core/configuration'
|
require 'middleman-core/configuration'
|
||||||
|
@ -30,6 +32,7 @@ require 'middleman-core/template_renderer'
|
||||||
module Middleman
|
module Middleman
|
||||||
class Application
|
class Application
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
|
include Contracts
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
# Global configuration for the whole Middleman project.
|
# Global configuration for the whole Middleman project.
|
||||||
|
@ -165,7 +168,11 @@ module Middleman
|
||||||
attr_reader :config
|
attr_reader :config
|
||||||
attr_reader :generic_template_context
|
attr_reader :generic_template_context
|
||||||
attr_reader :extensions
|
attr_reader :extensions
|
||||||
|
|
||||||
|
Contract None => SetOf['Middleman::Application::MiddlewareDescriptor']
|
||||||
attr_reader :middleware
|
attr_reader :middleware
|
||||||
|
|
||||||
|
Contract None => SetOf['Middleman::Application::MapDescriptor']
|
||||||
attr_reader :mappings
|
attr_reader :mappings
|
||||||
|
|
||||||
# Reference to Logger singleton
|
# Reference to Logger singleton
|
||||||
|
@ -179,8 +186,8 @@ module Middleman
|
||||||
# Search the root of the project for required files
|
# Search the root of the project for required files
|
||||||
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
||||||
|
|
||||||
@middleware = []
|
@middleware = Set.new
|
||||||
@mappings = []
|
@mappings = Set.new
|
||||||
|
|
||||||
@template_context_class = Class.new(Middleman::TemplateContext)
|
@template_context_class = Class.new(Middleman::TemplateContext)
|
||||||
@generic_template_context = @template_context_class.new(self)
|
@generic_template_context = @template_context_class.new(self)
|
||||||
|
@ -296,20 +303,26 @@ module Middleman
|
||||||
File.join(root, config[:source])
|
File.join(root, config[:source])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
MiddlewareDescriptor = Struct.new(:class, :options, :block)
|
||||||
|
|
||||||
# Use Rack middleware
|
# Use Rack middleware
|
||||||
#
|
#
|
||||||
# @param [Class] middleware Middleware module
|
# @param [Class] middleware Middleware module
|
||||||
# @return [void]
|
# @return [void]
|
||||||
|
Contract Any, Args[Any], Proc => Any
|
||||||
def use(middleware, *args, &block)
|
def use(middleware, *args, &block)
|
||||||
@middleware << [middleware, args, block]
|
@middleware << MiddlewareDescriptor.new(middleware, args, block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
MapDescriptor = Struct.new(:path, :block)
|
||||||
|
|
||||||
# Add Rack App mapped to specific path
|
# Add Rack App mapped to specific path
|
||||||
#
|
#
|
||||||
# @param [String] map Path to map
|
# @param [String] map Path to map
|
||||||
# @return [void]
|
# @return [void]
|
||||||
|
Contract String, Proc => Any
|
||||||
def map(map, &block)
|
def map(map, &block)
|
||||||
@mappings << [map, block]
|
@mappings << MapDescriptor.new(map, block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
||||||
|
|
|
@ -1,22 +1,56 @@
|
||||||
if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
|
if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
|
||||||
require 'contracts'
|
require 'contracts'
|
||||||
|
|
||||||
class IsA
|
module Contracts
|
||||||
def self.[](val)
|
class IsA
|
||||||
@lookup ||= {}
|
def self.[](val)
|
||||||
@lookup[val] ||= new(val)
|
@lookup ||= {}
|
||||||
|
@lookup[val] ||= new(val)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(val)
|
||||||
|
@val = val
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?(val)
|
||||||
|
val.is_a? @val.constantize
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(val)
|
class ArrayOf
|
||||||
@val = val
|
def initialize(contract)
|
||||||
|
@contract = contract.is_a?(String) ? IsA[contract] : contract
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid?(val)
|
class SetOf < CallableClass
|
||||||
val.is_a? @val.constantize
|
def initialize(contract)
|
||||||
|
@contract = contract.is_a?(String) ? IsA[contract] : contract
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?(vals)
|
||||||
|
return false unless vals.is_a?(Set)
|
||||||
|
vals.all? do |val|
|
||||||
|
res, _ = Contract.valid?(val, @contract)
|
||||||
|
res
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"a set of #{@contract}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def testable?
|
||||||
|
Testable.testable? @contract
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_data
|
||||||
|
Set.new([], [Testable.test_data(@contract)], [Testable.test_data(@contract), Testable.test_data(@contract)])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
|
||||||
end
|
end
|
||||||
|
|
||||||
ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
|
|
||||||
else
|
else
|
||||||
module Contracts
|
module Contracts
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
|
@ -91,5 +125,12 @@ else
|
||||||
|
|
||||||
class IsA < Callable
|
class IsA < Callable
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class SetOf < Callable
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Contracts
|
||||||
|
PATH_MATCHER = Or[String, RespondTo[:match], RespondTo[:call], RespondTo[:to_s]]
|
||||||
|
end
|
||||||
|
|
|
@ -140,7 +140,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
path << index_file if path.end_with?('/')
|
path << index_file if path.end_with?('/')
|
||||||
path = ::Middleman::Util.strip_leading_slash(path)
|
path = ::Middleman::Util.strip_leading_slash(path)
|
||||||
|
|
||||||
classes = []
|
classes = Set.new
|
||||||
parts = path.split('.').first.split('/')
|
parts = path.split('.').first.split('/')
|
||||||
parts.each_with_index { |_, i| classes << parts.first(i + 1).join('_') }
|
parts.each_with_index { |_, i| classes << parts.first(i + 1).join('_') }
|
||||||
|
|
||||||
|
|
|
@ -55,28 +55,30 @@ module Middleman
|
||||||
@app = app
|
@app = app
|
||||||
@known_paths = Set.new
|
@known_paths = Set.new
|
||||||
|
|
||||||
@_changed = []
|
@on_change_callbacks = Set.new
|
||||||
@_deleted = []
|
@on_delete_callbacks = Set.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
CallbackDescriptor = Struct.new(:proc, :matcher)
|
||||||
|
|
||||||
# Add callback to be run on file change
|
# Add callback to be run on file change
|
||||||
#
|
#
|
||||||
# @param [nil,Regexp] matcher A Regexp to match the change path against
|
# @param [nil,Regexp] matcher A Regexp to match the change path against
|
||||||
# @return [Array<Proc>]
|
# @return [Array<Proc>]
|
||||||
Contract Or[Regexp, Proc] => ArrayOf[ArrayOf[Or[Proc, Regexp, nil]]]
|
Contract Or[Regexp, Proc] => SetOf['Middleman::CoreExtensions::FileWatcher::API::CallbackDescriptor']
|
||||||
def changed(matcher=nil, &block)
|
def changed(matcher=nil, &block)
|
||||||
@_changed << [block, matcher] if block_given?
|
@on_change_callbacks << CallbackDescriptor.new(block, matcher) if block_given?
|
||||||
@_changed
|
@on_change_callbacks
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add callback to be run on file deletion
|
# Add callback to be run on file deletion
|
||||||
#
|
#
|
||||||
# @param [nil,Regexp] matcher A Regexp to match the deleted path against
|
# @param [nil,Regexp] matcher A Regexp to match the deleted path against
|
||||||
# @return [Array<Proc>]
|
# @return [Array<Proc>]
|
||||||
Contract Or[Regexp, Proc] => ArrayOf[ArrayOf[Or[Proc, Regexp, nil]]]
|
Contract Or[Regexp, Proc] => SetOf['Middleman::CoreExtensions::FileWatcher::API::CallbackDescriptor']
|
||||||
def deleted(matcher=nil, &block)
|
def deleted(matcher=nil, &block)
|
||||||
@_deleted << [block, matcher] if block_given?
|
@on_delete_callbacks << CallbackDescriptor.new(block, matcher) if block_given?
|
||||||
@_deleted
|
@on_delete_callbacks
|
||||||
end
|
end
|
||||||
|
|
||||||
# Notify callbacks that a file changed
|
# Notify callbacks that a file changed
|
||||||
|
@ -159,9 +161,9 @@ module Middleman
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def run_callbacks(path, callbacks_name)
|
def run_callbacks(path, callbacks_name)
|
||||||
path = path.to_s
|
path = path.to_s
|
||||||
send(callbacks_name).each do |callback, matcher|
|
send(callbacks_name).each do |callback|
|
||||||
next unless matcher.nil? || path.match(matcher)
|
next unless callback[:matcher].nil? || path.match(callback[:matcher])
|
||||||
@app.instance_exec(path, &callback)
|
@app.instance_exec(path, &callback[:proc])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ module Middleman
|
||||||
def initialize(app, options_hash={}, &block)
|
def initialize(app, options_hash={}, &block)
|
||||||
super
|
super
|
||||||
|
|
||||||
@page_configs = []
|
@page_configs = Set.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_configuration
|
def before_configuration
|
||||||
|
@ -20,12 +20,14 @@ module Middleman
|
||||||
Contract ResourceList => ResourceList
|
Contract ResourceList => ResourceList
|
||||||
def manipulate_resource_list(resources)
|
def manipulate_resource_list(resources)
|
||||||
resources.each do |resource|
|
resources.each do |resource|
|
||||||
@page_configs.each do |matcher, metadata|
|
@page_configs.each do |p|
|
||||||
resource.add_metadata(metadata) if Middleman::Util.path_match(matcher, "/#{resource.path}")
|
resource.add_metadata(p[:metadata]) if Middleman::Util.path_match(p[:path], "/#{resource.path}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
PageDescriptor = Struct.new(:path, :metadata)
|
||||||
|
|
||||||
# The page method allows options to be set for a given source path, regex, or glob.
|
# 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.
|
# Options that may be set include layout, locals, proxy, andx ignore.
|
||||||
#
|
#
|
||||||
|
@ -43,6 +45,7 @@ module Middleman
|
||||||
# @option opts [Hash] locals Local variables for the template. These will be available when the template renders.
|
# @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 [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}.
|
||||||
# @return [void]
|
# @return [void]
|
||||||
|
Contract String, Hash => Any
|
||||||
def page(path, opts={})
|
def page(path, opts={})
|
||||||
options = opts.dup
|
options = opts.dup
|
||||||
|
|
||||||
|
@ -63,7 +66,7 @@ module Middleman
|
||||||
|
|
||||||
path = '/' + Util.strip_leading_slash(path) if path.is_a?(String)
|
path = '/' + Util.strip_leading_slash(path) if path.is_a?(String)
|
||||||
|
|
||||||
@page_configs << [path, metadata]
|
@page_configs << PageDescriptor.new(path, metadata)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,9 +9,9 @@ module Middleman
|
||||||
@registered = {}
|
@registered = {}
|
||||||
@auto_activate = {
|
@auto_activate = {
|
||||||
# Activate before the Sitemap is instantiated
|
# Activate before the Sitemap is instantiated
|
||||||
before_sitemap: [],
|
before_sitemap: Set.new,
|
||||||
# Activate the extension before `config.rb` and the `:before_configuration` hook.
|
# Activate the extension before `config.rb` and the `:before_configuration` hook.
|
||||||
before_configuration: []
|
before_configuration: Set.new
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoActivation = Struct.new(:name, :modes)
|
AutoActivation = Struct.new(:name, :modes)
|
||||||
|
|
|
@ -32,6 +32,11 @@ class Middleman::Extensions::MinifyCss < ::Middleman::Extension
|
||||||
# Init
|
# Init
|
||||||
# @param [Class] app
|
# @param [Class] app
|
||||||
# @param [Hash] options
|
# @param [Hash] options
|
||||||
|
Contract RespondTo[:call], ({
|
||||||
|
ignore: ArrayOf[PATH_MATCHER],
|
||||||
|
inline: Bool,
|
||||||
|
compressor: Or[Proc, RespondTo[:to_proc], RespondTo[:compress]]
|
||||||
|
}) => Any
|
||||||
def initialize(app, options={})
|
def initialize(app, options={})
|
||||||
@app = app
|
@app = app
|
||||||
@ignore = options.fetch(:ignore)
|
@ignore = options.fetch(:ignore)
|
||||||
|
|
|
@ -23,6 +23,11 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension
|
||||||
# Init
|
# Init
|
||||||
# @param [Class] app
|
# @param [Class] app
|
||||||
# @param [Hash] options
|
# @param [Hash] options
|
||||||
|
Contract RespondTo[:call], ({
|
||||||
|
ignore: ArrayOf[PATH_MATCHER],
|
||||||
|
inline: Bool,
|
||||||
|
compressor: Or[Proc, RespondTo[:to_proc], RespondTo[:compress]]
|
||||||
|
}) => Any
|
||||||
def initialize(app, options={})
|
def initialize(app, options={})
|
||||||
@app = app
|
@app = app
|
||||||
@ignore = options.fetch(:ignore)
|
@ignore = options.fetch(:ignore)
|
||||||
|
|
|
@ -8,21 +8,31 @@ module Middleman
|
||||||
class InlineURLRewriter
|
class InlineURLRewriter
|
||||||
include Contracts
|
include Contracts
|
||||||
|
|
||||||
|
IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
|
||||||
|
|
||||||
|
Contract RespondTo[:call], ({
|
||||||
|
middleman_app: IsA['Middleman::Application'],
|
||||||
|
id: Maybe[Symbol],
|
||||||
|
proc: Or[Proc, Method],
|
||||||
|
url_extensions: ArrayOf[String],
|
||||||
|
source_extensions: ArrayOf[String],
|
||||||
|
ignore: ArrayOf[IGNORE_DESCRIPTOR]
|
||||||
|
}) => Any
|
||||||
def initialize(app, options={})
|
def initialize(app, options={})
|
||||||
@rack_app = app
|
@rack_app = app
|
||||||
@middleman_app = options[:middleman_app]
|
@middleman_app = options.fetch(:middleman_app)
|
||||||
|
|
||||||
@uid = options[:id]
|
@uid = options.fetch(:id, nil)
|
||||||
@proc = options[:proc]
|
@proc = options.fetch(:proc)
|
||||||
|
|
||||||
raise 'InlineURLRewriter requires a :proc to call with inline URL results' unless @proc
|
raise 'InlineURLRewriter requires a :proc to call with inline URL results' unless @proc
|
||||||
|
|
||||||
@exts = options[:url_extensions]
|
@exts = options.fetch(:url_extensions)
|
||||||
|
|
||||||
@source_exts = options[:source_extensions]
|
@source_exts = options.fetch(:source_extensions)
|
||||||
@source_exts_regex_text = Regexp.union(@source_exts).to_s
|
@source_exts_regex_text = Regexp.union(@source_exts).to_s
|
||||||
|
|
||||||
@ignore = options[:ignore]
|
@ignore = options.fetch(:ignore)
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
|
@ -66,7 +76,7 @@ module Middleman
|
||||||
[status, headers, response]
|
[status, headers, response]
|
||||||
end
|
end
|
||||||
|
|
||||||
Contract Or[Regexp, RespondTo[:call], String] => Bool
|
Contract IGNORE_DESCRIPTOR => Bool
|
||||||
def should_ignore?(validator, value)
|
def should_ignore?(validator, value)
|
||||||
if validator.is_a? Regexp
|
if validator.is_a? Regexp
|
||||||
# Treat as Regexp
|
# Treat as Regexp
|
||||||
|
|
|
@ -23,15 +23,15 @@ module Middleman
|
||||||
app.use ::Rack::Lint
|
app.use ::Rack::Lint
|
||||||
app.use ::Rack::Head
|
app.use ::Rack::Head
|
||||||
|
|
||||||
@middleman.middleware.each do |klass, options, middleware_block|
|
@middleman.middleware.each do |middleware|
|
||||||
app.use(klass, *options, &middleware_block)
|
app.use(middleware[:class], *middleware[:options], &middleware[:block])
|
||||||
end
|
end
|
||||||
|
|
||||||
inner_app = self
|
inner_app = self
|
||||||
app.map('/') { run inner_app }
|
app.map('/') { run inner_app }
|
||||||
|
|
||||||
@middleman.mappings.each do |path, map_block|
|
@middleman.mappings.each do |mapping|
|
||||||
app.map(path, &map_block)
|
app.map(mapping[:path], &mapping[:block])
|
||||||
end
|
end
|
||||||
|
|
||||||
app
|
app
|
||||||
|
|
|
@ -10,7 +10,7 @@ module Middleman
|
||||||
@app.define_singleton_method :ignore, &method(:create_ignore)
|
@app.define_singleton_method :ignore, &method(:create_ignore)
|
||||||
|
|
||||||
# Array of callbacks which can ass ignored
|
# Array of callbacks which can ass ignored
|
||||||
@ignored_callbacks = []
|
@ignored_callbacks = Set.new
|
||||||
|
|
||||||
@app.sitemap.define_singleton_method :ignored?, &method(:ignored?)
|
@app.sitemap.define_singleton_method :ignored?, &method(:ignored?)
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,8 +30,11 @@ module Middleman
|
||||||
# @return [String]
|
# @return [String]
|
||||||
alias_method :request_path, :destination_path
|
alias_method :request_path, :destination_path
|
||||||
|
|
||||||
|
METADATA_HASH = ({ options: Maybe[Hash], locals: Maybe[Hash], page: Maybe[Hash] })
|
||||||
|
|
||||||
# The metadata for this resource
|
# The metadata for this resource
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
|
Contract None => METADATA_HASH
|
||||||
attr_reader :metadata
|
attr_reader :metadata
|
||||||
|
|
||||||
# Initialize resource with parent store and URL
|
# Initialize resource with parent store and URL
|
||||||
|
@ -66,7 +69,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.
|
||||||
Contract Hash => Hash
|
Contract METADATA_HASH => METADATA_HASH
|
||||||
def add_metadata(meta={})
|
def add_metadata(meta={})
|
||||||
@metadata.deep_merge!(meta)
|
@metadata.deep_merge!(meta)
|
||||||
end
|
end
|
||||||
|
|
|
@ -124,7 +124,7 @@ module Middleman
|
||||||
# @param [String, #match, #call] matcher A matcher String, RegExp, Proc, etc.
|
# @param [String, #match, #call] matcher A matcher String, RegExp, Proc, etc.
|
||||||
# @param [String] path A path as a string
|
# @param [String] path A path as a string
|
||||||
# @return [Boolean] Whether the path matches the matcher
|
# @return [Boolean] Whether the path matches the matcher
|
||||||
Contract Or[String, RespondTo[:match], RespondTo[:call], RespondTo[:to_s]], String => Bool
|
Contract PATH_MATCHER, String => Bool
|
||||||
def self.path_match(matcher, path)
|
def self.path_match(matcher, path)
|
||||||
case
|
case
|
||||||
when matcher.is_a?(String)
|
when matcher.is_a?(String)
|
||||||
|
|
Loading…
Reference in a new issue