rdp-ruby-snarl 0.0.9

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