tenderlove-meow 2.1.0.20081101124146

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/.autotest ADDED
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ require 'meow/autotest'
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,36 @@
1
+ === 2.1.0
2
+
3
+ * 2 Minor enhancements
4
+
5
+ * Autotest integration. Just add this to your .autotest file:
6
+ require 'meow/autotest'
7
+ * The icon option now takes a string which is assumed to be the path to an
8
+ icon.
9
+
10
+
11
+ === 2.0.0
12
+
13
+ * 1 Major enhancement
14
+
15
+ * Run and stop methods have been removed (Thanks David Billskog!)
16
+
17
+ * 3 Bugfixes
18
+
19
+ * Updated Ruby/Cocoa syntax conventions
20
+ * Fixed a typo with "sticky" options
21
+ * Updated copyright
22
+
23
+ === 1.1.0 / 2008-06-13
24
+
25
+ * 3 major enhancements
26
+
27
+ * Added click callbacks so that Meow can be notified of clicks.
28
+ * Added Meow.run() to block and wait for clicks
29
+ * Meow.import_image() returns an image suitable for icon use
30
+
31
+ === 1.0.0 / 2008-06-05
32
+
33
+ * 1 major enhancement
34
+
35
+ * Birthday!
36
+
data/Manifest.txt ADDED
@@ -0,0 +1,16 @@
1
+ .autotest
2
+ CHANGELOG.rdoc
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ icons/fail.png
7
+ icons/initialize.jpeg
8
+ icons/pass.png
9
+ lib/meow.rb
10
+ lib/meow/autotest.rb
11
+ lib/meow/notifier.rb
12
+ meow.gemspec
13
+ test/assets/aaron.jpeg
14
+ test/helper.rb
15
+ test/test_meow.rb
16
+ vendor/hoe.rb
data/README.rdoc ADDED
@@ -0,0 +1,64 @@
1
+ = meow
2
+
3
+ * http://meow.rubyforge.org/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Send Growl notifications via Ruby.
8
+
9
+ == SYNOPSIS:
10
+
11
+ meep = Meow.new('Meow Test')
12
+ meep.notify('Title', 'Description')
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
+
20
+ == REQUIREMENTS:
21
+
22
+ * Growl: http://growl.info
23
+
24
+ == INSTALL:
25
+
26
+ * install Growl: http://growl.info
27
+ * sudo gem install meow
28
+
29
+ == THANKS:
30
+
31
+ Thanks to the Growl team! This code is heavily based on their ruby example.
32
+ Thanks to Satoshi for the click code from Lime Chat.
33
+
34
+ == LICENSE:
35
+
36
+ (The MIT License)
37
+
38
+ Copyright (c) 2008:
39
+
40
+ * {Aaron Patterson}[http://tenderlovemaking.com]
41
+ * Evan Phoenix
42
+ * Eric Hodel
43
+ * Justin Palmer
44
+ * Satoshi Nakagawa
45
+ * David Billskog
46
+
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of this software and associated documentation files (the
49
+ 'Software'), to deal in the Software without restriction, including
50
+ without limitation the rights to use, copy, modify, merge, publish,
51
+ distribute, sublicense, and/or sell copies of the Software, and to
52
+ permit persons to whom the Software is furnished to do so, subject to
53
+ the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be
56
+ included in all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
59
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
60
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
61
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
62
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
63
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
64
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require './vendor/hoe.rb'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
7
+ require 'meow'
8
+
9
+ HOE = Hoe.new('meow', Meow::VERSION) do |p|
10
+ p.readme = 'README.rdoc'
11
+ p.history = 'CHANGELOG.rdoc'
12
+ p.developer('Aaron Patterson', 'aaronp@rubyforge.org')
13
+ end
14
+
15
+ namespace :gem do
16
+ task :spec do
17
+ File.open("#{HOE.name}.gemspec", 'w') do |f|
18
+ HOE.spec.version = "#{HOE.version}.#{Time.now.strftime("%Y%m%d%H%M%S")}"
19
+ f.write(HOE.spec.to_ruby)
20
+ end
21
+ end
22
+ end
23
+
24
+ # vim: syntax=Ruby
data/icons/fail.png ADDED
Binary file
Binary file
data/icons/pass.png ADDED
Binary file
data/lib/meow.rb ADDED
@@ -0,0 +1,183 @@
1
+ require 'osx/cocoa'
2
+ require 'meow/notifier'
3
+
4
+ class Meow
5
+ VERSION = '2.1.0'
6
+ PRIORITIES = { :very_low => -2,
7
+ :moderate => -1,
8
+ :normal => 0,
9
+ :high => 1,
10
+ :emergency => 2,
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
+
25
+ # The thread that is responsible for catching native callbacks.
26
+ @@background_runner = nil
27
+
28
+ class << self
29
+ ###
30
+ # Send a message in one call.
31
+ #
32
+ # Example:
33
+ # Meow.notify('Meow', 'Title', 'Description', :priority => :very_high)
34
+ def notify(name, title, description, opts = {})
35
+ new(name).notify(title, description, opts)
36
+ end
37
+
38
+ ##
39
+ # Convert +image+ to an NSImage that displays nicely in growl. If
40
+ # +image+ is a String, it's assumed to be the path to an image
41
+ # on disk and is loaded.
42
+ def import_image(image, size=128)
43
+ if image.kind_of? String
44
+ image = OSX::NSImage.alloc.initWithContentsOfFile image
45
+ end
46
+
47
+ return image if image.size.width.to_i == 128
48
+
49
+ new_image = OSX::NSImage.alloc.initWithSize(OSX.NSMakeSize(size, size))
50
+ new_image.lockFocus
51
+ image.drawInRect_fromRect_operation_fraction(
52
+ OSX.NSMakeRect(0, 0, size, size),
53
+ OSX.NSMakeRect(0, 0, image.size.width, image.size.height),
54
+ OSX::NSCompositeSourceOver, 1.0)
55
+ new_image.unlockFocus
56
+
57
+ return new_image
58
+ end
59
+ end
60
+
61
+ attr_accessor :name, :note_type, :icon
62
+
63
+ ###
64
+ # Create a new Meow object.
65
+ #
66
+ # * +name+ is the application name.
67
+ # * +note_type+ is the type of note you send.
68
+ # * +icon+ is the icon displayed in the notification.
69
+ #
70
+ # Example:
71
+ # note = Meow.new('My Application')
72
+ def initialize(name, note_type = 'Note', icon = OSX::NSWorkspace.sharedWorkspace.iconForFileType('rb'))
73
+ @name = name
74
+ @icon = icon
75
+ @note_type = note_type
76
+ @registered = []
77
+
78
+ @pid = OSX::NSProcessInfo.processInfo.processIdentifier
79
+
80
+ # The notification name to look for when someone clicks on a notify bubble
81
+ # or the bubble is timed out.
82
+ @clicked_name = "#{name}-#{@pid}-#{GROWL_NOTIFICATION_CLICKED}"
83
+ @timeout_name = "#{name}-#{@pid}-#{GROWL_NOTIFICATION_TIMED_OUT}"
84
+
85
+ notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
86
+ notify_center.objc_send(:addObserver, @@callbacks,
87
+ :selector, "clicked:",
88
+ :name, @clicked_name,
89
+ :object, nil)
90
+ notify_center.objc_send(:addObserver, @@callbacks,
91
+ :selector, "timeout:",
92
+ :name, @timeout_name,
93
+ :object, nil)
94
+
95
+ start_runner unless @@background_runner
96
+ end
97
+
98
+ ###
99
+ # Send a notification to growl.
100
+ #
101
+ # * +title+ will be the title of the message.
102
+ # * +description+ is the description of the message
103
+ # * +opts+ is a hash of options.
104
+ # * +block+ is an optional block passed to +notify+. The block
105
+ # is called when someone clicks on the growl bubble.
106
+ #
107
+ # Possible values for +opts+ are:
108
+ # * :priority => Set the note priority
109
+ # * :icon => Override the current icon
110
+ # * :note_type => Override the current note type
111
+ #
112
+ # See Meow::PRIORITIES for the possible priorities.
113
+ #
114
+ # Example:
115
+ # note.notify('title', 'description', :priority => :very_low)
116
+ def notify(title, description, opts = {}, &block)
117
+ opts = {
118
+ :icon => icon,
119
+ :sticky => false,
120
+ :note_type => note_type,
121
+ :priority => 0
122
+ }.merge(opts)
123
+
124
+ register(opts[:note_type]) unless @registered.include?(opts[:note_type])
125
+ opts[:icon] = Meow.import_image(opts[:icon]) if opts[:icon].is_a?(String)
126
+
127
+ notification = {
128
+ :ApplicationName => name,
129
+ :ApplicationPID => @pid,
130
+ :NotificationName => opts[:note_type],
131
+ :NotificationTitle => title,
132
+ :NotificationDescription => description,
133
+ :NotificationIcon => opts[:icon].TIFFRepresentation(),
134
+ :NotificationPriority => opts[:priority].to_i
135
+ }
136
+
137
+ notification[:NotificationAppIcon] = opts[:app_icon].TIFFRepresentation if opts[:app_icon]
138
+ notification[:NotificationSticky] = OSX::NSNumber.numberWithBool(true) if opts[:sticky]
139
+
140
+ notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
141
+
142
+ if block
143
+ notification[:NotificationClickContext] = @@callbacks.add(block)
144
+ end
145
+
146
+ notify_center.postNotificationName_object_userInfo_deliverImmediately('GrowlNotification', nil, notification, true)
147
+ end
148
+
149
+ private
150
+
151
+ def register(types, default_types = nil)
152
+ types = [types].flatten
153
+ default_types ||= types
154
+
155
+ @registered = [@registered, types, default_types].flatten.uniq
156
+
157
+ dictionary = {
158
+ :ApplicationName => name,
159
+ :AllNotifications => types,
160
+ :DefaultNotifications => default_types,
161
+ :ApplicationIcon => icon.TIFFRepresentation
162
+ }
163
+
164
+ notify_center = OSX::NSDistributedNotificationCenter.defaultCenter
165
+ notify_center.postNotificationName_object_userInfo_deliverImmediately_('GrowlApplicationRegistrationNotification', nil, dictionary, true)
166
+ end
167
+
168
+ # Hides the infinite callback loop in the background so that it will not
169
+ # stop the flow of the application.
170
+ def start_runner
171
+ @@background_runner = Thread.new do
172
+ sleep 0.1
173
+ OSX::NSApp.run
174
+ end
175
+ at_exit do
176
+ loop do
177
+ sleep 1
178
+ OSX::NSApplication.sharedApplication.terminate(@@application) if @@callbacks.empty?
179
+ end
180
+ end
181
+ end
182
+
183
+ end
@@ -0,0 +1,44 @@
1
+ require 'meow'
2
+
3
+ class Meow
4
+ class Autotest
5
+ @icon_dirs = [File.expand_path(
6
+ File.join(File.dirname(__FILE__), '..', '..', 'icons')
7
+ )]
8
+
9
+ @@meow = Meow.new('Meow Autotest')
10
+
11
+ class << self
12
+ attr_accessor :icon_dirs
13
+
14
+ def icon_for action
15
+ @icon_dirs.reverse.each do |dir|
16
+ file = Dir[File.join(dir,'**')].find { |name| name =~ /#{action}/ }
17
+ return file if file
18
+ end
19
+ end
20
+ end
21
+
22
+ ::Autotest.add_hook :initialize do |at|
23
+ @@meow.notify "Autotest", 'started', { :icon => icon_for(:initialize) }
24
+ end
25
+
26
+ ::Autotest.add_hook :red do |at|
27
+ @@meow.notify "Autotest", "#{at.files_to_test.size} test are fail.",
28
+ { :icon => icon_for(:fail) }
29
+ end
30
+
31
+ ::Autotest.add_hook :green do |at|
32
+ if at.tainted
33
+ @@meow.notify "Autotest", "Tests pass!", { :icon => icon_for(:pass) }
34
+ end
35
+ end
36
+
37
+ ::Autotest.add_hook :all_good do |at|
38
+ if at.tainted
39
+ @@meow.notify "Autotest", "All tests pass!",
40
+ { :icon => icon_for(:pass) }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
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 empty?
10
+ @callbacks.empty?
11
+ end
12
+
13
+ def add(prc)
14
+ pos = prc.object_id
15
+ @callbacks[pos] = prc
16
+ return pos
17
+ end
18
+
19
+ def clicked(notification)
20
+ if block = remove_callback(notification)
21
+ block.call
22
+ end
23
+ end
24
+
25
+ def timeout(notification)
26
+ remove_callback(notification)
27
+ end
28
+
29
+ private
30
+
31
+ def remove_callback(notification)
32
+ idx = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT].to_i
33
+ @callbacks.delete idx
34
+ end
35
+ end
36
+ end
data/meow.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{meow}
3
+ s.version = "2.1.0.20081101124146"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Aaron Patterson"]
7
+ s.date = %q{2008-11-01}
8
+ s.description = %q{Send Growl notifications via Ruby.}
9
+ s.email = ["aaronp@rubyforge.org"]
10
+ s.extra_rdoc_files = ["Manifest.txt"]
11
+ s.files = [".autotest", "CHANGELOG.rdoc", "Manifest.txt", "README.rdoc", "Rakefile", "icons/fail.png", "icons/initialize.jpeg", "icons/pass.png", "lib/meow.rb", "lib/meow/autotest.rb", "lib/meow/notifier.rb", "meow.gemspec", "test/assets/aaron.jpeg", "test/helper.rb", "test/test_meow.rb", "vendor/hoe.rb"]
12
+ s.has_rdoc = true
13
+ s.homepage = %q{http://meow.rubyforge.org/}
14
+ s.rdoc_options = ["--main", "README.rdoc"]
15
+ s.require_paths = ["lib"]
16
+ s.rubyforge_project = %q{meow}
17
+ s.rubygems_version = %q{1.2.0}
18
+ s.summary = %q{Send Growl notifications via Ruby.}
19
+ s.test_files = ["test/test_meow.rb"]
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 2
24
+
25
+ if current_version >= 3 then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end