Permalink
Browse files

default enabled=true for registered notifications; updated README and…

… add license
  • Loading branch information...
ericgj committed Oct 13, 2010
1 parent ec071ab commit cd50c9f2b459da2bda30256b64de4ad31eb1a2d3
Showing with 128 additions and 20 deletions.
  1. +5 −0 HISTORY.markdown
  2. +109 −11 README.markdown
  3. +6 −8 TODO.markdown
  4. +1 −0 lib/groem/notification.rb
  5. +2 −1 spec/spec_helper.rb
  6. +5 −0 spec/unit/notification_spec.rb
View
@@ -1,4 +1,9 @@
# Release history
+## 0.0.4
+- Take out bundler dep except for spec_helper, set up gemspec
+- Default Notification-Enabled = 'True' for registered notifications
+- Update README, add LICENSE
+
## 0.0.3
- Initial release
View
@@ -4,47 +4,68 @@
For documentation of the GNTP protocol, see:
[http://www.growlforwindows.com/gfw/help/gntp.aspx](http://www.growlforwindows.com/gfw/help/gntp.aspx)
+and the [Growl for Windows mailing list](http://groups.google.com/group/growl-for-windows/topics?start=).
+
Note this is very much beta. The core functionality is fairly well tested, but the following features are not yet implemented:
- Binary resources (`x-growl-resource://`) in requests, including for icons
- Encryption
- Subscribe requests
+See other limitations below.
+
+## Platforms supported
+
+Groem does not rely on any OS-specific libraries per se. It's simply an implementation of a TCP protocol. It doesn't define any UI components, part of Growl's design is that's left to the user to decide. But of course: you need a Growl server running that speaks GNTP... and so far as I know, to this point it's only been implemented by Growl for Windows.
+
+## Motivation
+
+I wanted to be able to send desktop notifications on my Windows box from ruby running in cygwin. Call me crazy but I seem to enjoy hacking at Windows from cygwin...! And I wanted the experience of implementing a protocol in Eventmachine.
+
+Groem is a spin-off of sorts from my project for the free and wonderful [Ruby Mendicant University (RMU)](http://blog.majesticseacreature.com/).
+
## Examples of usage
### Registration
+Growl needs a 'register' request to define application options and what notifications to expect from your app.
+
+Besides what Growl needs for registration, you can also define a **default callback** for a given notification. This simplifies cases where *you don't care about anything except the user action* -- i.e. whether the user closed the box, clicked it, or ignored it (timed out). Every time you send that type of notification, the same callback context, context-type and/or target URL will be used.
- app = Groem::App.new('MyApp', :host => 'localhost')
+
+ app = Groem::App.new('Downloader', :host => 'localhost')
app.register do
icon 'http://www.example.com/icon.png'
header 'X-Custom-Header', 'default value'
# notification with callback expected
- notification :started, 'Your thing has started!' do |n|
- n.header 'Data-Filename'
- n.icon 'path/to/local/file.png' #=> generates x-growl-resource
- n.sticky
- n.callback 'process', :type => 'confirm'
+ notification :finished, 'Your download has finished!' do |n|
+ n.sticky = 'True'
+ n.text = 'Run it!'
+ n.icon 'path/to/local/icon.png' #=> generate x-growl-resource (future)
+ n.callback 'process', :type => 'run'
end
# notification with no callback
- notification :finished, :enabled => true
+ notification :started, 'Your download is starting!',
+ :display_name => 'Downloader working'
end
### Notification
+Notify returns the initial response from the server (whether request was OK or error). Callbacks (the second response from the server, based on what the user did) are handled through a routing scheme, see below.
+
# trigger notify and callbacks
app.notify(:started, 'XYZ has started!')
# trigger notify with 'ad-hoc' callback
- # -- with different settings than defined in app.register
- app.notify(:finished, 'ABC has finished!',
+ # == with different settings than defined in app.register
+ app.notify(:started, 'ABC has started!',
:callback => {:type => 'ad-hoc',
:target => 'www.my-callback-url.com'}
)
@@ -65,13 +86,19 @@ Note this is very much beta. The core functionality is fairly well tested, but
### Callbacks
+Callback procs allow you to capture responses from the user based on what they did (close, click, timeout), plus the two standard Growl data fields that the UI can return data in -- the context and the context-type.
+
+A given response will be routed to *all matching callback procs*, starting with the most specific.
+
+(Of course, if a callback target (URL) is specified in the request, you won't get back a second response -- Growl will open up your browser instead.)
+
app.when_close 'process' do |response|
# do something with close responses to process notifications
end
- app.when_click :context => 'process', :type => 'confirm' do |response|
- # do something with click responses that have 'process' contexts of type 'confirm'
+ app.when_click :context => 'process', :type => 'run' do |response|
+ # do something with click responses that have 'process' contexts of type 'run'
end
app.when_click :type => 'integer' do |response|
@@ -83,3 +110,74 @@ Note this is very much beta. The core functionality is fairly well tested, but
end
+## Lower-level interface
+
+If you prefer a more direct interface you can use Groem::Client, the EM connection which Groem::App is built on. It expects the request to be passed as a hash, and will throw OK, error, and callback responses back as a three-element array roughly modeled on Rack's interface (_status_, _headers_, and _body_ -- body in this case being a hash of GNTP callback headers).
+
+For instance,
+
+
+ regist = {'headers' => {
+ 'Application-Name' => 'SurfWriter',
+ 'Application-Icon' => 'http://www.site.org/image.jpg'
+ },
+ 'notifications' => {
+ 'Download Complete' => {
+ 'Notification-Display-Name' => 'Download completed',
+ 'Notification-Enabled' => 'True',
+ 'X-Language' => 'English',
+ 'X-Timezone' => 'PST'
+ }
+ }
+ }
+
+ connect = Groem::Client.register(regist)
+ connect.when_ok { |resp| # ... }
+ connect.errback { |resp| # ... }
+
+ notif = {'Application-Name' => 'SurfWriter',
+ 'Notification-Name' => 'Download Complete',
+ 'Notification-ID' => some_unique_id,
+ 'Notification-Callback-Context' => 'myfile',
+ 'Notification-Callback-Context-Type' => 'confirm'
+ }
+
+ connect2 = Groem::Client.notify(notif)
+ connect2.when_ok { |resp| # ... }
+ connect2.errback { |resp| # ... }
+ connect2.when_callback { |resp| #... }
+
+
+For more details see `lib/groem/marshal`, and `spec/functional/client_spec`.
+
+
+## Limitations
+
+- No casting or uncasting of GNTP headers to or from ruby types is done -- everything is a string (or a symbol which gets converted to a string). So the interface is a little clunky.
+
+- If a Growl server is not running, the client's EM loop will not exit and has to be interrupted. In the future it would be good to timeout, perhaps after several reconnect attempts.
+
+- It has only been tested on Ruby 1.8.7 running on cygwin on WinXP. I am planning to test on 1.9.2.
+
+
+## License
+
+Copyright (c) 2010 Eric Gjertsen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
@@ -1,9 +1,7 @@
-## Oct 10
+## Oct 12
-1. Take out bundler dep except for spec_helper, set up gemspec
-2. See if we can use Digest::Something instead of uuidtools gem
-3. Update README, add LICENSE
-3. Release gem
-4. Test/debug on ruby 1.9.2
-5. Implement binary resources
-6. Implement encryption
+- Test/debug on ruby 1.9.2
+- Timeout or reconnect client if no server running
+- Allow casting/uncasting ruby types from/to GNTP
+- Implement binary resources
+- Implement encryption
@@ -28,6 +28,7 @@ def initialize(name, *args)
self.environment = DEFAULT_ENV.merge(opts.delete(:environment) || {})
self.name = name.to_s if name
self.title = title.to_s if title
+ self.enabled = 'True'
self.headers = opts.delete(:headers) || {}
opts.each_pair do |opt, val|
if self.respond_to?(:"#{opt}=")
View
@@ -1,13 +1,14 @@
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))
require 'rubygems'
require 'bundler'
-Bundler.setup :development
+Bundler.setup :default
require 'lib/groem'
Dir[File.expand_path(File.join(File.dirname(__FILE__), 'shared', '**', '*.rb'))].each do |f|
load f
end
+Bundler.setup :development
require 'minitest/spec'
MiniTest::Unit.autorun
@@ -23,6 +23,11 @@
@subject['environment'].must_equal Groem::Notification::DEFAULT_ENV
end
+ it 'should default enabled to \'True\' when option not passed' do
+ @subject = Groem::Notification.new('verb')
+ @subject.enabled.must_equal 'True'
+ end
+
it 'should merge keys from input environment option into default environment' do
input = {'version' => '1.2',
'request_method' => 'HELLO',

0 comments on commit cd50c9f

Please sign in to comment.