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