meow 1.0.0 → 1.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/CHANGELOG.rdoc +8 -0
- data/Manifest.txt +2 -0
- data/README.rdoc +7 -1
- data/Rakefile +3 -1
- data/lib/meow.rb +78 -12
- data/lib/meow/notifier.rb +26 -0
- data/test/assets/aaron.jpeg +0 -0
- data/test/test_meow.rb +33 -4
- metadata +4 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 1.1.0 / 2008-06-13
|
2
|
+
|
3
|
+
* 3 major enhancements
|
4
|
+
|
5
|
+
* Added click callbacks so that Meow can be notified of clicks.
|
6
|
+
* Added Meow.run() to block and wait for clicks
|
7
|
+
* Meow.import_image() returns an image suitable for icon use
|
8
|
+
|
1
9
|
=== 1.0.0 / 2008-06-05
|
2
10
|
|
3
11
|
* 1 major enhancement
|
data/Manifest.txt
CHANGED
data/README.rdoc
CHANGED
@@ -11,6 +11,12 @@ Send Growl notifications via Ruby.
|
|
11
11
|
meep = Meow.new('Meow Test')
|
12
12
|
meep.notify('Title', 'Description')
|
13
13
|
|
14
|
+
## Handle clicks
|
15
|
+
meep.notify('Click Me', 'Do it!') do
|
16
|
+
puts "I got clicked!"
|
17
|
+
end
|
18
|
+
Meow.start # Start blocks
|
19
|
+
|
14
20
|
== REQUIREMENTS:
|
15
21
|
|
16
22
|
* Growl: http://growl.info
|
@@ -28,7 +34,7 @@ Thanks to the Growl team! This code is heavily based on their ruby example.
|
|
28
34
|
|
29
35
|
(The MIT License)
|
30
36
|
|
31
|
-
Copyright (c) 2008 Aaron Patterson
|
37
|
+
Copyright (c) 2008 Aaron Patterson, Evan Phoenix, Eric Hodel
|
32
38
|
|
33
39
|
Permission is hereby granted, free of charge, to any person obtaining
|
34
40
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
data/lib/meow.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'osx/cocoa'
|
2
|
+
require 'meow/notifier'
|
2
3
|
|
3
4
|
class Meow
|
4
|
-
VERSION = '1.
|
5
|
+
VERSION = '1.1.0'
|
5
6
|
PRIORITIES = { :very_low => -2,
|
6
7
|
:moderate => -1,
|
7
8
|
:normal => 0,
|
@@ -9,6 +10,18 @@ class Meow
|
|
9
10
|
:emergency => 2,
|
10
11
|
}
|
11
12
|
|
13
|
+
GROWL_IS_READY = "Lend Me Some Sugar; I Am Your Neighbor!"
|
14
|
+
GROWL_NOTIFICATION_CLICKED = "GrowlClicked!"
|
15
|
+
GROWL_NOTIFICATION_TIMED_OUT = "GrowlTimedOut!"
|
16
|
+
GROWL_KEY_CLICKED_CONTEXT = "ClickedContext"
|
17
|
+
|
18
|
+
# This sets up shared state properly that Cocoa uses.
|
19
|
+
@@application = OSX::NSApplication.sharedApplication
|
20
|
+
|
21
|
+
# Holds blocks waiting for clicks
|
22
|
+
@@callbacks = Notifier.new
|
23
|
+
@@callbacks.setup
|
24
|
+
|
12
25
|
class << self
|
13
26
|
###
|
14
27
|
# Send a message in one call.
|
@@ -18,6 +31,41 @@ class Meow
|
|
18
31
|
def notify(name, title, description, opts = {})
|
19
32
|
new(name).notify(title, description, opts)
|
20
33
|
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Convert +image+ to an NSImage that displays nicely in growl. If
|
37
|
+
# +image+ is a String, it's assumed to be the path to an image
|
38
|
+
# on disk and is loaded.
|
39
|
+
def import_image(image, size=128)
|
40
|
+
if image.kind_of? String
|
41
|
+
image = OSX::NSImage.alloc.initWithContentsOfFile image
|
42
|
+
end
|
43
|
+
|
44
|
+
return image if image.size.width.to_i == 128
|
45
|
+
|
46
|
+
new_image = OSX::NSImage.alloc.initWithSize(OSX.NSMakeSize(size, size))
|
47
|
+
new_image.lockFocus
|
48
|
+
image.drawInRect_fromRect_operation_fraction(
|
49
|
+
OSX.NSMakeRect(0, 0, size, size),
|
50
|
+
OSX.NSMakeRect(0, 0, image.size.width, image.size.height),
|
51
|
+
OSX::NSCompositeSourceOver, 1.0)
|
52
|
+
new_image.unlockFocus
|
53
|
+
|
54
|
+
return new_image
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Call this if you have passed blocks to #notify. This blocks forever, but
|
59
|
+
# it's the only way to properly get events.
|
60
|
+
def run
|
61
|
+
OSX::NSApp.run
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Call this to cause Meow to stop running.
|
66
|
+
def stop
|
67
|
+
OSX::NSApp.stop(nil)
|
68
|
+
end
|
21
69
|
end
|
22
70
|
|
23
71
|
attr_accessor :name, :note_type, :icon
|
@@ -36,6 +84,17 @@ class Meow
|
|
36
84
|
@icon = icon
|
37
85
|
@note_type = note_type
|
38
86
|
@registered = []
|
87
|
+
|
88
|
+
@pid = OSX::NSProcessInfo.processInfo.processIdentifier
|
89
|
+
|
90
|
+
# The notification name to look for when someone clicks on a notify bubble.
|
91
|
+
@clicked_name = "#{name}-#{@pid}-GrowlClicked!"
|
92
|
+
|
93
|
+
notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
|
94
|
+
notify_center.addObserver_selector_name_object_ @@callbacks,
|
95
|
+
"clicked:",
|
96
|
+
@clicked_name,
|
97
|
+
nil
|
39
98
|
end
|
40
99
|
|
41
100
|
###
|
@@ -44,6 +103,8 @@ class Meow
|
|
44
103
|
# * +title+ will be the title of the message.
|
45
104
|
# * +description+ is the description of the message
|
46
105
|
# * +opts+ is a hash of options.
|
106
|
+
# * +block+ is an optional block passed to +notify+. The block
|
107
|
+
# is called when someone clicks on the growl bubble.
|
47
108
|
#
|
48
109
|
# Possible values for +opts+ are:
|
49
110
|
# * :priority => Set the note priority
|
@@ -54,32 +115,36 @@ class Meow
|
|
54
115
|
#
|
55
116
|
# Example:
|
56
117
|
# note.notify('title', 'description', :priority => :very_low)
|
57
|
-
def notify(title, description, opts = {})
|
118
|
+
def notify(title, description, opts = {}, &block)
|
58
119
|
opts = {
|
59
120
|
:icon => icon,
|
60
121
|
:sticky => false,
|
61
122
|
:note_type => note_type,
|
123
|
+
:priority => 0
|
62
124
|
}.merge(opts)
|
63
125
|
|
64
126
|
register(opts[:note_type]) unless @registered.include?(opts[:note_type])
|
65
127
|
|
66
128
|
notification = {
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
129
|
+
:ApplicationName => name,
|
130
|
+
:ApplicationPID => @pid,
|
131
|
+
:NotificationName => opts[:note_type],
|
132
|
+
:NotificationTitle => title,
|
133
|
+
:NotificationDescription => description,
|
134
|
+
:NotificationIcon => opts[:icon].TIFFRepresentation(),
|
135
|
+
:NotificationPriority => opts[:priority].to_i
|
72
136
|
}
|
73
137
|
|
74
|
-
notification[
|
75
|
-
notification[
|
138
|
+
notification[:NotificationAppIcon] = opts[:app_icon].TIFFRepresentation if opts[:app_icon]
|
139
|
+
notification[:NotificationSticky] = OSX::NSNumber.numberWithBool_(true) if opts[:stick]
|
140
|
+
|
141
|
+
notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
|
76
142
|
|
77
|
-
if
|
78
|
-
notification[
|
143
|
+
if block
|
144
|
+
notification[:NotificationClickContext] = @@callbacks.add(block)
|
79
145
|
end
|
80
146
|
|
81
147
|
d = OSX::NSDictionary.dictionaryWithDictionary_(notification)
|
82
|
-
notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
|
83
148
|
notify_center.postNotificationName_object_userInfo_deliverImmediately_('GrowlNotification', nil, d, true)
|
84
149
|
end
|
85
150
|
|
@@ -100,4 +165,5 @@ class Meow
|
|
100
165
|
notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
|
101
166
|
notify_center.postNotificationName_object_userInfo_deliverImmediately_('GrowlApplicationRegistrationNotification', nil, dictionary, true)
|
102
167
|
end
|
168
|
+
|
103
169
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Meow
|
2
|
+
# addObserver can only be used with subclasses of NSObject, so we use this
|
3
|
+
# one.
|
4
|
+
class Notifier < OSX::NSObject
|
5
|
+
def setup
|
6
|
+
@callbacks = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(prc)
|
10
|
+
pos = prc.object_id
|
11
|
+
@callbacks[pos] = prc
|
12
|
+
return pos
|
13
|
+
end
|
14
|
+
|
15
|
+
def clicked(notification)
|
16
|
+
idx = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT].to_i
|
17
|
+
begin
|
18
|
+
if block = @callbacks[idx]
|
19
|
+
block.call
|
20
|
+
end
|
21
|
+
ensure
|
22
|
+
@callbacks.delete idx
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
Binary file
|
data/test/test_meow.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "helper"))
|
2
2
|
|
3
3
|
class MeowTest < Test::Unit::TestCase
|
4
|
+
ASSETS = File.expand_path(File.join(File.dirname(__FILE__), "assets"))
|
5
|
+
|
6
|
+
def my_method_name
|
7
|
+
/`(.*?)'/.match(caller.first)[1]
|
8
|
+
end
|
9
|
+
|
4
10
|
def test_initialize
|
5
11
|
meep = nil
|
6
12
|
assert_nothing_raised {
|
@@ -11,28 +17,51 @@ class MeowTest < Test::Unit::TestCase
|
|
11
17
|
|
12
18
|
def test_meow_has_static_method
|
13
19
|
assert_nothing_raised {
|
14
|
-
Meow.notify('Meow Test', 'Title',
|
20
|
+
Meow.notify('Meow Test', 'Title', my_method_name, :priority => :very_high)
|
15
21
|
}
|
16
22
|
end
|
17
23
|
|
18
24
|
def test_meow_can_notify_with_type
|
19
25
|
meep = Meow.new('Meow Test')
|
20
26
|
assert_nothing_raised {
|
21
|
-
meep.notify('Title',
|
27
|
+
meep.notify('Title', my_method_name, :type => 'Awesome')
|
22
28
|
}
|
23
29
|
end
|
24
30
|
|
25
31
|
def test_meow_can_notify_with_priority
|
26
32
|
meep = Meow.new('Meow Test')
|
27
33
|
assert_nothing_raised {
|
28
|
-
meep.notify('Title',
|
34
|
+
meep.notify('Title', my_method_name, :priority => :very_high)
|
29
35
|
}
|
30
36
|
end
|
31
37
|
|
32
38
|
def test_meow_can_notify_without_register
|
33
39
|
meep = Meow.new('Meow Test')
|
34
40
|
assert_nothing_raised {
|
35
|
-
meep.notify('Title',
|
41
|
+
meep.notify('Title', my_method_name)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_import_image
|
46
|
+
icon = Meow.import_image(File.join(ASSETS, 'aaron.jpeg'))
|
47
|
+
assert_kind_of(OSX::NSImage, icon)
|
48
|
+
meep = Meow.new('Meow Test')
|
49
|
+
assert_nothing_raised {
|
50
|
+
meep.notify('Icon', my_method_name, :icon => icon)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_clicks_work
|
55
|
+
$RUBYCOCOA_SUPPRESS_EXCEPTION_LOGGING = true
|
56
|
+
block_called = false
|
57
|
+
assert_raises(RuntimeError) {
|
58
|
+
meep = Meow.new('Meow Test')
|
59
|
+
meep.notify('Click Here', my_method_name) do
|
60
|
+
block_called = true
|
61
|
+
raise 'I do not know how to get run to stop blocking!'
|
62
|
+
end
|
63
|
+
Meow.run
|
36
64
|
}
|
65
|
+
assert block_called
|
37
66
|
end
|
38
67
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: meow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Patterson
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-06-
|
12
|
+
date: 2008-06-17 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -28,7 +28,9 @@ files:
|
|
28
28
|
- README.rdoc
|
29
29
|
- Rakefile
|
30
30
|
- lib/meow.rb
|
31
|
+
- lib/meow/notifier.rb
|
31
32
|
- meow.gemspec
|
33
|
+
- test/assets/aaron.jpeg
|
32
34
|
- test/helper.rb
|
33
35
|
- test/test_meow.rb
|
34
36
|
- vendor/hoe.rb
|