daemon 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,15 +1,10 @@
1
- source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
1
+ source 'http://rubygems.org'
5
2
 
6
3
  # Add dependencies to develop your gem here.
7
4
  # Include everything needed to run rake, tests, features, etc.
8
5
  group :development do
9
- gem "rspec", "~> 2.3.0"
10
- gem "shoulda", ">= 0"
11
- gem "bundler", "~> 1.0.0"
12
- gem "jeweler", "~> 1.6.4"
13
- gem "rcov", ">= 0"
6
+ gem 'rspec', '~> 2.13'
7
+ gem 'jeweler', '~> 1.8.4'
8
+ gem 'rdoc', '~> 3.9'
14
9
  end
15
10
 
@@ -1,30 +1,30 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- diff-lcs (1.1.3)
4
+ diff-lcs (1.2.4)
5
5
  git (1.2.5)
6
- jeweler (1.6.4)
6
+ jeweler (1.8.4)
7
7
  bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
- rake (0.9.2)
11
- rcov (0.9.10)
12
- rspec (2.3.0)
13
- rspec-core (~> 2.3.0)
14
- rspec-expectations (~> 2.3.0)
15
- rspec-mocks (~> 2.3.0)
16
- rspec-core (2.3.1)
17
- rspec-expectations (2.3.0)
18
- diff-lcs (~> 1.1.2)
19
- rspec-mocks (2.3.0)
20
- shoulda (2.11.3)
10
+ rdoc
11
+ json (1.7.7)
12
+ rake (10.0.4)
13
+ rdoc (3.12.2)
14
+ json (~> 1.4)
15
+ rspec (2.13.0)
16
+ rspec-core (~> 2.13.0)
17
+ rspec-expectations (~> 2.13.0)
18
+ rspec-mocks (~> 2.13.0)
19
+ rspec-core (2.13.1)
20
+ rspec-expectations (2.13.0)
21
+ diff-lcs (>= 1.1.3, < 2.0)
22
+ rspec-mocks (2.13.1)
21
23
 
22
24
  PLATFORMS
23
25
  ruby
24
26
 
25
27
  DEPENDENCIES
26
- bundler (~> 1.0.0)
27
- jeweler (~> 1.6.4)
28
- rcov
29
- rspec (~> 2.3.0)
30
- shoulda
28
+ jeweler (~> 1.8.4)
29
+ rdoc (~> 3.9)
30
+ rspec (~> 2.13)
@@ -24,8 +24,16 @@ So full usage may look like this:
24
24
  Daemon.daemonize('myscript.pid', 'out.log')
25
25
  end
26
26
 
27
+ To spawn a daemon process and keep current process runing:
28
+
29
+ pid, wait = Daemon.daemonize('myscript.pid', 'out.log') do |log|
30
+ # daemon code
31
+ end
32
+
33
+ wait.value # wait for daemon to finish; returns Process::Status
34
+
27
35
  == Contributing to daemon
28
-
36
+
29
37
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
30
38
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
31
39
  * Fork the project
data/Rakefile CHANGED
@@ -31,22 +31,9 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
31
31
  spec.pattern = FileList['spec/**/*_spec.rb']
32
32
  end
33
33
 
34
- RSpec::Core::RakeTask.new(:rcov) do |spec|
35
- spec.pattern = 'spec/**/*_spec.rb'
36
- spec.rcov = true
37
- end
38
-
39
- require 'rcov/rcovtask'
40
- Rcov::RcovTask.new do |test|
41
- test.libs << 'test'
42
- test.pattern = 'test/**/test_*.rb'
43
- test.verbose = true
44
- test.rcov_opts << '--exclude "gems/*"'
45
- end
46
-
47
34
  task :default => :spec
48
35
 
49
- require 'rake/rdoctask'
36
+ require 'rdoc/task'
50
37
  Rake::RDocTask.new do |rdoc|
51
38
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
52
39
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "daemon"
8
- s.version = "1.1.0"
8
+ s.version = "1.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jakub Pastuszek"]
12
- s.date = "2011-09-28"
12
+ s.date = "2014-09-01"
13
13
  s.description = "Make calling script to become a daemon with pid file locking support and stdout/stderr redirection"
14
14
  s.email = "jpastuszek@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -32,31 +32,25 @@ Gem::Specification.new do |s|
32
32
  s.homepage = "http://github.com/jpastuszek/daemon"
33
33
  s.licenses = ["MIT"]
34
34
  s.require_paths = ["lib"]
35
- s.rubygems_version = "1.8.10"
35
+ s.rubygems_version = "1.8.23"
36
36
  s.summary = "Daemonize your script with a single line of code"
37
37
 
38
38
  if s.respond_to? :specification_version then
39
39
  s.specification_version = 3
40
40
 
41
41
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
- s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
43
- s.add_development_dependency(%q<shoulda>, [">= 0"])
44
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
45
- s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
46
- s.add_development_dependency(%q<rcov>, [">= 0"])
42
+ s.add_development_dependency(%q<rspec>, ["~> 2.13"])
43
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
44
+ s.add_development_dependency(%q<rdoc>, ["~> 3.9"])
47
45
  else
48
- s.add_dependency(%q<rspec>, ["~> 2.3.0"])
49
- s.add_dependency(%q<shoulda>, [">= 0"])
50
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
51
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
52
- s.add_dependency(%q<rcov>, [">= 0"])
46
+ s.add_dependency(%q<rspec>, ["~> 2.13"])
47
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
48
+ s.add_dependency(%q<rdoc>, ["~> 3.9"])
53
49
  end
54
50
  else
55
- s.add_dependency(%q<rspec>, ["~> 2.3.0"])
56
- s.add_dependency(%q<shoulda>, [">= 0"])
57
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
58
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
59
- s.add_dependency(%q<rcov>, [">= 0"])
51
+ s.add_dependency(%q<rspec>, ["~> 2.13"])
52
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
53
+ s.add_dependency(%q<rdoc>, ["~> 3.9"])
60
54
  end
61
55
  end
62
56
 
@@ -6,35 +6,108 @@ class Daemon
6
6
  end
7
7
 
8
8
  def self.daemonize(pid_file, log_file = nil, sync = true)
9
- exit if fork
10
- Process.setsid # become session leader
11
- exit if fork # and exits
12
- # now in child
9
+ if block_given?
10
+ spawn do |send_ok, send_error|
11
+ log = begin
12
+ # try to lock before we kill stdin/out
13
+ lock(pid_file)
13
14
 
14
- # try to lock before we kill stdin/out
15
- lock(pid_file)
15
+ # close I/O
16
+ disconnect(log_file, sync)
17
+ rescue => error
18
+ send_error.call(error)
19
+ end
16
20
 
17
- if log_file
18
- log = File.open(log_file, 'a')
19
- log.sync = sync
21
+ send_ok.call
22
+
23
+ yield log
24
+ end # => pid, wait
20
25
  else
21
- log = '/dev/null'
26
+ # become new process group leader
27
+ fence
28
+
29
+ # try to lock before we kill stdin/out
30
+ lock(pid_file)
31
+
32
+ # close I/O
33
+ disconnect(log_file, sync) # => log
22
34
  end
35
+ end
23
36
 
24
- # disconnect
25
- STDIN.reopen '/dev/null'
26
- STDOUT.reopen log
27
- STDERR.reopen log
37
+ def self.spawn
38
+ r, w = IO.pipe
39
+
40
+ pid = fence do
41
+ r.close
42
+
43
+ yield(
44
+ ->{
45
+ w.write Marshal.dump(nil) # send OK to parent
46
+ w.close
47
+ },
48
+ ->(error){
49
+ w.write Marshal.dump(error) # send error to parent
50
+ w.close
51
+ exit 42
52
+ }
53
+ )
54
+ end
55
+ thr = Process.detach(pid)
56
+
57
+ w.close
58
+ data = r.read
59
+ data.empty? and fail 'ok/error handler not called!'
60
+
61
+ if error = Marshal.load(data)
62
+ thr.join # wait for child to die
63
+ raise error
64
+ end
65
+
66
+ return pid, thr
67
+ ensure
68
+ w.close unless w.closed?
69
+ r.close
70
+ end
71
+
72
+ def self.fence
73
+ if block_given?
74
+ fork do
75
+ Process.setsid # become new session leader
76
+ # now in child
77
+ yield
78
+ end # => pid
79
+ else
80
+ exit! 0 if fork
81
+ Process.setsid # become new session leader
82
+ # now in child
83
+ end
28
84
  end
29
85
 
30
86
  def self.lock(pid_file)
31
87
  pf = File.open(pid_file, File::RDWR | File::CREAT)
32
- raise LockError, pf unless pf.flock(File::LOCK_EX|File::LOCK_NB)
88
+ raise LockError, pf unless pf.flock(File::LOCK_EX | File::LOCK_NB)
33
89
  pf.truncate(0)
34
90
  pf.write(Process.pid.to_s + "\n")
35
91
  pf.flush
36
92
 
37
93
  @pf = pf # keep it open and locked until process exits
38
94
  end
39
- end
40
95
 
96
+ def self.disconnect(log_file = nil, sync = true)
97
+ if log_file
98
+ log = File.open(log_file, File::WRONLY | File::CREAT | File::APPEND | File::BINARY)
99
+ log.sync = sync
100
+ else
101
+ # don't raise on STDOUT/STDERR write
102
+ log = File.new('/dev/null', File::WRONLY | File::BINARY)
103
+ end
104
+
105
+ # disconnect
106
+ STDIN.close # raise IOError on STDIN.read
107
+ STDOUT.reopen log
108
+ STDERR.reopen log
109
+
110
+ # provide log IO
111
+ return log
112
+ end
113
+ end
@@ -1,23 +1,282 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'daemon'
3
-
4
- $pf = 'test.pid'
3
+ require 'timeout'
4
+ require 'tempfile'
5
5
 
6
6
  describe Daemon do
7
- it '#lock should create a pid file with current process pid' do
8
- Daemon.lock($pf)
9
- File.open($pf).read.should == "#{Process.pid}\n"
7
+ let! :pid_file do
8
+ Tempfile.new('daemon-pid')
9
+ end
10
+
11
+ let! :log_file do
12
+ Tempfile.new('daemon-log')
10
13
  end
11
14
 
12
- it '#lock should raise error if called twice on same pid file' do
13
- Daemon.lock($pf)
14
- lambda {
15
- Daemon.lock($pf)
16
- }.should raise_error Daemon::LockError
15
+ describe 'locking' do
16
+ it '#lock should create a pid file with current process pid' do
17
+ Daemon.lock(pid_file)
18
+ File.open(pid_file).read.should == "#{Process.pid}\n"
19
+ end
20
+
21
+ it '#lock should raise error if called twice on same pid file' do
22
+ Daemon.lock(pid_file)
23
+ lambda {
24
+ Daemon.lock(pid_file)
25
+ }.should raise_error Daemon::LockError
26
+ end
17
27
  end
18
28
 
19
- after :each do
20
- File.unlink($pf) if File.exist?($pf)
29
+ describe 'forking' do
30
+ it 'forked sub process can be terminated with SIGHUP to whole process group' do
31
+ cr, cw = *IO.pipe
32
+ mr, mw = *IO.pipe
33
+
34
+ pid = fork do # parent
35
+ Process.setsid # start new process group
36
+
37
+ pid = fork do # child
38
+ loop{cr.readline and mw.puts 'pong'}
39
+ end
40
+ Process.wait(pid)
41
+ end
42
+
43
+ # close our end
44
+ mw.close
45
+ cr.close
46
+
47
+ # wait for the child to start
48
+ cw.puts 'ping'
49
+ mr.readline.strip.should == 'pong'
50
+
51
+ Process.kill('HUP', -pid) # kill the group; this should kill the child
52
+ Process.wait(pid) # parent exit
53
+
54
+ expect {
55
+ Timeout.timeout(2) do
56
+ # child is dead
57
+ cw.puts 'ping'
58
+ end
59
+ }.to raise_error Errno::EPIPE
60
+ end
61
+
62
+ it '#fence should start new process group to protect the process from HUP signal' do
63
+ cr, cw = *IO.pipe
64
+ mr, mw = *IO.pipe
65
+
66
+ pid = fork do # parent
67
+ Process.setsid # start new process group
68
+
69
+ Daemon.fence
70
+
71
+ # now in protected child
72
+ loop{cr.readline and mw.puts 'pong'}
73
+ end
74
+ Process.wait(pid) # parent exits
75
+
76
+ # close our end
77
+ mw.close
78
+ cr.close
79
+
80
+ # wait for the child to start
81
+ cw.puts 'ping'
82
+ mr.readline.strip.should == 'pong'
83
+
84
+ expect {
85
+ Process.kill('HUP', -pid)
86
+ # the group is gone with the parent process
87
+ }.to raise_error Errno::ESRCH
88
+
89
+ Timeout.timeout(2) do
90
+ # child still there
91
+ cw.puts 'ping'
92
+ mr.readline.strip.should == 'pong'
93
+ end
94
+ end
95
+
96
+ it '#fence with block should start new process group to protect the process from HUP signal calling provided block within it' do
97
+ cr, cw = *IO.pipe
98
+ mr, mw = *IO.pipe
99
+
100
+ pid = fork do # parent
101
+ Process.setsid # start new process group
102
+
103
+ pid = Daemon.fence do
104
+ # now in protected child
105
+ loop{cr.readline and mw.puts 'pong'}
106
+ end
107
+
108
+ Process.wait(pid)
109
+ end
110
+
111
+ # close our end
112
+ mw.close
113
+ cr.close
114
+
115
+ # wait for the child to start
116
+ cw.puts 'ping'
117
+ mr.readline.strip.should == 'pong'
118
+
119
+ Process.kill('HUP', -pid) # kill the group; this would kill the child
120
+ Process.wait(pid) # parent exit
121
+
122
+ Timeout.timeout(2) do
123
+ # child still there
124
+ cw.puts 'ping'
125
+ mr.readline.strip.should == 'pong'
126
+ end
127
+ end
128
+
129
+ it '#spawn should call block in fenced child process and return child pid and wait thread' do
130
+ pid, wait = Daemon.spawn do |send_ok, send_error|
131
+ send_ok.call
132
+ sleep 0.2
133
+ end
134
+
135
+ pid.should > 0
136
+ wait.should be_alive
137
+
138
+ wait.value.should be_success
139
+ end
140
+
141
+ it '#spawn should call block in fenced child process raising reported errors in master' do
142
+ expect {
143
+ Daemon.spawn do |send_ok, send_error|
144
+ begin
145
+ fail 'test'
146
+ rescue => error
147
+ send_error.call error
148
+ end
149
+ end
150
+ }.to raise_error RuntimeError, 'test'
151
+ end
152
+ end
153
+
154
+ describe 'IO handling' do
155
+ it '#disconnect should close STDIN and redirect STDIN and STDERR to given log file' do
156
+ pid = fork do
157
+ Daemon.disconnect(log_file)
158
+
159
+ puts 'hello world'
160
+ begin
161
+ STDIN.read # should raise
162
+ rescue IOError
163
+ puts 'foo bar'
164
+ end
165
+ end
166
+ Process.wait(pid)
167
+
168
+ log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
169
+ end
170
+
171
+ it '#disconnect should provide log file IO' do
172
+ pid = fork do
173
+ log = Daemon.disconnect(log_file)
174
+ log.puts 'hello world'
175
+ puts 'foo bar'
176
+ end
177
+ Process.wait(pid)
178
+
179
+ log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
180
+ end
181
+
182
+ it '#disconnect should provide /dev/null file IO when no log file specified' do
183
+ pid = fork do
184
+ log = Daemon.disconnect
185
+ log.puts 'foo bar'
186
+ log.path.should == '/dev/null'
187
+ end
188
+
189
+ Process.wait2(pid).last.should be_success
190
+ end
191
+
192
+ it '#disconnect should append log file' do
193
+ pid = fork do
194
+ Daemon.disconnect(log_file)
195
+ puts 'hello world'
196
+ end
197
+ Process.wait(pid)
198
+
199
+ pid = fork do
200
+ Daemon.disconnect(log_file)
201
+ puts 'foo bar'
202
+ end
203
+
204
+ Process.wait(pid)
205
+ log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
206
+ end
207
+ end
208
+
209
+ it '#deamonize should terminate current process while keeping the script running' do
210
+ log_file.open do |log|
211
+
212
+ pid = fork do
213
+ puts master_pid = Process.pid
214
+ Daemon.daemonize(pid_file, log_file, true)
215
+ Process.pid.should_not == master_pid
216
+ puts 'hello world'
217
+ end
218
+
219
+ Process.wait2(pid).last.should be_success # wait for master to go away (successfully)
220
+
221
+ log.readline.map(&:strip).should == ['hello world']
222
+ end
223
+ end
224
+
225
+ it '#deamonize should return log file IO' do
226
+ log_file.open do |log|
227
+ pid = fork do
228
+ log = Daemon.daemonize(pid_file, log_file, true)
229
+ log.puts 'hello world'
230
+ end
231
+ Process.wait2(pid).last.should be_success # wait for master to go away
232
+
233
+ log.readline.map(&:strip).should == ['hello world']
234
+ end
235
+ end
236
+
237
+ it '#daemonize with block should fork new process with pid file and log file and call block with log IO' do
238
+ pid, wait = Daemon.daemonize(pid_file, log_file) do |log|
239
+ log.puts 'hello world'
240
+ puts 'foo bar'
241
+ end
242
+
243
+ # wait for process to finish
244
+ wait.join
245
+
246
+ log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
247
+ end
248
+
249
+ it '#daemonize with block should raise error when lock file is busy' do
250
+ pid, wait = Daemon.daemonize(pid_file, log_file) do |log|
251
+ log.puts 'hello world'
252
+ puts 'foo bar'
253
+ sleep 1
254
+ end
255
+
256
+ expect {
257
+ Daemon.daemonize(pid_file, log_file){|log|}
258
+ }.to raise_error Daemon::LockError
259
+
260
+ Process.kill('TERM', pid)
261
+ wait.join
262
+
263
+ log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
264
+ end
265
+
266
+ it '#daemnize should not call at_exit handler' do
267
+ pid = fork do
268
+ pid = Process.pid
269
+ at_exit do
270
+ fail 'at_exit called' if pid != Process.pid
271
+ end
272
+
273
+ fork do
274
+ Daemon.daemonize(pid_file, '/dev/stdout')
275
+ exit! # dont call at_exit
276
+ end
277
+ Process.wait
278
+ end
279
+ Process.wait2(pid).last.should be_success
21
280
  end
22
281
  end
23
282
 
metadata CHANGED
@@ -1,108 +1,73 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: daemon
3
- version: !ruby/object:Gem::Version
4
- hash: 19
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 1
9
- - 0
10
- version: 1.1.0
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Jakub Pastuszek
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-09-28 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- requirement: &id001 !ruby/object:Gem::Requirement
12
+ date: 2014-09-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
22
17
  none: false
23
- requirements:
18
+ requirements:
24
19
  - - ~>
25
- - !ruby/object:Gem::Version
26
- hash: 3
27
- segments:
28
- - 2
29
- - 3
30
- - 0
31
- version: 2.3.0
32
- version_requirements: *id001
33
- name: rspec
34
- prerelease: false
20
+ - !ruby/object:Gem::Version
21
+ version: '2.13'
35
22
  type: :development
36
- - !ruby/object:Gem::Dependency
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
46
- version_requirements: *id002
47
- name: shoulda
48
23
  prerelease: false
49
- type: :development
50
- - !ruby/object:Gem::Dependency
51
- requirement: &id003 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
52
25
  none: false
53
- requirements:
26
+ requirements:
54
27
  - - ~>
55
- - !ruby/object:Gem::Version
56
- hash: 23
57
- segments:
58
- - 1
59
- - 0
60
- - 0
61
- version: 1.0.0
62
- version_requirements: *id003
63
- name: bundler
64
- prerelease: false
65
- type: :development
66
- - !ruby/object:Gem::Dependency
67
- requirement: &id004 !ruby/object:Gem::Requirement
28
+ - !ruby/object:Gem::Version
29
+ version: '2.13'
30
+ - !ruby/object:Gem::Dependency
31
+ name: jeweler
32
+ requirement: !ruby/object:Gem::Requirement
68
33
  none: false
69
- requirements:
34
+ requirements:
70
35
  - - ~>
71
- - !ruby/object:Gem::Version
72
- hash: 7
73
- segments:
74
- - 1
75
- - 6
76
- - 4
77
- version: 1.6.4
78
- version_requirements: *id004
79
- name: jeweler
80
- prerelease: false
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.4
81
38
  type: :development
82
- - !ruby/object:Gem::Dependency
83
- requirement: &id005 !ruby/object:Gem::Requirement
84
- none: false
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- hash: 3
89
- segments:
90
- - 0
91
- version: "0"
92
- version_requirements: *id005
93
- name: rcov
94
39
  prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.8.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: rdoc
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.9'
95
54
  type: :development
96
- description: Make calling script to become a daemon with pid file locking support and stdout/stderr redirection
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.9'
62
+ description: Make calling script to become a daemon with pid file locking support
63
+ and stdout/stderr redirection
97
64
  email: jpastuszek@gmail.com
98
65
  executables: []
99
-
100
66
  extensions: []
101
-
102
- extra_rdoc_files:
67
+ extra_rdoc_files:
103
68
  - LICENSE.txt
104
69
  - README.rdoc
105
- files:
70
+ files:
106
71
  - .document
107
72
  - Gemfile
108
73
  - Gemfile.lock
@@ -115,37 +80,31 @@ files:
115
80
  - spec/daemon_spec.rb
116
81
  - spec/spec_helper.rb
117
82
  homepage: http://github.com/jpastuszek/daemon
118
- licenses:
83
+ licenses:
119
84
  - MIT
120
85
  post_install_message:
121
86
  rdoc_options: []
122
-
123
- require_paths:
87
+ require_paths:
124
88
  - lib
125
- required_ruby_version: !ruby/object:Gem::Requirement
89
+ required_ruby_version: !ruby/object:Gem::Requirement
126
90
  none: false
127
- requirements:
128
- - - ">="
129
- - !ruby/object:Gem::Version
130
- hash: 3
131
- segments:
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ segments:
132
96
  - 0
133
- version: "0"
134
- required_rubygems_version: !ruby/object:Gem::Requirement
97
+ hash: -3235773960414260177
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
99
  none: false
136
- requirements:
137
- - - ">="
138
- - !ruby/object:Gem::Version
139
- hash: 3
140
- segments:
141
- - 0
142
- version: "0"
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
143
104
  requirements: []
144
-
145
105
  rubyforge_project:
146
- rubygems_version: 1.8.10
106
+ rubygems_version: 1.8.23
147
107
  signing_key:
148
108
  specification_version: 3
149
109
  summary: Daemonize your script with a single line of code
150
110
  test_files: []
151
-