Finish porting to new callbacks manager
This commit is contained in:
parent
f8e4f6f059
commit
e64954fbff
15 changed files with 330 additions and 193 deletions
|
@ -1,29 +1,14 @@
|
|||
# i18n Built-in
|
||||
require 'i18n'
|
||||
|
||||
# Don't fail on invalid locale, that's not what our current
|
||||
# users expect.
|
||||
::I18n.enforce_available_locales = false
|
||||
|
||||
# Use ActiveSupport JSON
|
||||
require 'active_support/json'
|
||||
require 'active_support/core_ext/integer/inflections'
|
||||
|
||||
# Simple callback library
|
||||
require 'hooks'
|
||||
|
||||
# Our custom logger
|
||||
require 'middleman-core/logger'
|
||||
|
||||
require 'middleman-core/contracts'
|
||||
|
||||
require 'middleman-core/callback_manager'
|
||||
require 'middleman-core/logger'
|
||||
require 'middleman-core/sitemap/store'
|
||||
|
||||
require 'middleman-core/configuration'
|
||||
|
||||
require 'middleman-core/extension_manager'
|
||||
require 'middleman-core/core_extensions'
|
||||
|
||||
require 'middleman-core/config_context'
|
||||
require 'middleman-core/file_renderer'
|
||||
require 'middleman-core/template_renderer'
|
||||
|
@ -38,6 +23,9 @@ module Middleman
|
|||
include Contracts
|
||||
|
||||
class << self
|
||||
extend Forwardable
|
||||
def_delegator :config, :define_setting
|
||||
|
||||
# Global configuration for the whole Middleman project.
|
||||
# @return [ConfigurationManager]
|
||||
def config
|
||||
|
@ -56,38 +44,37 @@ module Middleman
|
|||
end
|
||||
end
|
||||
|
||||
# Uses callbacks
|
||||
include Hooks
|
||||
include Hooks::InstanceHooks
|
||||
Contract ::Middleman::ConfigContext
|
||||
attr_reader :config_context
|
||||
|
||||
define_hook :initialized
|
||||
define_hook :after_configuration
|
||||
define_hook :before_configuration
|
||||
Contract ::Middleman::Sitemap::Store
|
||||
attr_reader :sitemap
|
||||
|
||||
# Before request hook
|
||||
define_hook :before
|
||||
# An anonymous subclass of ::Middleman::TemplateContext
|
||||
attr_reader :template_context_class
|
||||
|
||||
# Ready (all loading and parsing of extensions complete) hook
|
||||
define_hook :ready
|
||||
# An instance of the above anonymouse class.
|
||||
attr_reader :generic_template_context
|
||||
|
||||
# Runs before the build is started
|
||||
define_hook :before_build
|
||||
Contract ::Middleman::Configuration::ConfigurationManager
|
||||
attr_reader :config
|
||||
|
||||
# Runs after the build is finished
|
||||
define_hook :after_build
|
||||
Contract ::Middleman::ExtensionManager
|
||||
attr_reader :extensions
|
||||
|
||||
define_hook :before_shutdown
|
||||
Contract SetOf[MiddlewareDescriptor]
|
||||
attr_reader :middleware
|
||||
|
||||
define_hook :before_render
|
||||
define_hook :after_render
|
||||
Contract SetOf[MapDescriptor]
|
||||
attr_reader :mappings
|
||||
|
||||
# Which host preview should start on.
|
||||
# @return [Fixnum]
|
||||
config.define_setting :host, '0.0.0.0', 'The preview server host'
|
||||
define_setting :host, '0.0.0.0', 'The preview server host'
|
||||
|
||||
# Which port preview should start on.
|
||||
# @return [Fixnum]
|
||||
config.define_setting :port, 4567, 'The preview server port'
|
||||
define_setting :port, 4567, 'The preview server port'
|
||||
|
||||
# Whether to serve the preview server over HTTPS.
|
||||
# @return [Boolean]
|
||||
|
@ -103,73 +90,73 @@ module Middleman
|
|||
|
||||
# Name of the source directory
|
||||
# @return [String]
|
||||
config.define_setting :source, 'source', 'Name of the source directory'
|
||||
define_setting :source, 'source', 'Name of the source directory'
|
||||
|
||||
# Middleman mode. Defaults to :server, set to :build by the build process
|
||||
# @return [String]
|
||||
config.define_setting :mode, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :server), 'Middleman mode. Defaults to :server'
|
||||
define_setting :mode, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :server), 'Middleman mode. Defaults to :server'
|
||||
|
||||
# Middleman environment. Defaults to :development
|
||||
# @return [String]
|
||||
config.define_setting :environment, :development, 'Middleman environment. Defaults to :development'
|
||||
define_setting :environment, :development, 'Middleman environment. Defaults to :development'
|
||||
|
||||
# Which file should be used for directory indexes
|
||||
# @return [String]
|
||||
config.define_setting :index_file, 'index.html', 'Which file should be used for directory indexes'
|
||||
define_setting :index_file, 'index.html', 'Which file should be used for directory indexes'
|
||||
|
||||
# Whether to strip the index file name off links to directory indexes
|
||||
# @return [Boolean]
|
||||
config.define_setting :strip_index_file, true, 'Whether to strip the index file name off links to directory indexes'
|
||||
define_setting :strip_index_file, true, 'Whether to strip the index file name off links to directory indexes'
|
||||
|
||||
# Whether to include a trailing slash when stripping the index file
|
||||
# @return [Boolean]
|
||||
config.define_setting :trailing_slash, true, 'Whether to include a trailing slash when stripping the index file'
|
||||
define_setting :trailing_slash, true, 'Whether to include a trailing slash when stripping the index file'
|
||||
|
||||
# Location of javascripts within source.
|
||||
# @return [String]
|
||||
config.define_setting :js_dir, 'javascripts', 'Location of javascripts within source'
|
||||
define_setting :js_dir, 'javascripts', 'Location of javascripts within source'
|
||||
|
||||
# Location of stylesheets within source. Used by Compass.
|
||||
# @return [String]
|
||||
config.define_setting :css_dir, 'stylesheets', 'Location of stylesheets within source'
|
||||
define_setting :css_dir, 'stylesheets', 'Location of stylesheets within source'
|
||||
|
||||
# Location of images within source. Used by HTML helpers and Compass.
|
||||
# @return [String]
|
||||
config.define_setting :images_dir, 'images', 'Location of images within source'
|
||||
define_setting :images_dir, 'images', 'Location of images within source'
|
||||
|
||||
# Location of fonts within source. Used by Compass.
|
||||
# @return [String]
|
||||
config.define_setting :fonts_dir, 'fonts', 'Location of fonts within source'
|
||||
define_setting :fonts_dir, 'fonts', 'Location of fonts within source'
|
||||
|
||||
# Location of layouts within source. Used by renderers.
|
||||
# @return [String]
|
||||
config.define_setting :layouts_dir, 'layouts', 'Location of layouts within source'
|
||||
define_setting :layouts_dir, 'layouts', 'Location of layouts within source'
|
||||
|
||||
# Where to build output files
|
||||
# @return [String]
|
||||
config.define_setting :build_dir, 'build', 'Where to build output files'
|
||||
define_setting :build_dir, 'build', 'Where to build output files'
|
||||
|
||||
# Default prefix for building paths. Used by HTML helpers and Compass.
|
||||
# @return [String]
|
||||
config.define_setting :http_prefix, '/', 'Default prefix for building paths'
|
||||
define_setting :http_prefix, '/', 'Default prefix for building paths'
|
||||
|
||||
# Default layout name
|
||||
# @return [String, Symbold]
|
||||
config.define_setting :layout, :_auto_layout, 'Default layout name'
|
||||
define_setting :layout, :_auto_layout, 'Default layout name'
|
||||
|
||||
# Default string encoding for templates and output.
|
||||
# @return [String]
|
||||
config.define_setting :encoding, 'utf-8', 'Default string encoding for templates and output'
|
||||
define_setting :encoding, 'utf-8', 'Default string encoding for templates and output'
|
||||
|
||||
# Should Padrino include CRSF tag
|
||||
# @return [Boolean]
|
||||
config.define_setting :protect_from_csrf, false, 'Should Padrino include CRSF tag'
|
||||
define_setting :protect_from_csrf, false, 'Should Padrino include CRSF tag'
|
||||
|
||||
# Set to automatically convert some characters into a directory
|
||||
config.define_setting :automatic_directory_matcher, nil, 'Set to automatically convert some characters into a directory'
|
||||
define_setting :automatic_directory_matcher, nil, 'Set to automatically convert some characters into a directory'
|
||||
|
||||
# Setup callbacks which can exclude paths from the sitemap
|
||||
config.define_setting :ignored_sitemap_matchers, {
|
||||
define_setting :ignored_sitemap_matchers, {
|
||||
# Files starting with an underscore, but not a double-underscore
|
||||
partials: proc { |file|
|
||||
ignored = false
|
||||
|
@ -190,37 +177,40 @@ module Middleman
|
|||
}
|
||||
}, 'Callbacks that can exclude paths from the sitemap'
|
||||
|
||||
config.define_setting :watcher_disable, false, 'If the Listen watcher should not run'
|
||||
config.define_setting :watcher_force_polling, false, 'If the Listen watcher should run in polling mode'
|
||||
config.define_setting :watcher_latency, nil, 'The Listen watcher latency'
|
||||
define_setting :watcher_disable, false, 'If the Listen watcher should not run'
|
||||
define_setting :watcher_force_polling, false, 'If the Listen watcher should run in polling mode'
|
||||
define_setting :watcher_latency, nil, 'The Listen watcher latency'
|
||||
|
||||
attr_reader :config_context
|
||||
attr_reader :sitemap
|
||||
attr_reader :cache
|
||||
attr_reader :template_context_class
|
||||
attr_reader :config
|
||||
attr_reader :generic_template_context
|
||||
attr_reader :extensions
|
||||
attr_reader :sources
|
||||
|
||||
Contract SetOf[MiddlewareDescriptor]
|
||||
attr_reader :middleware
|
||||
|
||||
Contract SetOf[MapDescriptor]
|
||||
attr_reader :mappings
|
||||
|
||||
# Reference to Logger singleton
|
||||
# Delegate convenience methods off to their implementations
|
||||
def_delegator :"::Middleman::Logger", :singleton, :logger
|
||||
def_delegator :"::Middleman::Util", :instrument
|
||||
def_delegators :"self.class", :root, :root_path
|
||||
def_delegators :@generic_template_context, :link_to, :image_tag, :asset_path
|
||||
def_delegators :@extensions, :activate
|
||||
def_delegators :config, :define_setting
|
||||
|
||||
# Initialize the Middleman project
|
||||
def initialize(&block)
|
||||
# Search the root of the project for required files
|
||||
$LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
|
||||
|
||||
@callbacks = ::Middleman::CallbackManager.new
|
||||
@callbacks.install_methods!(self, [
|
||||
:initialized,
|
||||
:configure,
|
||||
:before_sitemap,
|
||||
:before_configuration,
|
||||
:after_configuration,
|
||||
:after_configuration_eval,
|
||||
:ready,
|
||||
:before_build,
|
||||
:after_build,
|
||||
:before_shutdown,
|
||||
:before, # Before Rack requests
|
||||
:before_render,
|
||||
:after_render
|
||||
])
|
||||
|
||||
@middleware = Set.new
|
||||
@mappings = Set.new
|
||||
|
||||
|
@ -228,21 +218,22 @@ module Middleman
|
|||
@generic_template_context = @template_context_class.new(self)
|
||||
@config_context = ConfigContext.new(self, @template_context_class)
|
||||
|
||||
::Middleman::FileRenderer.cache.clear
|
||||
::Middleman::TemplateRenderer.cache.clear
|
||||
|
||||
# Setup the default values from calls to set before initialization
|
||||
@config = ::Middleman::Configuration::ConfigurationManager.new
|
||||
@config.load_settings(self.class.config.all_settings)
|
||||
|
||||
config[:source] = ENV['MM_SOURCE'] if ENV['MM_SOURCE']
|
||||
|
||||
# TODO, make this less global
|
||||
::Middleman::FileRenderer.cache.clear
|
||||
::Middleman::TemplateRenderer.cache.clear
|
||||
|
||||
@extensions = ::Middleman::ExtensionManager.new(self)
|
||||
|
||||
# Evaluate a passed block if given
|
||||
config_context.instance_exec(&block) if block_given?
|
||||
|
||||
@extensions.auto_activate(:before_sitemap)
|
||||
execute_callbacks(:before_sitemap)
|
||||
|
||||
# Initialize the Sitemap
|
||||
@sitemap = ::Middleman::Sitemap::Store.new(self)
|
||||
|
@ -254,42 +245,34 @@ module Middleman
|
|||
|
||||
::Middleman::Extension.clear_after_extension_callbacks
|
||||
|
||||
@extensions.auto_activate(:before_configuration)
|
||||
after_configuration_eval(&method(:prune_tilt_templates))
|
||||
|
||||
run_hook :initialized
|
||||
|
||||
run_hook :before_configuration
|
||||
|
||||
evaluate_configuration
|
||||
|
||||
# This is for making the tests work - since the tests
|
||||
# don't completely reload middleman, I18n.load_path can get
|
||||
# polluted with paths from other test app directories that don't
|
||||
# exist anymore.
|
||||
if ENV['TEST']
|
||||
::I18n.load_path.delete_if { |path| path =~ %r{tmp/aruba} }
|
||||
::I18n.reload!
|
||||
end
|
||||
|
||||
# Clean up missing Tilt exts
|
||||
Tilt.mappings.each do |key, _|
|
||||
begin
|
||||
Tilt[".#{key}"]
|
||||
rescue LoadError, NameError
|
||||
Tilt.mappings.delete(key)
|
||||
end
|
||||
end
|
||||
|
||||
@extensions.activate_all
|
||||
|
||||
run_hook :after_configuration
|
||||
config_context.execute_callbacks(:after_configuration)
|
||||
|
||||
run_hook :ready
|
||||
@config_context.execute_callbacks(:ready)
|
||||
start_lifecycle
|
||||
end
|
||||
|
||||
def evaluate_configuration
|
||||
# Boot the app.
|
||||
def start_lifecycle
|
||||
# Before config is parsed, before extensions get to it.
|
||||
execute_callbacks(:initialized)
|
||||
|
||||
# Before config is parsed. Mostly used for extensions.
|
||||
execute_callbacks(:before_configuration)
|
||||
|
||||
# Eval config.
|
||||
evaluate_configuration!
|
||||
|
||||
# Post parsing, pre-extension callback
|
||||
execute_callbacks(:after_configuration_eval)
|
||||
|
||||
# After extensions have worked after_config
|
||||
execute_callbacks(:after_configuration)
|
||||
|
||||
# Everything is stable
|
||||
execute_callbacks(:ready)
|
||||
end
|
||||
|
||||
# Eval config
|
||||
def evaluate_configuration!
|
||||
# Check for and evaluate local configuration in `config.rb`
|
||||
config_rb = File.join(root, 'config.rb')
|
||||
if File.exist? config_rb
|
||||
|
@ -311,49 +294,67 @@ module Middleman
|
|||
end
|
||||
|
||||
# Run any `configure` blocks for the current environment.
|
||||
config_context.execute_callbacks([:configure, config[:environment]])
|
||||
execute_callbacks([:configure, config[:environment]])
|
||||
|
||||
# Run any `configure` blocks for the current mode.
|
||||
config_context.execute_callbacks([:configure, config[:mode]])
|
||||
execute_callbacks([:configure, config[:mode]])
|
||||
end
|
||||
|
||||
# Clean up missing Tilt exts
|
||||
def prune_tilt_templates
|
||||
::Tilt.mappings.each do |key, _|
|
||||
begin
|
||||
::Tilt[".#{key}"]
|
||||
rescue LoadError, NameError
|
||||
::Tilt.mappings.delete(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Whether we're in server mode
|
||||
# @return [Boolean] If we're in dev mode
|
||||
Contract Bool
|
||||
def server?
|
||||
config[:mode] == :server
|
||||
end
|
||||
|
||||
# Whether we're in build mode
|
||||
# @return [Boolean] If we're in dev mode
|
||||
Contract Bool
|
||||
def build?
|
||||
config[:mode] == :build
|
||||
end
|
||||
|
||||
# Whether we're in a specific environment
|
||||
# @return [Boolean]
|
||||
Contract Bool
|
||||
def environment?(key)
|
||||
config[:environment] == key
|
||||
end
|
||||
|
||||
# Backwards compatible helper. What the current environment is.
|
||||
# @return [Symbol]
|
||||
Contract Symbol
|
||||
def environment
|
||||
config[:environment]
|
||||
end
|
||||
|
||||
# Backwards compatible helper. Whether we're in dev mode.
|
||||
# @return [Boolean]
|
||||
Contract Bool
|
||||
def development?
|
||||
environment?(:development)
|
||||
end
|
||||
|
||||
# Backwards compatible helper. Whether we're in production mode.
|
||||
# @return [Boolean]
|
||||
Contract Bool
|
||||
def production?
|
||||
environment?(:production)
|
||||
end
|
||||
|
||||
# Backwards compatible helper. The full path to the default source dir.
|
||||
Contract Pathname
|
||||
def source_dir
|
||||
Pathname(File.join(root, config[:source]))
|
||||
end
|
||||
|
@ -376,8 +377,9 @@ module Middleman
|
|||
@mappings << MapDescriptor.new(map, block)
|
||||
end
|
||||
|
||||
# Let everyone know we're shutting down.
|
||||
def shutdown!
|
||||
run_hook :before_shutdown
|
||||
execute_callbacks(:before_shutdown)
|
||||
end
|
||||
|
||||
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
||||
|
|
|
@ -2,6 +2,7 @@ require 'pathname'
|
|||
require 'fileutils'
|
||||
require 'tempfile'
|
||||
require 'middleman-core/rack'
|
||||
require 'middleman-core/callback_manager'
|
||||
require 'middleman-core/contracts'
|
||||
|
||||
module Middleman
|
||||
|
@ -36,10 +37,11 @@ module Middleman
|
|||
@glob = opts.fetch(:glob)
|
||||
@cleaning = opts.fetch(:clean)
|
||||
|
||||
@_event_callbacks = []
|
||||
|
||||
rack_app = ::Middleman::Rack.new(@app).to_app
|
||||
@rack = ::Rack::MockRequest.new(rack_app)
|
||||
|
||||
@callbacks = ::Middleman::CallbackManager.new
|
||||
@callbacks.install_methods!(self, [:on_build_event])
|
||||
end
|
||||
|
||||
# Run the build phase.
|
||||
|
@ -49,7 +51,7 @@ module Middleman
|
|||
@has_error = false
|
||||
@events = {}
|
||||
|
||||
@app.run_hook :before_build, self
|
||||
@app.execute_callbacks(:before_build, [self])
|
||||
|
||||
queue_current_paths if @cleaning
|
||||
prerender_css
|
||||
|
@ -60,21 +62,11 @@ module Middleman
|
|||
|
||||
::Middleman::Profiling.report('build')
|
||||
|
||||
# Run hooks
|
||||
@app.run_hook :after_build, self
|
||||
@app.config_context.execute_callbacks(:after_build, [self])
|
||||
@app.execute_callbacks(:after_build, [self])
|
||||
|
||||
!@has_error
|
||||
end
|
||||
|
||||
# Attach callbacks for build events.
|
||||
# @return [Array<Proc>] All the attached events.
|
||||
Contract Proc => ArrayOf[Proc]
|
||||
def on_build_event(&block)
|
||||
@_event_callbacks << block if block_given?
|
||||
@_event_callbacks
|
||||
end
|
||||
|
||||
# Pre-request CSS to give Compass a chance to build sprites
|
||||
# @return [Array<Resource>] List of css resources that were output.
|
||||
Contract ResourceList
|
||||
|
@ -253,9 +245,7 @@ module Middleman
|
|||
@events[event_type] ||= []
|
||||
@events[event_type] << target
|
||||
|
||||
@_event_callbacks.each do |callback|
|
||||
callback.call(event_type, target, extra)
|
||||
end
|
||||
execute_callbacks(:on_build_event, [event_type, target, extra])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,22 +11,23 @@ module Middleman
|
|||
@callbacks = ::Hamster.hash
|
||||
end
|
||||
|
||||
Contract RespondTo[:define_singleton_method], ArrayOf[Symbol], Maybe[Proc] => Any
|
||||
def install_methods!(install_target, names, &block)
|
||||
Contract RespondTo[:define_singleton_method], ArrayOf[Symbol] => Any
|
||||
def install_methods!(install_target, names)
|
||||
manager = self
|
||||
|
||||
names.each do |name|
|
||||
method_name = block_given? ? block.call(name) : name
|
||||
|
||||
names.each do |method_name|
|
||||
install_target.define_singleton_method(method_name) do |*keys, &b|
|
||||
key_set = keys.unshift(name)
|
||||
manager.add(key_set.length > 1 ? key_set : key_set.first, &b)
|
||||
key_set = keys.unshift(method_name)
|
||||
manager.add(key_set.length > 1 ? key_set : key_set[0], &b)
|
||||
end
|
||||
end
|
||||
|
||||
install_target.define_singleton_method(:execute_callbacks) do |keys, *args|
|
||||
manager.execute(keys, args, self)
|
||||
install_target.define_singleton_method(:execute_callbacks) do |*args|
|
||||
keys = args.shift
|
||||
manager.execute(keys, args[0], self)
|
||||
end
|
||||
|
||||
install_target.define_singleton_method(:callbacks_for, &method(:callbacks_for))
|
||||
end
|
||||
|
||||
Contract Or[Symbol, ArrayOf[Symbol]], Proc => Any
|
||||
|
@ -34,16 +35,19 @@ module Middleman
|
|||
immutable_keys = keys.is_a?(Symbol) ? keys : ::Hamster::Vector.new(keys)
|
||||
|
||||
@callbacks = @callbacks.put(immutable_keys) do |v|
|
||||
v.nil? ? ::Hamster.set(block) : v.add(block)
|
||||
v.nil? ? ::Hamster::Vector.new([block]) : v.push(block)
|
||||
end
|
||||
end
|
||||
|
||||
Contract Or[Symbol, ArrayOf[Symbol]], Maybe[ArrayOf[Any]], Maybe[RespondTo[:instance_exec]] => Any
|
||||
def execute(keys, args=[], scope=self)
|
||||
immutable_keys = keys.is_a?(Symbol) ? keys : ::Hamster::Vector.new(keys)
|
||||
callbacks_for(keys).each { |b| scope.instance_exec(*args, &b) }
|
||||
end
|
||||
|
||||
callbacks = @callbacks.get(immutable_keys)
|
||||
callbacks && callbacks.each { |b| scope.instance_exec(*args, &b) }
|
||||
Contract Or[Symbol, ArrayOf[Symbol]] => ::Hamster::Vector
|
||||
def callbacks_for(keys)
|
||||
immutable_keys = keys.is_a?(Symbol) ? keys : ::Hamster::Vector.new(keys)
|
||||
@callbacks.get(immutable_keys) || ::Hamster.vector
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,8 +15,19 @@ module Middleman
|
|||
@app = app
|
||||
@template_context_class = template_context_class
|
||||
|
||||
sub_callbacks = [:before_build, :after_build, :configure, :after_configuration, :ready]
|
||||
|
||||
@callbacks = ::Middleman::CallbackManager.new
|
||||
@callbacks.install_methods!(self, [:ready, :after_build, :after_configuration, :configure])
|
||||
@callbacks.install_methods!(self, sub_callbacks)
|
||||
|
||||
# Trigger internal callbacks when app level are executed.
|
||||
self_context = self
|
||||
|
||||
sub_callbacks.each do |key|
|
||||
app.send(key) do |*args|
|
||||
self_context.execute_callbacks(key, args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def helpers(*helper_modules, &block)
|
||||
|
|
|
@ -10,6 +10,25 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
|
|||
# Exposes `langs` to templates
|
||||
expose_to_template :langs
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
|
||||
require 'i18n'
|
||||
|
||||
# Don't fail on invalid locale, that's not what our current
|
||||
# users expect.
|
||||
::I18n.enforce_available_locales = false
|
||||
|
||||
# This is for making the tests work - since the tests
|
||||
# don't completely reload middleman, I18n.load_path can get
|
||||
# polluted with paths from other test app directories that don't
|
||||
# exist anymore.
|
||||
app.after_configuration_eval do
|
||||
::I18n.load_path.delete_if { |path| path =~ %r{tmp/aruba} }
|
||||
::I18n.reload!
|
||||
end if ENV['TEST']
|
||||
end
|
||||
|
||||
def after_configuration
|
||||
# See https://github.com/svenfuchs/i18n/wiki/Fallbacks
|
||||
unless options[:no_fallbacks]
|
||||
|
|
|
@ -380,6 +380,7 @@ module Middleman
|
|||
|
||||
def bind_after_configuration
|
||||
ext = self
|
||||
|
||||
@app.after_configuration do
|
||||
ext.after_configuration if ext.respond_to?(:after_configuration)
|
||||
|
||||
|
|
|
@ -8,6 +8,17 @@ module Middleman
|
|||
def initialize(app)
|
||||
@app = app
|
||||
@activated = {}
|
||||
|
||||
manager = self
|
||||
{
|
||||
before_sitemap: :before_sitemap,
|
||||
initialized: :before_configuration
|
||||
}.each do |key, value|
|
||||
cb = proc { manager.auto_activate(value) }
|
||||
@app.send(key, &cb)
|
||||
end
|
||||
|
||||
@app.after_configuration_eval(&method(:activate_all))
|
||||
end
|
||||
|
||||
def auto_activate(key)
|
||||
|
|
|
@ -59,14 +59,10 @@ module Middleman
|
|||
options = options.deep_merge(options[:renderer_options]) if options[:renderer_options]
|
||||
|
||||
template_class = ::Tilt[path]
|
||||
|
||||
# Allow hooks to manipulate the template before render
|
||||
@app.class.callbacks_for_hook(:before_render).each do |callback|
|
||||
newbody = if callback.respond_to?(:call)
|
||||
callback.call(body, path, locs, template_class)
|
||||
elsif callback.respond_to?(:evaluate)
|
||||
callback.evaluate(self, body, path, locs, template_class)
|
||||
end
|
||||
body = newbody if newbody # Allow the callback to return nil to skip it
|
||||
body = @app.callbacks_for(:before_render).reduce(body) do |sum, callback|
|
||||
callback.call(sum, path, locs, template_class) || sum
|
||||
end
|
||||
|
||||
# Read compiled template from disk or cache
|
||||
|
@ -80,14 +76,8 @@ module Middleman
|
|||
end
|
||||
|
||||
# Allow hooks to manipulate the result after render
|
||||
@app.class.callbacks_for_hook(:after_render).each do |callback|
|
||||
# Uber::Options::Value doesn't respond to call
|
||||
newcontent = if callback.respond_to?(:call)
|
||||
callback.call(content, path, locs, template_class)
|
||||
elsif callback.respond_to?(:evaluate)
|
||||
callback.evaluate(self, content, path, locs, template_class)
|
||||
end
|
||||
content = newcontent if newcontent # Allow the callback to return nil to skip it
|
||||
content = @app.callbacks_for(:before_render).reduce(content) do |sum, callback|
|
||||
callback.call(sum, path, locs, template_class) || sum
|
||||
end
|
||||
|
||||
output = ::ActiveSupport::SafeBuffer.new ''
|
||||
|
|
|
@ -85,7 +85,7 @@ module Middleman
|
|||
full_request_path = File.join(env['SCRIPT_NAME'], request_path) # Path including rack mount
|
||||
|
||||
# Run before callbacks
|
||||
@middleman.run_hook :before
|
||||
@middleman.execute_callbacks(:before)
|
||||
|
||||
# Get the resource object for this path
|
||||
resource = @middleman.sitemap.find_resource_by_destination_path(request_path.gsub(' ', '%20'))
|
||||
|
|
|
@ -13,9 +13,7 @@ module Middleman
|
|||
::Tilt.register 'coffee', DebuggingCoffeeScriptTemplate
|
||||
::Tilt.prefer(DebuggingCoffeeScriptTemplate)
|
||||
|
||||
app.before_configuration do
|
||||
DebuggingCoffeeScriptTemplate.middleman_app = self
|
||||
end
|
||||
DebuggingCoffeeScriptTemplate.middleman_app = app
|
||||
end
|
||||
|
||||
# A Template for Tilt which outputs debug messages
|
||||
|
|
|
@ -12,7 +12,7 @@ module Middleman
|
|||
def initialize(app, config={}, &block)
|
||||
super
|
||||
|
||||
# Array of callbacks which can ass ignored
|
||||
# Array of callbacks which can assign ignored
|
||||
@ignored_callbacks = Set.new
|
||||
|
||||
@app.sitemap.define_singleton_method(:ignored?, &method(:ignored?))
|
||||
|
|
|
@ -345,4 +345,4 @@ module Middleman
|
|||
end
|
||||
|
||||
# And, require the actual default implementation for a watcher.
|
||||
require 'middleman-core/sources/source_watcher.rb'
|
||||
require 'middleman-core/sources/source_watcher'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Watcher Library
|
||||
require 'listen'
|
||||
require 'middleman-core/contracts'
|
||||
require 'middleman-core/contracts'
|
||||
require 'backports/2.0.0/enumerable/lazy'
|
||||
|
||||
module Middleman
|
||||
|
@ -55,7 +56,8 @@ module Middleman
|
|||
|
||||
@listener = nil
|
||||
|
||||
@on_change_callbacks = Set.new
|
||||
@callbacks = ::Middleman::CallbackManager.new
|
||||
@callbacks.install_methods!(self, [:on_change])
|
||||
|
||||
@waiting_for_existence = !@directory.exist?
|
||||
end
|
||||
|
@ -174,16 +176,6 @@ module Middleman
|
|||
listen!
|
||||
end
|
||||
|
||||
# Add callback to be run on file change
|
||||
#
|
||||
# @param [Proc] matcher A Regexp to match the change path against
|
||||
# @return [Set<Proc>]
|
||||
Contract Proc => SetOf[Proc]
|
||||
def on_change(&block)
|
||||
@on_change_callbacks << block
|
||||
@on_change_callbacks
|
||||
end
|
||||
|
||||
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
||||
# where Ruby will call to_s/inspect while printing exception
|
||||
# messages, which can take a long time (minutes at full CPU)
|
||||
|
@ -237,11 +229,11 @@ module Middleman
|
|||
logger.debug "== Deletion (#{f[:types].inspect}): #{f[:relative_path]}"
|
||||
end
|
||||
|
||||
run_callbacks(
|
||||
@on_change_callbacks,
|
||||
execute_callbacks(:on_change, [
|
||||
valid_updates,
|
||||
valid_removes
|
||||
) unless valid_updates.empty? && valid_removes.empty?
|
||||
valid_removes,
|
||||
self
|
||||
]) unless valid_updates.empty? && valid_removes.empty?
|
||||
end
|
||||
|
||||
def add_file_to_cache(f)
|
||||
|
@ -289,17 +281,5 @@ module Middleman
|
|||
|
||||
::Middleman::SourceFile.new(Pathname(relative_path), path, @directory, types)
|
||||
end
|
||||
|
||||
# Notify callbacks for a file given an array of callbacks
|
||||
#
|
||||
# @param [Pathname] path The file that was changed
|
||||
# @param [Symbol] callbacks_name The name of the callbacks method
|
||||
# @return [void]
|
||||
Contract Set, ArrayOf[IsA['Middleman::SourceFile']], ArrayOf[IsA['Middleman::SourceFile']] => Any
|
||||
def run_callbacks(callbacks, updated_files, removed_files)
|
||||
callbacks.each do |callback|
|
||||
callback.call(updated_files, removed_files, self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,7 +24,6 @@ Gem::Specification.new do |s|
|
|||
s.add_dependency('rack', ['>= 1.4.5', '< 2.0'])
|
||||
s.add_dependency('tilt', ['~> 1.4.1'])
|
||||
s.add_dependency('erubis')
|
||||
s.add_dependency('hooks', ['~> 0.3'])
|
||||
|
||||
# Helpers
|
||||
s.add_dependency('activesupport', ['~> 4.2.0'])
|
||||
|
|
132
middleman-core/spec/middleman-core/callbacks_spec.rb
Normal file
132
middleman-core/spec/middleman-core/callbacks_spec.rb
Normal file
|
@ -0,0 +1,132 @@
|
|||
# require 'spec_helper'
|
||||
require 'middleman-core/callback_manager'
|
||||
|
||||
describe ::Middleman::CallbackManager do
|
||||
it "adds a simple key" do
|
||||
counters = {
|
||||
test1: 0,
|
||||
test2: 0,
|
||||
test3: 0
|
||||
}
|
||||
|
||||
m = ::Middleman::CallbackManager.new
|
||||
m.add(:test3) { counters[:test3] += 1 }
|
||||
m.add(:test1) { counters[:test1] += 1 }
|
||||
m.add(:test2) { counters[:test2] += 1 }
|
||||
m.add(:test1) { counters[:test1] += 1 }
|
||||
m.add(:test2) { counters[:test2] += 1 }
|
||||
m.add(:test1) { counters[:test1] += 1 }
|
||||
m.add(:test3) { counters[:test3] += 1 }
|
||||
|
||||
m.execute(:test1)
|
||||
m.execute(:test2)
|
||||
|
||||
expect(counters[:test1]).to eq 3
|
||||
expect(counters[:test2]).to eq 2
|
||||
expect(counters[:test3]).to eq 0
|
||||
end
|
||||
|
||||
it "callbacks run in order" do
|
||||
result = []
|
||||
|
||||
m = ::Middleman::CallbackManager.new
|
||||
m.add(:test) { result.push(1) }
|
||||
m.add(:test) { result.push(2) }
|
||||
m.add(:test) { result.push(3) }
|
||||
|
||||
m.execute(:test)
|
||||
|
||||
expect(result.join('')).to eq '123'
|
||||
end
|
||||
|
||||
it "adds a nested key" do
|
||||
counters = {
|
||||
test1: 0,
|
||||
test1a: 0
|
||||
}
|
||||
|
||||
m = ::Middleman::CallbackManager.new
|
||||
m.add([:test1, :a]) { |n| counters[:test1a] += n }
|
||||
m.add(:test1) { counters[:test1] += 1 }
|
||||
|
||||
m.execute([:test1, :a], [2])
|
||||
m.execute([:test1, :b], [5])
|
||||
|
||||
expect(counters[:test1]).to eq 0
|
||||
expect(counters[:test1a]).to eq 2
|
||||
end
|
||||
|
||||
it "works in isolation" do
|
||||
m1 = ::Middleman::CallbackManager.new
|
||||
m2 = ::Middleman::CallbackManager.new
|
||||
|
||||
counters = {
|
||||
test1: 0,
|
||||
test2: 0
|
||||
}
|
||||
|
||||
m1.add(:test1) { |n| counters[:test1] += n }
|
||||
m2.add(:test1) { |n| counters[:test2] += n }
|
||||
|
||||
m1.execute(:test1, [2])
|
||||
m2.execute(:test1, [5])
|
||||
m1.execute(:test2, [20])
|
||||
m2.execute(:test2, [50])
|
||||
|
||||
expect(counters[:test1]).to eq 2
|
||||
expect(counters[:test2]).to eq 5
|
||||
end
|
||||
|
||||
it "installs to arbitrary instances" do
|
||||
instance = Class.new(Object).new
|
||||
|
||||
m = ::Middleman::CallbackManager.new
|
||||
m.install_methods!(instance, [:ready])
|
||||
|
||||
counter = 0
|
||||
instance.ready { |n| counter += n }
|
||||
instance.execute_callbacks(:ready, [2])
|
||||
instance.execute_callbacks(:ready2, [10])
|
||||
instance.execute_callbacks([:ready], [20])
|
||||
instance.execute_callbacks([:ready, :two], [20])
|
||||
expect(counter).to eq 2
|
||||
end
|
||||
|
||||
it "executes in default scope" do
|
||||
instance = Class.new(Object).new
|
||||
m = ::Middleman::CallbackManager.new
|
||||
m.install_methods!(instance, [:ready])
|
||||
|
||||
internal_self = nil
|
||||
instance.ready do
|
||||
internal_self = self
|
||||
end
|
||||
|
||||
instance.execute_callbacks(:ready)
|
||||
|
||||
expect(internal_self) === instance
|
||||
end
|
||||
|
||||
it "executes in custom scope" do
|
||||
instance = Class.new(Object).new
|
||||
m = ::Middleman::CallbackManager.new
|
||||
m.install_methods!(instance, [:ready])
|
||||
|
||||
external_class = Struct.new(:counter, :scope) do
|
||||
def when_ready(n)
|
||||
self[:scope] = self
|
||||
self[:counter] += n
|
||||
end
|
||||
end
|
||||
|
||||
external_instance = external_class.new(0, nil)
|
||||
|
||||
instance.ready(&external_instance.method(:when_ready))
|
||||
|
||||
instance.execute_callbacks(:ready, [5])
|
||||
|
||||
expect(external_instance[:scope]).to eq external_instance
|
||||
expect(external_instance[:counter]).to eq 5
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue