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 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