meow 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -3,7 +3,9 @@ Manifest.txt
3
3
  README.rdoc
4
4
  Rakefile
5
5
  lib/meow.rb
6
+ lib/meow/notifier.rb
6
7
  meow.gemspec
8
+ test/assets/aaron.jpeg
7
9
  test/helper.rb
8
10
  test/test_meow.rb
9
11
  vendor/hoe.rb
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
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require './vendor/hoe.rb'
5
- require './lib/meow.rb'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
7
+ require 'meow'
6
8
 
7
9
  Hoe.new('meow', Meow::VERSION) do |p|
8
10
  p.readme = 'README.rdoc'
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.0.0'
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
- 'NotificationName' => opts[:note_type],
68
- 'ApplicationName' => name,
69
- 'NotificationTitle' => title,
70
- 'NotificationDescription' => description,
71
- 'NotificationIcon' => opts[:icon].TIFFRepresentation(),
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['NotificationAppIcon'] = opts[:app_icon].TIFFRepresentation if opts[:app_icon]
75
- notification['NotificationSticky'] = OSX::NSNumber.numberWithBool_(true) if opts[:stick]
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 opts[:priority]
78
- notification['NotificationPriority'] = OSX::NSNumber.numberWithInt_(PRIORITIES[opts[:priority]])
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', 'Description', :priority => :very_high)
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', 'Description', :type => 'Awesome')
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', 'Description', :priority => :very_high)
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', 'Description')
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.0.0
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-06 00:00:00 -07:00
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