# Copyright (c) 2008 Simon Menke
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Example:
# recorder = Message::Recorder.new
# recorder.record.downcase.intern
# recorder.before do |message_call|
# p message_call.class # => Message::Recorder::MessageCall
# !(message_call.subject.nil? or message_callsubject.empty?)
# end
# recorder.after do |message_call|
# p message_call.class # => Message::Recorder::MessageCall
# p message_call.return_value
# end
# recorder.send_to(nil) # => nil
# recorder.send_to("") # => nil
# recorder.send_to("Mr_Henry") # => :mr_henry
class Message::Recorder
# BEFORE CALL FILTER:
#
# Takes a block with one argument of type Message::Recorder::MessageCall
# recorder.before { |message_call| ... }
# recorder.before :call { |message_call| ... }
# recorder.before :call, :my_filter_method
# def my_filter_method(message_call)
# ...
# end
# if the block returns false the chain will be broken.
#
# BEFORE CHAIN FILTER:
#
# Takes a block with one argument of type Message::Recorder::Message
# recorder.before :chain { |message| ... }
# recorder.before :chain, :my_filter_method
# def my_filter_method(message)
# ...
# end
#
# BEFORE BRANCH FILTER:
#
# Takes a block with one argument of type Message::Recorder::Collector
# recorder.before :branch { |collector| ... }
# recorder.before :branch, :my_filter_method
# def my_filter_method(collector)
# ...
# end
def before(*options,&block)
type = options.shift if [:call, :chain, :branch].include? options.first
type ||= :call
filter = block
filter ||= method(options.shift)
case type
when :call then before_call_filters << filter
when :chain then before_chain_filters << filter
when :branch then before_branch_filters << filter
end
end
# AFTER CALL FILTER:
#
# Takes a block with one argument of type Message::Recorder::MessageCall
# recorder.after { |message_call| ... }
# recorder.after :call { |message_call| ... }
# recorder.after :call, :my_filter_method
# def my_filter_method(message_call)
# ...
# end
# if the block returns false the chain will be broken.
#
# AFTER CHAIN FILTER:
#
# Takes a block with one argument of type Message::Recorder::Message
# recorder.after :chain { |message| ... }
# recorder.after :chain, :my_filter_method
# def my_filter_method(message)
# ...
# end
#
# AFTER BRANCH FILTER:
#
# Takes a block with two arguments of type Message::Recorder::Collector
# recorder.after :branch { |original_collector, new_collector| ... }
# recorder.after :branch, :my_filter_method
# def my_filter_method(original_collector, new_collector)
# ...
# end
def after(*options,&block)
type = options.shift if [:call, :chain, :branch].include? options.first
type ||= :call
filter = block
filter ||= method(options.shift)
case type
when :call then after_call_filters << filter
when :chain then after_chain_filters << filter
when :branch then after_branch_filters << filter
end
end
# #record returns a mock object which will store all the messages you send to it.
def record
@collector = nil
collector.collect_messages
end
# #send_to will send the recorded messages to the #subject.
def send_to(subject)
collector.send_to(subject, self)
end
attr_accessor :before_call_filters # :nodoc:
attr_accessor :after_call_filters # :nodoc:
attr_accessor :before_branch_filters # :nodoc:
attr_accessor :after_branch_filters # :nodoc:
attr_accessor :before_chain_filters # :nodoc:
attr_accessor :after_chain_filters # :nodoc:
def before_call_filters # :nodoc:
@before_call_filters ||= []
end
def after_call_filters # :nodoc:
@after_call_filters ||= []
end
def before_branch_filters # :nodoc:
@before_branch_filters ||= []
end
def after_branch_filters # :nodoc:
@after_branch_filters ||= []
end
def before_chain_filters # :nodoc:
@before_chain_filters ||= []
end
def after_chain_filters # :nodoc:
@after_chain_filters ||= []
end
def filter_before_call(message_call) # :nodoc:
before_call_filters.each do |filter|
should_break = filter.call(message_call)
return false if should_break === false
end
return true
end
def filter_after_call(message_call) # :nodoc:
after_call_filters.each do |filter|
should_break = filter.call(message_call)
return false if should_break === false
end
return true
end
def filter_before_branch(collector) # :nodoc:
before_branch_filters.each do |filter|
filter.call(collector)
end
end
def filter_after_branch(original, branch) # :nodoc:
after_branch_filters.each do |filter|
filter.call(original, branch)
end
end
def filter_before_chain(message) # :nodoc:
before_chain_filters.each do |filter|
filter.call(collector)
end
end
def filter_after_chain(message) # :nodoc:
after_chain_filters.each do |filter|
filter.call(message)
end
end
def collector # :nodoc:
@collector ||= ::Message::Recorder::Collector.new(:recorder => self)
end
end