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