async_io 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/async_io/base.rb +97 -0
- data/lib/async_io/load.rb +1 -0
- data/lib/async_io/rescuer.rb +19 -0
- data/lib/async_io/version.rb +3 -0
- data/lib/async_io/worker.rb +80 -0
- data/lib/async_io.rb +34 -0
- data/spec/async_io/base_spec.rb +140 -0
- data/spec/async_io/rescuer_spec.rb +49 -0
- data/spec/async_io/worker_spec.rb +80 -0
- data/spec/spec_helper.rb +30 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6987084439444f8b65360b694efe1367a3abda31
|
4
|
+
data.tar.gz: 875b9b38b82ed030e711d84790029f1d0034bbc5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 994b5606932c7a7e2b9c5d3052f1468a9a08a85448ab009801a00da31b7d8c09328747f95af1ef5d4d4624345bf0434a8caa27d9c3336ace26825e4b2d30c8d1
|
7
|
+
data.tar.gz: 24629df537bf4b3f7313a2fbb5340a3577d4733b24394cb42ac854407f532d13708f6c14a1dc12843ca744d8c0a60d03b178d2d89e8d10ccfda2fca1adcbcdba
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'async_io/worker'
|
3
|
+
require 'async_io/rescuer'
|
4
|
+
|
5
|
+
module AsyncIO
|
6
|
+
class Base
|
7
|
+
include AsyncIO::Rescuer
|
8
|
+
|
9
|
+
##
|
10
|
+
# Default:
|
11
|
+
# Number of threads to be spanwed is 1
|
12
|
+
#
|
13
|
+
# NOTE: Any sort of exception raised while
|
14
|
+
# 'getting' a job done will not be raised at all.
|
15
|
+
# Instead it will be logged to a specified log file.
|
16
|
+
#
|
17
|
+
# Whenever an exception is raised, the thread that the
|
18
|
+
# exception was raised from is killed, so we need a
|
19
|
+
# way to prevent threads from being killed. Therefore it
|
20
|
+
# rescues all exceptions raised and logs them.
|
21
|
+
#
|
22
|
+
attr_reader :queue, :threads
|
23
|
+
attr_accessor :logger
|
24
|
+
def initialize(n_threads=1)
|
25
|
+
@logger = AsyncIO::Logger
|
26
|
+
@queue = Queue.new
|
27
|
+
@threads = []
|
28
|
+
n_threads.times { @threads << Thread.new { consumer } }
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Ruby Queue#pop sets non_block to false.
|
33
|
+
# It waits until data is pushed on to
|
34
|
+
# the queue and then process it.
|
35
|
+
#
|
36
|
+
def consumer
|
37
|
+
rescuer do
|
38
|
+
while worker = queue.pop
|
39
|
+
worker.call
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
private(:consumer)
|
44
|
+
|
45
|
+
##
|
46
|
+
# It creates a new Worker, pushes it onto the queue,
|
47
|
+
# whenever a 'job' (i.e a Ruby object ) is finished
|
48
|
+
# it calls the payload and passes the result of job
|
49
|
+
# to it.
|
50
|
+
#
|
51
|
+
# For example:
|
52
|
+
#
|
53
|
+
# def aget_user(uid, &payload)
|
54
|
+
# worker(payload) do
|
55
|
+
# User.find(ui)
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# It returns the worker created for a particular job
|
60
|
+
# which you could send message +done+ to it in order
|
61
|
+
# to retrieve its job done.
|
62
|
+
# see prediction_io/worker.rb
|
63
|
+
#
|
64
|
+
# For example:
|
65
|
+
# result = aget_user(1) { |u| Logger.info(u.name) }
|
66
|
+
#
|
67
|
+
# # job may take a while to be done...
|
68
|
+
#
|
69
|
+
# user = result.done
|
70
|
+
# user.name
|
71
|
+
# => "John"
|
72
|
+
#
|
73
|
+
# NOTE: Whenever you use the snippet above, if the job
|
74
|
+
# has not been finished yet you will get +false+
|
75
|
+
# whenever you send a message +job+ to it. Once
|
76
|
+
# job is finished you will be able to get its result.
|
77
|
+
#
|
78
|
+
def worker(payload, &job)
|
79
|
+
rescuer do
|
80
|
+
Worker.new(payload, job).tap { |w|
|
81
|
+
queue.push(w)
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Perform any sort of task that needs to be
|
88
|
+
# asynchronously done.
|
89
|
+
# NOTE: It does not return anything, as it receives
|
90
|
+
# and empty job. ( i.e empty block of code )
|
91
|
+
#
|
92
|
+
def async(&payload)
|
93
|
+
worker(payload) { }
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'async_io/async_io'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AsyncIO
|
2
|
+
module Rescuer
|
3
|
+
|
4
|
+
##
|
5
|
+
# Rescues any sort of exception raised and
|
6
|
+
# log it to a default logger, returns :rescued
|
7
|
+
# if any exception was raised.
|
8
|
+
#
|
9
|
+
def rescuer
|
10
|
+
begin
|
11
|
+
yield
|
12
|
+
rescue Exception => notice
|
13
|
+
AsyncIO::Logger.error("[-:AsyncIO::AsyncIO:-] - #{notice}\n")
|
14
|
+
:rescued
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'timeout'
|
3
|
+
require 'async_io/rescuer'
|
4
|
+
|
5
|
+
module AsyncIO
|
6
|
+
class Worker
|
7
|
+
include AsyncIO::Rescuer
|
8
|
+
|
9
|
+
attr_reader :payload, :job
|
10
|
+
attr_reader :finished, :done
|
11
|
+
|
12
|
+
def initialize(payload, job)
|
13
|
+
@payload = payload
|
14
|
+
@job = job
|
15
|
+
@done = false
|
16
|
+
@finished = false
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# It sends payload a message +call+
|
21
|
+
# and passes the result of a job, by sending
|
22
|
+
# job a message +call+ as well, as its argument.
|
23
|
+
# This allows us to do:
|
24
|
+
#
|
25
|
+
# aget_user(1) { |u| print u.name }
|
26
|
+
#=> Paul Clark Manson
|
27
|
+
#
|
28
|
+
# Or any other sort of task that you may
|
29
|
+
# need its result to be available within a block without
|
30
|
+
# needing to wait for it to finish and non blocking IO.
|
31
|
+
#
|
32
|
+
# A payload is a Ruby object must pass, for example:
|
33
|
+
#
|
34
|
+
# payload = lambda { |u| print u.name }
|
35
|
+
# payload = Object.new
|
36
|
+
# def payload.call(result); warn(result); end
|
37
|
+
#
|
38
|
+
# job is pre-definied inside a method, it can
|
39
|
+
# be anything, for example:
|
40
|
+
# worker(payload) do
|
41
|
+
# User.find(uid)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
def call
|
45
|
+
try do
|
46
|
+
@finished = true
|
47
|
+
@done = job.call
|
48
|
+
payload.call(done)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Tries to get the first job done, when an exception
|
54
|
+
# is raised it then calls payload again passing a
|
55
|
+
# fallback as its argument.
|
56
|
+
#
|
57
|
+
def try
|
58
|
+
begin
|
59
|
+
yield
|
60
|
+
rescue Exception => notice
|
61
|
+
rescuer { payload.call(fallback(notice)) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
##
|
68
|
+
# Instances of OpenStruct returns nil when the method
|
69
|
+
# called does not exist. This prevents another exception
|
70
|
+
# from being raised.
|
71
|
+
# It returns an instance of OpenStruct object with the
|
72
|
+
# exception rescued ( i.e notice ) and the worker that
|
73
|
+
# was assigned to this particular job.
|
74
|
+
#
|
75
|
+
def fallback(notice)
|
76
|
+
OpenStruct.new({ notice: notice, worker: self })
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/lib/async_io.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'async_io/load'
|
2
|
+
|
3
|
+
module AsyncIO
|
4
|
+
|
5
|
+
def self.async_creator=(new_async)
|
6
|
+
@@async_creator = new_async
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.async_creator
|
10
|
+
@@async_creator ||= Base.new(5)
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Creates async jobs, if a payload (i.e ruby block)
|
15
|
+
# is not given it passes an empty payload to woker.
|
16
|
+
# That allows us to do:
|
17
|
+
#
|
18
|
+
# User.aget(1)
|
19
|
+
# User.aget(1) { |u| print u.id }
|
20
|
+
#
|
21
|
+
# The response will be a worker that was created for this
|
22
|
+
# particular job.
|
23
|
+
#
|
24
|
+
# NOTE: If you read PredictionIO::Worker you will see that
|
25
|
+
# it calls payload and passes job as its arguments. This is
|
26
|
+
# how it is available within a block later on.
|
27
|
+
# NOTE: You must pass a job ( i.e ruby block ).
|
28
|
+
#
|
29
|
+
def self.async(payload, &job)
|
30
|
+
payload = payload || ->(n) { n }
|
31
|
+
async_creator.worker(payload, &job)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'async_io/base'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module AsyncIO
|
6
|
+
Base.class_eval do
|
7
|
+
##
|
8
|
+
# Returns queue's size and pops one
|
9
|
+
# item from queue.
|
10
|
+
def extract_size!
|
11
|
+
queue.size.tap { queue.pop }
|
12
|
+
end
|
13
|
+
|
14
|
+
public(:consumer)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe AsyncIO::Base do
|
20
|
+
|
21
|
+
before { Thread.stub(:new).and_return(double) }
|
22
|
+
let(:alien) { AsyncIO::Base.new }
|
23
|
+
let(:logger) { AsyncIO::Logger }
|
24
|
+
|
25
|
+
context "initialising" do
|
26
|
+
it "should have a queue" do
|
27
|
+
alien.queue.should respond_to :push
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should create 1 thread as default" do
|
31
|
+
alien.threads.size.should eq(1)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
context "#worker" do
|
37
|
+
|
38
|
+
it "should have a worker" do
|
39
|
+
alien.should respond_to :worker
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should_not raise_error when no block is passed" do
|
43
|
+
expect {
|
44
|
+
alien.worker(:jason)
|
45
|
+
}.to_not raise_error
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not raise_error when block is passed" do
|
49
|
+
expect {
|
50
|
+
alien.worker(:lizza) { }
|
51
|
+
}.to_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should push worker onto the queue" do
|
55
|
+
alien.worker(:paul) { }
|
56
|
+
alien.extract_size!.should eq(1)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return worker" do
|
60
|
+
result = alien.worker(:blunt) { }
|
61
|
+
result.should be_instance_of AsyncIO::Worker
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "#async" do
|
66
|
+
it { alien.should respond_to :async }
|
67
|
+
|
68
|
+
##
|
69
|
+
# NOTE: this snippet here can be a little tricky
|
70
|
+
# First we create a lambda ( -> its just Ruby syntatic sugar )
|
71
|
+
# Second we create a double ( a mock )
|
72
|
+
# Third we stub out the state of our original
|
73
|
+
# method and return the double
|
74
|
+
#
|
75
|
+
# Then we call the method +async+ which takes a block to be
|
76
|
+
# 'passed' an object.
|
77
|
+
#
|
78
|
+
# Last but not least we check if our object has received
|
79
|
+
# that message with that particular argument.
|
80
|
+
#
|
81
|
+
# Ruby allows us to do some cool stuff with coercion and
|
82
|
+
# closures while using blocks.
|
83
|
+
# The following might be helpul:
|
84
|
+
# robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas
|
85
|
+
|
86
|
+
#
|
87
|
+
it "should pass this payload block onto Worker" do
|
88
|
+
payload = -> { :im_an_async_job }
|
89
|
+
|
90
|
+
worker = double
|
91
|
+
alien.stub(:worker).
|
92
|
+
and_return(worker)
|
93
|
+
|
94
|
+
##
|
95
|
+
# See the link below for a better understading how to
|
96
|
+
# pass/call blocks of code in Ruby.
|
97
|
+
# pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html
|
98
|
+
#
|
99
|
+
alien.async(&payload)
|
100
|
+
|
101
|
+
alien.should have_received(:worker).with(payload)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "#consumer" do
|
106
|
+
it { alien.should respond_to :consumer }
|
107
|
+
|
108
|
+
it "should pop and consume items in a queue" do
|
109
|
+
bob = double
|
110
|
+
|
111
|
+
##
|
112
|
+
# returns false to break the while loop.
|
113
|
+
#
|
114
|
+
bob.should_receive(:pop).and_return(false)
|
115
|
+
alien.stub(:queue).and_return(bob)
|
116
|
+
|
117
|
+
alien.consumer.should be_nil
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should not raise any error" do
|
121
|
+
tob = -> { raise "Not going to be Raised" }
|
122
|
+
alien.queue.push(tob)
|
123
|
+
|
124
|
+
expect {
|
125
|
+
alien.consumer
|
126
|
+
}.to_not raise_error
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should call a worker" do
|
130
|
+
duck = double
|
131
|
+
duck.should_receive(:call)
|
132
|
+
|
133
|
+
alien.stub(:queue).and_return([duck])
|
134
|
+
|
135
|
+
alien.consumer
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'async_io/rescuer.rb'
|
3
|
+
|
4
|
+
class Guard
|
5
|
+
include AsyncIO::Rescuer
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@logger = AsyncIO::Logger
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
describe AsyncIO::Rescuer do
|
14
|
+
let(:logger) { AsyncIO::Logger }
|
15
|
+
let(:guard) { Guard.new }
|
16
|
+
|
17
|
+
it { guard.should respond_to :rescuer }
|
18
|
+
|
19
|
+
context "#rescuer" do
|
20
|
+
|
21
|
+
it "should rescue when an exception is raised" do
|
22
|
+
expect {
|
23
|
+
guard.rescuer { raise "hell" }
|
24
|
+
}.to_not raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not raise when no block" do
|
28
|
+
expect {
|
29
|
+
guard.rescuer
|
30
|
+
}.to_not raise_error
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not raise when block is present" do
|
34
|
+
expect {
|
35
|
+
guard.rescuer { :imma_block }
|
36
|
+
}.to_not raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "Logs", "whenever an exception is raised" do
|
41
|
+
|
42
|
+
it "should write error to logger" do
|
43
|
+
guard.rescuer { raise "log me!" }
|
44
|
+
logger.read.should match /log me!/
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'async_io/worker'
|
3
|
+
|
4
|
+
module AsyncIO
|
5
|
+
Worker.class_eval do
|
6
|
+
public(:fallback)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Worker do
|
10
|
+
|
11
|
+
let(:payload) { ->(r) { r } }
|
12
|
+
let(:job) { -> { :am_a_dog } }
|
13
|
+
let(:worker) { Worker.new(payload, job) }
|
14
|
+
|
15
|
+
context "initialising" do
|
16
|
+
|
17
|
+
it "must take a payload" do
|
18
|
+
worker.payload.should be_kind_of Proc
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must take a job" do
|
22
|
+
worker.job.should be_kind_of Proc
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
it { worker.should respond_to :done }
|
28
|
+
|
29
|
+
it "should not be done as job is not finished" do
|
30
|
+
worker.done.should be_false
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must call payload and pass job as its argument" do
|
34
|
+
worker.call.should eq(:am_a_dog)
|
35
|
+
end
|
36
|
+
|
37
|
+
context "Getting a job done" do
|
38
|
+
it "should set done to its last finished job" do
|
39
|
+
worker.call
|
40
|
+
worker.done.should eq(:am_a_dog)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#try" do
|
45
|
+
it { worker.should respond_to :try }
|
46
|
+
|
47
|
+
context "failed" do
|
48
|
+
it "should call fallback" do
|
49
|
+
worker.should_receive(:fallback)
|
50
|
+
worker.try { raise "failed" }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "success" do
|
55
|
+
it "should not call fallback" do
|
56
|
+
worker.should_not_receive(:fallback)
|
57
|
+
worker.try { :happy }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "#fallback" do
|
62
|
+
let(:fallback) { worker.fallback("notice") }
|
63
|
+
|
64
|
+
it "should have a notice" do
|
65
|
+
fallback.notice.should eq("notice")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should have a worker" do
|
69
|
+
fallback.worker.should eq worker
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return nil when method not found" do
|
73
|
+
fallback.will_return_nil.should be_nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module AsyncIO
|
2
|
+
CONFIG_PATH = File.expand_path("../support", __FILE__)
|
3
|
+
|
4
|
+
Logger = Object.new
|
5
|
+
def Logger.error(n); @n = n; end
|
6
|
+
def Logger.read; @n; end
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec.configure do |c|
|
10
|
+
c.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
end
|
12
|
+
|
13
|
+
class AsyncIO::FakeAsync
|
14
|
+
##
|
15
|
+
# Calls payload and passes whatever
|
16
|
+
# job.call yields as its argument.
|
17
|
+
#
|
18
|
+
def self.async(payload, &job)
|
19
|
+
payload = payload || ->(n) { n }
|
20
|
+
payload.call(job.call)
|
21
|
+
end
|
22
|
+
|
23
|
+
def worker(payload, &job)
|
24
|
+
payload.call(job.call)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec::Matchers.define(:be_rescued){ |e| match { |a| a === :rescued } }
|
30
|
+
RSpec::Matchers.define(:be_deleted){ |e| match { |a| a === :deleted } }
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: async_io
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Antonio C Nalesso
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-27 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
|
+
description: Perform asyncrhonous IO for ruby using blocks and threads just pure old
|
28
|
+
ruby code.
|
29
|
+
email:
|
30
|
+
- acnalesso@yahoo.co.uk
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- lib/async_io.rb
|
36
|
+
- lib/async_io/base.rb
|
37
|
+
- lib/async_io/load.rb
|
38
|
+
- lib/async_io/rescuer.rb
|
39
|
+
- lib/async_io/version.rb
|
40
|
+
- lib/async_io/worker.rb
|
41
|
+
- spec/async_io/base_spec.rb
|
42
|
+
- spec/async_io/rescuer_spec.rb
|
43
|
+
- spec/async_io/worker_spec.rb
|
44
|
+
- spec/spec_helper.rb
|
45
|
+
homepage: https://github.com/acnalesso/async_io
|
46
|
+
licenses:
|
47
|
+
- MIT
|
48
|
+
metadata: {}
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 2.0.3
|
66
|
+
signing_key:
|
67
|
+
specification_version: 4
|
68
|
+
summary: Simple asynchronous IO for ruby.
|
69
|
+
test_files:
|
70
|
+
- spec/async_io/base_spec.rb
|
71
|
+
- spec/async_io/rescuer_spec.rb
|
72
|
+
- spec/async_io/worker_spec.rb
|
73
|
+
- spec/spec_helper.rb
|
74
|
+
has_rdoc:
|