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 +11 -0
- data/examples/.autotest +1 -0
- data/examples/example1.rb +3 -0
- data/examples/example2.rb +14 -0
- data/examples/example3.rb +9 -0
- data/examples/example4.rb +11 -0
- data/examples/test.png +0 -0
- data/icons/accept.png +0 -0
- data/icons/exclamation.png +0 -0
- data/icons/information.png +0 -0
- data/lib/autosnarl.rb +47 -0
- data/lib/snarl.rb +353 -0
- data/readme.txt +70 -0
- data/test/readme.txt +8 -0
- data/test/test_snarl.rb +48 -0
- metadata +103 -0
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
|
data/examples/.autotest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'autosnarl'
|
@@ -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
|
+
|
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)...
|
data/test/test_snarl.rb
ADDED
@@ -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
|