growlnotifier 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,2 @@
1
+ Copyright (c) 2007-2008 Satoshi Nakagawa <psychs@limechat.net>, Eloy Duran <e.duran@superalloy.nl>
2
+ You can redistribute it and/or modify it under the same terms as Ruby.
data/Manifest.txt ADDED
@@ -0,0 +1,11 @@
1
+ Manifest.txt
2
+ README.txt
3
+ Rakefile
4
+ LICENSE
5
+ lib/growl.rb
6
+ lib/growl_helpers.rb
7
+ samples/growl_block_sample.rb
8
+ samples/growl_delegate_sample.rb
9
+ test/growl_test.rb
10
+ test/growl_helpers_test.rb
11
+ test/test_helper.rb
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
@@ -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
@@ -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