1 | #--
|
---|
2 | #
|
---|
3 | # Author:: Nathaniel Talbott.
|
---|
4 | # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
|
---|
5 | # License:: Ruby license.
|
---|
6 |
|
---|
7 | require 'test/unit/util/procwrapper'
|
---|
8 |
|
---|
9 | module Test
|
---|
10 | module Unit
|
---|
11 | module Util
|
---|
12 |
|
---|
13 | # This is a utility class that allows anything mixing
|
---|
14 | # it in to notify a set of listeners about interesting
|
---|
15 | # events.
|
---|
16 | module Observable
|
---|
17 | # We use this for defaults since nil might mean something
|
---|
18 | NOTHING = "NOTHING/#{__id__}"
|
---|
19 |
|
---|
20 | # Adds the passed proc as a listener on the
|
---|
21 | # channel indicated by channel_name. listener_key
|
---|
22 | # is used to remove the listener later; if none is
|
---|
23 | # specified, the proc itself is used.
|
---|
24 | #
|
---|
25 | # Whatever is used as the listener_key is
|
---|
26 | # returned, making it very easy to use the proc
|
---|
27 | # itself as the listener_key:
|
---|
28 | #
|
---|
29 | # listener = add_listener("Channel") { ... }
|
---|
30 | # remove_listener("Channel", listener)
|
---|
31 | def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value
|
---|
32 | unless(block_given?)
|
---|
33 | raise ArgumentError.new("No callback was passed as a listener")
|
---|
34 | end
|
---|
35 |
|
---|
36 | key = listener_key
|
---|
37 | if (listener_key == NOTHING)
|
---|
38 | listener_key = listener
|
---|
39 | key = ProcWrapper.new(listener)
|
---|
40 | end
|
---|
41 |
|
---|
42 | channels[channel_name] ||= {}
|
---|
43 | channels[channel_name][key] = listener
|
---|
44 | return listener_key
|
---|
45 | end
|
---|
46 |
|
---|
47 | # Removes the listener indicated by listener_key
|
---|
48 | # from the channel indicated by
|
---|
49 | # channel_name. Returns the registered proc, or
|
---|
50 | # nil if none was found.
|
---|
51 | def remove_listener(channel_name, listener_key)
|
---|
52 | channel = channels[channel_name]
|
---|
53 | return nil unless (channel)
|
---|
54 | key = listener_key
|
---|
55 | if (listener_key.instance_of?(Proc))
|
---|
56 | key = ProcWrapper.new(listener_key)
|
---|
57 | end
|
---|
58 | if (channel.has_key?(key))
|
---|
59 | return channel.delete(key)
|
---|
60 | end
|
---|
61 | return nil
|
---|
62 | end
|
---|
63 |
|
---|
64 | # Calls all the procs registered on the channel
|
---|
65 | # indicated by channel_name. If value is
|
---|
66 | # specified, it is passed in to the procs,
|
---|
67 | # otherwise they are called with no arguments.
|
---|
68 | #
|
---|
69 | #--
|
---|
70 | #
|
---|
71 | # Perhaps this should be private? Would it ever
|
---|
72 | # make sense for an external class to call this
|
---|
73 | # method directly?
|
---|
74 | def notify_listeners(channel_name, *arguments)
|
---|
75 | channel = channels[channel_name]
|
---|
76 | return 0 unless (channel)
|
---|
77 | listeners = channel.values
|
---|
78 | listeners.each { |listener| listener.call(*arguments) }
|
---|
79 | return listeners.size
|
---|
80 | end
|
---|
81 |
|
---|
82 | private
|
---|
83 | def channels
|
---|
84 | @channels ||= {}
|
---|
85 | return @channels
|
---|
86 | end
|
---|
87 | end
|
---|
88 | end
|
---|
89 | end
|
---|
90 | end
|
---|