Module: Cosell
- Defined in:
- lib/cosell.rb,
lib/cosell/announcer.rb
Constant Summary collapse
- VERSION =
:stopdoc:
'0.0.2'
- LIBPATH =
::File.(::File.dirname(__FILE__)) + ::File::SEPARATOR
- PATH =
::File.dirname(LIBPATH) + ::File::SEPARATOR
Class Method Summary collapse
-
.libpath(*args) ⇒ Object
Returns the library path for the module.
-
.path(*args) ⇒ Object
Returns the lpath for the module.
-
.require_all_libs_relative_to(fname, dir = nil) ⇒ Object
Utility method used to require all files ending in .rb that lie in the directory below this file that has the same name as the filename passed in.
-
.version ⇒ Object
Returns the version string for the library.
Instance Method Summary collapse
-
#announce(announcement) ⇒ Object
If queue_announcements? true, puts announcement in a Queue.
-
#announce_now!(an_announcement_or_announcement_factory) ⇒ Object
First, an announcement is made by calling ‘as_announcement’ on an_announcement_or_announcement_factory, and subscribers to the announcement’s class are then notified.
- #initialize(*args) ⇒ Object
-
#initialize_cosell! ⇒ Object
Will blow away any queue, and reset all state.
-
#initialize_cosell_if_needed ⇒ Object
lazy initialization of cosell.
-
#kill_queue! ⇒ Object
Kill the announcments queue.
-
#queue_announcements!(opts = {}) ⇒ Object
Place all announcments in a queue, and make announcements in a background thread.
-
#queue_announcements? ⇒ Boolean
return whether annoucements are queued or sent out immediately when the #announce method is called.
-
#spy!(opts = {}) ⇒ Object
Log a message every time this announcer makes an announcement.
-
#subscribe(*announce_classes, &block) ⇒ Object
(also: #when_announcing)
Pass in an anouncement class (or array of announcement classes), along with a block defining the action to be taken when an announcment of one of the specified classes is announced by this announcer.
- #subscriptions ⇒ Object
- #subscriptions=(x) ⇒ Object
-
#unsubscribe(*announce_classes) ⇒ Object
Stop announcing for a given announcement class (or array of classes).
Class Method Details
.libpath(*args) ⇒ Object
Returns the library path for the module. If any arguments are given, they will be joined to the end of the libray path using File.join
.
18 19 20 |
# File 'lib/cosell.rb', line 18 def self.libpath( *args ) args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten) end |
.path(*args) ⇒ Object
Returns the lpath for the module. If any arguments are given, they will be joined to the end of the path using File.join
.
26 27 28 |
# File 'lib/cosell.rb', line 26 def self.path( *args ) args.empty? ? PATH : ::File.join(PATH, args.flatten) end |
.require_all_libs_relative_to(fname, dir = nil) ⇒ Object
Utility method used to require all files ending in .rb that lie in the directory below this file that has the same name as the filename passed in. Optionally, a specific directory name can be passed in such that the filename does not have to be equivalent to the directory.
35 36 37 38 39 40 41 |
# File 'lib/cosell.rb', line 35 def self.require_all_libs_relative_to( fname, dir = nil ) dir ||= ::File.basename(fname, '.*') search_me = ::File.( ::File.join(::File.dirname(fname), dir, '**', '*.rb')) Dir.glob(search_me).sort.each {|rb| require rb} end |
Instance Method Details
#announce(announcement) ⇒ Object
If queue_announcements? true, puts announcement in a Queue. Otherwise, calls announce_now! Queued announcements are announced in a background thread in batches (see the #initialize method doc for details).
116 117 118 119 120 121 122 |
# File 'lib/cosell/announcer.rb', line 116 def announce announcement if self.queue_announcements? self.announcements_queue << announcement else self.announce_now! announcement end end |
#announce_now!(an_announcement_or_announcement_factory) ⇒ Object
First, an announcement is made by calling ‘as_announcement’ on an_announcement_or_announcement_factory, and subscribers to the announcement’s class are then notified
subscribers to this announcer will be filtered to those that match to the announcement’s class, and those subscriptions will be ‘fired’. Subscribers should use the ‘subscribe’ method (also called ‘when_announcing’) to configure actions to take when a given announcement is made.
Typically, an announcement is passed in for an_announcement_factory, in which case as_announcement does nothing but return the announcement. But any class can override as_announcement to adapt into an anouncement as they see fit.
(see Cossell::Announcer for full explanation)
138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/cosell/announcer.rb', line 138 def announce_now! an_announcement_or_announcement_factory announcement = an_announcement_or_announcement_factory.as_announcement self.subscriptions.each do |subscription_type, subscriptions_for_type | if announcement.is_a?(subscription_type) subscriptions_for_type.each{|subscription| subscription.call(announcement) } end end return announcement end |
#initialize(*args) ⇒ Object
5 6 7 8 |
# File 'lib/cosell/announcer.rb', line 5 def initialize *args initialize_cosell! super end |
#initialize_cosell! ⇒ Object
Will blow away any queue, and reset all state. Should not be necessary to call this, but left public for testing.
181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/cosell/announcer.rb', line 181 def initialize_cosell! # Using pseudo-scoped var names. # Unfortunately cant lazily init these w/out ruby warnings going berzerk in verbose mode, # So explicitly declaring them here. @__queue_announcements ||= false @__announcements_queue ||= nil @__kill_announcement_queue ||= false @__announcements_thread ||= nil @__subscriptions ||= {} @__queue_logger ||= {} end |
#initialize_cosell_if_needed ⇒ Object
lazy initialization of cosell. Optional – calling this will get rid of any subsequent warnings about uninitialized ivs In most cases not necessary, and should never have an effect except to get rid of some warnings.
175 176 177 |
# File 'lib/cosell/announcer.rb', line 175 def initialize_cosell_if_needed self.initialize_cosell! if @__subscriptions.nil? end |
#kill_queue! ⇒ Object
Kill the announcments queue. This is called automatically if you call queue_announcements!, before starting the next announcments thread, so it’s optional. A way of stopping announcments.
196 197 198 |
# File 'lib/cosell/announcer.rb', line 196 def kill_queue! @__kill_announcement_queue = true end |
#queue_announcements!(opts = {}) ⇒ Object
Place all announcments in a queue, and make announcements in a background thread.
Arguments:
:logger => a logger. Where to log exceptions and warnings.
This argument is mandatory -- it is too hard to debug exceptions in announcement
handler code without a logger. If you _really_ want your code to fail silently,
you will have to create a logger on /dev/null.
:sleep_time => how long to sleep (in seconds) after making a batch of announchements
optional arg, default: 0.01
:announcements_per_cycle => how many announcements to make before sleeping for sleep_time
optional arg, default: 25
WARNING: If you do not pass in a logger, announcement code will fail silently (the queue is in a background thread).
Note: at the moment, this method may only be called once, and cannot be undone. There is no way to interrupt the thread.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/cosell/announcer.rb', line 34 def queue_announcements!(opts = {}) self.initialize_cosell_if_needed # The logger in mandatory if opts[:logger] self.queue_logger = opts[:logger] else raise "Cosell error: You have to provide a logger, otherwise failures in announcement handler code are to hard to debug" end # kill off the last queue first if self.announcements_thread kill_queue! sleep 0.01 queue_announcements! opts end self.should_queue_announcements = true @__announcements_queue ||= Queue.new how_many_per_cycle = opts[:announcements_per_cycle] || 25 cycle_duration = opts[:sleep_time] || 0.01 count = 0 self.announcements_thread = Thread.new do loop do if queue_killed? self.kill_announcement_queue = false self.announcements_thread = nil log "Announcement queue killed with #{self.announcements_queue.size} announcements still queued", :info break else begin self.announce_now! self.announcements_queue.pop count += 1 if (count%how_many_per_cycle).eql?(0) log "Announcement queue finished batch of #{how_many_per_cycle}, sleeping for #{cycle_duration} sec", :debug count = 0 sleep cycle_duration end rescue Exception => x log "Exception: #{x}, trace: \n\t#{x.backtrace.join("\n\t")}", :error end end end end end |
#queue_announcements? ⇒ Boolean
return whether annoucements are queued or sent out immediately when the #announce method is called.
201 202 203 |
# File 'lib/cosell/announcer.rb', line 201 def queue_announcements? return @__queue_announcements.eql?(true) end |
#spy!(opts = {}) ⇒ Object
Log a message every time this announcer makes an announcement
Options:
:on => Which class of announcements to spy on. Default is Object (ie. all announcements)
:logger => The log to log to. Default is a logger on STDOUT
:level => The log level to log with. Default is :info
:preface_with => A message to prepend to all log messages. Default is "Announcement Spy: "
164 165 166 167 168 169 170 |
# File 'lib/cosell/announcer.rb', line 164 def spy!(opts = {}) on = opts[:on] || Object logger = opts[:logger] || Logger.new(STDOUT) level = opts[:level] || :info preface = opts[:preface_with] || "Announcement Spy: " self.subscribe(on){|ann| logger.send(level, "#{preface} #{ann.as_announcement_trace}")} end |
#subscribe(*announce_classes, &block) ⇒ Object Also known as: when_announcing
Pass in an anouncement class (or array of announcement classes), along with a block defining the action to be taken when an announcment of one of the specified classes is announced by this announcer. (see Cossell::Announcer for full explanation)
93 94 95 96 97 98 99 100 101 102 |
# File 'lib/cosell/announcer.rb', line 93 def subscribe *announce_classes, &block self.initialize_cosell_if_needed Array(announce_classes).each do |announce_class| raise "Can only subscribe to classes. Not a class: #{announce_class}" unless announce_class.is_a?(Class) self.subscriptions[announce_class] ||= [] self.subscriptions[announce_class] << lambda(&block) end end |
#subscriptions ⇒ Object
206 |
# File 'lib/cosell/announcer.rb', line 206 def subscriptions; @__subscriptions ||= []; end |
#subscriptions=(x) ⇒ Object
205 |
# File 'lib/cosell/announcer.rb', line 205 def subscriptions= x; @__subscriptions = x; end |
#unsubscribe(*announce_classes) ⇒ Object
Stop announcing for a given announcement class (or array of classes)
106 107 108 109 110 |
# File 'lib/cosell/announcer.rb', line 106 def unsubscribe *announce_classes Array(announce_classes).each do |announce_class| self.subscriptions.delete announce_class end end |