wonko9-i_can_daemonize 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-07-09
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,58 @@
1
+ .git/COMMIT_EDITMSG
2
+ .git/FETCH_HEAD
3
+ .git/HEAD
4
+ .git/ORIG_HEAD
5
+ .git/config
6
+ .git/description
7
+ .git/hooks/applypatch-msg
8
+ .git/hooks/commit-msg
9
+ .git/hooks/post-commit
10
+ .git/hooks/post-receive
11
+ .git/hooks/post-update
12
+ .git/hooks/pre-applypatch
13
+ .git/hooks/pre-commit
14
+ .git/hooks/pre-rebase
15
+ .git/hooks/prepare-commit-msg
16
+ .git/hooks/update
17
+ .git/index
18
+ .git/info/exclude
19
+ .git/logs/HEAD
20
+ .git/logs/refs/heads/master
21
+ .git/logs/refs/remotes/origin/HEAD
22
+ .git/logs/refs/remotes/origin/master
23
+ .git/objects/12/d7cbe8190afdd97a7a0859d9ce822ebc9846cd
24
+ .git/objects/46/c5d39136616bca92118f3dbf16e474a9df7379
25
+ .git/objects/4b/0480e9beae3ad3b1b17effeeaa1201560d7d02
26
+ .git/objects/61/22343c51b970ba436bc47e3cf97f6221492291
27
+ .git/objects/67/672462a81c734937a6b579751405f168e6fcb0
28
+ .git/objects/69/69a6a4e8a6d185528b33de649ea3feb1516fb7
29
+ .git/objects/6a/ddd18336cbaebdff0f727a06305c9232dbb058
30
+ .git/objects/6c/eeb3df1cb65a06e0b434b7a78551d1d7c1c242
31
+ .git/objects/73/ae5eefb32e4f335716aa281e9f78c3a61398b1
32
+ .git/objects/8f/9c4a5a3c9a41935160b96fe005a54b3d3f18b2
33
+ .git/objects/9c/878acd4b53fb8abaed6ba81ef78e2c3268c9f5
34
+ .git/objects/a3/5a57b3e8003dcdd039a48441554799b417779d
35
+ .git/objects/c3/d75d5327524a548ed2cfb997342b2107b83403
36
+ .git/objects/cb/34e6ff08e94036d69d296284a62d723a2d8a90
37
+ .git/objects/d4/b772650c4ad1378392aa5f2bb3c773a3818b73
38
+ .git/objects/f5/9a3860619e3b9d956caa110ff00d0449977fea
39
+ .git/objects/pack/pack-4efe288a1b0fd1df2942754b498c4480f00a7d52.idx
40
+ .git/objects/pack/pack-4efe288a1b0fd1df2942754b498c4480f00a7d52.keep
41
+ .git/objects/pack/pack-4efe288a1b0fd1df2942754b498c4480f00a7d52.pack
42
+ .git/refs/heads/master
43
+ .git/refs/remotes/origin/HEAD
44
+ .git/refs/remotes/origin/master
45
+ .gitignore
46
+ History.txt
47
+ Manifest.txt
48
+ README.txt
49
+ Rakefile
50
+ examples/feature_demo.rb
51
+ examples/rails_daemon.rb
52
+ examples/simple_daemon.rb
53
+ examples/starling_queue_daemon.rb
54
+ lib/i_can_daemonize.rb
55
+ lib/i_can_daemonize/version.rb
56
+ test/simple_daemon.rb
57
+ test/test_helper.rb
58
+ test/test_i_can_daemonize.rb
data/README.txt ADDED
@@ -0,0 +1,99 @@
1
+ = i_can_daemonize
2
+
3
+ == DESCRIPTION:
4
+
5
+ ICanDaemonize makes it dead simple to create daemons of your own.
6
+
7
+ == REQUIREMENTS:
8
+
9
+ * A Computer
10
+ * Ruby
11
+
12
+ == INSTALL:
13
+
14
+ * Get ICanDaemonize off github
15
+
16
+ == THE BASICS:
17
+
18
+ require 'rubygems'
19
+ require 'i_can_daemonize'
20
+ class MyDaemonClass
21
+ include ICanDaemonize
22
+
23
+ daemonize do
24
+ # your code here
25
+ end
26
+
27
+ end
28
+
29
+ Run your daemon
30
+
31
+ ruby your_daemon_script start
32
+
33
+ ICD will create a log file in log/ called your_daemon_script.log as well as a pid file in log called your_daemon_script.pid
34
+
35
+ It will essentially run the block given to daemonize within a loop.
36
+
37
+ == USAGE:
38
+
39
+ The daemonize method accepts a number of options see ICanDaemonize::ClassMethods daemonize() for options
40
+
41
+ There are a number of other blocks you can define in your class as well, including:
42
+
43
+ before do/end
44
+
45
+ after do/end
46
+
47
+ die_if do/end
48
+
49
+ exit_if do/end
50
+
51
+ See ICanDaemonize docs for more info on these options.
52
+
53
+ Your daemon can be called with a number of options
54
+
55
+ --loop-every SECONDS How long to sleep between each loop
56
+ -t, --ontop Stay on top (does not daemonize)
57
+ --instances=NUM Allow multiple instances to run simultaneously? 0 for infinite. default: 1
58
+ --log-file=LOGFILE Logfile to log to
59
+ --pid-file=PIDFILE Directory to put pidfile
60
+ -h, --help Show this message
61
+
62
+ You can add your own command line options by using the 'arg' class macro.
63
+ See http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html for more info on OptionParser.
64
+
65
+ arg '--scott-rocks', 'Does scott rock?') do |value|
66
+ @scott_rocks = value
67
+ end
68
+
69
+ == BUGS:
70
+
71
+ My method names may be too common to be included class methods
72
+
73
+ ICanDaemonize attempts to capture all STDOUT or STDERR and prepend that output with a timestamp and PID.
74
+ I don't like how this was implemented anyway. Feels dirty.
75
+
76
+ == LICENSE:
77
+
78
+ (The MIT License)
79
+
80
+ Copyright (c) 2009 Adam Pisoni, Amos Elliston
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining
83
+ a copy of this software and associated documentation files (the
84
+ 'Software'), to deal in the Software without restriction, including
85
+ without limitation the rights to use, copy, modify, merge, publish,
86
+ distribute, sublicense, and/or sell copies of the Software, and to
87
+ permit persons to whom the Software is furnished to do so, subject to
88
+ the following conditions:
89
+
90
+ The above copyright notice and this permission notice shall be
91
+ included in all copies or substantial portions of the Software.
92
+
93
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
94
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
95
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
96
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
97
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
98
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
99
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rcov/rcovtask'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |s|
9
+ s.name = "i_can_daemonize"
10
+ s.summary = "ICanDaemonize makes it dead simple to create daemons of your own"
11
+ s.email = "wonko9@gmail.com"
12
+ s.homepage = "http://github.com/wonko9/i_can_daemonize"
13
+ s.description = "ICanDaemonize makes it dead simple to create daemons of your own"
14
+ s.authors = ["Adam Pisoni", "Amos Elliston"]
15
+ s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+ Rake::TestTask.new
22
+
23
+ Rake::RDocTask.new do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'test'
26
+ rdoc.options << '--line-numbers' << '--inline-source'
27
+ rdoc.rdoc_files.include('README*')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
30
+
31
+ Rcov::RcovTask.new do |t|
32
+ t.libs << 'test'
33
+ t.test_files = FileList['test/**/*_test.rb']
34
+ t.verbose = true
35
+ end
36
+
37
+ task :default => :test
@@ -0,0 +1,482 @@
1
+ require 'optparse'
2
+ require 'timeout'
3
+
4
+ module ICanDaemonize
5
+ class DieTime < StandardError; end
6
+ class TimeoutError < StandardError; end
7
+
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ base.initialize_options
11
+ end
12
+
13
+ class Config
14
+ METHODS = [:script_path]
15
+ CONFIG = {}
16
+ def method_missing(name, *args)
17
+ name = name.to_s.upcase.to_sym
18
+ if name.to_s =~ /^(.*)=$/
19
+ name = $1.to_sym
20
+ CONFIG[name] = args.first
21
+ else
22
+ CONFIG[name]
23
+ end
24
+ end
25
+ end
26
+
27
+ module ClassMethods
28
+
29
+ def initialize_options
30
+ @@config = Config.new
31
+ @@config.script_path = File.expand_path(File.dirname($0))
32
+ $0 = script_name
33
+ end
34
+
35
+ def parse_options
36
+ opts = OptionParser.new do |opt|
37
+ opt.banner = "Usage: #{script_name} [options] [start|stop]"
38
+
39
+ opt.on_tail('-h', '--help', 'Show this message') do
40
+ puts opt
41
+ exit
42
+ end
43
+
44
+ opt.on('--loop-every=SECONDS', 'How long to sleep between each loop') do |value|
45
+ options[:loop_every] = value
46
+ end
47
+
48
+ opt.on('-t', '--ontop', 'Stay on top (does not daemonize)') do
49
+ options[:ontop] = true
50
+ end
51
+
52
+ opt.on('--instances=NUM', 'Allow multiple instances to run simultaneously? 0 for infinite. default: 1') do |value|
53
+ self.instances = value.to_i
54
+ end
55
+
56
+ opt.on('--log-file=LOGFILE', 'Logfile to log to') do |value|
57
+ options[:log_file] = File.expand_path(value)
58
+ end
59
+
60
+ opt.on('--pid-file=PIDFILE', 'Location of pidfile') do |value|
61
+ options[:pid_file] = File.expand_path(value)
62
+ end
63
+
64
+ opt.on('--no-log-prefix', 'Do not prefix PID and date/time in log file.') do
65
+ options[:log_prefix] = false
66
+ end
67
+ end
68
+
69
+ extra_args.each do |arg|
70
+ opts.on(*arg.first) do |value|
71
+ arg.last.call(value) if arg.last
72
+ end
73
+ end
74
+
75
+ opts.parse!
76
+
77
+ if ARGV.include?('stop')
78
+ stop_daemons
79
+ elsif ARGV.include?('restart')
80
+ restart_daemons
81
+ elsif ARGV.include?('start') or ontop?
82
+ self.running = true
83
+ self.restarted = true if ARGV.include?('HUP')
84
+ else
85
+ puts opts.help
86
+ end
87
+ end
88
+
89
+ def arg(*args, &block)
90
+ self.extra_args << [args, block]
91
+ end
92
+
93
+ def extra_args
94
+ @extra_args ||= []
95
+ end
96
+
97
+ def callbacks
98
+ @callbacks ||= {}
99
+ end
100
+
101
+ def options
102
+ @options ||= {}
103
+ end
104
+
105
+ def config
106
+ yield @@config
107
+ end
108
+
109
+ def before(&block)
110
+ callbacks[:before] = block
111
+ end
112
+
113
+ def after(&block)
114
+ callbacks[:after] = block
115
+ end
116
+
117
+ def sig(signal, &block)
118
+ callbacks["sig_#{signal}".to_sym] = block
119
+ end
120
+
121
+ def die_if(method=nil,&block)
122
+ options[:die_if] = method || block
123
+ end
124
+
125
+ def exit_if(method=nil,&block)
126
+ options[:exit_if] = method || block
127
+ end
128
+
129
+ def callback!(callback)
130
+ callbacks[callback].call if callbacks[callback]
131
+ end
132
+
133
+ # options may include:
134
+ #
135
+ # <tt>:loop_every</tt> Fixnum (DEFAULT 0)
136
+ # How many seconds to sleep between calls to your block
137
+ #
138
+ # <tt>:timeout</tt> Fixnum (DEFAULT 0)
139
+ # Timeout in if block does not execute withing passed number of seconds
140
+ #
141
+ # <tt>:die_on_timeout</tt> BOOL (DEFAULT False)
142
+ # Should the daemon continue running if a block times out, or just run the block again
143
+ #
144
+ # <tt>:ontop</tt> BOOL (DEFAULT False)
145
+ # Do not daemonize. Run in current process
146
+ #
147
+ # <tt>:before</tt> BLOCK
148
+ # Run this block after daemonizing but before begining the daemonize loop.
149
+ # You can also define the before block by putting a before do/end block in your class.
150
+ #
151
+ # <tt>:after</tt> BLOCK
152
+ # Run this block before program exists.
153
+ # You can also define the after block by putting an after do/end block in your class.
154
+ #
155
+ # <tt>:die_if</tt> BLOCK
156
+ # Run this check after each iteration of the loop. If the block returns true, throw a DieTime exception and exit
157
+ # You can also define the after block by putting an die_if do/end block in your class.
158
+ #
159
+ # <tt>:exit_if</tt> BLOCK
160
+ # Run this check after each iteration of the loop. If the block returns true, exit gracefully
161
+ # You can also define the after block by putting an exit_if do/end block in your class.
162
+ #
163
+ # <tt>:log_prefix</tt> BOOL (DEFAULT true)
164
+ # Prefix log file entries with PID and timestamp
165
+ def daemonize(opts={}, &block)
166
+ parse_options
167
+ return unless ok_to_start?
168
+
169
+ options.merge!(opts)
170
+ puts "Starting #{instances_to_start} #{script_name} #{pluarlize('instance', instances_to_start)}..."
171
+ puts "Logging to: #{log_file}" unless ontop?
172
+
173
+ unless ontop?
174
+ instances_to_start.times do
175
+ safefork do
176
+ open(pid_file, 'a+') {|f| f << Process.pid << "\n"}
177
+ at_exit { remove_pid! }
178
+
179
+
180
+ trap('TERM') { callback!(:sig_term) ; self.running = false }
181
+ trap('INT') { callback!(:sig_int) ; Process.kill('TERM', $$) }
182
+ trap('HUP') { callback!(:sig_hup) ; restart_self }
183
+
184
+ sess_id = Process.setsid
185
+ reopen_filehandes
186
+
187
+ begin
188
+ at_exit { callback!(:after) }
189
+ callback!(:before)
190
+ run_block(&block)
191
+ rescue SystemExit
192
+ rescue Exception => e
193
+ $stdout.puts "Something bad happened #{e.inspect} #{e.backtrace.join("\n")}"
194
+ end
195
+ end
196
+ end
197
+ else
198
+ begin
199
+ callback!(:before)
200
+ run_block(&block)
201
+ rescue SystemExit, Interrupt
202
+ callback!(:after)
203
+ end
204
+ end
205
+ end
206
+
207
+ private
208
+
209
+ def run_block(&block)
210
+ loop do
211
+ break unless running?
212
+ if options[:timeout]
213
+ begin
214
+ Timeout::timeout(options[:timeout].to_i) do
215
+ block.call if block
216
+ end
217
+ rescue Timeout::Error => e
218
+ if options[:die_on_timeout]
219
+ raise TimeoutError.new("#{self} timed out after #{options[:timeout]} seconds while executing block in loop")
220
+ else
221
+ $stderr.puts "#{self} timed out after #{options[:timeout]} seconds while executing block in loop #{e.backtrace.join("\n")}"
222
+ end
223
+ end
224
+ else
225
+ block.call if block
226
+
227
+ end
228
+ if options[:loop_every]
229
+ sleep options[:loop_every].to_i
230
+ elsif not block
231
+ sleep 0.1
232
+ end
233
+ break if should_exit?
234
+ raise DieTime.new('Die if conditions were met!') if should_die?
235
+ end
236
+ exit(0)
237
+ end
238
+
239
+ def should_die?
240
+ die_if = options[:die_if]
241
+ if die_if
242
+ if die_if.is_a?(Symbol) or die_if.is_a?(String)
243
+ self.send(die_if)
244
+ elsif die_if.is_a?(Proc)
245
+ die_if.call
246
+ end
247
+ else
248
+ false
249
+ end
250
+ end
251
+
252
+ def should_exit?
253
+ exit_if = options[:exit_if]
254
+ if exit_if
255
+ if exit_if.is_a?(Symbol) or exit_if.is_a?(String)
256
+ self.send(exit_if.to_sym)
257
+ elsif exit_if.is_a?(Proc)
258
+ exit_if.call
259
+ end
260
+ else
261
+ false
262
+ end
263
+ end
264
+
265
+ def instances_to_start
266
+ return 1 if restarted?
267
+ instances - pids.size
268
+ end
269
+
270
+ def ok_to_start?
271
+ return false unless running?
272
+ return true if restarted?
273
+
274
+ living_pids = []
275
+ if pids and pids.any?
276
+ pids.each do |pid|
277
+ if process_alive?(pid)
278
+ living_pids << pid
279
+ else
280
+ $stderr.puts "Removing stale pid: #{pid}..."
281
+ pids -= [pid]
282
+ self.pids = pids
283
+ end
284
+ end
285
+ if instances > 0 and living_pids.size >= instances
286
+ $stderr.puts "#{script_name} is already running #{living_pids.size} out of #{pluralize('instance', instances)}"
287
+ return false
288
+ end
289
+ end
290
+ return true
291
+ end
292
+
293
+ # stop the daemon, nicely at first, and then forcefully if necessary
294
+ def stop_daemons
295
+ self.running = false
296
+ puts "Stopping #{instances} #{script_name} #{pluarlize('instance', instances)}..."
297
+ if pids.empty?
298
+ $stderr.puts "#{script_name} doesn't appear to be running"
299
+ exit
300
+ end
301
+ pids.each_with_index do |pid, ii|
302
+ kill_pid(pid)
303
+ break if ii == (instances - 1)
304
+ end
305
+ end
306
+
307
+ def restart_daemons
308
+ pids.each do |pid|
309
+ kill_pid(pid, 'HUP')
310
+ end
311
+ end
312
+
313
+ def kill_pid(pid, signal='TERM')
314
+ $stdout.puts("Stopping pid #{pid} with #{signal}...")
315
+ begin
316
+ Process.kill(signal, pid)
317
+ if pid_running?(pid, options[:timeout] || 120)
318
+ $stdout.puts("Using kill -9 #{pid}")
319
+ Process.kill(9, pid)
320
+ else
321
+ $stdout.puts("Process #{pid} stopped")
322
+ end
323
+ rescue Errno::ESRCH
324
+ $stdout.puts("Couldn't #{signal} #{pid} as it wasn't running")
325
+ end
326
+ end
327
+
328
+ def pid_running?(pid,time_to_wait=0)
329
+ times_to_check = 1
330
+ if time_to_wait > 0.5
331
+ times_to_check = (time_to_wait / 0.5).to_i
332
+ end
333
+
334
+ begin
335
+ times_to_check.times do
336
+ Process.kill(0, pid)
337
+ sleep 0.5
338
+ end
339
+ return true
340
+ rescue Errno::ESRCH
341
+ return false
342
+ end
343
+ end
344
+
345
+ def restart_self
346
+ remove_pid!
347
+ cmd = "#{@@config.script_path}/#{script_name} "
348
+ cmd << 'HUP ' unless ARGV.include?('HUP')
349
+ cmd << ARGV.join(' ')
350
+ puts "Restarting #{cmd} pid: #{$$}..."
351
+ system(cmd)
352
+ Process.kill('TERM', $$)
353
+ end
354
+
355
+ def safefork(&block)
356
+ fork_tries ||= 0
357
+ fork(&block)
358
+ rescue Errno::EWOULDBLOCK
359
+ raise if fork_tries >= 20
360
+ fork_tries += 1
361
+ sleep 5
362
+ retry
363
+ end
364
+
365
+ def process_alive?(process_pid)
366
+ Process.kill(0, process_pid)
367
+ return true
368
+ rescue Errno::ESRCH => e
369
+ return false
370
+ end
371
+
372
+ LOG_FORMAT = '%-6d %-19s %s'
373
+ TIME_FORMAT = '%Y/%m/%d %H:%M:%S'
374
+ def reopen_filehandes
375
+ STDIN.reopen('/dev/null')
376
+ STDOUT.reopen(log_file, 'a')
377
+ STDOUT.sync = true
378
+ STDERR.reopen(STDOUT)
379
+ if log_prefix?
380
+ def STDOUT.write(string)
381
+ if @no_prefix
382
+ @no_prefix = false if string[-1, 1] == "\n"
383
+ else
384
+ string = LOG_FORMAT % [$$, Time.now.strftime(TIME_FORMAT), string]
385
+ @no_prefix = true
386
+ end
387
+ super(string)
388
+ end
389
+ end
390
+ end
391
+
392
+ def remove_pid!(pid=Process.pid)
393
+ pids.delete(pid)
394
+ self.pids = pids
395
+ end
396
+
397
+ def pids=(pids)
398
+ if pids.any?
399
+ open(pid_file, 'w') {|f| f << pids.join("\n") << "\n"}
400
+ else
401
+ File.unlink(pid_file) if File.exists?(pid_file)
402
+ end
403
+ @pids = pids
404
+ end
405
+
406
+ def pids
407
+ @pids ||= begin
408
+ if File.exist?(pid_file)
409
+ File.readlines(pid_file).collect {|p| p.to_i}
410
+ else
411
+ []
412
+ end
413
+ end
414
+ end
415
+
416
+ def instances=(num)
417
+ @instances = num
418
+ end
419
+
420
+ def instances
421
+ @instances ||= 1
422
+ end
423
+
424
+ def pluarlize(name, num)
425
+ num == 1 ? name : "#{name}s"
426
+ end
427
+
428
+ def running?
429
+ @running || false
430
+ end
431
+
432
+ def running=(bool)
433
+ @running = bool
434
+ end
435
+
436
+ def restarted?
437
+ @restarted || false
438
+ end
439
+
440
+ def restarted=(bool)
441
+ @restarted = bool
442
+ end
443
+
444
+ def ontop?
445
+ options[:ontop]
446
+ end
447
+
448
+ def log_prefix?
449
+ options[:log_prefix] || true
450
+ end
451
+
452
+ LOG_PATHS = ['log/', 'logs/', '../log/', '../logs/', '../../log', '../../logs', '.']
453
+ LOG_PATHS.unshift("#{RAILS_ROOT}/log") if defined?(RAILS_ROOT)
454
+ def log_dir
455
+ options[:log_dir] ||= begin
456
+ LOG_PATHS.detect do |path|
457
+ File.exists?(File.expand_path(path))
458
+ end
459
+ end
460
+ end
461
+
462
+ def log_file
463
+ options[:log_file] ||= File.expand_path("#{log_dir}/#{script_name}.log")
464
+ end
465
+
466
+ def pid_dir
467
+ options[:pid_dir] ||= log_dir
468
+ end
469
+
470
+ def pid_file
471
+ options[:pid_file] ||= File.expand_path("#{pid_dir}/#{script_name}.pid")
472
+ end
473
+
474
+ def script_name
475
+ @script_name ||= File.basename($0).gsub('.rb', '')
476
+ end
477
+
478
+ def script_name=(script_name)
479
+ @script_name = script_name
480
+ end
481
+ end
482
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require File.dirname(__FILE__) + '/../lib/i_can_daemonize'
3
+
4
+ class SimpleDaemon
5
+ include ICanDaemonize
6
+
7
+ arg '--test=VALUE', 'Test Arg' do |value|
8
+ @test = value
9
+ end
10
+
11
+ arg '-s', '--short-test=VALUE', 'Test arg with shortname' do |value|
12
+ @short_test = value
13
+ end
14
+
15
+ counter = 0
16
+ daemonize do
17
+ if @options[:loop_every]
18
+ counter += 1
19
+ File.open(TEST_FILE, 'w'){|f| f << counter}
20
+ elsif @test
21
+ File.open(TEST_FILE, 'w'){|f| f << "#{@test}|#{@short_test}"}
22
+ else
23
+ File.open(TEST_FILE, 'w'){|f| f << "#{log_file}|#{pid_file}"}
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ require 'test/unit'
2
+ require 'pp'
3
+
4
+ TEST_FILE = File.dirname(__FILE__) + '/test.txt' unless defined?(TEST_FILE)
5
+
6
+ unless Test::Unit::TestCase.respond_to?(:test)
7
+ class << Test::Unit::TestCase
8
+ def test(name, &block)
9
+ test_name = "test_#{name.gsub(/[\s\W]/,'_')}"
10
+ raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name
11
+ define_method test_name, &block
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestICanDaemonize < Test::Unit::TestCase
4
+ DEFAULT_LOG_FILE = File.join(File.dirname(__FILE__), 'test_daemon.rb.log')
5
+
6
+ def setup
7
+ File.delete(TEST_FILE) if File.exist?(TEST_FILE)
8
+ @daemon = "#{File.dirname(__FILE__)}/simple_daemon.rb"
9
+ end
10
+
11
+ def teardown
12
+ File.delete(TEST_FILE) if File.exist?(TEST_FILE)
13
+ File.delete(DEFAULT_LOG_FILE) if File.exist?(DEFAULT_LOG_FILE)
14
+ end
15
+
16
+ test "passing options" do
17
+ log_file = File.expand_path(File.join(File.dirname(__FILE__), 'test.log'))
18
+ pid_file = File.expand_path(File.join(File.dirname(__FILE__), 'test.pid'))
19
+ `ruby #{@daemon} --log-file #{log_file} --pid-file #{pid_file} start`
20
+ `ruby #{@daemon} --log-file #{log_file} --pid-file #{pid_file} stop`
21
+ File.delete(log_file)
22
+ assert_equal "#{log_file}|#{pid_file}", File.read(TEST_FILE)
23
+ end
24
+
25
+ test "loop every" do
26
+ `ruby #{@daemon} --loop-every 1 start`
27
+ sleep 5
28
+ `ruby #{@daemon} stop`
29
+ counter = File.read(TEST_FILE).to_i
30
+ assert counter > 5
31
+ end
32
+
33
+ test "arg class macro" do
34
+ `ruby #{@daemon} --test test -s short-test start`
35
+ `ruby #{@daemon} stop`
36
+ assert_equal "test|short-test", File.read(TEST_FILE)
37
+ end
38
+
39
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wonko9-i_can_daemonize
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Pisoni
8
+ - Amos Elliston
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-01-19 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: ICanDaemonize makes it dead simple to create daemons of your own
18
+ email: wonko9@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - History.txt
27
+ - Manifest.txt
28
+ - Rakefile
29
+ - README.txt
30
+ - lib/i_can_daemonize
31
+ - lib/i_can_daemonize/version.rb
32
+ - lib/i_can_daemonize.rb
33
+ - test/simple_daemon.rb
34
+ - test/test_helper.rb
35
+ - test/test_i_can_daemonize.rb
36
+ has_rdoc: true
37
+ homepage: http://github.com/wonko9/i_can_daemonize
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --inline-source
41
+ - --charset=UTF-8
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.2.0
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: ICanDaemonize makes it dead simple to create daemons of your own
63
+ test_files: []
64
+