with_lock 0.0.4.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTIxODdiOTM5NjRiZGEwMWRmYTE3NDJiMDEyMmQ5N2NiZWNhNTRiOQ==
5
+ data.tar.gz: !binary |-
6
+ NDNkNjI2MDUxMmZhYmE3OWNmZThiOTI5NzMzNjgzOTFlOTU0NTNlMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MDNhYTE5YTI3ZTE3ZWJhMTY4ODNlNWExNjI4YTQ2Y2ExNjM3NjVkM2M4OTk1
10
+ ODlhMmM4MTNlNzEyOGZkZjVjMzIyODcwZWNjMDc5NGRjM2MxOTlmYTFmZGE0
11
+ ZTBjNmFlOGRjZDgwZGU0MjA2NDNhZTJjZTc2MThjN2FkM2FjZWY=
12
+ data.tar.gz: !binary |-
13
+ NzQzMWRhZTE5YjFlZDkyODFhY2FmNzRlODdkYzcxMmQyZWFhMWI3YjgzYWI3
14
+ NThiMjNlNDExYjkzYjZmM2FiMzAyZTc0Y2M1ZjE2ZWNjMWU5NDQ5NzFmNjU3
15
+ OTFmMWY3NTZiYmRmOTgwYmFkNGFmMmU3N2Y4MzFhYzRmYmExYzY=
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ # no tmp files
2
+ /tmp
3
+
4
+ # no log files
5
+ /log
6
+
7
+ # no OS files
8
+ *.DS_Store
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in with_lock.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ with_lock (0.0.4.alpha)
5
+ daemons
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ daemons (1.1.9)
11
+ diff-lcs (1.1.3)
12
+ rspec (2.8.0)
13
+ rspec-core (~> 2.8.0)
14
+ rspec-expectations (~> 2.8.0)
15
+ rspec-mocks (~> 2.8.0)
16
+ rspec-core (2.8.0)
17
+ rspec-expectations (2.8.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.8.0)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ rspec
26
+ with_lock!
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # WithLock
2
+
3
+ Provides a DRb service to provide locking across a distributed ruby application.
4
+
5
+ ## Installation
6
+
7
+ Add to your Gemfile and run the `bundle` command to install it.
8
+
9
+ ```ruby
10
+ gem "with_lock", git: 'https://github.com/chrisboy333/with_lock.git'
11
+ ```
12
+
13
+ **Tested under Ruby 1.9.3.**
14
+
15
+ Add script and config files to your project(from console):
16
+ ```ruby
17
+ WithLock.setup
18
+ ```
19
+ In the configuration file you can change some settings if you like ... it defaults to using the following... where 'scope' is the application directory name with rails environment appended(if present):
20
+ url: druby://loclahost:9999
21
+ scope: <%= File.basename(File.expand_path('.')) %><%= ":#{Rails.env}" if defined?(Rails) %>
22
+ directory: tmp
23
+
24
+ The scope is used to let different applications use the same drb server ... or different parts of an app acquire the same named locks(not that I think this latter is a great idea) ...
25
+
26
+ Start/Stop the service from ruby
27
+ ```ruby
28
+ WithLock::Server.start_service
29
+ WithLock::Server.stop_service
30
+ ```
31
+ Start/Stop service from
32
+
33
+ ## Usage
34
+ A "with_lock()" function is provided globally to wrap with_lock sections of code.
35
+
36
+ ```ruby
37
+ with_lock('lock_name') do
38
+ puts "This is something only I can do right now, provided others are using the locks!"
39
+ end
40
+ ```
41
+ ## Development
42
+
43
+ Questions or problems? Please post them on the [issue tracker](https://github.com/chrisboy333/with_lock/issues). You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`.
44
+
45
+ This gem is created by Christopher Hauboldt and is under the MIT License.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ desc 'Run the specs'
5
+ RSpec::Core::RakeTask.new do |r|
6
+ r.verbose = false
7
+ end
8
+
9
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ url: druby://localhost:9999
2
+ scope: <%= File.basename(File.expand_path('.')) %><%= ":#{Rails.env}" if defined?(Rails) %>
3
+ directory: 'tmp'
@@ -0,0 +1,3 @@
1
+ url: druby://localhost:9999
2
+ scope: <%= File.basename(File.expand_path('.')) %><%= ":#{Rails.env}" if defined?(Rails) %>
3
+ directory: 'tmp'
data/lib/with_lock.rb ADDED
@@ -0,0 +1,89 @@
1
+ require "with_lock/version"
2
+ require 'erb'
3
+ require 'yaml'
4
+ require 'fileutils'
5
+ require 'logger'
6
+
7
+ module WithLock
8
+ class LockException < Exception
9
+ end
10
+
11
+ def self.setup
12
+ gem_dir = File.expand_path(File.join('..','..'),__FILE__)
13
+ app_dir = File.expand_path('.')
14
+ FileUtils.cp(File.join(gem_dir,'config','with_lock.yml'),File.join(app_dir,'config','with_lock.yml'))
15
+ FileUtils.cp(File.join(gem_dir,'script','with_lock'),File.join(app_dir,'script','with_lock'))
16
+ FileUtils.chmod(0755, File.join(app_dir,'script','with_lock'))
17
+ true
18
+ end
19
+
20
+ module Public
21
+ def with_lock(name,timeout=5,&block)
22
+ WithLock::Client.with_lock(name,timeout) do
23
+ yield
24
+ end
25
+ end
26
+ end
27
+
28
+ module Common
29
+ def logger
30
+ return @@logger if defined?(@@logger) && !@@logger.nil?
31
+ @@logger = nil
32
+ @@logger = Rails.logger if defined?(Rails)
33
+ FileUtils.mkdir_p('log') if @@logger.nil?
34
+ @@logger ||= Logger.new(File.join('log','with_lock.log'))
35
+ end
36
+
37
+ def url
38
+ settings['url']
39
+ end
40
+
41
+ def pidfile
42
+ File.join('tmp','pids','with_lock.pid')
43
+ end
44
+
45
+ def pid
46
+ File.read(pidfile).strip
47
+ rescue => e
48
+ nil
49
+ end
50
+
51
+ def running?(pid)
52
+ `ps -p#{pid} | wc -l`.to_i == 2
53
+ end
54
+
55
+ def settings_filename
56
+ File.join('config','with_lock.yml')
57
+ end
58
+
59
+ def local_settings_filename
60
+ File.join('config','with_lock.local.yml')
61
+ end
62
+
63
+ def settings
64
+ return @@settings if defined? @@settings
65
+ @@settings = default_settings
66
+ @@settings = @@settings.merge!(load_settings(settings_filename)||{}) if File.exists?(settings_filename)
67
+ @@settings.merge!(load_settings(local_settings_filename)||{}) if File.exists?(local_settings_filename)
68
+ @@settings
69
+ end
70
+
71
+ def default_settings
72
+ {
73
+ 'directory' => File.join('tmp'),
74
+ 'url' => "druby://localhost:9999",
75
+ 'scope' => "#{File.basename(File.expand_path('.'))}#{":#{Rails.env}" if defined?(Rails)}"
76
+ }
77
+ end
78
+
79
+ def load_settings(filename)
80
+ YAML.load(ERB.new(File.read(filename)).result)
81
+ end
82
+ end
83
+ end
84
+
85
+ WithLock::Public.respond_to?(:with_lock)
86
+
87
+ require 'with_lock/server'
88
+ require 'with_lock/client'
89
+ Object.send :include, WithLock::Public
@@ -0,0 +1,76 @@
1
+ class WithLock::Client
2
+ extend WithLock::Common
3
+ @@locker = nil
4
+
5
+ def self.scoped_name(name)
6
+ "#{scope}-#{name}"
7
+ end
8
+
9
+ def self.identity
10
+ "#{`hostname`.strip}|#{$$}"
11
+ end
12
+
13
+ def self.get(name,timeout=5)
14
+ locker.get(identity,scoped_name(name),timeout)
15
+ end
16
+
17
+ def self.release(name)
18
+ locker.release(identity,scoped_name(name))
19
+ end
20
+
21
+ def self.mine?(name)
22
+ locker.mine?(identity,scoped_name(name))
23
+ end
24
+
25
+ def self.with_lock(name, timeout=5, &block)
26
+ begin
27
+ locked = mine?(name) && increment(name)
28
+ locked ||= get(name,timeout) || raise(WithLock::LockException.new("Failed to obtain lock #{name} in #{timeout} seconds."))
29
+ yield
30
+ ensure
31
+ if locker_available?
32
+ decrement(name).to_i > 0 || release(name) || logger.debug("Warning: lock #{name} not released!")
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.locker_available?
38
+ locker.url
39
+ true
40
+ rescue DRb::DRbConnError => e
41
+ false
42
+ end
43
+
44
+ def self.increment(name)
45
+ locker.increment(identity,scoped_name(name))
46
+ end
47
+
48
+ def self.decrement(name)
49
+ locker.decrement(identity,scoped_name(name))
50
+ end
51
+
52
+ def self.scope
53
+ @@scope ||= Rails.env if defined? Rails
54
+ @@scope ||= File.expand_path('.').split(File::SEPARATOR).last
55
+ end
56
+
57
+ def self.reconnect!
58
+ DRb.stop_service
59
+ @@uri = DRb.start_service
60
+ @@locker = DRbObject.new_with_uri(url)
61
+ end
62
+
63
+ def self.locker
64
+ return @@locker if (@@locker.url rescue false)
65
+ @@locker = nil
66
+ tries = 3
67
+ while @@locker.nil? && tries > 0 do
68
+ sleep 0.2 if tries < 3
69
+ tries -= 1
70
+ reconnect!
71
+ @@locker = nil unless (@@locker.url rescue false)
72
+ end
73
+ raise WithLock::LockException.new("Couldn't connect to locker.") if @@locker.nil?
74
+ @@locker
75
+ end
76
+ end
@@ -0,0 +1,119 @@
1
+ require 'drb'
2
+ require 'daemons'
3
+
4
+ class WithLock::Server
5
+ extend WithLock::Common
6
+
7
+ def self.mutex
8
+ @@mutex ||= Mutex.new
9
+ end
10
+
11
+ def self.owner_uri?(name)
12
+ locks[name][:owner]
13
+ rescue => e
14
+ ''
15
+ end
16
+
17
+ def self.owner_pid(name)
18
+ locks[name][:pid]
19
+ rescue => e
20
+ ''
21
+ end
22
+
23
+ def self.count(name)
24
+ locks[name][:count]
25
+ rescue => e
26
+ 0
27
+ end
28
+
29
+ def self.locked?(name)
30
+ !locks[name].nil?# && owner_active?(name)
31
+ end
32
+
33
+ def self.mine?(owner,name)
34
+ locked?(name) && locks[name][:owner].eql?(owner)
35
+ end
36
+
37
+ def self.get(owner,name,timeout=5)
38
+ endtime = Time.now.to_f + timeout.to_f
39
+ owner_uri, owner_pid = owner.split('|')
40
+ while !mine?(owner,name) && (Time.now.to_f < endtime)
41
+ mutex.synchronize do
42
+ if !locked?(name)
43
+ locks[name] = {owner: owner, count: 1}
44
+ end
45
+ end
46
+ sleep 0.01 unless mine?(owner,name)
47
+ end
48
+ mine?(owner,name)
49
+ end
50
+
51
+ def self.release(owner,name)
52
+ if mine?(owner,name)
53
+ locks.delete(name)
54
+ true
55
+ else
56
+ false
57
+ end
58
+ end
59
+
60
+ def self.increment(owner,name)
61
+ if mine?(owner,name)
62
+ locks[name][:count] += 1
63
+ end
64
+ count(name)
65
+ end
66
+
67
+ def self.decrement(owner,name)
68
+ if mine?(owner,name)
69
+ locks[name][:count] -= 1
70
+ end
71
+ count(name)
72
+ end
73
+
74
+ def self.locks
75
+ @@locks ||= {}
76
+ end
77
+
78
+ def self.write_url(url)
79
+ File.open(File.join(settings['directory'],'with_lock'),'w'){|file| file.write(url)}
80
+ end
81
+
82
+ def self.started?
83
+ pid.to_i > 0 && running?(pid)
84
+ end
85
+
86
+ def self.daemon_settings
87
+ {
88
+ :multiple => false,
89
+ :ontop => false,
90
+ :backtrace => true,
91
+ :log_output => true,
92
+ :monitor => false,
93
+ :dir_mode => :normal,
94
+ :dir => 'tmp/pids'
95
+ }
96
+ end
97
+
98
+ def self.start_service
99
+ return if started?
100
+ FileUtils.rm(pidfile) if File.exists?(pidfile)
101
+ options = daemon_settings.merge(:ARGV => ['start'])
102
+ Daemons.run_proc('with_lock', options) do
103
+ DRb.start_service(WithLock::Server::url,WithLock::Server)
104
+ DRb.thread.join
105
+ end
106
+ end
107
+
108
+ def self.run_service
109
+ return if started?
110
+ DRb.start_service(WithLock::Server::url,WithLock::Server)
111
+ DRb.thread.join
112
+ end
113
+
114
+ def self.stop_service
115
+ return unless started?
116
+ `kill #{pid}`
117
+ FileUtils.rm_f(pidfile)
118
+ end
119
+ end
@@ -0,0 +1,4 @@
1
+ module WithLock
2
+ VERSION = "0.0.4.alpha"
3
+ end
4
+
data/script/with_lock ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+ $:.push File.expand_path(File.join('..','..','lib'), __FILE__)
4
+
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup
8
+
9
+ FileUtils.mkdir_p('tmp/pids') unless File.exists?('tmp/pids')
10
+
11
+ require 'with_lock'
12
+ if ARGV.include?('start')
13
+ begin
14
+ locker = WithLock::Client.locker
15
+ rescue WithLock::LockException => e
16
+ puts "Starting WithLock on #{WithLock::Server::url}!"
17
+ WithLock::Server::start_service
18
+ locker = WithLock::Client.locker
19
+ end
20
+ puts "Clearing WithLock locks!"
21
+ locker = WithLock::Client.locker
22
+ locker.locks.each_pair do |lock,data|
23
+ pid = data[:owner].split('|').last
24
+ if locker.running?(pid) || !data[:owner].include?(`hostname`.strip)
25
+ puts "Running - pid"
26
+ else
27
+ puts "Not Running - pid"
28
+ locker.release(data[:owner],lock)
29
+ end
30
+ end
31
+ elsif ARGV.include?('stop')
32
+ puts "Stopping WithLock!"
33
+ WithLock::Server::stop_service
34
+ elsif ARGV.include?('run')
35
+ puts "Running WithLock!"
36
+ WithLock::Server::run_service
37
+ end
@@ -0,0 +1,2 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__),'..','lib'))
2
+ require 'with_lock'
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ echo $$
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ $:.push File.expand_path(File.join('..','..','lib'), __FILE__)
5
+
6
+ require "rubygems"
7
+ require "bundler"
8
+ Bundler.setup
9
+
10
+ require 'with_lock'
11
+ include WithLock::Public
12
+
13
+ begin
14
+ with_lock(ARGV[0],ARGV[1].to_f||0.5) do
15
+ sleep ARGV[2].to_f
16
+ Kernel.exit! if ARGV[3].eql?('kernel_exit')
17
+ exit(0) if ARGV[2].eql?('exit')
18
+ end
19
+ rescue WithLock::LockException => e
20
+ puts exit(1)
21
+ end
@@ -0,0 +1,130 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.join('..','spec','spec_helper'), File.dirname(__FILE__))
3
+
4
+ describe WithLock do
5
+ describe "#settings" do
6
+ it "should have default settings" do
7
+ WithLock::Client::settings.should == {
8
+ 'url' => 'druby://localhost:9999',
9
+ 'directory' => 'tmp',
10
+ 'scope' => 'with_lock'
11
+ }
12
+ end
13
+ end
14
+
15
+ describe "#url" do
16
+ it "returns the druby url from settings" do
17
+ WithLock::Client::settings['url'].should == WithLock::Client::url
18
+ end
19
+ end
20
+
21
+ describe "#running(pid)" do
22
+ it "should report if given process id represents a running pid" do
23
+ WithLock::Server::running?($$).should be_true
24
+ end
25
+ it "should report if given process id doesn't represent a running pid" do
26
+ pid = `spec/support/echo_pid.sh`.to_s.strip
27
+ sleep 0.2
28
+ WithLock::Server::running?(pid).should be_false
29
+ end
30
+ end
31
+
32
+ describe "#with_lock" do
33
+ it "should raise an exception if with_lock server not started" do
34
+ WithLock::Server.stop_service
35
+ started_trying = Time.now
36
+ while WithLock::Server.started? do
37
+ sleep 0.2
38
+ raise Exception.new("Couldn't stop server!") unless (Time.now - 3.seconds) > started_trying
39
+ end
40
+ error_message = ''
41
+ begin
42
+ with_lock('my_lock') do
43
+ "I should not get here!".should be_nil
44
+ end
45
+ rescue WithLock::LockException => e
46
+ e.message.should == "Couldn't connect to locker."
47
+ end
48
+ end
49
+ describe "when the server is running" do
50
+ before(:all) do
51
+ `script/with_lock start`
52
+ started_trying = Time.now
53
+ while !WithLock::Server.started? do
54
+ sleep 0.2
55
+ raise Exception.new("Couldn't start server!") unless (Time.now - 3.seconds) > started_trying
56
+ end
57
+ @locker = WithLock::Client.locker
58
+ end
59
+ after(:all) do
60
+ `script/with_lock stop`
61
+ while WithLock::Server.started? do
62
+ sleep 0.1
63
+ end
64
+ end
65
+ it "should grab the named lock if its not locked" do
66
+ with_lock('name') do
67
+ WithLock::Client.mine?('name').should be_true
68
+ end
69
+ end
70
+ it "should not allow another process to grab the same named lock" do
71
+ system("spec/support/get_lock.rb name 0.5 10 &")
72
+ sleep 1
73
+ expect {
74
+ with_lock('name',0.5) do
75
+ end
76
+ }.to raise_exception(WithLock::LockException)
77
+ end
78
+
79
+ it "should have a counter of 1 when it first grabs the lock" do
80
+ with_lock('blarg') do
81
+ @locker.count(WithLock::Client.scoped_name('blarg')).should == 1
82
+ end
83
+ end
84
+
85
+ it "should allow the same process to grab the same lock and increment its counter" do
86
+ with_lock('blarg') do
87
+ with_lock('blarg') do
88
+ @locker.count(WithLock::Client.scoped_name('blarg')).should == 2
89
+ end
90
+ end
91
+ end
92
+
93
+ it "should decrement a lock's counter when it ends the block" do
94
+ with_lock('blarg') do
95
+ with_lock('blarg') do
96
+ end
97
+ @locker.count(WithLock::Client.scoped_name('blarg')).should == 1
98
+ end
99
+ end
100
+
101
+ it "should release the lock when the block ends" do
102
+ with_lock('blarg') do
103
+ end
104
+ @locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
105
+ end
106
+
107
+ it "should release the lock if an exception closes the block" do
108
+ begin
109
+ with_lock('blarg') do
110
+ raise "Blarg!!"
111
+ end
112
+ rescue => e
113
+ end
114
+ @locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
115
+ end
116
+
117
+ it "should release the lock on a clean exit" do
118
+ `spec/support/get_lock.rb blarg 0.3 exit`
119
+ sleep 0.2
120
+ @locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
121
+ end
122
+
123
+ it "should release the lock on an immediate exit" do
124
+ `spec/support/get_lock.rb blarg 0.3 kernel_exit`
125
+ sleep 0.2
126
+ @locker.locks[WithLock::Client.scoped_name('blarg')].should be_nil
127
+ end
128
+ end
129
+ end
130
+ end
data/with_lock.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'with_lock/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "with_lock"
7
+ s.version = WithLock::VERSION
8
+ s.authors = ["Christopher Louis Hauboldt"]
9
+ s.email = ["chris@hauboldt.us"]
10
+ s.homepage = "https://github.com/chrisboy333/with_lock"
11
+ s.summary = %q{Implements named mutexes for ruby applications.}
12
+ s.description = %q{Implements named mutexes for ruby applications by creating a resource server to query for locks.}
13
+
14
+ s.rubyforge_project = "with_lock"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec"
22
+ s.add_dependency "daemons"
23
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: with_lock
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Christopher Louis Hauboldt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: daemons
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Implements named mutexes for ruby applications by creating a resource
42
+ server to query for locks.
43
+ email:
44
+ - chris@hauboldt.us
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - .rspec
51
+ - Gemfile
52
+ - Gemfile.lock
53
+ - README.md
54
+ - Rakefile
55
+ - config/with_lock.local.yml
56
+ - config/with_lock.yml
57
+ - lib/with_lock.rb
58
+ - lib/with_lock/client.rb
59
+ - lib/with_lock/server.rb
60
+ - lib/with_lock/version.rb
61
+ - script/with_lock
62
+ - spec/spec_helper.rb
63
+ - spec/support/echo_pid.sh
64
+ - spec/support/get_lock.rb
65
+ - spec/with_lock_spec.rb
66
+ - with_lock.gemspec
67
+ homepage: https://github.com/chrisboy333/with_lock
68
+ licenses: []
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>'
82
+ - !ruby/object:Gem::Version
83
+ version: 1.3.1
84
+ requirements: []
85
+ rubyforge_project: with_lock
86
+ rubygems_version: 2.2.2
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Implements named mutexes for ruby applications.
90
+ test_files:
91
+ - spec/spec_helper.rb
92
+ - spec/support/echo_pid.sh
93
+ - spec/support/get_lock.rb
94
+ - spec/with_lock_spec.rb