growlnotifier 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +2 -0
- data/Manifest.txt +11 -0
- data/README.txt +69 -0
- data/Rakefile +43 -0
- data/lib/growl.rb +161 -0
- data/lib/growl_helpers.rb +25 -0
- data/samples/growl_block_sample.rb +29 -0
- data/samples/growl_delegate_sample.rb +36 -0
- data/test/growl_helpers_test.rb +41 -0
- data/test/growl_test.rb +254 -0
- data/test/test_helper.rb +23 -0
- metadata +77 -0
data/LICENSE
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
= Growl Notifier
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
Growl::Notifier is a class that allows your application to post notifications to the Growl daemon.
|
6
|
+
It can also receive clicked and timeout notifications as well as take blocks for clicked callback handlers.
|
7
|
+
|
8
|
+
This is an extraction and cleanup of the Growl code from LimeChat (http://github.com/psychs/limechat/tree/master) and later on extended for WebApp (http://github.com/alloy/webapp-app/tree/master).
|
9
|
+
|
10
|
+
== Requirements
|
11
|
+
|
12
|
+
* Mac OS X 10.4 or 10.5
|
13
|
+
* Ruby 1.8 (http://ruby-lang.org/)
|
14
|
+
* RubyCocoa (http://rubycocoa.sourceforge.net/)
|
15
|
+
|
16
|
+
== How to use Growl Notifier
|
17
|
+
|
18
|
+
A simple example:
|
19
|
+
|
20
|
+
require 'growl'
|
21
|
+
|
22
|
+
g = Growl::Notifier.sharedInstance
|
23
|
+
g.register('test_app', ['message_type'])
|
24
|
+
g.notify('message_type', 'title', 'desc')
|
25
|
+
|
26
|
+
How to receive clicked and timeout notifications in your application:
|
27
|
+
|
28
|
+
require 'growl'
|
29
|
+
|
30
|
+
class GrowlController < OSX::NSObject
|
31
|
+
def init
|
32
|
+
if super_init
|
33
|
+
@g = Growl::Notifier.sharedInstance
|
34
|
+
@g.delegate = self
|
35
|
+
@g.register('test_app', ['message_type'])
|
36
|
+
@g.notify('message_type', 'title', 'desc')
|
37
|
+
self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def growlNotifierClicked_context(sender, context)
|
42
|
+
puts context
|
43
|
+
end
|
44
|
+
|
45
|
+
def growlNotifierTimedOut_context(sender, context)
|
46
|
+
puts context
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Include the Growl module into your class to get access to a few convenience methods:
|
51
|
+
|
52
|
+
require 'growl'
|
53
|
+
|
54
|
+
class GrowlController < OSX::NSObject
|
55
|
+
include Growl
|
56
|
+
Growl::Notifier.sharedInstance.register('test_app', ['message_type'])
|
57
|
+
|
58
|
+
def init
|
59
|
+
if super_init
|
60
|
+
growl('message_type', 'title', 'desc')
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
== License
|
67
|
+
|
68
|
+
Copyright (c) 2007-2008 Satoshi Nakagawa <psychs@limechat.net>, Eloy Duran <e.duran@superalloy.nl>
|
69
|
+
You can redistribute it and/or modify it under the same terms as Ruby.
|
data/Rakefile
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
require 'lib/growl.rb'
|
5
|
+
|
6
|
+
# Install the Hoe gem to be able to use the deploy tasks.
|
7
|
+
begin
|
8
|
+
require 'hoe'
|
9
|
+
|
10
|
+
class Hoe
|
11
|
+
def extra_deps
|
12
|
+
@extra_deps.reject do |x|
|
13
|
+
Array(x).first == 'hoe'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Hoe.new('growlnotifier', Growl::Notifier::VERSION) do |p|
|
19
|
+
p.author = ["Satoshi Nakagawa", "Eloy Duran"]
|
20
|
+
p.description = "A ruby library which allows you to send Growl notifications."
|
21
|
+
p.email = ["psychs@limechat.net", "e.duran@superalloy.nl"]
|
22
|
+
p.summary = "Growl::Notifier is a OSX RubyCocoa class that allows your application to post notifications to the Growl daemon."
|
23
|
+
p.url = "http://growlnotifier.rubyforge.org/"
|
24
|
+
p.clean_globs = ['coverage'] # Remove this directory on "rake clean"
|
25
|
+
p.remote_rdoc_dir = '' # Release to root
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :test
|
31
|
+
|
32
|
+
Rake::TestTask.new do |t|
|
33
|
+
t.libs << "test"
|
34
|
+
t.test_files = FileList['test/*_test.rb']
|
35
|
+
t.options = '-rs'
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Run code-coverage analysis using rcov"
|
39
|
+
task :coverage do
|
40
|
+
rm_rf "coverage"
|
41
|
+
sh "rcov test/*_test.rb --exclude=mocha,RubyCocoa.framework,osx,rcov"
|
42
|
+
sh "open coverage/index.html"
|
43
|
+
end
|
data/lib/growl.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'osx/cocoa'
|
2
|
+
|
3
|
+
module Growl
|
4
|
+
class Notifier < OSX::NSObject
|
5
|
+
VERSION = '1.0'
|
6
|
+
|
7
|
+
GROWL_IS_READY = "Lend Me Some Sugar; I Am Your Neighbor!"
|
8
|
+
GROWL_NOTIFICATION_CLICKED = "GrowlClicked!"
|
9
|
+
GROWL_NOTIFICATION_TIMED_OUT = "GrowlTimedOut!"
|
10
|
+
GROWL_KEY_CLICKED_CONTEXT = "ClickedContext"
|
11
|
+
|
12
|
+
PRIORITIES = {
|
13
|
+
:emergency => 2,
|
14
|
+
:high => 1,
|
15
|
+
:normal => 0,
|
16
|
+
:moderate => -1,
|
17
|
+
:very_low => -2,
|
18
|
+
}
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# Returns the singleton instance of Growl::Notifier with which you register and send your Growl notifications.
|
22
|
+
def sharedInstance
|
23
|
+
@sharedInstance ||= alloc.init
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :application_name, :application_icon, :notifications, :default_notifications
|
28
|
+
attr_accessor :delegate
|
29
|
+
|
30
|
+
# Registers the applications metadata and the notifications, that your application might send, to Growl.
|
31
|
+
# The +default_notifications+ are notifications that will be enabled by default, the regular +notifications+ are
|
32
|
+
# optional and should be enabled by the user in the Growl system preferences.
|
33
|
+
#
|
34
|
+
# Register the applications name and the notifications that will be used.
|
35
|
+
# * +default_notifications+ defaults to the regular +notifications+.
|
36
|
+
# * +application_icon+ defaults to OSX::NSApplication.sharedApplication.applicationIconImage.
|
37
|
+
#
|
38
|
+
# Growl::Notifier.sharedInstance.register 'FoodApp', ['YourHamburgerIsReady', 'OhSomeoneElseAteIt']
|
39
|
+
#
|
40
|
+
# Register the applications name, the notifications plus the default notifications that will be used and the icon that's to be used in the Growl notifications.
|
41
|
+
#
|
42
|
+
# Growl::Notifier.sharedInstance.register 'FoodApp', ['YourHamburgerIsReady', 'OhSomeoneElseAteIt'], ['DefaultNotification], OSX::NSImage.imageNamed('GreasyHamburger')
|
43
|
+
def register(application_name, notifications, default_notifications = nil, application_icon = nil)
|
44
|
+
@application_name, @application_icon = application_name, (application_icon || OSX::NSApplication.sharedApplication.applicationIconImage)
|
45
|
+
@notifications, @default_notifications = notifications, (default_notifications || notifications)
|
46
|
+
@callbacks = {}
|
47
|
+
send_registration!
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sends a Growl notification.
|
51
|
+
#
|
52
|
+
# * +notification_name+ : the name of one of the notifcations that your apllication registered with Growl. See register for more info.
|
53
|
+
# * +title+ : the title that should be used in the Growl notification.
|
54
|
+
# * +description+ : the body of the Grow notification.
|
55
|
+
# * +options+ : specifies a few optional options:
|
56
|
+
# * <tt>:sticky</tt> : indicates if the Grow notification should "stick" to the screen. Defaults to +false+.
|
57
|
+
# * <tt>:priority</tt> : sets the priority level of the Growl notification. Defaults to 0.
|
58
|
+
# * <tt>:icon</tt> : specifies the icon to be used in the Growl notification. Defaults to the registered +application_icon+, see register for more info.
|
59
|
+
#
|
60
|
+
# Simple example:
|
61
|
+
#
|
62
|
+
# name = 'YourHamburgerIsReady'
|
63
|
+
# title = 'Your hamburger is ready for consumption!'
|
64
|
+
# description = 'Please pick it up at isle 4.'
|
65
|
+
#
|
66
|
+
# Growl::Notifier.sharedInstance.notify(name, title, description)
|
67
|
+
#
|
68
|
+
# Example with optional options:
|
69
|
+
#
|
70
|
+
# Growl::Notifier.sharedInstance.notify(name, title, description, :sticky => true, :priority => 1, :icon => OSX::NSImage.imageNamed('SuperBigHamburger'))
|
71
|
+
#
|
72
|
+
# When you pass notify a block, that block will be used as the callback handler if the Growl notification was clicked. Eg:
|
73
|
+
#
|
74
|
+
# Growl::Notifier.sharedInstance.notify(name, title, description, :sticky => true) do
|
75
|
+
# user_clicked_notification_so_do_something!
|
76
|
+
# end
|
77
|
+
def notify(notification_name, title, description, options = {}, &callback)
|
78
|
+
dict = {
|
79
|
+
:ApplicationName => @application_name,
|
80
|
+
:ApplicationPID => pid,
|
81
|
+
:NotificationName => notification_name,
|
82
|
+
:NotificationTitle => title,
|
83
|
+
:NotificationDescription => description,
|
84
|
+
:NotificationPriority => PRIORITIES[options[:priority]] || options[:priority] || 0
|
85
|
+
}
|
86
|
+
dict[:NotificationIcon] = options[:icon].TIFFRepresentation if options[:icon]
|
87
|
+
dict[:NotificationSticky] = 1 if options[:sticky]
|
88
|
+
|
89
|
+
context = {}
|
90
|
+
context[:user_click_context] = options[:click_context] if options[:click_context]
|
91
|
+
if block_given?
|
92
|
+
@callbacks[callback.object_id] = callback
|
93
|
+
context[:callback_object_id] = callback.object_id.to_s
|
94
|
+
end
|
95
|
+
dict[:NotificationClickContext] = context unless context.empty?
|
96
|
+
|
97
|
+
notification_center.postNotificationName_object_userInfo_deliverImmediately(:GrowlNotification, nil, dict, true)
|
98
|
+
end
|
99
|
+
|
100
|
+
def onReady(notification)
|
101
|
+
send_registration!
|
102
|
+
end
|
103
|
+
|
104
|
+
def onClicked(notification)
|
105
|
+
user_context = nil
|
106
|
+
if context = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT]
|
107
|
+
user_context = context[:user_click_context]
|
108
|
+
if callback_object_id = context[:callback_object_id]
|
109
|
+
@callbacks.delete(callback_object_id.to_i).call
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
@delegate.growlNotifierClicked_context(self, user_context) if @delegate && @delegate.respond_to?(:growlNotifierClicked_context)
|
114
|
+
end
|
115
|
+
|
116
|
+
def onTimeout(notification)
|
117
|
+
user_context = nil
|
118
|
+
if context = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT]
|
119
|
+
@callbacks.delete(context[:callback_object_id].to_i) if context[:callback_object_id]
|
120
|
+
user_context = context[:user_click_context]
|
121
|
+
end
|
122
|
+
|
123
|
+
@delegate.growlNotifierTimedOut_context(self, user_context) if @delegate && @delegate.respond_to?(:growlNotifierTimedOut_context)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def pid
|
129
|
+
OSX::NSProcessInfo.processInfo.processIdentifier.to_i
|
130
|
+
end
|
131
|
+
|
132
|
+
def notification_center
|
133
|
+
OSX::NSDistributedNotificationCenter.defaultCenter
|
134
|
+
end
|
135
|
+
|
136
|
+
def send_registration!
|
137
|
+
add_observer 'onReady:', GROWL_IS_READY, false
|
138
|
+
add_observer 'onClicked:', GROWL_NOTIFICATION_CLICKED, true
|
139
|
+
add_observer 'onTimeout:', GROWL_NOTIFICATION_TIMED_OUT, true
|
140
|
+
|
141
|
+
dict = {
|
142
|
+
:ApplicationName => @application_name,
|
143
|
+
:ApplicationIcon => application_icon.TIFFRepresentation,
|
144
|
+
:AllNotifications => @notifications,
|
145
|
+
:DefaultNotifications => @default_notifications
|
146
|
+
}
|
147
|
+
|
148
|
+
notification_center.objc_send(
|
149
|
+
:postNotificationName, :GrowlApplicationRegistrationNotification,
|
150
|
+
:object, nil,
|
151
|
+
:userInfo, dict,
|
152
|
+
:deliverImmediately, true
|
153
|
+
)
|
154
|
+
end
|
155
|
+
|
156
|
+
def add_observer(selector, name, prepend_name_and_pid)
|
157
|
+
name = "#{@application_name}-#{pid}-#{name}" if prepend_name_and_pid
|
158
|
+
notification_center.addObserver_selector_name_object self, selector, name, nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path('../growl', __FILE__)
|
2
|
+
|
3
|
+
# Defines a few convenience methods that you can use in your class if you include the Growl module.
|
4
|
+
# Eg:
|
5
|
+
#
|
6
|
+
# class FoodReporter < OSX::NSObject
|
7
|
+
# include Growl
|
8
|
+
#
|
9
|
+
# def hamburger_time!
|
10
|
+
# growl 'YourHamburgerIsReady', 'Your hamburger is ready for consumption!', 'Please pick it up at isle 4.', :priority => 1 do
|
11
|
+
# throw_it_away_before_user_reaches_counter!
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
module Growl
|
16
|
+
# Sends a Growl notification. See Growl::Notifier#notify for more info.
|
17
|
+
def growl(name, title, description, options = {}, &callback)
|
18
|
+
Growl::Notifier.sharedInstance.notify name, title, description, options, &callback
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sends a sticky Growl notification. See Growl::Notifier#notify for more info.
|
22
|
+
def sticky_growl(name, title, description, options = {}, &callback)
|
23
|
+
growl name, title, description, options.merge!(:sticky => true), &callback
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'osx/cocoa'
|
2
|
+
require File.expand_path('../../lib/growl_helpers', __FILE__)
|
3
|
+
|
4
|
+
class GrowlController < OSX::NSObject
|
5
|
+
# Makes the #growl and #sticky_growl shortcut methods available.
|
6
|
+
include Growl
|
7
|
+
|
8
|
+
HELLO_TYPE = 'Hello message received'
|
9
|
+
Growl::Notifier.sharedInstance.register('GrowlSample', [HELLO_TYPE])
|
10
|
+
|
11
|
+
def init
|
12
|
+
if super_init
|
13
|
+
growl HELLO_TYPE, 'Not sticky', 'Hello world' do
|
14
|
+
puts "Clicked not sticky: #{ Time.now }"
|
15
|
+
OSX::NSApp.terminate(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
sticky_growl HELLO_TYPE, 'Sticky', 'Hello world' do
|
19
|
+
puts "Clicked sticky: #{ Time.now }"
|
20
|
+
OSX::NSApp.terminate(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
g = GrowlController.alloc.init
|
29
|
+
OSX::NSApp.run
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'osx/cocoa'
|
2
|
+
require File.expand_path('../../lib/growl', __FILE__)
|
3
|
+
|
4
|
+
class GrowlController < OSX::NSObject
|
5
|
+
HELLO_TYPE = 'Hello message received'
|
6
|
+
|
7
|
+
def init
|
8
|
+
if super_init
|
9
|
+
@g = Growl::Notifier.sharedInstance
|
10
|
+
@g.delegate = self
|
11
|
+
@g.register('GrowlSample', [HELLO_TYPE])
|
12
|
+
@g.notify(HELLO_TYPE, 'Sticky', 'Hello world', :sticky => true, :click_context => Time.now.to_s )
|
13
|
+
@g.notify(HELLO_TYPE, 'Timed out', 'Hello world', :click_context => Time.now.to_s )
|
14
|
+
@count = 2
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def growlNotifierClicked_context(sender, context)
|
20
|
+
puts "Clicked: #{context}"
|
21
|
+
checkCount
|
22
|
+
end
|
23
|
+
|
24
|
+
def growlNotifierTimedOut_context(sender, context)
|
25
|
+
puts "Timed out: #{context}"
|
26
|
+
checkCount
|
27
|
+
end
|
28
|
+
|
29
|
+
def checkCount
|
30
|
+
@count -= 1
|
31
|
+
OSX::NSApp.terminate(nil) if @count == 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
g = GrowlController.alloc.init
|
36
|
+
OSX::NSApp.run
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
require File.expand_path('../../lib/growl_helpers', __FILE__)
|
3
|
+
|
4
|
+
class Foo < OSX::NSObject
|
5
|
+
include Growl
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "Growl, when mixed into a class" do
|
9
|
+
before do
|
10
|
+
@name = 'YourHamburgerIsReady'
|
11
|
+
@title = 'Your hamburger is ready for consumption!'
|
12
|
+
@description = 'Please pick it up at isle 4.'
|
13
|
+
@options = { :sticky => true, :priority => 1 }
|
14
|
+
|
15
|
+
@object = Foo.alloc.init
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should define a #growl instance method" do
|
19
|
+
@object.should.respond_to :growl
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should call Growl::Notifier.sharedInstance.notify with the arguments passed to #growl" do
|
23
|
+
should_call_sticky_notify_with_priority_1
|
24
|
+
@object.growl @name, @title, @description, :sticky => true, :priority => 1
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should define a #sticky_growl instance method which is a shortcut method to send a sticky Growl notification" do
|
28
|
+
@object.should.respond_to :sticky_growl
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should call Growl::Notifier.sharedInstance.notify with the arguments passed to #sticky_growl and the sticky option set to true" do
|
32
|
+
should_call_sticky_notify_with_priority_1
|
33
|
+
@object.sticky_growl @name, @title, @description, :priority => 1
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def should_call_sticky_notify_with_priority_1
|
39
|
+
Growl::Notifier.sharedInstance.expects(:notify).with(@name, @title, @description, @options)
|
40
|
+
end
|
41
|
+
end
|
data/test/growl_test.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
require File.expand_path('../../lib/growl', __FILE__)
|
3
|
+
|
4
|
+
describe 'Growl::Notifier' do
|
5
|
+
include GrowlNotifierSpecHelper
|
6
|
+
|
7
|
+
before do
|
8
|
+
set_variables!
|
9
|
+
@instance.stubs(:send_registration!)
|
10
|
+
@instance.register @name, @notifications
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be a singleton class" do
|
14
|
+
@instance.should.be.instance_of Growl::Notifier
|
15
|
+
@instance.should.be Growl::Notifier.sharedInstance
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'Growl::Notifier#register' do
|
20
|
+
include GrowlNotifierSpecHelper
|
21
|
+
|
22
|
+
before do
|
23
|
+
set_variables!
|
24
|
+
@instance.stubs(:send_registration!)
|
25
|
+
@instance.register @name, @notifications
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should take the name of the application" do
|
29
|
+
@instance.application_name.should == @name
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should take an array of notifications that should be registered" do
|
33
|
+
@instance.notifications.should == @notifications
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should set the default notifications to the same as the notifications array if none is specified" do
|
37
|
+
@instance.default_notifications.should == @notifications
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should take an array of notifications that should be registered as the default notifications" do
|
41
|
+
@instance.register @name, @notifications, @default_notifications
|
42
|
+
@instance.default_notifications.should == @default_notifications
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should by default use the NSAppication's sharedApplication icon if none was specified" do
|
46
|
+
@instance.application_icon.should.be OSX::NSApplication.sharedApplication.applicationIconImage
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should take an optional application icon" do
|
50
|
+
@instance.register @name, @notifications, nil, @icon
|
51
|
+
@instance.application_icon.should.be @icon
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should register the configuration" do
|
55
|
+
@instance.expects(:send_registration!)
|
56
|
+
@instance.register @name, @notifications
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'Growl::Notifier#send_registration!' do
|
61
|
+
include GrowlNotifierSpecHelper
|
62
|
+
|
63
|
+
before do
|
64
|
+
set_variables!
|
65
|
+
@tiff = mock('TIFFRepresentation')
|
66
|
+
@icon.stubs(:TIFFRepresentation).returns(@tiff)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should register itself with Growl" do
|
70
|
+
pid = 54231
|
71
|
+
@instance.stubs(:pid).returns(pid)
|
72
|
+
|
73
|
+
@instance.expects(:add_observer).with('onReady:', "Lend Me Some Sugar; I Am Your Neighbor!", false)
|
74
|
+
@instance.expects(:add_observer).with('onClicked:', "GrowlClicked!", true)
|
75
|
+
@instance.expects(:add_observer).with('onTimeout:', "GrowlTimedOut!", true)
|
76
|
+
|
77
|
+
dict = {
|
78
|
+
:ApplicationName => @name,
|
79
|
+
:ApplicationIcon => @tiff,
|
80
|
+
:AllNotifications => @notifications,
|
81
|
+
:DefaultNotifications => @default_notifications
|
82
|
+
}
|
83
|
+
|
84
|
+
@center.expects(:objc_send).with(
|
85
|
+
:postNotificationName, :GrowlApplicationRegistrationNotification,
|
86
|
+
:object, nil,
|
87
|
+
:userInfo, dict,
|
88
|
+
:deliverImmediately, true
|
89
|
+
)
|
90
|
+
|
91
|
+
@instance.register @name, @notifications, @default_notifications, @icon
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "Growl::Notifier.sharedInstance" do
|
96
|
+
include GrowlNotifierSpecHelper
|
97
|
+
|
98
|
+
before do
|
99
|
+
set_variables!
|
100
|
+
|
101
|
+
@pid = 54231
|
102
|
+
OSX::NSProcessInfo.processInfo.stubs(:processIdentifier).returns(@pid)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return the applications PID" do
|
106
|
+
@instance.send(:pid).should.be @pid
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should be able to easily add observers to the NSDistributedNotificationCenter" do
|
110
|
+
@center.expects(:addObserver_selector_name_object).with(@instance, 'selector:', "name", nil)
|
111
|
+
@instance.send(:add_observer, 'selector:', 'name', false)
|
112
|
+
|
113
|
+
@center.expects(:addObserver_selector_name_object).with(@instance, 'selector:', "#{@name}-#{@pid}-name", nil)
|
114
|
+
@instance.send(:add_observer, 'selector:', 'name', true)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should send a notification to Growl" do
|
118
|
+
another_icon = mock('Another icon')
|
119
|
+
another_icons_tiff_rep = mock('Another icons tiff representation')
|
120
|
+
another_icon.stubs(:TIFFRepresentation).returns(another_icons_tiff_rep)
|
121
|
+
|
122
|
+
dict = {
|
123
|
+
:ApplicationName => @name,
|
124
|
+
:ApplicationPID => @pid,
|
125
|
+
:NotificationName => @notifications.first,
|
126
|
+
:NotificationTitle => 'title',
|
127
|
+
:NotificationDescription => 'description',
|
128
|
+
:NotificationPriority => 1,
|
129
|
+
:NotificationIcon => another_icons_tiff_rep,
|
130
|
+
:NotificationSticky => 1,
|
131
|
+
:NotificationClickContext => { :user_click_context => 'foo' }
|
132
|
+
}
|
133
|
+
|
134
|
+
@center.expects(:postNotificationName_object_userInfo_deliverImmediately).with(:GrowlNotification, nil, dict, true)
|
135
|
+
|
136
|
+
@instance.notify(@notifications.first, 'title', 'description', :sticky => true, :priority => 1, :icon => another_icon, :click_context => 'foo')
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not require all options to be specified when sending a notification to Growl" do
|
140
|
+
dict = {
|
141
|
+
:ApplicationName => @name,
|
142
|
+
:ApplicationPID => @pid,
|
143
|
+
:NotificationName => @notifications.first,
|
144
|
+
:NotificationTitle => 'title',
|
145
|
+
:NotificationDescription => 'description',
|
146
|
+
:NotificationPriority => 0
|
147
|
+
}
|
148
|
+
|
149
|
+
@center.expects(:postNotificationName_object_userInfo_deliverImmediately).with(:GrowlNotification, nil, dict, true)
|
150
|
+
@instance.notify(@notifications.first, 'title', 'description')
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should take a symbol instead of an integer to specify the priority level when sending a notification to Growl" do
|
154
|
+
priority_table = { :very_low => -2, :moderate => -1, :normal => 0, :high => 1, :emergency => 2 }
|
155
|
+
|
156
|
+
priority_table.each do |key, value|
|
157
|
+
@center.expects(:postNotificationName_object_userInfo_deliverImmediately).with do |name, object, info, immediately|
|
158
|
+
info[:NotificationPriority] == value
|
159
|
+
end
|
160
|
+
|
161
|
+
@instance.notify(@notifications.first, 'title', 'description', :priority => key)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should add a callback to the callbacks if a block is given to #notify" do
|
166
|
+
callback = proc { message_from_callback }
|
167
|
+
@center.expects(:postNotificationName_object_userInfo_deliverImmediately).with do |name, object, info, immediately|
|
168
|
+
info[:NotificationClickContext] = { :callback_object_id => callback.object_id, :user_click_context => 'foo' }
|
169
|
+
end
|
170
|
+
|
171
|
+
@instance.notify(@notifications.first, 'title', 'description', { :click_context => 'foo' }, &callback)
|
172
|
+
|
173
|
+
@instance.instance_variable_get(:@callbacks)[callback.object_id].should.be callback
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should call a callback handler if the notification that it belongs to is clicked and then remove the callback" do
|
177
|
+
callback = nil
|
178
|
+
@instance.instance_eval do
|
179
|
+
callback = proc { message_from_callback }
|
180
|
+
end
|
181
|
+
@instance.notify(@notifications.first, 'title', 'description', &callback)
|
182
|
+
|
183
|
+
@instance.expects(:message_from_callback)
|
184
|
+
@instance.onClicked(stubbed_notification(:callback_object_id => callback.object_id.to_s.to_ns))
|
185
|
+
@instance.instance_variable_get(:@callbacks)[callback.object_id].should.be nil
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should send a message to the delegate if a notification was clicked with the specified context" do
|
189
|
+
notification = stubbed_notification(:user_click_context => 'foo')
|
190
|
+
assign_delegate.expects(:growlNotifierClicked_context).with(@instance, 'foo')
|
191
|
+
@instance.onClicked(notification)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should send a message to the delegate if a notification was clicked with nil as the context if none was specified" do
|
195
|
+
notification = stubbed_notification
|
196
|
+
assign_delegate.expects(:growlNotifierClicked_context).with(@instance, nil)
|
197
|
+
@instance.onClicked(notification)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should not send a message to the delegate if a notification was clicked but the delegate doesn't respond to the delegate method" do
|
201
|
+
assign_delegate
|
202
|
+
@instance.onClicked(stubbed_notification)
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should remove a callback handler if the notification that it belongs to times out" do
|
206
|
+
callback = proc {}
|
207
|
+
notification = stubbed_notification(:callback_object_id => callback.object_id.to_s.to_ns)
|
208
|
+
|
209
|
+
@instance.notify(@notifications.first, 'title', 'description', &callback)
|
210
|
+
@instance.delegate = nil
|
211
|
+
|
212
|
+
callback.expects(:call).times(0)
|
213
|
+
@instance.onTimeout(notification)
|
214
|
+
@instance.instance_variable_get(:@callbacks)[callback.object_id].should.be nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should send a message to the delegate if a notification times out with the specified context" do
|
218
|
+
notification = stubbed_notification(:user_click_context => 'foo')
|
219
|
+
assign_delegate.expects(:growlNotifierTimedOut_context).with(@instance, 'foo')
|
220
|
+
|
221
|
+
@instance.onTimeout(notification)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should send a message to the delegate if a notification times out with nil as the context in none was specified" do
|
225
|
+
notification = stubbed_notification
|
226
|
+
assign_delegate.expects(:growlNotifierTimedOut_context).with(@instance, nil)
|
227
|
+
|
228
|
+
@instance.onTimeout(notification)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should not send a message to the delegate if a notification times out but the delegate doesn't respond to the delegate method" do
|
232
|
+
assign_delegate
|
233
|
+
@instance.onTimeout(stubbed_notification)
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should resend the registration data to Growl if Growl was restarted for some reason" do
|
237
|
+
@instance.expects(:send_registration!)
|
238
|
+
@instance.onReady(nil)
|
239
|
+
end
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
def assign_delegate
|
244
|
+
delegate = mock('delegate')
|
245
|
+
@instance.delegate = delegate
|
246
|
+
delegate
|
247
|
+
end
|
248
|
+
|
249
|
+
def stubbed_notification(options = {})
|
250
|
+
notification = stub('timeout notification')
|
251
|
+
notification.stubs(:userInfo).returns("ClickedContext" => options.to_ns)
|
252
|
+
notification
|
253
|
+
end
|
254
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "test/unit"
|
3
|
+
require "test/spec"
|
4
|
+
require "mocha"
|
5
|
+
require 'osx/cocoa'
|
6
|
+
|
7
|
+
def OSX._ignore_ns_override; true; end
|
8
|
+
|
9
|
+
$: << File.expand_path('../../lib', __FILE__)
|
10
|
+
|
11
|
+
module GrowlNotifierSpecHelper
|
12
|
+
def set_variables!
|
13
|
+
@instance = Growl::Notifier.sharedInstance
|
14
|
+
@name = 'GrowlerApp'
|
15
|
+
@icon = mock('PrettyIcon')
|
16
|
+
@notifications = ['YourHamburgerIsReady', 'OhSomeoneElseAteIt']
|
17
|
+
@default_notifications = ['ADefaultNotification', *@notifications]
|
18
|
+
|
19
|
+
@center = mock('NSDistributedNotificationCenter')
|
20
|
+
@center.stubs(:postNotificationName_object_userInfo_deliverImmediately)
|
21
|
+
OSX::NSDistributedNotificationCenter.stubs(:defaultCenter).returns(@center)
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: growlnotifier
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "1.0"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Satoshi Nakagawa
|
8
|
+
- Eloy Duran
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-08-04 00:00:00 +09:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: hoe
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.7.0
|
25
|
+
version:
|
26
|
+
description: A ruby library which allows you to send Growl notifications.
|
27
|
+
email:
|
28
|
+
- psychs@limechat.net
|
29
|
+
- e.duran@superalloy.nl
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files:
|
35
|
+
- Manifest.txt
|
36
|
+
- README.txt
|
37
|
+
files:
|
38
|
+
- Manifest.txt
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- LICENSE
|
42
|
+
- lib/growl.rb
|
43
|
+
- lib/growl_helpers.rb
|
44
|
+
- samples/growl_block_sample.rb
|
45
|
+
- samples/growl_delegate_sample.rb
|
46
|
+
- test/growl_test.rb
|
47
|
+
- test/growl_helpers_test.rb
|
48
|
+
- test/test_helper.rb
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://growlnotifier.rubyforge.org/
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --main
|
54
|
+
- README.txt
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: growlnotifier
|
72
|
+
rubygems_version: 1.2.0
|
73
|
+
signing_key:
|
74
|
+
specification_version: 2
|
75
|
+
summary: Growl::Notifier is a OSX RubyCocoa class that allows your application to post notifications to the Growl daemon.
|
76
|
+
test_files:
|
77
|
+
- test/test_helper.rb
|