screw 0.0.1
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/.gitignore +22 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/Guardfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/lib/screw.rb +10 -0
- data/lib/screw/logger.rb +57 -0
- data/lib/screw/proxy.rb +20 -0
- data/lib/screw/queue.rb +61 -0
- data/lib/screw/semaphore.rb +51 -0
- data/lib/screw/version.rb +3 -0
- data/screw.gemspec +23 -0
- data/spec/lib/screw/logger_spec.rb +35 -0
- data/spec/lib/screw/proxy_spec.rb +70 -0
- data/spec/lib/screw/queue_spec.rb +23 -0
- data/spec/lib/screw/semaphore_spec.rb +22 -0
- data/spec/spec_helper.rb +60 -0
- metadata +124 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
guard :bundler do
|
2
|
+
watch("Gemfile")
|
3
|
+
watch(/^.+\.gemspec/)
|
4
|
+
end
|
5
|
+
|
6
|
+
guard :rspec do
|
7
|
+
watch(%r{^spec/.+_spec\.rb$})
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
9
|
+
watch("spec/spec_helper.rb") { "spec" }
|
10
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
11
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Mark Lanett
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Screw
|
2
|
+
|
3
|
+
Small classes to help bolt together a threaded application.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'screw'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install screw
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/[my-github-username]/screw/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/screw.rb
ADDED
data/lib/screw/logger.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "thread"
|
3
|
+
|
4
|
+
module Screw
|
5
|
+
module Logger
|
6
|
+
|
7
|
+
class SafeLogger
|
8
|
+
|
9
|
+
def initialize(theLogger)
|
10
|
+
@logger = theLogger
|
11
|
+
@mutex = Mutex.new
|
12
|
+
end
|
13
|
+
|
14
|
+
::Logger::Severity.constants.each do |sym|
|
15
|
+
level = ::Logger::Severity.const_get(sym)
|
16
|
+
name = sym.to_s.downcase.to_sym
|
17
|
+
pred = "#{name}?".to_sym
|
18
|
+
define_method(name) do |message = nil, progname = nil, &block|
|
19
|
+
# Executing blocks in this mutex is not be a good idea. Resolve them first.
|
20
|
+
if block && (level >= @logger.level)
|
21
|
+
message = block.call.to_s
|
22
|
+
end
|
23
|
+
@mutex.synchronize do
|
24
|
+
@logger.add(level, message, progname)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
define_method(pred) do
|
28
|
+
level >= @logger.level
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def close
|
33
|
+
@mutex.synchronize do
|
34
|
+
@logger.close
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# This logger will be shared by every class which includes the module. It's global.
|
41
|
+
def logger=(aLogger)
|
42
|
+
Thread.exclusive do
|
43
|
+
@@logger = aLogger
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def logger
|
48
|
+
# I'm assuming that reads are atomic.
|
49
|
+
@@logger ||= begin
|
50
|
+
Thread.exclusive do
|
51
|
+
@@logger ||= SafeLogger.new(::Logger.new(STDERR))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end # Logger
|
57
|
+
end # Screw
|
data/lib/screw/proxy.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Screw
|
2
|
+
# Proxy allows you to intercept calls to one object and divert them to a handler.
|
3
|
+
# Each method call is memoized using method_missing/define_method.
|
4
|
+
class Proxy
|
5
|
+
|
6
|
+
def initialize(target, &block)
|
7
|
+
@target = target
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method, *arguments, &block)
|
12
|
+
raise ::NoMethodError, method.to_s if ! @target.respond_to?(method)
|
13
|
+
self.singleton_class.send(:define_method, method) do |*arguments,&block|
|
14
|
+
@block.call(method, *arguments, &block)
|
15
|
+
end
|
16
|
+
send(method, *arguments, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
end # Proxy
|
20
|
+
end # Screw
|
data/lib/screw/queue.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "thread"
|
2
|
+
|
3
|
+
module Screw
|
4
|
+
class Queue
|
5
|
+
|
6
|
+
Unlimited = 0
|
7
|
+
Forever = (2 ** (0.size * 8 - 2) - 1) # Ruby uses an extra bit as a Fixnum flag.
|
8
|
+
NoWait = 0
|
9
|
+
|
10
|
+
class Timeout < ::Exception
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param max is the maximum size of the queue. Optional, defaults to 0 (Unlimited).
|
14
|
+
def initialize(max = Unlimited)
|
15
|
+
raise max.inspect unless (Fixnum === max && max >= 0)
|
16
|
+
@max = max
|
17
|
+
@queue = []
|
18
|
+
@mutex = Mutex.new
|
19
|
+
@nempty = ConditionVariable.new
|
20
|
+
@nfull = ConditionVariable.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def push(it)
|
24
|
+
@mutex.synchronize do
|
25
|
+
while @max > 0 && @queue.size >= @max do
|
26
|
+
@nfull.wait(@mutex)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Push. But also if anyone else is waiting to pop, they can do it now.
|
30
|
+
@queue << it
|
31
|
+
@nempty.signal
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param wait is timeout in seconds; Optional, defaults to Forever.
|
37
|
+
# @raises Timeout in the event of a timeout
|
38
|
+
def pop(wait = Forever)
|
39
|
+
raise wait.inspect unless (Fixnum === wait && wait >= 0)
|
40
|
+
|
41
|
+
@mutex.synchronize do
|
42
|
+
while @queue.size == 0
|
43
|
+
|
44
|
+
# Have we run out of time?
|
45
|
+
raise Timeout if wait <= 0
|
46
|
+
|
47
|
+
# Wait. Subtract wait time from timeout.
|
48
|
+
now = Time.now.to_i
|
49
|
+
@nempty.wait(@mutex, wait)
|
50
|
+
wait -= (Time.now.to_i - now)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Pop
|
54
|
+
it = @queue.shift
|
55
|
+
@nfull.signal
|
56
|
+
it
|
57
|
+
end # synchronize
|
58
|
+
end # pop
|
59
|
+
|
60
|
+
end # Queue
|
61
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "thread"
|
2
|
+
|
3
|
+
module Screw
|
4
|
+
# Semaphore implements a resource counting control.
|
5
|
+
# Call #wait! to acquire a resource.
|
6
|
+
# Call #signal! to release one.
|
7
|
+
# Originally based on https://gist.github.com/pettyjamesm/3746457, but rewritten and fixed.
|
8
|
+
class Semaphore
|
9
|
+
|
10
|
+
def initialize(max = nil, count = 0)
|
11
|
+
max = max.to_i unless max.nil?
|
12
|
+
count = count.to_i
|
13
|
+
raise NonPositiveMax, max.to_s if max and max <= 0
|
14
|
+
raise CountOverflow, count.to_s if max and max < count
|
15
|
+
@max = max
|
16
|
+
@count = count
|
17
|
+
@mon = Mutex.new
|
18
|
+
@nempty = ConditionVariable.new
|
19
|
+
@nfull = ConditionVariable.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def count
|
23
|
+
@mon.synchronize { @count }
|
24
|
+
end
|
25
|
+
|
26
|
+
# e.g. release (back into pool)
|
27
|
+
def signal!
|
28
|
+
@mon.synchronize do
|
29
|
+
@nfull.wait(@mon) while @max and @count == @max
|
30
|
+
@count += 1
|
31
|
+
@nempty.signal
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# e.g. acquire (from pool)
|
36
|
+
def wait!
|
37
|
+
@mon.synchronize do
|
38
|
+
@nempty.wait(@mon) while @count == 0
|
39
|
+
@count -= 1
|
40
|
+
@nfull.signal
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class NonPositiveMax < ArgumentError
|
45
|
+
end
|
46
|
+
|
47
|
+
class CountOverflow < ArgumentError
|
48
|
+
end
|
49
|
+
|
50
|
+
end # Semaphore
|
51
|
+
end # Screw
|
data/screw.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'screw/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "screw"
|
8
|
+
spec.version = Screw::VERSION
|
9
|
+
spec.authors = ["Mark Lanett"]
|
10
|
+
spec.email = ["mark.lanett@gmail.com"]
|
11
|
+
spec.summary = %q{Small classes to help bolt together a threaded application.}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rspec"
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "logger"
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
describe Screw::Logger::SafeLogger do
|
6
|
+
|
7
|
+
let(:buffer) { StringIO.new("") }
|
8
|
+
let(:base) { ::Logger.new(buffer).tap { |it| it.formatter = ->(severity, datetime, program, message) { "#{message}\n" } } }
|
9
|
+
subject { Screw::Logger::SafeLogger.new(base) }
|
10
|
+
|
11
|
+
it "logs" do
|
12
|
+
subject.info "Hello, world"
|
13
|
+
expect(buffer.string).to eq "Hello, world\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "resolves blocks" do
|
17
|
+
subject.info { "Hello, world" }
|
18
|
+
expect(buffer.string).to eq "Hello, world\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does not log to quiet loggers" do
|
22
|
+
base.level = 1
|
23
|
+
subject.debug "This is a test."
|
24
|
+
expect(buffer.string.size).to eq 0
|
25
|
+
subject.debug { "This is also a test." }
|
26
|
+
expect(buffer.string.size).to eq 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it "does not interleave output", stress: true do
|
30
|
+
subject # force
|
31
|
+
((1..100).map { Thread.new { subject.info "Hello, world" } }).shuffle.map(&:join)
|
32
|
+
expect(buffer.string).to eq "Hello, world\n" * 100
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class ProxyTest
|
4
|
+
attr_accessor :a, :b
|
5
|
+
def one(a)
|
6
|
+
self.a = a
|
7
|
+
self
|
8
|
+
end
|
9
|
+
def two(a,b)
|
10
|
+
self.a = a
|
11
|
+
self.b = b
|
12
|
+
self
|
13
|
+
end
|
14
|
+
def pass(&block)
|
15
|
+
block.call
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Screw::Proxy do
|
20
|
+
|
21
|
+
let(:base) { ProxyTest.new }
|
22
|
+
subject { Screw::Proxy.new(base,&handler) }
|
23
|
+
let(:subject2) { Screw::Proxy.new(base,&handler) }
|
24
|
+
|
25
|
+
describe "for one argument" do
|
26
|
+
let(:handler) { ->(method, arg1, &block) { base.one(arg1) } }
|
27
|
+
|
28
|
+
it "memoizes methods" do
|
29
|
+
expect(subject).to_not respond_to(:one)
|
30
|
+
|
31
|
+
expect(subject.one(0)).to eq base
|
32
|
+
expect(subject).to respond_to(:one)
|
33
|
+
|
34
|
+
expect(subject2).to_not respond_to(:one)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "passes one argument and returns the source" do
|
38
|
+
expect(subject.one(1)).to eq base
|
39
|
+
expect(base.a).to eq 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "for two arguments" do
|
44
|
+
let(:handler) { ->(method, arg1, arg2, &block) { base.two(arg1,arg2) } }
|
45
|
+
it "passes one argument and returns the source" do
|
46
|
+
subject.two(2,3)
|
47
|
+
expect(base.a).to eq 2
|
48
|
+
expect(base.b).to eq 3
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "for various arguments" do
|
53
|
+
let(:handler) { ->(method, *arguments, &block) { base.send(method,*arguments) } }
|
54
|
+
it "passes one argument and returns the source" do
|
55
|
+
subject.one(4)
|
56
|
+
expect(base.a).to eq 4
|
57
|
+
subject.two(5,6)
|
58
|
+
expect(base.a).to eq 5
|
59
|
+
expect(base.b).to eq 6
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "with blocks" do
|
64
|
+
let(:handler) { ->(method, *arguments, &block) { base.send(method,*arguments,&block) } }
|
65
|
+
it "evaluates blocks" do
|
66
|
+
expect(subject.pass { 3 }).to eq 3
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Screw::Queue do
|
4
|
+
|
5
|
+
subject { Screw::Queue.new }
|
6
|
+
|
7
|
+
it "can push and pop ordered in same thread" do
|
8
|
+
subject.push :a
|
9
|
+
subject.push :b
|
10
|
+
expect(subject.pop).to eq :a
|
11
|
+
expect(subject.pop).to eq :b
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can push and pop in different threads" do
|
15
|
+
Thread.new do
|
16
|
+
subject.push :a
|
17
|
+
subject.push :b
|
18
|
+
end
|
19
|
+
expect(subject.pop).to eq :a
|
20
|
+
expect(subject.pop).to eq :b
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Screw::Semaphore do
|
4
|
+
|
5
|
+
let(:num) { 25 }
|
6
|
+
let(:max) { 5 }
|
7
|
+
subject { Screw::Semaphore.new(nil, max) }
|
8
|
+
before { expect(subject.count).to eq max }
|
9
|
+
after { expect(subject.count).to eq max }
|
10
|
+
|
11
|
+
it "does not deadlock", stress: true do
|
12
|
+
t = (1..num).map do
|
13
|
+
Thread.new do
|
14
|
+
subject.wait!
|
15
|
+
sleep rand
|
16
|
+
subject.signal!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
t.map(&:join)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "screw"
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
# These two settings work together to allow you to limit a spec run
|
5
|
+
# to individual examples or groups you care about by tagging them with
|
6
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
7
|
+
# get run.
|
8
|
+
config.filter_run :focus
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
|
11
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
12
|
+
# file, and it's useful to allow more verbose output when running an
|
13
|
+
# individual spec file.
|
14
|
+
if config.files_to_run.one?
|
15
|
+
# Use the documentation formatter for detailed output,
|
16
|
+
# unless a formatter has already been configured
|
17
|
+
# (e.g. via a command-line flag).
|
18
|
+
config.default_formatter = 'doc'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Print the 10 slowest examples and example groups at the
|
22
|
+
# end of the spec run, to help surface which specs are running
|
23
|
+
# particularly slow.
|
24
|
+
config.profile_examples = 10
|
25
|
+
|
26
|
+
# Run specs in random order to surface order dependencies. If you find an
|
27
|
+
# order dependency and want to debug it, you can fix the order by providing
|
28
|
+
# the seed, which is printed after each run.
|
29
|
+
# --seed 1234
|
30
|
+
config.order = :random
|
31
|
+
|
32
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
33
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
34
|
+
# test failures related to randomization by passing the same `--seed` value
|
35
|
+
# as the one that triggered the failure.
|
36
|
+
Kernel.srand config.seed
|
37
|
+
|
38
|
+
# rspec-expectations config goes here. You can use an alternate
|
39
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
40
|
+
# assertions if you prefer.
|
41
|
+
config.expect_with :rspec do |expectations|
|
42
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
43
|
+
# For more details, see:
|
44
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
45
|
+
expectations.syntax = :expect
|
46
|
+
end
|
47
|
+
|
48
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
49
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
50
|
+
config.mock_with :rspec do |mocks|
|
51
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
52
|
+
# For more details, see:
|
53
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
54
|
+
mocks.syntax = :expect
|
55
|
+
|
56
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
57
|
+
# a real object. This is generally recommended.
|
58
|
+
mocks.verify_partial_doubles = true
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: screw
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mark Lanett
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-07-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description:
|
63
|
+
email:
|
64
|
+
- mark.lanett@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- Gemfile
|
72
|
+
- Guardfile
|
73
|
+
- LICENSE.txt
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- lib/screw.rb
|
77
|
+
- lib/screw/logger.rb
|
78
|
+
- lib/screw/proxy.rb
|
79
|
+
- lib/screw/queue.rb
|
80
|
+
- lib/screw/semaphore.rb
|
81
|
+
- lib/screw/version.rb
|
82
|
+
- screw.gemspec
|
83
|
+
- spec/lib/screw/logger_spec.rb
|
84
|
+
- spec/lib/screw/proxy_spec.rb
|
85
|
+
- spec/lib/screw/queue_spec.rb
|
86
|
+
- spec/lib/screw/semaphore_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
homepage: ''
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
hash: 3114135878833884078
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
hash: 3114135878833884078
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.8.23
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Small classes to help bolt together a threaded application.
|
119
|
+
test_files:
|
120
|
+
- spec/lib/screw/logger_spec.rb
|
121
|
+
- spec/lib/screw/proxy_spec.rb
|
122
|
+
- spec/lib/screw/queue_spec.rb
|
123
|
+
- spec/lib/screw/semaphore_spec.rb
|
124
|
+
- spec/spec_helper.rb
|