2015-05-03 03:47:16 +02:00
|
|
|
require 'hamster'
|
|
|
|
require 'middleman-core/contracts'
|
|
|
|
|
|
|
|
# Immutable Callback Management, complete with Contracts validation.
|
|
|
|
module Middleman
|
|
|
|
class CallbackManager
|
|
|
|
include Contracts
|
|
|
|
|
|
|
|
Contract Any
|
|
|
|
def initialize
|
2015-11-28 00:26:46 +01:00
|
|
|
@callbacks = ::Hamster::Hash.empty
|
|
|
|
@subscribers = ::Hamster::Vector.empty
|
2015-05-03 03:47:16 +02:00
|
|
|
end
|
|
|
|
|
2015-05-04 00:38:18 +02:00
|
|
|
Contract RespondTo[:define_singleton_method], ArrayOf[Symbol] => Any
|
|
|
|
def install_methods!(install_target, names)
|
2015-05-03 03:47:16 +02:00
|
|
|
manager = self
|
|
|
|
|
2015-05-04 00:38:18 +02:00
|
|
|
names.each do |method_name|
|
2015-05-03 03:47:16 +02:00
|
|
|
install_target.define_singleton_method(method_name) do |*keys, &b|
|
2015-05-04 00:38:18 +02:00
|
|
|
key_set = keys.unshift(method_name)
|
|
|
|
manager.add(key_set.length > 1 ? key_set : key_set[0], &b)
|
2015-05-03 03:47:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-05-04 00:38:18 +02:00
|
|
|
install_target.define_singleton_method(:execute_callbacks) do |*args|
|
|
|
|
keys = args.shift
|
|
|
|
manager.execute(keys, args[0], self)
|
2015-05-03 03:47:16 +02:00
|
|
|
end
|
2015-05-04 00:38:18 +02:00
|
|
|
|
|
|
|
install_target.define_singleton_method(:callbacks_for, &method(:callbacks_for))
|
2015-05-04 18:58:29 +02:00
|
|
|
install_target.define_singleton_method(:subscribe_to_callbacks, &method(:subscribe))
|
2015-05-03 03:47:16 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
Contract Or[Symbol, ArrayOf[Symbol]], Proc => Any
|
|
|
|
def add(keys, &block)
|
|
|
|
immutable_keys = keys.is_a?(Symbol) ? keys : ::Hamster::Vector.new(keys)
|
|
|
|
|
|
|
|
@callbacks = @callbacks.put(immutable_keys) do |v|
|
2015-05-04 00:38:18 +02:00
|
|
|
v.nil? ? ::Hamster::Vector.new([block]) : v.push(block)
|
2015-05-03 03:47:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-05-04 18:58:29 +02:00
|
|
|
Contract Proc => Any
|
|
|
|
def subscribe(&block)
|
|
|
|
@subscribers = @subscribers.push(block)
|
|
|
|
end
|
|
|
|
|
2015-05-03 03:47:16 +02:00
|
|
|
Contract Or[Symbol, ArrayOf[Symbol]], Maybe[ArrayOf[Any]], Maybe[RespondTo[:instance_exec]] => Any
|
|
|
|
def execute(keys, args=[], scope=self)
|
2016-01-14 02:16:36 +01:00
|
|
|
callbacks = callbacks_for(keys)
|
|
|
|
callbacks_count = callbacks.length + @subscribers.length
|
|
|
|
|
|
|
|
return if callbacks_count < 1
|
|
|
|
|
|
|
|
# ::Middleman::Util.instrument "callbacks.execute", keys: keys, length: callbacks_count do
|
2016-01-14 20:21:42 +01:00
|
|
|
callbacks.each { |b| scope.instance_exec(*args, &b) }
|
|
|
|
@subscribers.each { |b| scope.instance_exec(keys, args, &b) }
|
2016-01-14 02:16:36 +01:00
|
|
|
# end
|
2015-05-04 00:38:18 +02:00
|
|
|
end
|
2015-05-03 03:47:16 +02:00
|
|
|
|
2015-05-04 00:38:18 +02:00
|
|
|
Contract Or[Symbol, ArrayOf[Symbol]] => ::Hamster::Vector
|
|
|
|
def callbacks_for(keys)
|
|
|
|
immutable_keys = keys.is_a?(Symbol) ? keys : ::Hamster::Vector.new(keys)
|
2015-11-28 00:26:46 +01:00
|
|
|
@callbacks.get(immutable_keys) || ::Hamster::Vector.empty
|
2015-05-03 03:47:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|