rdp-ruby-snarl 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'jeweler'
2
+ Jeweler::Tasks.new do |s|
3
+ s.name = "rdp-ruby-snarl"
4
+ s.version = "0.0.9"
5
+ s.author = "Patrick Hurley, Roger Pack"
6
+ s.email = "phurley@gmail.com"
7
+ s.homepage = "http://github.com/rdp/ruby-snarl"
8
+ s.summary = "Snarl (http://www.fullphat.net/snarl.html) is a simple notification system, similar to Growl under OSX. This is a simple pure Ruby wrapper to the native API. Also see http://ruby-snarl.rubyforge.org/"
9
+ s.add_development_dependency 'sane'
10
+ s.add_dependency "ffi_ez"
11
+ end
@@ -0,0 +1 @@
1
+ require 'autosnarl'
@@ -0,0 +1,3 @@
1
+ require 'snarl'
2
+
3
+ Snarl.show_message('title', 'body test', 'test.png')
@@ -0,0 +1,14 @@
1
+ require 'snarl'
2
+
3
+ puts "Snarl Version: #{Snarl.version}"
4
+
5
+ 10.downto(1) do |i|
6
+ Snarl.show_message("Message", "Counting down #{i}", nil, i)
7
+ end
8
+
9
+ sleep 11
10
+
11
+ 10.times do |i|
12
+ Snarl.show_message("Message", "Counting down #{i+1}", nil, i+1)
13
+ end
14
+
@@ -0,0 +1,9 @@
1
+ require 'snarl'
2
+
3
+ clock_message = Snarl.new('Time', Time.now.to_s, nil, Snarl::NO_TIMEOUT)
4
+ while clock_message.visible?
5
+ clock_message.update('Time', Time.now.to_s)
6
+ sleep 0.75
7
+ end
8
+
9
+
@@ -0,0 +1,11 @@
1
+ require'snarl'
2
+
3
+ m = Snarl.new("Count down", "Here we go", nil, Snarl::NO_TIMEOUT)
4
+
5
+ 10.downto(0) do |i|
6
+ m.update("Count down", "T Minus #{i} and counting")
7
+ sleep 1
8
+ end
9
+ m.update("*BOOM*")
10
+ m.hide
11
+
data/examples/test.png ADDED
Binary file
data/icons/accept.png ADDED
Binary file
Binary file
Binary file
data/lib/autosnarl.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'snarl'
2
+
3
+ module AutoSnarl
4
+ def self.icon
5
+ # icons from http://www.famfamfam.com/lab/icons/silk/
6
+ path = File.join(File.dirname(__FILE__), "/../icons")
7
+ {
8
+ :green => "#{path}/accept.png",
9
+ :red => "#{path}/exclamation.png",
10
+ :info => "#{path}/information.png"
11
+ }
12
+ end
13
+
14
+ def self.snarl title, msg, ico = nil
15
+ Snarl.show_message(title, msg, icon[ico])
16
+ end
17
+
18
+ Autotest.add_hook :run do |at|
19
+ snarl "Run", "Run" unless $TESTING
20
+ end
21
+
22
+ Autotest.add_hook :red do |at|
23
+ failed_tests = at.files_to_test.inject(0){ |s,a| k,v = a; s + v.size}
24
+ snarl "Tests Failed", "#{failed_tests} tests failed", :red
25
+ end
26
+
27
+ Autotest.add_hook :green do |at|
28
+ snarl "Tests Passed", "All tests passed", :green #if at.tainted
29
+ end
30
+
31
+ Autotest.add_hook :run do |at|
32
+ snarl "autotest", "autotest was started", :info unless $TESTING
33
+ end
34
+
35
+ Autotest.add_hook :interrupt do |at|
36
+ snarl "autotest", "autotest was reset", :info unless $TESTING
37
+ end
38
+
39
+ Autotest.add_hook :quit do |at|
40
+ snarl "autotest", "autotest is exiting", :info unless $TESTING
41
+ end
42
+
43
+ Autotest.add_hook :all do |at|_hook
44
+ snarl "autotest", "Tests have fully passed", :green unless $TESTING
45
+ end
46
+
47
+ end
data/lib/snarl.rb ADDED
@@ -0,0 +1,353 @@
1
+ require "Win32API"
2
+ # how does this relate to require 'win32/api' #Win32API = Win32::API
3
+
4
+ require 'ffi_ez'
5
+
6
+ class Fixnum # 1.8.6 compat
7
+ def ord
8
+ self
9
+ end
10
+ end
11
+
12
+ # Snarl (http://www.fullphat.net/snarl.html) is a simple notification system,
13
+ # similar to Growl under OSX. This is a simple pure Ruby wrapper to the
14
+ # native API.
15
+
16
+ class FFI::Struct # ltodo add to ez
17
+
18
+ def copy_chars(to_field, string)
19
+ i = 0
20
+ string.each_byte{|b|
21
+ self[to_field][i] = string[i].ord
22
+ i += 1
23
+ }
24
+ self[to_field][string.length] = 0
25
+ # todo assert we don't tramp :)
26
+ end
27
+
28
+ def method_missing(*args) # like a.value = "b"
29
+ name = args[0].to_s
30
+ value = args[1]
31
+ if name[-1..-1] == '='
32
+ name = name[0..-2].to_sym
33
+ self[name] = value
34
+ else
35
+ self[name] # like a.value
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ class Snarl
42
+
43
+ # This is the lowlevel API implemenation using DL and a few handy
44
+ # constants from the snarl api and the Win32 API
45
+ # Note that I have jump through some hoops to get the array of
46
+ # characters to work corretly -- if you know a better way please
47
+ # send me (phurley@gmail.com) a note.
48
+ module SnarlAPI
49
+
50
+ extend FFI::EZ
51
+
52
+ ffi_lib 'user32'
53
+ attach_ez 'FindWindowA' => :findWindow, [:string, :string] => :pointer
54
+ attach_ez 'IsWindow' => :isWindow, [:pointer] => :bool
55
+ attach_ez 'SendMessageA' => :sendMessage, [:pointer, :uint, :long, :pointer] => :int
56
+ #extern "HWND CreateWindowEx(DWORD, LPCSTR, LPCSTR, DWORD, int, int, HWND, HMENU, HINSTANCE, LPVOID)"
57
+ CreateWindow = Win32API.new("user32", "CreateWindowExA", ['L', 'p', 'p', 'l', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'p'], 'L')
58
+ DestroyWindow = Win32API.new("user32", "DestroyWindow", ['L'], 'L')
59
+
60
+ #WIN32API
61
+ HWND_MESSAGE = 0x84
62
+ WM_USER = 0x400
63
+
64
+ #Global Event Ids
65
+ SNARL_GLOBAL_MSG = "SnarlGlobalEvent"
66
+ SNARL_LAUNCHED = 1
67
+ SNARL_QUIT = 2
68
+ SNARL_ASK_APPLET_VER = 3 #introduced in V36
69
+ SNARL_SHOW_APP_UP = 4 #introduced in V37
70
+
71
+ #Message Event Ids
72
+ SNARL_NOTIFICATION_CLICKED = 32
73
+ SNARL_NOTIFICATION_TIMED_OUT = 33
74
+ SNARL_NOTIFICATION_ACK = 34
75
+ SNARL_NOTIFICATION_CANCLED = SNARL_NOTIFICATION_CLICKED # yes that's right.
76
+
77
+ #Snarl Commands
78
+ SNARL_SHOW = 1
79
+ SNARL_HIDE = 2
80
+ SNARL_UPDATE = 3
81
+ SNARL_IS_VISIBLE = 4
82
+ SNARL_GET_VERSION = 5
83
+ SNARL_REGISTER_CONFIG_WINDOW = 6
84
+ SNARL_REVOKE_CONFIG_WINDOW = 7
85
+ SNARL_REGISTER_ALERT = 8
86
+ SNARL_REVOKE_ALERT = 9
87
+ SNARL_REGISTER_CONFIG_WINDOW_2 = 10
88
+ SNARL_GET_VERSION_EX = 11
89
+ SNARL_SET_TIMEOUT = 12
90
+ SNARL_EX_SHOW = 32
91
+ SNARL_TEXT_LENGTH = 1024
92
+ WM_COPYDATA = 0x4a
93
+
94
+ BASE = [:cmd, :int,
95
+ :id, :long,
96
+ :timeout, :long,
97
+ :data2, :long,
98
+ :title, [:char, SNARL_TEXT_LENGTH],
99
+ :text, [:char, SNARL_TEXT_LENGTH],
100
+ :icon, [:char, SNARL_TEXT_LENGTH]
101
+ ]
102
+
103
+
104
+ class SnarlStruct < FFI::Struct
105
+ layout(*BASE)
106
+ def set_title(title)
107
+ copy_chars(:title, title);
108
+ end
109
+ def set_text(text)
110
+ copy_chars(:text, text)
111
+ end
112
+ def set_icon(icon)
113
+ copy_chars(:icon, icon)
114
+ end
115
+ end
116
+
117
+ class SnarlStructEx < FFI::Struct
118
+ all = BASE + [
119
+ :snarl_class, [:char, SNARL_TEXT_LENGTH],
120
+ :extra, [:char, SNARL_TEXT_LENGTH],
121
+ :extra2, [:char, SNARL_TEXT_LENGTH],
122
+ :reserved1, :int,
123
+ :reserved2, :int
124
+ ]
125
+ layout(*all)
126
+ end
127
+
128
+ class CopyDataStruct < FFI::Struct
129
+ layout :dwData, :long,
130
+ :cbData, :long,
131
+ :lpData, :pointer
132
+ end
133
+
134
+
135
+ # character array hoop jumping, we take the passed string and convert
136
+ # it into an array of integers, padded out to the correct length
137
+ # to_cha --> to character array
138
+ # I do this as it seems necessary to fit the DL API, if there is a
139
+ # better way please let me know
140
+ def self.to_cha(str)
141
+ raise 'bad'
142
+ result = str.split(/(.)/).map { |ch| ch[0] }.compact
143
+ result + Array.new(SNARL_TEXT_LENGTH - result.size, 0)
144
+ end
145
+
146
+ # Send the structure off to snarl, the routine will return (if everything
147
+ # goes well) the result of SendMessage which has an overloaded meaning
148
+ # based upon the cmd being sent
149
+ def self.send(ss)
150
+ if isWindow(hwnd = findWindow(nil, 'Snarl'))
151
+ cd = CopyDataStruct.new
152
+ cd.dwData = 2
153
+ cd.cbData = ss.size
154
+ cd.lpData = ss.to_ptr
155
+ [:pointer, :uint, :long, :long]
156
+ got = sendMessage(hwnd, WM_COPYDATA, 0, cd.to_ptr)
157
+ _dbg unless got
158
+ got
159
+
160
+ end
161
+ end
162
+ end
163
+
164
+ include SnarlAPI
165
+ DEFAULT_TIMEOUT = 3
166
+ NO_TIMEOUT = 0
167
+
168
+ # Create a new snarl message, the only thing you need to send is a title
169
+ # note that if you decide to send an icon, you must provide the complete
170
+ # path. The timeout file has a default value (DEFAULT_TIMEOUT -> 3 seconds)
171
+ # but can be set to Snarl::NO_TIMEOUT, to force a manual acknowledgement
172
+ # of the notification.
173
+ def initialize(title, *options)
174
+ # allow both ways of calling it...
175
+ if options && !options[0].is_a?(Hash)
176
+ options2 = {}
177
+ options2[:msg] = options.shift
178
+ options2[:timeout] = options.shift
179
+ options2[:icon] = options.shift
180
+ raise unless options.empty?
181
+ options = options2
182
+ else
183
+ options = options[0] || {}
184
+ end
185
+ options = {:snarl_class => nil, :msg => " ", :timeout => DEFAULT_TIMEOUT, :icon => nil, :extra => nil}.merge(options)
186
+
187
+ if options[:extra] && options[:snarl_class].nil? then raise ArgumentError.new("Must specificy a snarl_class to use sound notifications") end
188
+
189
+ if options[:snarl_class].nil? then
190
+ @ss = SnarlStruct.new
191
+ show(title, options)
192
+ else
193
+ @ss = SnarlStructEx.new
194
+ show(title, options)
195
+ end
196
+ end
197
+
198
+ # a quick and easy method to create a new message, when you don't care
199
+ # to access it again.
200
+ # Note that if you decide to send an icon, you must provide the complete
201
+ # path. The timeout file has a default value (DEFAULT_TIMEOUT -> 3 seconds)
202
+ # but can be set to Snarl::NO_TIMEOUT, to force a manual acknowledgement
203
+ # of the notification.
204
+ def self.show_message(title, options = {:snarl_class => nil, :msg => " ", :timeout => DEFAULT_TIMEOUT, :icon => nil, :extra => nil})
205
+ Snarl.new(title, options)
206
+ end
207
+
208
+ # Update an existing message, it will return true/false depending upon
209
+ # success (it will fail if the message has already timed out or been
210
+ # dismissed)
211
+ # Note that if you decide to send an icon, you must provide the complete
212
+ # path. The timeout file has a default value (DEFAULT_TIMEOUT -> 3 seconds)
213
+ # but can be set to Snarl::NO_TIMEOUT, to force a manual acknowledgement
214
+ # of the notification.
215
+ def update(title,msg=" ",icon=nil, timeout=DEFAULT_TIMEOUT)
216
+ @ss.cmd = SNARL_UPDATE
217
+ @ss.set_title(title)
218
+ @ss.set_text(msg)
219
+ if icon
220
+ icon = File.expand_path(icon)
221
+ @ss.set_icon(icon) if File.exist?(icon.to_s)
222
+ end
223
+ @ss.timeout = timeout
224
+ send?
225
+ end
226
+
227
+ # Hide you message -- this is the same as dismissing it
228
+ def hide
229
+ @ss.cmd = SNARL_HIDE
230
+ send?
231
+ end
232
+
233
+ # Check to see if the message is still being displayed
234
+ def visible?
235
+ @ss.cmd = SNARL_IS_VISIBLE
236
+ send?
237
+ end
238
+
239
+ # Return the current version of snarl (not the snarl gem) as a character
240
+ # string "1.0" format
241
+ def self.version
242
+ ss = SnarlAPI::SnarlStruct.new
243
+ ss.cmd = SNARL_GET_VERSION
244
+ version = SnarlAPI.send(ss)
245
+ "#{version >> 16}.#{version & 0xffff}"
246
+ end
247
+
248
+ # Return the current build number of snarl (not the snarl gem)
249
+ # If zero will call the original version.
250
+ def self.versionex
251
+ ssx = SnarlAPI::SnarlStructEx.new
252
+ ssx.cmd = SNARL_GET_VERSION_EX
253
+ versionex = SnarlAPI.send(ssx);
254
+ if versionex == 0 then
255
+ self.version
256
+ else
257
+ "#{versionex}"
258
+ end
259
+ end
260
+
261
+ protected
262
+ # Return the internal snarl id
263
+ def id
264
+ @ss.id
265
+ end
266
+
267
+ #Register an application, and optionally an icon for it
268
+ #We return the message_only window we create.
269
+ #NOTE: We do not support config windows.
270
+ def self.registerconfig(title, icon=nil)
271
+ ss = SnarlAPI::SnarlStruct.new
272
+ ss.set_title(title)
273
+ ss.cmd = SNARL_REGISTER_CONFIG_WINDOW
274
+ ss.id = WM_USER
275
+ if not icon.nil? then
276
+ ss.set_icon(icon) if File.exist?(icon)
277
+ ss.cmd = SNARL_REGISTER_CONFIG_WINDOW_2
278
+ end
279
+
280
+ win = SnarlAPI::CreateWindow.call(0, "Message", 0, 0 ,0 ,0 ,0 ,0 ,HWND_MESSAGE, 0, 0, 0)
281
+ ss.data2 = win
282
+ SnarlAPI.send(ss)
283
+ win
284
+ end
285
+
286
+ #Unregister application, passing in the value returned from registerconfig
287
+ def self.revokeconfig(hWnd)
288
+ ss = SnarlAPI::SnarlStruct.new
289
+ ss.data2 = hWnd
290
+ ss.cmd = SNARL_REVOKE_CONFIG_WINDOW
291
+ SnarlAPI.send(ss)
292
+ Snarl::DestroyWindow.call(hWnd)
293
+ end
294
+
295
+ #Register an alert for [app] using the name [text]
296
+ def self.registeralert(app, text)
297
+ ss = SnarlAPI::SnarlStruct.new
298
+ ss.set_title(app)
299
+ ss.set_text(tex)
300
+ ss.cmd = SNARL_REGSITER_ALERT
301
+ SnarlAPI.send(ss)
302
+ end
303
+
304
+
305
+ # exactly like the contructor -- this will create a new message, loosing
306
+ # the original
307
+ def show(title, options = {:snarl_class => nil, :msg => " ", :timeout => DEFAULT_TIMEOUT, :icon => nil, :extra => nil})
308
+
309
+ options[:timeout] = DEFAULT_TIMEOUT if options[:timeout].nil?
310
+ options[:msg] = " " if options[:msg].nil?
311
+
312
+ if options[:snarl_class].nil? then
313
+ @ss.cmd = SNARL_SHOW
314
+ else
315
+ @ss.cmd = SNARL_EX_SHOW
316
+ @ss.snarl_class = options[:snarl_class]
317
+ end
318
+
319
+ @ss.set_title(title)
320
+ @ss.set_text(options[:msg])
321
+
322
+ if options[:icon]
323
+ #Expand Path in Cygwin causes the cygwin path to be returned (ie /cygdrive/c/blah) this is not what we want
324
+ #as Snarl is running in windows and expects a C:\blah path. We've told them to use an absolute path anyway.
325
+ #options[:icon] = File.expand_path(options[:icon])
326
+ @ss.set_icon(options[:icon]) if File.exist?(options[:icon].to_s)
327
+ end
328
+
329
+ if options[:extra]
330
+ unless options[:extra][0] == 43
331
+ #options[:extra] = File.expand_path(options[:extra])
332
+ @ss.set_extra(options[:extra]) if File.exist?(options[:extra].to_s)
333
+ else
334
+ @ss.set_extra(options[:extra])
335
+ end
336
+ end
337
+
338
+ @ss.timeout = options[:timeout]
339
+ @ss.id = send
340
+ end
341
+
342
+
343
+ # Send the snarl structure, return the unfiltered result
344
+ def send
345
+ SnarlAPI.send(@ss)
346
+ end
347
+
348
+ # Send the snarl structure, return a true/false (interpreted from snarl)
349
+ def send?
350
+ !send.zero?
351
+ end
352
+ end
353
+
data/readme.txt ADDED
@@ -0,0 +1,70 @@
1
+ You must install snarl for this to work: http://www.fullphat.net/snarl.html,
2
+ it is a GPL growl like notification system for Win32.
3
+
4
+ I saw zenspiders autotest movie and cried once again that for a variety of
5
+ reasons primarly centered around my employment I am still using a Win32
6
+ platform for development. What beautiful test notifications -- I needed it.
7
+
8
+ I decided it would be much easier to implement then to get my office manager to
9
+ get me a Mac (not to mention most of my customers are using Win32), so I
10
+ started looking into the issue. At the South East Michigan Ruby Users Group
11
+ (www.rubymi.org) I mentioned it and Winston Tsang mentioned snarl and even
12
+ found the somewhat difficult to google for link.
13
+
14
+ I started writing a C extention, but remembered DL and decided it would be much
15
+ easier to distrubute a pure ruby extension -- so here it is.
16
+
17
+ I would like to thank Gordon Thiesfeld, he found the great icons at
18
+ famfamfam.com and I stole much of his autotest (in preference to the)
19
+ one I originally wrote -- of course I hacked it up, so if anything does
20
+ not work I am sure it is all my fault. He also helped layout the code
21
+ for gemification.
22
+
23
+ If you have any problems please let me know. Also if you have any pointers
24
+ on providing tests for this code please contact me.
25
+
26
+
27
+ ----------------------------
28
+ A few autotest notes, I changed line 71 in autotest.rb
29
+
30
+ *** autotest.rb Mon Aug 7 12:47:30 2006
31
+ --- \tmp\autotest.rb Mon Aug 7 12:20:29 2006
32
+ ***************
33
+ *** 68,74 ****
34
+ @files = Hash.new Time.at(0)
35
+ @files_to_test = Hash.new { |h,k| h[k] = [] }
36
+ @exceptions = false
37
+ ! @libs = '.:lib:test'
38
+ @output = $stderr
39
+ @sleep = 2
40
+ end
41
+ --- 68,74 ----
42
+ @files = Hash.new Time.at(0)
43
+ @files_to_test = Hash.new { |h,k| h[k] = [] }
44
+ @exceptions = false
45
+ ! @libs = %w[. lib test].join(File::PATH_SEPARATOR)
46
+ @output = $stderr
47
+ @sleep = 2
48
+ end
49
+ ***************
50
+
51
+
52
+ And if you are using a 4NT (www.jpsoft.com) shell, this helps as well (works
53
+ fine if you are using cmd.exe)
54
+
55
+ *** 208,214 ****
56
+
57
+ unless full.empty? then
58
+ classes = full.map {|k,v| k}.flatten.join(' ')
59
+ ! cmds << "#{ruby} -I#{@libs} -rtest/unit -e \"%w[#{classes}].each { |f| load f }\" | unit_diff -u"
60
+ end
61
+
62
+ partial.each do |klass, methods|
63
+ --- 208,214 ----
64
+
65
+ unless full.empty? then
66
+ classes = full.map {|k,v| k}.flatten.join(' ')
67
+ ! cmds << "#{ruby} -I#{@libs} -rtest/unit -e \"%%w[#{classes}].each { |f| load f }\" | unit_diff -u"
68
+ end
69
+
70
+ partial.each do |klass, methods|
data/test/readme.txt ADDED
@@ -0,0 +1,8 @@
1
+ Irony of ironies,
2
+
3
+ I wrote ruby-snarl, to support my testing and it does not have any.
4
+ If you can come up with some useful tests let me know, there is not
5
+ much code and it only interfaces with an external system. I suppose
6
+ writing a mock snarl and testing against it, but the issue is how
7
+ do I know if there are bugs in the mock snarl (it would be at least
8
+ as complicated as the code I am testing)...
@@ -0,0 +1,48 @@
1
+ require 'rubygems' if RUBY_VERSION < '1.9'
2
+ require 'sane'
3
+ require_rel '../lib/snarl'
4
+ require 'test/unit' unless defined? $ZENTEST and $ZENTEST
5
+
6
+ class TestSnarl < Test::Unit::TestCase
7
+
8
+ def test_new_api
9
+ assert(Snarl.new('title'))
10
+ assert(Snarl.new('title', 'msg'))
11
+ assert_raises(TypeError) { Snarl.new('title', 'msg', 0) }
12
+ assert(Snarl.new('title', 'msg', nil))
13
+ assert(Snarl.new('title', 'msg', 'missing_file'))
14
+ assert(Snarl.new('title', 'short', nil, 1))
15
+ end
16
+
17
+ def test_show_api
18
+ assert(Snarl.show_message('title'))
19
+ assert(Snarl.show_message('title', 'msg'))
20
+
21
+ assert_raises(TypeError) { Snarl.show_message('title', 'msg', 0) }
22
+ assert(Snarl.show_message('title', 'msg', nil))
23
+ assert(Snarl.show_message('title', 'msg', 'missing_file'))
24
+ assert(Snarl.show_message('title', 'short', nil, 1))
25
+ end
26
+
27
+ def test_update_api
28
+ assert(s = Snarl.new('title'))
29
+ assert(s.update('new title')) # not sure why this one fails in test, not in debug...
30
+ assert(s.update('title', 'msg'))
31
+
32
+ assert_raises(TypeError) { s.update('title', 'msg', 0) }
33
+ assert(s.update('title', 'msg', nil))
34
+ assert(s.update('title', 'msg', 'missing_file'))
35
+ assert(s.update('title', 'short', nil, 1))
36
+ end
37
+
38
+ def test_visible
39
+ assert(s = Snarl.new('title', 'hold me', nil, 1))
40
+ assert(s.visible?)
41
+ assert(s.hide)
42
+ end
43
+
44
+ # this one is a little fragile, but it passes right now...
45
+ def test_version
46
+ assert Snarl.version >= '1.1'
47
+ end
48
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdp-ruby-snarl
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 9
9
+ version: 0.0.9
10
+ platform: ruby
11
+ authors:
12
+ - Patrick Hurley, Roger Pack
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-05 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sane
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: ffi_ez
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ description:
45
+ email: phurley@gmail.com
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ extra_rdoc_files:
51
+ - readme.txt
52
+ files:
53
+ - Rakefile
54
+ - examples/.autotest
55
+ - examples/example1.rb
56
+ - examples/example2.rb
57
+ - examples/example3.rb
58
+ - examples/example4.rb
59
+ - examples/test.png
60
+ - icons/accept.png
61
+ - icons/exclamation.png
62
+ - icons/information.png
63
+ - lib/autosnarl.rb
64
+ - lib/snarl.rb
65
+ - readme.txt
66
+ - test/readme.txt
67
+ - test/test_snarl.rb
68
+ has_rdoc: true
69
+ homepage: http://github.com/rdp/ruby-snarl
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options:
74
+ - --charset=UTF-8
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.3.6
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Snarl (http://www.fullphat.net/snarl.html) is a simple notification system, similar to Growl under OSX. This is a simple pure Ruby wrapper to the native API. Also see http://ruby-snarl.rubyforge.org/
98
+ test_files:
99
+ - test/test_snarl.rb
100
+ - examples/example1.rb
101
+ - examples/example2.rb
102
+ - examples/example3.rb
103
+ - examples/example4.rb