sander6 / growler

Ruby gem providing support for Growl — Read more

This URL has Read+Write access

README
= Growler: Growl support for your Ruby applications

Growler is a Ruby utility for posting notifications and registering applications through the Growl Framework. Unlike 
other Growl libraries, Growler uses Ruby idioms and intelligent data massaging to make it easy and natural to post 
notifications without having to know too much about how finicky Growl actually is.

== Requirements

Growler is compatible with Growl versions >= 1.1.2; versions as old as 0.6 might work, but haven't been tested.

Growler can work in two ways: on OSX machines, it can register applications and post notifications both locally and 
remotely. On non-OSX machines, it can create applications and notifications to be registered and posted remotely (to a 
Mac with Growl, of course). When Growler is required, it checks your RUBY_PLATFORM and loads either the Mac-specific 
libraries or the other libraries.

For the Mac version, Growler requires RubyCocoa version >= 0.13.1. RubyCocoa 0.13.1 is included with Leopard.

If your system is pre-Leopard, you'll have to install RubyCocoa. There seems to be no gem for it, but if you have 
MacPorts, RubyCocoa can be installed with simply

  $ sudo port install rb-cocoa

Alternately, binaries and source code are available from the RubyCocoa SourceForge page 
(http://sourceforge.net/project/showfiles.php?group_id=44114).

RubyCocoa has its own set of requirements to build and use. Read about them at the RubyCocoa project page 
http://rubycocoa.sourceforge.net/GettingStarted.

For the non-Mac version, there aren't any specific requirements. Growl away.

== License

Growler is released under the Ruby License. See the included LICENSE file for details.

== Installation

Growler can be installed via RubyGems.

  $ sudo gem install sander6-growler --source=http://gems.github.com
  
Or cloned from the git repository and installed from local source.

  $ git clone git://github.com/sander6/growler.git
  $ cd growler
  $ rake install

= Summary

To use Growler, require the gem

  require 'growler'

Growler can be used in one of two ways:
1. to send simple notifications, or
2. to register a full application with the Growl framework and send messages through that.

If you are on a Mac, you can send notifications and register applications either locally or remotely to another Mac with 
Growl installed. If you are not on a Mac, you can (obviously) only send notifications and register applications to 
remote Macs. In either case, the remote host must have "Listen for incoming notifications" and "Allow remote application 
registration" checked in the Growl preference pane for network notifications and registration to work.

=== Simple notifications

Sending "simple" notifications is mediated through methods on the Growl module itself. The Growl module wraps the 
growlnotify command line utility. To use, call Growl.post and pass a hash of message attributes:

  Growl.post(:title => "Process Complete", :message => "My work here is done.", :sticky => true)
  
If you are going to send multiple similar messages, you can set defaults as instance variable on the Growl module. When 
you call Growl.post, your defaults will be merged with the hash you send.

  Growl.title = "Process Complete"
  Growl.sticky = true
  Growl.post(:message => "Time to go home.")
  
Alternately, you can use the similarly named pass-through methods to do the same thing on one line:

  Growl.title("Process Complete").message("My work here is done.").sticky(true).post

See the Growl module for a full list of options and usage instructions.

=== Registering applications

Growl::Application objects define applications registered with Growl, specifically the name, the default icon, and a 
list of notifications available to that application.

To create and register an application, instantiate a new application object, pass the attributes you want to set to it, 
create some notifications for it, and then call register!.

  app = Growl::Application.new
  app.name = "My Awesome Ruby Application"
  n1 = Growl::Notification.new(...)
  n2 = Growl::Notification.new(...)
  app.add_notifications(n1, n2)
  app.register!
  
Alternately, you can call Growl.application and set the attributes of the new application in a block.
Calling #application will automatically register the application for you.
  
  app = Growl.application do |a|
    a.name = "My Awesome Ruby Application"
    a.image_path = "~/path/to/some/image"
    a.notification do |n|
      n.name = "Process Complete!"
    end
    a.notification do |n|
      n.name = "Process Interrupted!"
    end
  end
  
This will register the application with Growl. Building and registering an application with Growl allows you much more 
control and flexibility in the display of your notifications; after registration you can then open the Growl preference 
pane and set display options for each of that application's notifications, such as the display style, screen position, 
and priority. Unfortunately, there is no way to script these settings; it's up to your end-users to set fancy display 
styles for themselves.

=== Posting notifications from a registered application

To post notifications, call notify on the Application instance and pass it a name that you defined when registering of 
the notification you want. Make sure both the application and the name of the notification you want have both been 
registered or else nothing will happen.

  app.post("Process Complete")
  
You can also refer to an application's notifications by name using the [] syntax.

  app["Process Complete"].post
    
See Growl::Application for full details on building and registering applications and see Growl::Notification for details 
on building notifications and modifying their attributes when posting.


=== Building and using notifications

Growler takes a significant turn from other Ruby Growl libraries in its application and notification handling. A 
Growl::Application object holds a library of Growl::Notification objects, which can have all their useful attributes set 
once and then simply called as needed, opposed to having to hand-roll the entire notification each time you want to post 
it.

To build a notification for an application, call application.notification and set the attributes in block format.

  app.notification do |note|
    note.name = "Process Complete!"
    note.message = "The process is complete!"
    note.image_path = "./complete.png"
  end

'name' is the name under which this notification will be registered (you'll see it by this name in the drop-down list of 
notifications under this application in the Growl preference pane), and the name by which this application will fetch 
this notification object. 'name' is also the default title of the notification. You can set 'title' separately if you 
want, for instance, a simpler name to refer to this notification by but a more descriptive title.

  app.notification do |note|
    note.name = "Complete"
    note.title = "Process is Totally Completed!"
    ...
  end
  app["Complete"].post
  
The same icon helper methods that work with the Growl module will also work with setting the icon for a application or 
notification. By default, a notification inherits its icon from the application it belongs to.

  app["Complete"].app_icon = "Mail"
  
The example above will use deep, dark magics to set the icon of the notification to the application icon of Mail.app. 
Yes, it works just like that.

When calling post on a notification, you can pass a hash of overrides that will change its display behavior just that 
once without affecting its defaults. This is also useful for dynamic content.

  app["Complete"].post(:sticky => true)             # posted with sticky
  app["Complete"].post(:app_icon => "Address Book") # posted not sticky, but with new icon
  app["Complete"].post                              # posted as normal


=== Technical stuff

Growl::Applications are NSObjects and conform to the GrowlApplicationBridgeDelegate protocol. Unlike other Growl 
libraries that bother the NSDistributedNotificationCenter each time they want to talk to Growl, Growler actually loads 
the Growl Framework, imports it into Ruby across the RubyCocoa bridge, and sets Growl::Applications up as delegates of 
the GrowlApplicationBridge. This cuts out a fair bit of longwinded Objective C methods as well as gives access to some 
of the methods of the GrowlApplicationBridge, such as methods to tell whether Growl is running or not.

You can get at the bridge by calling Growl.application_bridge. If you want to see what it can do, you can unpack this 
gem and find a copy of the Growl framework in the ext directory, inside which is GrowlApplicationBridge.h that will tell 
you everything you need to know.

=== Bugs and other gripes

Currently, if you are on a Mac, Growler assumes you have Growl installed and running when you attempt to use it. If you 
don't, there tend to be segmentation faults all over the place.

Currently, both the OSXy and non-OSXy flavors of Growl::Application and Growl::Notification are merged together in the 
RDocs. Either set of files get loaded depending on the RUBY_PLATFORM. This will get fixed once I change the class names 
and make the appropriate switch statements in the other libraries that depend on them.

Concerning click and timeout callbacks, while these _technically_ work just fine, they are only accessible while an 
OSX::NSApp.run loop is going on (i.e. while OSX is paying attention). This has the unfortunate side-effect of locking 
the entire thread. Attempts to spawn a new thread to handle this have failed due to RubyCocoa's wanky handling of both 
Ruby and Cocoa threads. I should think that if you used Growler in a full RubyCocoa application, where NSApp.run loops 
are flying around all over the place, you should be fine and have all the callbacks you can handle. For plain ol' Ruby 
scripts and applications, however, callbacks are currently a no-go.

I have no idea how to get meaningful information back from Growl in order to test things like whether the notifications 
got posted correctly with the correct message and so on. Testing so far has been a real try-it-and-see process.