growlnotifier 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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