summaryrefslogtreecommitdiffstats
path: root/lib/puppet/event-loop
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/event-loop')
-rw-r--r--lib/puppet/event-loop/better-definers.rb367
-rw-r--r--lib/puppet/event-loop/event-loop.rb355
-rw-r--r--lib/puppet/event-loop/signal-system.rb220
3 files changed, 0 insertions, 942 deletions
diff --git a/lib/puppet/event-loop/better-definers.rb b/lib/puppet/event-loop/better-definers.rb
deleted file mode 100644
index 0af37da62..000000000
--- a/lib/puppet/event-loop/better-definers.rb
+++ /dev/null
@@ -1,367 +0,0 @@
-## better-definers.rb --- better attribute and method definers
-# Copyright (C) 2005 Daniel Brockman
-
-# This program is free software; you can redistribute it
-# and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation;
-# either version 2 of the License, or (at your option) any
-# later version.
-
-# This file is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty
-# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public
-# License along with this program; if not, write to the Free
-# Software Foundation, 51 Franklin Street, Fifth Floor,
-# Boston, MA 02110-1301, USA.
-
-class Symbol
- def predicate?
- to_s.include? "?" end
- def imperative?
- to_s.include? "!" end
- def writer?
- to_s.include? "=" end
-
- def punctuated?
- predicate? or imperative? or writer? end
- def without_punctuation
- to_s.delete("?!=").to_sym end
-
- def predicate
- without_punctuation.to_s + "?" end
- def imperative
- without_punctuation.to_s + "!" end
- def writer
- without_punctuation.to_s + "=" end
-end
-
-class Hash
- def collect! (&block)
- replace Hash[*collect(&block).flatten]
- end
-
- def flatten
- to_a.flatten
- end
-end
-
-module Kernel
- def returning (value)
- yield value ; value
- end
-end
-
-class Module
- def define_hard_aliases (name_pairs)
- for new_aliases, existing_name in name_pairs do
- new_aliases.kind_of? Array or new_aliases = [new_aliases]
- for new_alias in new_aliases do
- alias_method(new_alias, existing_name)
- end
- end
- end
-
- def define_soft_aliases (name_pairs)
- for new_aliases, existing_name in name_pairs do
- new_aliases.kind_of? Array or new_aliases = [new_aliases]
- for new_alias in new_aliases do
- class_eval %{def #{new_alias}(*args, &block)
- #{existing_name}(*args, &block) end}
- end
- end
- end
-
- define_soft_aliases \
- :define_hard_alias => :define_hard_aliases,
- :define_soft_alias => :define_soft_aliases
-
- # This method lets you define predicates like :foo?,
- # which will be defined to return the value of @foo.
- def define_readers (*names)
- for name in names.map { |x| x.to_sym } do
- if name.punctuated?
- # There's no way to define an efficient reader whose
- # name is different from the instance variable.
- class_eval %{def #{name} ; @#{name.without_punctuation} end}
- else
- # Use `attr_reader' to define an efficient method.
- attr_reader(name)
- end
- end
- end
-
- def writer_defined? (name)
- method_defined? name.to_sym.writer
- end
-
- # If you pass a predicate symbol :foo? to this method, it'll first
- # define a regular writer method :foo, without a question mark.
- # Then it'll define an imperative writer method :foo! as a shorthand
- # for setting the property to true.
- def define_writers (*names, &body)
- for name in names.map { |x| x.to_sym } do
- if block_given?
- define_method(name.writer, &body)
- else
- attr_writer(name.without_punctuation)
- end
- if name.predicate?
- class_eval %{def #{name.imperative}
- self.#{name.writer} true end}
- end
- end
- end
-
- define_soft_aliases \
- :define_reader => :define_readers,
- :define_writer => :define_writers
-
- # We don't need a singular alias for `define_accessors',
- # because it always defines at least two methods.
-
- def define_accessors (*names)
- define_readers(*names)
- define_writers(*names)
- end
-
- def define_opposite_readers (name_pairs)
- name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
- for opposite_name, name in name_pairs do
- define_reader(name) unless method_defined? name
- class_eval %{def #{opposite_name} ; not #{name} end}
- end
- end
-
- def define_opposite_writers (name_pairs)
- name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
- for opposite_name, name in name_pairs do
- define_writer(name) unless writer_defined? name
- class_eval %{def #{opposite_name.writer} x
- self.#{name.writer} !x end}
- class_eval %{def #{opposite_name.imperative}
- self.#{name.writer} false end}
- end
- end
-
- define_soft_aliases \
- :define_opposite_reader => :define_opposite_readers,
- :define_opposite_writer => :define_opposite_writers
-
- def define_opposite_accessors (name_pairs)
- define_opposite_readers name_pairs
- define_opposite_writers name_pairs
- end
-
- def define_reader_with_opposite (name_pair, &body)
- name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
- define_method(name, &body)
- define_opposite_reader(opposite_name => name)
- end
-
- def define_writer_with_opposite (name_pair, &body)
- name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
- define_writer(name, &body)
- define_opposite_writer(opposite_name => name)
- end
-
- public :define_method
-
- def define_methods (*names, &body)
- names.each { |name| define_method(name, &body) }
- end
-
- def define_private_methods (*names, &body)
- define_methods(*names, &body)
- names.each { |name| private name }
- end
-
- def define_protected_methods (*names, &body)
- define_methods(*names, &body)
- names.each { |name| protected name }
- end
-
- def define_private_method (name, &body)
- define_method(name, &body)
- private name
- end
-
- def define_protected_method (name, &body)
- define_method(name, &body)
- protected name
- end
-end
-
-class ImmutableAttributeError < StandardError
- def initialize (attribute=nil, message=nil)
- super message
- @attribute = attribute
- end
-
- define_accessors :attribute
-
- def to_s
- if @attribute and @message
- "cannot change the value of `#@attribute': #@message"
- elsif @attribute
- "cannot change the value of `#@attribute'"
- elsif @message
- "cannot change the value of attribute: #@message"
- else
- "cannot change the value of attribute"
- end
- end
-end
-
-class Module
- # Guard each of the specified attributes by replacing the writer
- # method with a proxy that asks the supplied block before proceeding
- # with the change.
- #
- # If it's okay to change the attribute, the block should return
- # either nil or the symbol :mutable. If it isn't okay, the block
- # should return a string saying why the attribute can't be changed.
- # If you don't want to provide a reason, you can have the block
- # return just the symbol :immutable.
- def guard_writers(*names, &predicate)
- for name in names.map { |x| x.to_sym } do
- define_hard_alias("__unguarded_#{name.writer}" => name.writer)
- define_method(name.writer) do |new_value|
- case result = predicate.call
- when :mutable, nil
- __send__("__unguarded_#{name.writer}", new_value)
- when :immutable
- raise ImmutableAttributeError.new(name)
- else
- raise ImmutableAttributeError.new(name, result)
- end
- end
- end
- end
-
- def define_guarded_writers (*names, &block)
- define_writers(*names)
- guard_writers(*names, &block)
- end
-
- define_soft_alias :guard_writer => :guard_writers
- define_soft_alias :define_guarded_writer => :define_guarded_writers
-end
-
-if __FILE__ == $0
- require "test/unit"
-
- class DefineAccessorsTest < Test::Unit::TestCase
- def setup
- @X = Class.new
- @Y = Class.new @X
- @x = @X.new
- @y = @Y.new
- end
-
- def test_define_hard_aliases
- @X.define_method(:foo) { 123 }
- @X.define_method(:baz) { 321 }
- @X.define_hard_aliases :bar => :foo, :quux => :baz
- assert_equal @x.foo, 123
- assert_equal @x.bar, 123
- assert_equal @y.foo, 123
- assert_equal @y.bar, 123
- assert_equal @x.baz, 321
- assert_equal @x.quux, 321
- assert_equal @y.baz, 321
- assert_equal @y.quux, 321
- @Y.define_method(:foo) { 456 }
- assert_equal @y.foo, 456
- assert_equal @y.bar, 123
- @Y.define_method(:quux) { 654 }
- assert_equal @y.baz, 321
- assert_equal @y.quux, 654
- end
-
- def test_define_soft_aliases
- @X.define_method(:foo) { 123 }
- @X.define_method(:baz) { 321 }
- @X.define_soft_aliases :bar => :foo, :quux => :baz
- assert_equal @x.foo, 123
- assert_equal @x.bar, 123
- assert_equal @y.foo, 123
- assert_equal @y.bar, 123
- assert_equal @x.baz, 321
- assert_equal @x.quux, 321
- assert_equal @y.baz, 321
- assert_equal @y.quux, 321
- @Y.define_method(:foo) { 456 }
- assert_equal @y.foo, @y.bar, 456
- @Y.define_method(:quux) { 654 }
- assert_equal @y.baz, 321
- assert_equal @y.quux, 654
- end
-
- def test_define_readers
- @X.define_readers :foo, :bar
- assert !@x.respond_to?(:foo=)
- assert !@x.respond_to?(:bar=)
- @x.instance_eval { @foo = 123 ; @bar = 456 }
- assert_equal @x.foo, 123
- assert_equal @x.bar, 456
- @X.define_readers :baz?, :quux?
- assert !@x.respond_to?(:baz=)
- assert !@x.respond_to?(:quux=)
- @x.instance_eval { @baz = false ; @quux = true }
- assert !@x.baz?
- assert @x.quux?
- end
-
- def test_define_writers
- assert !@X.writer_defined?(:foo)
- assert !@X.writer_defined?(:bar)
- @X.define_writers :foo, :bar
- assert @X.writer_defined?(:foo)
- assert @X.writer_defined?(:bar)
- assert @X.writer_defined?(:foo=)
- assert @X.writer_defined?(:bar=)
- assert @X.writer_defined?(:foo?)
- assert @X.writer_defined?(:bar?)
- assert !@x.respond_to?(:foo)
- assert !@x.respond_to?(:bar)
- @x.foo = 123
- @x.bar = 456
- assert_equal @x.instance_eval { @foo }, 123
- assert_equal @x.instance_eval { @bar }, 456
- @X.define_writers :baz?, :quux?
- assert !@x.respond_to?(:baz?)
- assert !@x.respond_to?(:quux?)
- @x.baz = true
- @x.quux = false
- assert_equal @x.instance_eval { @baz }, true
- assert_equal @x.instance_eval { @quux }, false
- end
-
- def test_define_accessors
- @X.define_accessors :foo, :bar
- @x.foo = 123 ; @x.bar = 456
- assert_equal @x.foo, 123
- assert_equal @x.bar, 456
- end
-
- def test_define_opposite_readers
- @X.define_opposite_readers :foo? => :bar?, :baz? => :quux?
- assert !@x.respond_to?(:foo=)
- assert !@x.respond_to?(:bar=)
- assert !@x.respond_to?(:baz=)
- assert !@x.respond_to?(:quux=)
- @x.instance_eval { @bar = true ; @quux = false }
- assert !@x.foo?
- assert @x.bar?
- assert @x.baz?
- assert !@x.quux?
- end
-
- def test_define_opposite_writers
- @X.define_opposite_writers :foo? => :bar?, :baz => :quux
- end
- end
-end
diff --git a/lib/puppet/event-loop/event-loop.rb b/lib/puppet/event-loop/event-loop.rb
deleted file mode 100644
index 5d78844ef..000000000
--- a/lib/puppet/event-loop/event-loop.rb
+++ /dev/null
@@ -1,355 +0,0 @@
-## event-loop.rb --- high-level IO multiplexer
-# Copyright (C) 2005 Daniel Brockman
-
-# This program is free software; you can redistribute it
-# and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation;
-# either version 2 of the License, or (at your option) any
-# later version.
-
-# This file is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty
-# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public
-# License along with this program; if not, write to the Free
-# Software Foundation, 51 Franklin Street, Fifth Floor,
-# Boston, MA 02110-1301, USA.
-
-require "puppet/event-loop/better-definers"
-require "puppet/event-loop/signal-system"
-
-require "fcntl"
-
-class EventLoop
- include SignalEmitter
-
- IO_STATES = [:readable, :writable, :exceptional]
-
- class << self
- def default ; @default ||= new end
- def default= x ; @default = x end
-
- def current
- Thread.current["event-loop::current"] || default end
- def current= x
- Thread.current["event-loop::current"] = x end
-
- def with_current (new)
- if current == new
- yield
- else
- begin
- old = self.current
- self.current = new
- yield
- ensure
- self.current = old
- end
- end
- end
-
- def method_missing (name, *args, &block)
- if current.respond_to? name
- current.__send__(name, *args, &block)
- else
- super
- end
- end
- end
-
- define_signals :before_sleep, :after_sleep
-
- def initialize
- @running = false
- @awake = false
- @wakeup_time = nil
- @timers = []
-
- @io_arrays = [[], [], []]
- @ios = Hash.new do |h, k| raise ArgumentError,
- "invalid IO event: #{k}", caller(2) end
- IO_STATES.each_with_index { |x, i| @ios[x] = @io_arrays[i] }
-
- @notify_src, @notify_snk = IO.pipe
-
- @notify_src.will_block = false
- @notify_snk.will_block = false
-
- # Each time a byte is sent through the notification pipe
- # we need to read it, or IO.select will keep returning.
- monitor_io(@notify_src, :readable)
- @notify_src.extend(Watchable)
- @notify_src.on_readable do
- begin
- @notify_src.sysread(256)
- rescue Errno::EAGAIN
- # The pipe wasn't readable after all.
- end
- end
- end
-
- define_opposite_accessors \
- :stopped? => :running?,
- :sleeping? => :awake?
-
- def run
- if block_given?
- thread = Thread.new { run }
- yield ; quit ; thread.join
- else
- running!
- iterate while running?
- end
- ensure
- quit
- end
-
- def iterate (user_timeout=nil)
- t1, t2 = user_timeout, max_timeout
- timeout = t1 && t2 ? [t1, t2].min : t1 || t2
- select(timeout).zip(IO_STATES) do |ios, state|
- ios.each { |x| x.signal(state) } if ios
- end
- end
-
- private
-
- def select (timeout)
- @wakeup_time = timeout ? Time.now + timeout : nil
- # puts "waiting: #{timeout} seconds"
- signal :before_sleep ; sleeping!
- IO.select(*@io_arrays + [timeout]) || []
- ensure
- awake! ; signal :after_sleep
- @timers.each { |x| x.sound_alarm if x.ready? }
- end
-
- public
-
- def quit ; stopped! ; wake_up ; self end
-
- def monitoring_io? (io, event)
- @ios[event].include? io end
- def monitoring_timer? (timer)
- @timers.include? timer end
-
- def monitor_io (io, *events)
- for event in events do
- unless monitoring_io?(io, event)
- @ios[event] << io ; wake_up
- end
- end
- end
-
- def monitor_timer (timer)
- unless monitoring_timer? timer
- @timers << timer
- end
- end
-
- def check_timer (timer)
- wake_up if timer.end_time < @wakeup_time
- end
-
- def ignore_io (io, *events)
- events = IO_STATES if events.empty?
- for event in events do
- wake_up if @ios[event].delete(io)
- end
- end
-
- def ignore_timer (timer)
- # Don't need to wake up for this.
- @timers.delete(timer)
- end
-
- def max_timeout
- return nil if @timers.empty?
- [@timers.collect { |x| x.time_left }.min, 0].max
- end
-
- def wake_up
- @notify_snk.write('.') if sleeping?
- end
-end
-
-class Symbol
- def io_state?
- EventLoop::IO_STATES.include? self
- end
-end
-
-module EventLoop::Watchable
- include SignalEmitter
-
- define_signals :readable, :writable, :exceptional
-
- def monitor_events (*events)
- EventLoop.monitor_io(self, *events) end
- def ignore_events (*events)
- EventLoop.ignore_io(self, *events) end
-
- define_soft_aliases \
- :monitor_event => :monitor_events,
- :ignore_event => :ignore_events
-
- def close ; super
- ignore_events end
- def close_read ; super
- ignore_event :readable end
- def close_write ; super
- ignore_event :writable end
-
- module Automatic
- include EventLoop::Watchable
-
- def add_signal_handler (name, &handler) super
- monitor_event(name) if name.io_state?
- end
-
- def remove_signal_handler (name, handler) super
- if @signal_handlers[name].empty?
- ignore_event(name) if name.io_state?
- end
- end
- end
-end
-
-class IO
- def on_readable &block
- extend EventLoop::Watchable::Automatic
- on_readable(&block)
- end
-
- def on_writable &block
- extend EventLoop::Watchable::Automatic
- on_writable(&block)
- end
-
- def on_exceptional &block
- extend EventLoop::Watchable::Automatic
- on_exceptional(&block)
- end
-
- def will_block?
- require "fcntl"
- fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0
- end
-
- def will_block= (wants_blocking)
- require "fcntl"
- flags = fcntl(Fcntl::F_GETFL, 0)
- if wants_blocking
- flags &= ~Fcntl::O_NONBLOCK
- else
- flags |= Fcntl::O_NONBLOCK
- end
- fcntl(Fcntl::F_SETFL, flags)
- end
-end
-
-class EventLoop::Timer
- include SignalEmitter
-
- DEFAULT_INTERVAL = 0.0
- DEFAULT_TOLERANCE = 0.001
-
- def initialize (options={}, &handler)
- @running = false
- @start_time = nil
-
- if options.kind_of? Numeric
- options = { :interval => options }
- end
-
- if options[:interval]
- @interval = options[:interval].to_f
- else
- @interval = DEFAULT_INTERVAL
- end
-
- if options[:tolerance]
- @tolerance = options[:tolerance].to_f
- elsif DEFAULT_TOLERANCE < @interval
- @tolerance = DEFAULT_TOLERANCE
- else
- @tolerance = 0.0
- end
-
- @event_loop = options[:event_loop] || EventLoop.current
-
- if block_given?
- add_signal_handler(:alarm, &handler)
- start unless options[:start?] == false
- else
- start if options[:start?]
- end
- end
-
- define_readers :interval, :tolerance
- define_signal :alarm
-
- def stopped? ; @start_time == nil end
- def running? ; @start_time != nil end
-
- def interval= (new_interval)
- old_interval = @interval
- @interval = new_interval
- if new_interval < old_interval
- @event_loop.check_timer(self)
- end
- end
-
- def end_time
- @start_time + @interval end
- def time_left
- end_time - Time.now end
- def ready?
- time_left <= @tolerance end
-
- def restart
- @start_time = Time.now
- end
-
- def sound_alarm
- signal :alarm
- restart if running?
- end
-
- def start
- @start_time = Time.now
- @event_loop.monitor_timer(self)
- end
-
- def stop
- @start_time = nil
- @event_loop.ignore_timer(self)
- end
-end
-
-if __FILE__ == $0
- require "test/unit"
-
- class TimerTest < Test::Unit::TestCase
- def setup
- @timer = EventLoop::Timer.new(:interval => 0.001)
- end
-
- def test_timer
- @timer.on_alarm do
- puts "[#{@timer.time_left} seconds left after alarm]"
- EventLoop.quit
- end
- 8.times do
- t0 = Time.now
- @timer.start ; EventLoop.run
- t1 = Time.now
- assert(t1 - t0 > @timer.interval - @timer.tolerance)
- end
- end
- end
-end
-
-## event-loop.rb ends here.
diff --git a/lib/puppet/event-loop/signal-system.rb b/lib/puppet/event-loop/signal-system.rb
deleted file mode 100644
index f7fe9b52c..000000000
--- a/lib/puppet/event-loop/signal-system.rb
+++ /dev/null
@@ -1,220 +0,0 @@
-## signal-system.rb --- simple intra-process signal system
-# Copyright (C) 2005 Daniel Brockman
-
-# This program is free software; you can redistribute it
-# and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation;
-# either version 2 of the License, or (at your option) any
-# later version.
-
-# This file is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty
-# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public
-# License along with this program; if not, write to the Free
-# Software Foundation, 51 Franklin Street, Fifth Floor,
-# Boston, MA 02110-1301, USA.
-
-require "puppet/event-loop/better-definers"
-
-module SignalEmitterModule
- def self.extended (object)
- if object.kind_of? Module and not object < SignalEmitter
- if object.respond_to? :fcall
- # This is the way to call private methods
- # in Ruby 1.9 as of November 16.
- object.fcall :include, SignalEmitter
- else
- object.__send__ :include, SignalEmitter
- end
- end
- end
-
- def define_signal (name, slot=:before, &body)
- # Can't use `define_method' and take a block pre-1.9.
- class_eval %{ def on_#{name} &block
- add_signal_handler(:#{name}, &block) end }
- define_signal_handler(name, :before, &lambda {|*a|})
- define_signal_handler(name, :after, &lambda {|*a|})
- define_signal_handler(name, slot, &body) if block_given?
- end
-
- def define_signals (*names, &body)
- names.each { |x| define_signal(x, &body) }
- end
-
- def define_signal_handler (name, slot=:before, &body)
- case slot
- when :before
- define_protected_method "handle_#{name}", &body
- when :after
- define_protected_method "after_handle_#{name}", &body
- else
- raise ArgumentError, "invalid slot `#{slot.inspect}'; " +
- "should be `:before' or `:after'", caller(1)
- end
- end
-end
-
-# This is an old name for the same thing.
-SignalEmitterClass = SignalEmitterModule
-
-module SignalEmitter
- def self.included (includer)
- if not includer.kind_of? SignalEmitterClass
- includer.extend SignalEmitterClass
- end
- end
-
- def __maybe_initialize_signal_emitter
- @signal_handlers ||= Hash.new { |h, k| h[k] = Array.new }
- @allow_dynamic_signals ||= false
- end
-
- define_accessors :allow_dynamic_signals?
-
- def add_signal_handler (name, &handler)
- __maybe_initialize_signal_emitter
- @signal_handlers[name] << handler
- return handler
- end
-
- define_soft_aliases [:on, :on_signal] => :add_signal_handler
-
- def remove_signal_handler (name, handler)
- __maybe_initialize_signal_emitter
- @signal_handlers[name].delete(handler)
- end
-
- def __signal__ (name, *args, &block)
- __maybe_initialize_signal_emitter
- respond_to? "on_#{name}" or allow_dynamic_signals? or
- fail "undefined signal `#{name}' for #{self}:#{self.class}"
- __send__("handle_#{name}", *args, &block) if
- respond_to? "handle_#{name}"
- @signal_handlers[name].each { |x| x.call(*args, &block) }
- __send__("after_handle_#{name}", *args, &block) if
- respond_to? "after_handle_#{name}"
- end
-
- define_soft_alias :signal => :__signal__
-end
-
-# This module is indended to be a convenience mixin to be used by
-# classes whose objects need to observe foreign signals. That is,
-# if you want to observe some signals coming from an object, *you*
-# should mix in this module.
-#
-# You cannot use this module at two different places of the same
-# inheritance chain to observe signals coming from the same object.
-#
-# XXX: This has not seen much use, and I'd like to provide a
-# better solution for the problem in the future.
-module SignalObserver
- def __maybe_initialize_signal_observer
- @observed_signals ||= Hash.new do |signals, object|
- signals[object] = Hash.new do |handlers, name|
- handlers[name] = Array.new
- end
- end
- end
-
- def observe_signal (subject, name, &handler)
- __maybe_initialize_signal_observer
- @observed_signals[subject][name] << handler
- subject.add_signal_handler(name, &handler)
- end
-
- def map_signals (source, pairs={})
- pairs.each do |src_name, dst_name|
- observe_signal(source, src_name) do |*args|
- __signal__(dst_name, *args)
- end
- end
- end
-
- def absorb_signals (subject, *names)
- names.each do |name|
- observe_signal(subject, name) do |*args|
- __signal__(name, *args)
- end
- end
- end
-
- define_soft_aliases \
- :map_signal => :map_signals,
- :absorb_signal => :absorb_signals
-
- def ignore_signal (subject, name)
- __maybe_initialize_signal_observer
- __ignore_signal_1(subject, name)
- @observed_signals.delete(subject) if
- @observed_signals[subject].empty?
- end
-
- def ignore_signals (subject, *names)
- __maybe_initialize_signal_observer
- names = @observed_signals[subject] if names.empty?
- names.each { |x| __ignore_signal_1(subject, x) }
- end
-
- private
-
- def __ignore_signal_1(subject, name)
- @observed_signals[subject][name].each do |handler|
- subject.remove_signal_handler(name, handler) end
- @observed_signals[subject].delete(name)
- end
-end
-
-if __FILE__ == $0
- require "test/unit"
- class SignalEmitterTest < Test::Unit::TestCase
- class X
- include SignalEmitter
- define_signal :foo
- end
-
- def setup
- @x = X.new
- end
-
- def test_on_signal
- moomin = 0
- @x.on_signal(:foo) { moomin = 1 }
- @x.signal :foo
- assert moomin == 1
- end
-
- def test_on_foo
- moomin = 0
- @x.on_foo { moomin = 1 }
- @x.signal :foo
- assert moomin == 1
- end
-
- def test_multiple_on_signal
- moomin = 0
- @x.on_signal(:foo) { moomin += 1 }
- @x.on_signal(:foo) { moomin += 2 }
- @x.on_signal(:foo) { moomin += 4 }
- @x.on_signal(:foo) { moomin += 8 }
- @x.signal :foo
- assert moomin == 15
- end
-
- def test_multiple_on_foo
- moomin = 0
- @x.on_foo { moomin += 1 }
- @x.on_foo { moomin += 2 }
- @x.on_foo { moomin += 4 }
- @x.on_foo { moomin += 8 }
- @x.signal :foo
- assert moomin == 15
- end
- end
-end
-
-## application-signals.rb ends here.