|
require 'fiber' |
|
|
|
module FiberExtension |
|
@@root_fiber = Fiber.current |
|
|
|
def map(template, options) |
|
super(template, options) |
|
register_fiber(@handler.last) if options and options[:fibers] |
|
end |
|
|
|
def map!(template, options) |
|
super(template, options) |
|
register_fiber(@handler.last) if options and options[:fibers] |
|
end |
|
|
|
# hooks the action method and wraps the call in handle_fiber |
|
def register_fiber(tmpl) |
|
action = tmpl.options[:action] |
|
self.class.class_eval do |
|
alias_method 'old_'+action, action |
|
define_method action do |m, params| |
|
handle_fiber do |
|
send('old_'+action, m, params) |
|
end |
|
end |
|
end |
|
end |
|
|
|
# just hooks the call in a fiber instance |
|
def handle_fiber(&hook) |
|
fiber = Fiber.new do |
|
hook.call |
|
end |
|
fiber.resume |
|
end |
|
|
|
# source is either: Irc::User or Irc::Channel |
|
def wait_for(pattern, source) |
|
raise 'tried to yield root fiber!' if Fiber.current == @@root_fiber |
|
add_fiber_resume_condition pattern, source |
|
Fiber.yield |
|
end |
|
|
|
# adds a fiber to the list, that is resumed when a source's message matches pattern |
|
def add_fiber_resume_condition(pattern, source) |
|
@fiber_resume_condition = @fiber_resume_condition || [] |
|
|
|
# first remove all existing pattern/source conditions |
|
remove_fiber_resume_condition(pattern, source) |
|
|
|
# adds the resume condition |
|
@fiber_resume_condition << {fiber: Fiber.current, pattern: pattern, source: source} |
|
end |
|
|
|
# removes the resume condition/ and destroys the fiber |
|
def remove_fiber_resume_condition(pattern, source) |
|
@fiber_resume_condition.delete_if { |x| x[:pattern] == pattern and x[:source] == source } |
|
end |
|
|
|
# listens for _all_ messages in channel/query |
|
def message(m, dummy=nil) |
|
return if not @fiber_resume_condition or @fiber_resume_condition.empty? |
|
|
|
# need to iterate over a duplicate, because this might add a new condition.. |
|
# its resuming the fiber and this might trigger another wait_for() that adds |
|
# to this condition array. |
|
@fiber_resume_condition.dup.each do |condition| |
|
resume_fiber_if(m, condition) |
|
end |
|
end |
|
|
|
# resumes the fiber if the conditions are met, if the |
|
# source(channel/user) sends a message not matching the pattern, |
|
# the fiber is destroyed. |
|
def resume_fiber_if(m, condition) |
|
source = condition[:source] |
|
pattern = condition[:pattern] |
|
fiber = condition[:fiber] # condition stores a reference to the fiber aswell |
|
|
|
if fiber_source_condition_matches(m, source) |
|
if m.message.match pattern |
|
fiber.resume |
|
else |
|
remove_fiber_resume_condition(pattern, source) |
|
end |
|
end |
|
end |
|
|
|
# the source of conditions might be a channel or user instance |
|
def fiber_source_condition_matches(m, source) |
|
if source.instance_of? Irc::Channel and m.channel == source |
|
true |
|
elsif source.instance_of? Irc::User and m.source == source |
|
true |
|
end |
|
end |
|
end |