process_lock 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +46 -0
- data/.rspec +2 -0
- data/.travis.yml +22 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/README.md +137 -0
- data/Rakefile +8 -0
- data/lib/process_lock/version.rb +3 -0
- data/lib/process_lock.rb +116 -0
- data/process_lock.gemspec +24 -0
- data/spec/other_process.sh +14 -0
- data/spec/process_lock_spec.rb +231 -0
- data/spec/run_example.sh +404 -0
- data/spec/spec_helper.rb +20 -0
- metadata +115 -0
data/.gitignore
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Suggested by bundler
|
2
|
+
*.gem
|
3
|
+
*.rbc
|
4
|
+
.bundle
|
5
|
+
.config
|
6
|
+
.yardoc
|
7
|
+
Gemfile.lock
|
8
|
+
InstalledFiles
|
9
|
+
_yardoc
|
10
|
+
coverage
|
11
|
+
doc/
|
12
|
+
lib/bundler/man
|
13
|
+
pkg
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
test/tmp
|
17
|
+
test/version_tmp
|
18
|
+
tmp
|
19
|
+
|
20
|
+
## RUBYMINE
|
21
|
+
.idea/
|
22
|
+
|
23
|
+
## MAC OS
|
24
|
+
.DS_Store
|
25
|
+
|
26
|
+
## TEXTMATE
|
27
|
+
*.tmproj
|
28
|
+
tmtags
|
29
|
+
|
30
|
+
## EMACS
|
31
|
+
*~
|
32
|
+
\#*
|
33
|
+
.\#*
|
34
|
+
|
35
|
+
## VIM
|
36
|
+
*.swp
|
37
|
+
*~
|
38
|
+
|
39
|
+
## PROJECT::SPECIFIC
|
40
|
+
tmp/example*
|
41
|
+
,*
|
42
|
+
|
43
|
+
# Local ruby version config
|
44
|
+
.rbenv-version
|
45
|
+
.ruby-version
|
46
|
+
.rvmrc
|
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
language: ruby
|
2
|
+
# Just to override the --deployment default arg
|
3
|
+
bundler_args: --no-color
|
4
|
+
script: "bundle exec rake"
|
5
|
+
|
6
|
+
notifications:
|
7
|
+
email:
|
8
|
+
on_success: change
|
9
|
+
on_failure: always
|
10
|
+
|
11
|
+
rvm:
|
12
|
+
- 1.8.7
|
13
|
+
- 1.9.3
|
14
|
+
- 2.0.0
|
15
|
+
- 2.1.0
|
16
|
+
- jruby-19mode
|
17
|
+
- rbx
|
18
|
+
|
19
|
+
matrix:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: rbx
|
22
|
+
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
process_lock (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.5)
|
10
|
+
rake (10.1.1)
|
11
|
+
rspec (2.14.1)
|
12
|
+
rspec-core (~> 2.14.0)
|
13
|
+
rspec-expectations (~> 2.14.0)
|
14
|
+
rspec-mocks (~> 2.14.0)
|
15
|
+
rspec-core (2.14.7)
|
16
|
+
rspec-expectations (2.14.4)
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
18
|
+
rspec-mocks (2.14.4)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (~> 1.3)
|
25
|
+
process_lock!
|
26
|
+
rake
|
27
|
+
rspec (~> 2.0)
|
data/README.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# ProcessLock
|
2
|
+
|
3
|
+
A simple class to acquire and check process-id file based locks on a unix filesystem.
|
4
|
+
|
5
|
+
[![Build Status](https://travis-ci.org/ianheggie/ruby-process-lock.png?branch=master)](https://travis-ci.org/ianheggie/ruby-process-lock)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'process_lock'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install process_lock
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Create an instance of ProcessLock with a filename as the lock.
|
24
|
+
You may have more than one lock per process.
|
25
|
+
|
26
|
+
Methods:
|
27
|
+
* acquire - Acquires a lock if it can. Returns true (or value of block if block is passed) if a lock was acquired, otherwise false.
|
28
|
+
* acquire! - Same as acquire except it throws an exception if a lock could not be obtained.
|
29
|
+
* release - Releases the lock if we are the owner. Returns true if the lock was released.
|
30
|
+
* release! - Same as release except it throws an exception if a lock was not released.
|
31
|
+
* filename - the filename passed when the instance was created
|
32
|
+
* read - the process id in the lock file, otherwise 0 (zero)
|
33
|
+
|
34
|
+
Note:
|
35
|
+
* locks don't stack - if we have already acquired the lock subsequent calls will reacquire the lock. releasing an already released lock will fail.
|
36
|
+
|
37
|
+
To acquire a lock, do some work and then release it:
|
38
|
+
|
39
|
+
pl = ProcessLock.new('tmp/name_of_lock.pid')
|
40
|
+
|
41
|
+
acquired = pl.acquire do
|
42
|
+
puts "Do some work!"
|
43
|
+
end
|
44
|
+
puts "Unable to obtain a lock" unless acquired
|
45
|
+
|
46
|
+
# OR
|
47
|
+
|
48
|
+
while ! pl.acquire
|
49
|
+
puts "Trying to acquire a lock"
|
50
|
+
sleep(1)
|
51
|
+
end
|
52
|
+
puts "Do some work!"
|
53
|
+
pl.release
|
54
|
+
|
55
|
+
|
56
|
+
Example:
|
57
|
+
|
58
|
+
irb - run first
|
59
|
+
|
60
|
+
>> require 'process_lock'
|
61
|
+
=> true
|
62
|
+
>> Process.pid
|
63
|
+
=> 16568
|
64
|
+
>> p = ProcessLock.new('tmp/example.tmp')
|
65
|
+
=> #<ProcessLock:0x00000001489c10 @filename="tmp/example.tmp">
|
66
|
+
>> p.alive?
|
67
|
+
=> false
|
68
|
+
>> p.owner?
|
69
|
+
=> false
|
70
|
+
>> p.read
|
71
|
+
=> 0
|
72
|
+
|
73
|
+
>> p.acquire!
|
74
|
+
=> true
|
75
|
+
|
76
|
+
>> p.alive?
|
77
|
+
=> true
|
78
|
+
>> p.owner?
|
79
|
+
=> true
|
80
|
+
>> p.read
|
81
|
+
=> 16568
|
82
|
+
>> sleep(10)
|
83
|
+
=> 10
|
84
|
+
>> p.release!
|
85
|
+
=> true
|
86
|
+
>> p.alive?
|
87
|
+
=> false
|
88
|
+
>> p.owner?
|
89
|
+
=> false
|
90
|
+
>> p.read
|
91
|
+
=> 0
|
92
|
+
|
93
|
+
2nd irb, run after first has acquired the lock
|
94
|
+
|
95
|
+
>> require 'process_lock'
|
96
|
+
=> true
|
97
|
+
>> Process.pid
|
98
|
+
=> 16569
|
99
|
+
>> q = ProcessLock.new('tmp/example.tmp')
|
100
|
+
=> #<ProcessLock:0x000000026e4090 @filename="tmp/example.tmp">
|
101
|
+
>> q.alive?
|
102
|
+
=> true
|
103
|
+
>> q.owner?
|
104
|
+
=> false
|
105
|
+
>> q.read
|
106
|
+
=> 16568
|
107
|
+
|
108
|
+
>> q.acquire!
|
109
|
+
ProcessLock::AlreadyLocked: Unable to acquire lock
|
110
|
+
from /home/ianh/Projects/Github/ruby-process-lock/lib/process_lock.rb:28:in `acquire!'
|
111
|
+
from (irb):7
|
112
|
+
from /home/ianh/.rbenv/versions/1.9.3-p484/bin/irb:12:in `<main>'
|
113
|
+
|
114
|
+
>> q.alive?
|
115
|
+
=> true
|
116
|
+
>> q.owner?
|
117
|
+
=> false
|
118
|
+
>> q.read
|
119
|
+
=> 16568
|
120
|
+
>>
|
121
|
+
|
122
|
+
example.tmp will contain the pid of the running process
|
123
|
+
|
124
|
+
## Contributing
|
125
|
+
|
126
|
+
1. Fork it
|
127
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
128
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
129
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
130
|
+
5. Create new Pull Request
|
131
|
+
|
132
|
+
## License and contributions
|
133
|
+
|
134
|
+
* Based on work Copyright (c) 2008 Simon Engledew, released under the MIT license.
|
135
|
+
* Subsequent work by Ian Heggie: packaged into a gem, added tests and acquire method, fixed acquire so it didn't overwrite locks by other processes.
|
136
|
+
* See git log for other contributers
|
137
|
+
|
data/Rakefile
ADDED
data/lib/process_lock.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'process_lock/version'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class ProcessLock
|
5
|
+
|
6
|
+
attr_reader :filename
|
7
|
+
|
8
|
+
class AlreadyLocked < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
class NotLocked < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(filename)
|
15
|
+
@filename = filename
|
16
|
+
FileUtils.touch(@filename)
|
17
|
+
end
|
18
|
+
|
19
|
+
def acquire!
|
20
|
+
result = acquired = acquire_without_block
|
21
|
+
if acquired and block_given?
|
22
|
+
begin
|
23
|
+
result = yield
|
24
|
+
ensure
|
25
|
+
release
|
26
|
+
end
|
27
|
+
end
|
28
|
+
raise(AlreadyLocked.new('Unable to acquire lock')) unless acquired
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
def acquire
|
33
|
+
result = acquire_without_block
|
34
|
+
if result and block_given?
|
35
|
+
begin
|
36
|
+
result = yield
|
37
|
+
ensure
|
38
|
+
release
|
39
|
+
end
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
def release!
|
45
|
+
unless release
|
46
|
+
raise NotLocked.new('Unable to release lock (probably did not own it)')
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def release
|
52
|
+
acquired = false
|
53
|
+
open_and_lock do |f|
|
54
|
+
acquired = owner?
|
55
|
+
if acquired
|
56
|
+
f.truncate(f.write(''))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
acquired
|
60
|
+
end
|
61
|
+
|
62
|
+
def alive?
|
63
|
+
pid = read
|
64
|
+
return pid > 0 ? Process.kill(0, pid) > 0 : false
|
65
|
+
rescue
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
|
69
|
+
def owner?
|
70
|
+
pid = read
|
71
|
+
pid and pid > 0 and pid == Process.pid
|
72
|
+
end
|
73
|
+
|
74
|
+
def read
|
75
|
+
open_and_lock{|f| f.read.to_i}
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def acquire_without_block
|
81
|
+
result = false
|
82
|
+
open_and_lock do |f|
|
83
|
+
result = owner? || ! alive?
|
84
|
+
if result
|
85
|
+
f.rewind
|
86
|
+
f.truncate(f.write(Process.pid))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
def open_and_lock
|
93
|
+
old_locked_file = @locked_file
|
94
|
+
if @locked_file
|
95
|
+
@locked_file.rewind
|
96
|
+
return yield @locked_file
|
97
|
+
else
|
98
|
+
File.open(@filename, 'r+') do |f|
|
99
|
+
lock(f) do
|
100
|
+
@locked_file = f
|
101
|
+
return yield f
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
ensure
|
106
|
+
@locked_file = old_locked_file
|
107
|
+
end
|
108
|
+
|
109
|
+
def lock(file, blocking = true)
|
110
|
+
file.flock(blocking ? File::LOCK_EX : File::LOCK_EX | File::LOCK_NB)
|
111
|
+
return yield
|
112
|
+
ensure
|
113
|
+
file.flock(File::LOCK_UN)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'process_lock/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "process_lock"
|
8
|
+
spec.version = ProcessLock::VERSION
|
9
|
+
spec.authors = ["Simon Engledew", "Ian Heggie"]
|
10
|
+
spec.email = ["ian@heggie.biz"]
|
11
|
+
spec.description = %q{A simple class to aquire and check process-id file based locks on a unix filesystem.}
|
12
|
+
spec.summary = %q{Use process lock to see if a process is already running or designate a master process when running concurrent applications.}
|
13
|
+
spec.homepage = "https://github.com/ianheggie/ruby-process-lock"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec", '~> 2.0'
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# For testing with jruby because it doesnt have fork
|
4
|
+
# and it was a pain getting the script right from ruby system call.
|
5
|
+
|
6
|
+
file=${1:-/dev/null}
|
7
|
+
secs=${2:-0}
|
8
|
+
(
|
9
|
+
sleep ${secs} <&- >&- 2>&- &
|
10
|
+
echo $! > "$file"
|
11
|
+
echo "Background process: sleep $secs & echo $! > $file"
|
12
|
+
) &
|
13
|
+
wait
|
14
|
+
exit 0
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
describe 'ProcessLock' do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
FileUtils.mkdir_p('tmp')
|
9
|
+
FileUtils.rm_f Dir.glob('tmp/example*.tmp')
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#acquire' do
|
13
|
+
|
14
|
+
it 'should acquire a lock when called without a block' do
|
15
|
+
p = ProcessLock.new('tmp/example1.txt')
|
16
|
+
p.should_not be_owner
|
17
|
+
p.acquire.should be_true
|
18
|
+
p.should be_owner
|
19
|
+
p.should be_alive
|
20
|
+
p.release.should be_true
|
21
|
+
p.should_not be_owner
|
22
|
+
p.should_not be_alive
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should acquire a lock when called with a block and then release it' do
|
26
|
+
p = ProcessLock.new('tmp/example2.txt')
|
27
|
+
p.should_not be_owner
|
28
|
+
did_something = false
|
29
|
+
p.acquire do
|
30
|
+
did_something = true
|
31
|
+
p.should be_owner
|
32
|
+
p.should be_alive
|
33
|
+
'value from block'
|
34
|
+
end.should == 'value from block'
|
35
|
+
did_something.should be_true
|
36
|
+
p.should_not be_owner
|
37
|
+
p.should_not be_alive
|
38
|
+
end
|
39
|
+
|
40
|
+
def acquire_and_then_return_block_value(pl)
|
41
|
+
pl.acquire do
|
42
|
+
@acquired_lock = true
|
43
|
+
pl.should be_owner
|
44
|
+
pl.should be_alive
|
45
|
+
return yield
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should acquire a lock when called with a block containing a return and then release it' do
|
50
|
+
p = ProcessLock.new('tmp/example3.txt')
|
51
|
+
p.should_not be_owner
|
52
|
+
acquire_and_then_return_block_value(p) do
|
53
|
+
'value returned by block'
|
54
|
+
end.should == 'value returned by block'
|
55
|
+
p.should_not be_owner
|
56
|
+
p.should_not be_alive
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should not acquire a lock if some other process has the lock' do
|
60
|
+
fn = 'tmp/example4.txt'
|
61
|
+
system('bash spec/other_process.sh "%s" 100' % fn)
|
62
|
+
p = ProcessLock.new(fn)
|
63
|
+
200.times do |i|
|
64
|
+
break if p.read > 0
|
65
|
+
sleep(0.5)
|
66
|
+
puts "waited #{i+1} times" if i > 2
|
67
|
+
end
|
68
|
+
pid = p.read
|
69
|
+
puts "+ps -fp %d" % pid
|
70
|
+
system "ps -fp %d" % pid
|
71
|
+
# other process should have acquired the lock
|
72
|
+
p.should_not be_owner
|
73
|
+
p.should be_alive
|
74
|
+
p.acquire.should be_false
|
75
|
+
p.should_not be_owner
|
76
|
+
p.should be_alive
|
77
|
+
# also try block
|
78
|
+
did_something = false
|
79
|
+
p.acquire do
|
80
|
+
did_something = true
|
81
|
+
'Some value'
|
82
|
+
end.should be_false
|
83
|
+
did_something.should be_false
|
84
|
+
p.should_not be_owner
|
85
|
+
p.should be_alive
|
86
|
+
Process.kill(9, pid) if pid> 0
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should acquire a lock if an completed process has the lock' do
|
90
|
+
fn = 'tmp/example5.txt'
|
91
|
+
system('bash spec/other_process.sh "%s" 0' % fn)
|
92
|
+
p = ProcessLock.new(fn)
|
93
|
+
200.times do |i|
|
94
|
+
break if p.read > 0 && ! p.alive?
|
95
|
+
sleep(0.5)
|
96
|
+
puts "waited #{i+1} times" if i > 2
|
97
|
+
end
|
98
|
+
|
99
|
+
p = ProcessLock.new(fn)
|
100
|
+
p.should_not be_owner
|
101
|
+
p.should_not be_alive
|
102
|
+
p.acquire.should be_true
|
103
|
+
p.should be_owner
|
104
|
+
p.should be_alive
|
105
|
+
p.release
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should allow multiple sequential locked sections' do
|
109
|
+
3.times do
|
110
|
+
p = ProcessLock.new('tmp/example6.txt')
|
111
|
+
p.should_not be_owner
|
112
|
+
did_something = false
|
113
|
+
p.acquire do
|
114
|
+
did_something = true
|
115
|
+
p.should be_owner
|
116
|
+
p.should be_alive
|
117
|
+
end.should be_true
|
118
|
+
p.should_not be_owner
|
119
|
+
p.should_not be_alive
|
120
|
+
did_something.should be_true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should allow multiple parallel but differently named locked sections' do
|
125
|
+
ps = 3.times.collect { |i| ProcessLock.new('tmp/example7-%d.txt' % i) }
|
126
|
+
did_something = 0
|
127
|
+
ps.each do |p|
|
128
|
+
p.should_not be_owner
|
129
|
+
p.acquire
|
130
|
+
p.should be_owner
|
131
|
+
p.should be_alive
|
132
|
+
end
|
133
|
+
ps.each do |p|
|
134
|
+
p.should be_owner
|
135
|
+
p.should be_alive
|
136
|
+
p.release
|
137
|
+
p.should_not be_owner
|
138
|
+
p.should_not be_alive
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '#acquire!' do
|
145
|
+
|
146
|
+
it 'should call acquire and expect true' do
|
147
|
+
p = ProcessLock.new('tmp/example8.txt')
|
148
|
+
p.stub(:acquire_without_block).and_return(true)
|
149
|
+
p.acquire!.should be_true
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'throw an error if acquire returns false' do
|
153
|
+
p = ProcessLock.new('tmp/example9.txt')
|
154
|
+
p.stub(:acquire_without_block).and_return(false)
|
155
|
+
expect { p.acquire! }.to raise_error(ProcessLock::AlreadyLocked)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should acquire a lock when called with a block and then release it' do
|
159
|
+
p = ProcessLock.new('tmp/example2.txt')
|
160
|
+
p.should_not be_owner
|
161
|
+
did_something = false
|
162
|
+
p.acquire! do
|
163
|
+
did_something = true
|
164
|
+
p.should be_owner
|
165
|
+
p.should be_alive
|
166
|
+
'some value'
|
167
|
+
end.should == 'some value'
|
168
|
+
did_something.should be_true
|
169
|
+
p.should_not be_owner
|
170
|
+
p.should_not be_alive
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#release!' do
|
176
|
+
|
177
|
+
it 'should call release and expect true' do
|
178
|
+
p = ProcessLock.new('tmp/example10.txt')
|
179
|
+
p.stub(:release).and_return(true)
|
180
|
+
p.release!.should be_true
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'throw an error if release returns false' do
|
184
|
+
p = ProcessLock.new('tmp/example11.txt')
|
185
|
+
p.stub(:release).and_return(false)
|
186
|
+
expect { p.release! }.to raise_error(ProcessLock::NotLocked)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
describe '#read' do
|
192
|
+
|
193
|
+
it 'should return the current PID if the lock was acquired' do
|
194
|
+
p = ProcessLock.new('tmp/example12.txt')
|
195
|
+
p.acquire do
|
196
|
+
p.read.should == Process.pid
|
197
|
+
p.should be_alive
|
198
|
+
end
|
199
|
+
p.should_not be_alive
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'should return whatever number is in the file' do
|
203
|
+
p = ProcessLock.new('tmp/example13.txt')
|
204
|
+
File.open(p.filename, 'w') do |f|
|
205
|
+
f.puts('314152653')
|
206
|
+
end
|
207
|
+
p.read.should == 314152653
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#filename' do
|
213
|
+
|
214
|
+
it 'should return the filename' do
|
215
|
+
fn = 'tmp/example14.txt'
|
216
|
+
p = ProcessLock.new(fn)
|
217
|
+
p.filename.should == fn
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should use a string for the current PID in filename' do
|
222
|
+
p = ProcessLock.new('tmp/example15.txt')
|
223
|
+
p.acquire do
|
224
|
+
File.open(p.filename, 'r') do |f|
|
225
|
+
contents = f.read
|
226
|
+
contents.should == Process.pid.to_s
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
data/spec/run_example.sh
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
irb='irb -f --inspect -I lib --prompt simple '
|
2
|
+
rm -f tmp/example.tmp
|
3
|
+
set -x
|
4
|
+
(
|
5
|
+
$irb > ,irb1.out <<EOF
|
6
|
+
require 'process_lock'
|
7
|
+
Process.pid
|
8
|
+
p = ProcessLock.new('tmp/example.tmp')
|
9
|
+
p.alive?
|
10
|
+
p.owner?
|
11
|
+
p.read
|
12
|
+
p.acquire!
|
13
|
+
p.alive?
|
14
|
+
p.owner?
|
15
|
+
p.read
|
16
|
+
sleep(10)
|
17
|
+
p.release!
|
18
|
+
p.alive?
|
19
|
+
p.owner?
|
20
|
+
p.read
|
21
|
+
EOF
|
22
|
+
) &
|
23
|
+
|
24
|
+
(
|
25
|
+
sleep 2
|
26
|
+
$irb <<EOF
|
27
|
+
require 'process_lock'
|
28
|
+
Process.pid
|
29
|
+
q = ProcessLock.new('tmp/example.tmp')
|
30
|
+
q.alive?
|
31
|
+
q.owner?
|
32
|
+
q.read
|
33
|
+
q.acquire!
|
34
|
+
q.alive?
|
35
|
+
q.owner?
|
36
|
+
q.read
|
37
|
+
EOF
|
38
|
+
) | tee ,irb2.out
|
39
|
+
|
40
|
+
wait
|
41
|
+
|
42
|
+
exit
|
43
|
+
|
44
|
+
IRB1.9(1) General Commands Manual IRB1.9(1)
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
NAME
|
49
|
+
irb1.9.1 - interactive ruby
|
50
|
+
|
51
|
+
SYNOPSIS
|
52
|
+
irb [options]
|
53
|
+
|
54
|
+
DESCRIPTION
|
55
|
+
irb stands for `interactive ruby'. irb is a tool to execute interac‐
|
56
|
+
tively ruby expressions read from stdin. Use of irb is easy if you
|
57
|
+
know ruby. Executing irb, prompts are displayed as follows. Then,
|
58
|
+
enter expression of ruby. A input is executed when it is syntacticaly
|
59
|
+
completed.
|
60
|
+
|
61
|
+
$ irb1.9.1
|
62
|
+
irb(main):001:0> 1+2
|
63
|
+
3
|
64
|
+
irb(main):002:0> class Foo
|
65
|
+
irb(main):003:1> def foo
|
66
|
+
irb(main):004:2> print 1
|
67
|
+
irb(main):005:2> end
|
68
|
+
irb(main):006:1> end
|
69
|
+
nil
|
70
|
+
irb(main):007:0>
|
71
|
+
|
72
|
+
And, Readline extesion module can be used with irb. Using Readline is
|
73
|
+
the standard default action if Readline is installed.
|
74
|
+
|
75
|
+
OPTIONS
|
76
|
+
-f suppress read ~/.irbrc
|
77
|
+
|
78
|
+
-m bc mode (fraction or matrix are available)
|
79
|
+
|
80
|
+
-d set $DEBUG to true (same as `ruby -d')
|
81
|
+
|
82
|
+
-r load-module
|
83
|
+
same as `ruby -r'
|
84
|
+
|
85
|
+
--inspect
|
86
|
+
uses `inspect' for output (the default except bc mode)
|
87
|
+
|
88
|
+
--noinspect
|
89
|
+
doesn't uses inspect for output
|
90
|
+
|
91
|
+
--readline
|
92
|
+
uses Readline extension module
|
93
|
+
|
94
|
+
--noreadline
|
95
|
+
doesn't use Readline extension module
|
96
|
+
|
97
|
+
--prompt prompt-mode
|
98
|
+
|
99
|
+
--prompt-mode prompt-mode
|
100
|
+
switches prompt mode. Pre-defined prompt modes are `default',
|
101
|
+
`simple', `xmp' and `inf-ruby'
|
102
|
+
|
103
|
+
--inf-ruby-mode
|
104
|
+
uses prompt appreciate for inf-ruby-mode on emacs. Suppresses
|
105
|
+
--readline.
|
106
|
+
|
107
|
+
--simple-prompt
|
108
|
+
simple prompt mode
|
109
|
+
|
110
|
+
--noprompt
|
111
|
+
no prompt
|
112
|
+
|
113
|
+
--tracer
|
114
|
+
display trace for each execution of commands.
|
115
|
+
|
116
|
+
--back-trace-limit n
|
117
|
+
displayes backtrace top n and tail n. The default value is 16.
|
118
|
+
|
119
|
+
--irb_debug n
|
120
|
+
sets internal debug level to n (It shouldn't be used)
|
121
|
+
|
122
|
+
-v, --version
|
123
|
+
prints the version of irb
|
124
|
+
|
125
|
+
CONFIGURATIONS
|
126
|
+
irb reads `~/.irbrc' when it is invoked. If `~/.irbrb' doesn't exist
|
127
|
+
irb try to read in the order `.irbrc', `irb.rc', `_irbrc' then
|
128
|
+
`$irbrc'. The following is altanative to the command line option. To
|
129
|
+
use them type as follows in an irb session.
|
130
|
+
|
131
|
+
IRB.conf[:IRB_NAME]="irb"
|
132
|
+
IRB.conf[:MATH_MODE]=false
|
133
|
+
IRB.conf[:USE_TRACER]=false
|
134
|
+
IRB.conf[:USE_LOADER]=false
|
135
|
+
IRB.conf[:IGNORE_SIGINT]=true
|
136
|
+
IRB.conf[:IGNORE_EOF]=false
|
137
|
+
IRB.conf[:INSPECT_MODE]=nil
|
138
|
+
IRB.conf[:IRB_RC] = nil
|
139
|
+
IRB.conf[:BACK_TRACE_LIMIT]=16
|
140
|
+
IRB.conf[:USE_LOADER] = false
|
141
|
+
IRB.conf[:USE_READLINE] = nil
|
142
|
+
IRB.conf[:USE_TRACER] = false
|
143
|
+
IRB.conf[:IGNORE_SIGINT] = true
|
144
|
+
IRB.conf[:IGNORE_EOF] = false
|
145
|
+
IRB.conf[:PROMPT_MODE] = :DEFALUT
|
146
|
+
IRB.conf[:PROMPT] = {...}
|
147
|
+
IRB.conf[:DEBUG_LEVEL]=0
|
148
|
+
IRB.conf[:VERBOSE]=true
|
149
|
+
|
150
|
+
Customizing prompt
|
151
|
+
To costomize the prompt you set a variable
|
152
|
+
|
153
|
+
IRB.conf[:PROMPT]
|
154
|
+
|
155
|
+
For example, describe as follows in `.irbrc'.
|
156
|
+
|
157
|
+
IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
|
158
|
+
:PROMPT_I => nil, # normal prompt
|
159
|
+
:PROMPT_S => nil, # prompt for continuated strings
|
160
|
+
:PROMPT_C => nil, # prompt for continuated statement
|
161
|
+
:RETURN => " ==>%s\n" # format to return value
|
162
|
+
}
|
163
|
+
|
164
|
+
Then, invoke irb with the above prompt mode by
|
165
|
+
|
166
|
+
$ irb1.9.1 --prompt my-prompt
|
167
|
+
|
168
|
+
Or add the following in `.irbrc'.
|
169
|
+
|
170
|
+
IRB.conf[:PROMPT_MODE] = :MY_PROMPT
|
171
|
+
|
172
|
+
Constants PROMPT_I, PROMPT_S and PROMPT_C specifies the format. In the
|
173
|
+
prompt specification, some special strings are available.
|
174
|
+
|
175
|
+
%N command name which is running
|
176
|
+
%m to_s of main object (self)
|
177
|
+
%M inspect of main object (self)
|
178
|
+
%l type of string(", ', /, ]), `]' is inner %w[...]
|
179
|
+
%NNi indent level. NN is degits and means as same as printf("%NNd").
|
180
|
+
It can be ommited
|
181
|
+
%NNn line number.
|
182
|
+
%% %
|
183
|
+
For instance, the default prompt mode is defined as follows:
|
184
|
+
IRB.conf[:PROMPT_MODE][:DEFAULT] = {
|
185
|
+
|
186
|
+
PROMPT_I => "%N(%m):%03n:%i> ",
|
187
|
+
|
188
|
+
PROMPT_S => "%N(%m):%03n:%i%l ",
|
189
|
+
|
190
|
+
PROMPT_C => "%N(%m):%03n:%i* ",
|
191
|
+
|
192
|
+
RETURN => "%s\n"}
|
193
|
+
RETURN is used to printf.
|
194
|
+
|
195
|
+
Configurating subirb
|
196
|
+
The command line option or IRB.conf specify the default behavior of
|
197
|
+
(sub)irb. On the other hand, each conf of in the next sction `6. Com‐
|
198
|
+
mand' is used to individually configurate (sub)irb. If proc is set to
|
199
|
+
IRB.conf[:IRB_RC], its subirb will be invoked after execution of that
|
200
|
+
proc under giving the context of irb as its aregument. By this mecha‐
|
201
|
+
nism each subirb can be configurated.
|
202
|
+
|
203
|
+
Command
|
204
|
+
For irb commands, both simple name and `irb_'-prefixed name are pre‐
|
205
|
+
pared.
|
206
|
+
|
207
|
+
exit, quit, irb_exit
|
208
|
+
Quits (sub)irb. if you've done cb (see below), exit from the
|
209
|
+
binding mode.
|
210
|
+
|
211
|
+
|
212
|
+
conf, irb_context
|
213
|
+
Displays current configuration. Modifing the configuration is
|
214
|
+
achieved by sending message to `conf'.
|
215
|
+
|
216
|
+
conf.back_trace_limit
|
217
|
+
Sets display lines of backtrace as top n and tail n. The
|
218
|
+
default value is 16.
|
219
|
+
|
220
|
+
conf.debug_level = N
|
221
|
+
Sets debug level of irb.
|
222
|
+
|
223
|
+
conf.ignore_eof = true/false
|
224
|
+
Whether ^D (control-d) will be ignored or not. If false is set,
|
225
|
+
^D means quit.
|
226
|
+
|
227
|
+
conf.ignore_sigint= true/false
|
228
|
+
Whether ^C (control-c) will be ignored or not. If false is set,
|
229
|
+
^D means quit. If true,
|
230
|
+
during input: cancel inputing then return to top level.
|
231
|
+
during execute: abondon current execution.
|
232
|
+
|
233
|
+
conf.inf_ruby_mode = true/false
|
234
|
+
Whether inf-ruby-mode or not. The default value is false.
|
235
|
+
|
236
|
+
conf.inspect_mode = true/false/nil
|
237
|
+
Specifies inspect mode. true: display inspect false: display
|
238
|
+
to_s nil: inspect mode in non math mode,
|
239
|
+
non inspect mode in math mode.
|
240
|
+
|
241
|
+
conf.irb_level
|
242
|
+
The level of cb.
|
243
|
+
|
244
|
+
conf.math_mode
|
245
|
+
Whether bc mode or not.
|
246
|
+
|
247
|
+
conf.use_loader = true/false
|
248
|
+
Whether irb's own file reader method is used when load/require
|
249
|
+
or not. This mode is globaly affected (irb wide).
|
250
|
+
|
251
|
+
conf.prompt_c
|
252
|
+
prompt for a continuating statement (e.g, immediately after of
|
253
|
+
`if')
|
254
|
+
|
255
|
+
conf.prompt_i
|
256
|
+
standard prompt
|
257
|
+
|
258
|
+
conf.prompt_s
|
259
|
+
prompt for a continuating string
|
260
|
+
|
261
|
+
conf.rc
|
262
|
+
Whether ~/.irbrc is read or not.
|
263
|
+
|
264
|
+
conf.use_prompt = true/false
|
265
|
+
Prompting or not.
|
266
|
+
|
267
|
+
conf.use_readline = true/false/nil
|
268
|
+
Whether readline is used or not. true: uses false: doen't use
|
269
|
+
nil: intends to use readline except for inf-reuby-mode (default)
|
270
|
+
|
271
|
+
conf.verbose=T/F
|
272
|
+
Whether verbose messages are display or not.
|
273
|
+
|
274
|
+
cb, irb_change_binding [obj]
|
275
|
+
Enter new binding which has a distinct scope of local variables.
|
276
|
+
If obj is given, obj will be self.
|
277
|
+
|
278
|
+
irb [obj]
|
279
|
+
Invoke subirb. If obj is given, obj will be self.
|
280
|
+
|
281
|
+
jobs, irb_jobs
|
282
|
+
List of subirb
|
283
|
+
|
284
|
+
fg n, irb_fg n
|
285
|
+
Switch into specified subirb. The following is candidates of n:
|
286
|
+
irb number
|
287
|
+
thhread
|
288
|
+
irb object
|
289
|
+
self(obj which is specified of irb obj)
|
290
|
+
|
291
|
+
kill n, irb_kill n
|
292
|
+
Kill subirb. The means of n is as same as the case of irb_fg.
|
293
|
+
|
294
|
+
System variable
|
295
|
+
_ The latest value of evaluation (it is local)
|
296
|
+
|
297
|
+
Session Example
|
298
|
+
$ irb1.9.1
|
299
|
+
irb(main):001:0> irb # invoke subirb
|
300
|
+
irb#1(main):001:0> jobs # list of subirbs
|
301
|
+
#0->irb on main (#<Thread:0x400fb7e4> : stop)
|
302
|
+
#1->irb#1 on main (#<Thread:0x40125d64> : running)
|
303
|
+
nil
|
304
|
+
irb#1(main):002:0> fg 0 # switch job
|
305
|
+
nil
|
306
|
+
irb(main):002:0> class Foo;end
|
307
|
+
nil
|
308
|
+
irb(main):003:0> irb Foo # invoke subirb which has the
|
309
|
+
# context of Foo
|
310
|
+
irb#2(Foo):001:0> def foo # define Foo#foo
|
311
|
+
irb#2(Foo):002:1> print 1
|
312
|
+
irb#2(Foo):003:1> end
|
313
|
+
nil
|
314
|
+
irb#2(Foo):004:0> fg 0 # switch job
|
315
|
+
nil
|
316
|
+
irb(main):004:0> jobs # list of job
|
317
|
+
#0->irb on main (#<Thread:0x400fb7e4> : running)
|
318
|
+
#1->irb#1 on main (#<Thread:0x40125d64> : stop)
|
319
|
+
#2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
|
320
|
+
nil
|
321
|
+
irb(main):005:0> Foo.instance_methods # Foo#foo is defined asurely
|
322
|
+
["foo"]
|
323
|
+
irb(main):006:0> fg 2 # switch job
|
324
|
+
nil
|
325
|
+
irb#2(Foo):005:0> def bar # define Foo#bar
|
326
|
+
irb#2(Foo):006:1> print "bar"
|
327
|
+
irb#2(Foo):007:1> end
|
328
|
+
nil
|
329
|
+
irb#2(Foo):010:0> Foo.instance_methods
|
330
|
+
["bar", "foo"]
|
331
|
+
irb#2(Foo):011:0> fg 0
|
332
|
+
nil
|
333
|
+
irb(main):007:0> f = Foo.new
|
334
|
+
#<Foo:0x4010af3c>
|
335
|
+
irb(main):008:0> irb f # invoke subirb which has the
|
336
|
+
# context of f (instance of Foo)
|
337
|
+
irb#3(#<Foo:0x4010af3c>):001:0> jobs
|
338
|
+
#0->irb on main (#<Thread:0x400fb7e4> : stop)
|
339
|
+
#1->irb#1 on main (#<Thread:0x40125d64> : stop)
|
340
|
+
#2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
|
341
|
+
#3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running)
|
342
|
+
nil
|
343
|
+
irb#3(#<Foo:0x4010af3c>):002:0> foo # evaluate f.foo
|
344
|
+
1nil
|
345
|
+
irb#3(#<Foo:0x4010af3c>):003:0> bar # evaluate f.bar
|
346
|
+
barnil
|
347
|
+
irb#3(#<Foo:0x4010af3c>):004:0> kill 1, 2, 3# kill job
|
348
|
+
nil
|
349
|
+
irb(main):009:0> jobs
|
350
|
+
#0->irb on main (#<Thread:0x400fb7e4> : running)
|
351
|
+
nil
|
352
|
+
irb(main):010:0> exit # exit
|
353
|
+
|
354
|
+
Restrictions
|
355
|
+
Because irb evaluates the inputs immediately after the imput is syntac‐
|
356
|
+
tically completed, irb gives slight different result than directly use
|
357
|
+
ruby. Known difference is pointed out here.
|
358
|
+
|
359
|
+
Declaration of the local variable
|
360
|
+
The following causes an error in ruby:
|
361
|
+
|
362
|
+
eval "foo = 0"
|
363
|
+
foo
|
364
|
+
--
|
365
|
+
-:2: undefined local variable or method `foo' for #<Object:0x40283118> (NameError)
|
366
|
+
---
|
367
|
+
NameError
|
368
|
+
|
369
|
+
Though, the above will successfully done by irb.
|
370
|
+
|
371
|
+
>> eval "foo = 0"
|
372
|
+
=> 0
|
373
|
+
>> foo
|
374
|
+
=> 0
|
375
|
+
|
376
|
+
Ruby evaluates a code after reading entire of code and determination of
|
377
|
+
the scope of local variables. On the other hand, irb do immediately.
|
378
|
+
More precisely, irb evaluate at first
|
379
|
+
|
380
|
+
evel "foo = 0"
|
381
|
+
|
382
|
+
then foo is defined on this timing. It is because of this incompatibil‐
|
383
|
+
ity. If you'd like to detect those differences, begin...end can be
|
384
|
+
used:
|
385
|
+
|
386
|
+
>> begin
|
387
|
+
?> eval "foo = 0"
|
388
|
+
>> foo
|
389
|
+
>> end
|
390
|
+
NameError: undefined local variable or method `foo' for #<Object:0x4013d0f0>
|
391
|
+
(irb):3
|
392
|
+
(irb_local_binding):1:in `eval'
|
393
|
+
|
394
|
+
Here-document
|
395
|
+
Implementation of Here-document is incomplete.
|
396
|
+
|
397
|
+
Symbol
|
398
|
+
Irb can not always recognize a symbol as to be Symbol. Concretely, an
|
399
|
+
expression have completed, however Irb regard it as continuation line.
|
400
|
+
|
401
|
+
|
402
|
+
|
403
|
+
|
404
|
+
December 2002 IRB1.9(1)
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require 'process_lock'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: process_lock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Simon Engledew
|
9
|
+
- Ian Heggie
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bundler
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.3'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.3'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rake
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '2.0'
|
63
|
+
description: A simple class to aquire and check process-id file based locks on a unix
|
64
|
+
filesystem.
|
65
|
+
email:
|
66
|
+
- ian@heggie.biz
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- .rspec
|
73
|
+
- .travis.yml
|
74
|
+
- Gemfile
|
75
|
+
- Gemfile.lock
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/process_lock.rb
|
79
|
+
- lib/process_lock/version.rb
|
80
|
+
- process_lock.gemspec
|
81
|
+
- spec/other_process.sh
|
82
|
+
- spec/process_lock_spec.rb
|
83
|
+
- spec/run_example.sh
|
84
|
+
- spec/spec_helper.rb
|
85
|
+
homepage: https://github.com/ianheggie/ruby-process-lock
|
86
|
+
licenses:
|
87
|
+
- MIT
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 1.8.23
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Use process lock to see if a process is already running or designate a master
|
110
|
+
process when running concurrent applications.
|
111
|
+
test_files:
|
112
|
+
- spec/other_process.sh
|
113
|
+
- spec/process_lock_spec.rb
|
114
|
+
- spec/run_example.sh
|
115
|
+
- spec/spec_helper.rb
|