async_methods 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +35 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/async_methods.gemspec +58 -0
- data/lib/async_methods/async_methods.rb +95 -0
- data/lib/async_methods.rb +2 -0
- data/spec/async_method_spec.rb +102 -0
- data/spec/method_tester.rb +32 -0
- data/spec/spec_helper.rb +26 -0
- metadata +110 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Brian Durand
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
== AsyncMethods
|
2
|
+
|
3
|
+
For those times you application is bound on I/O...
|
4
|
+
|
5
|
+
== Enter AsyncMethods.
|
6
|
+
|
7
|
+
This plugin adds a virtual asynchronous version of every method on every class. Asynchronouse methods have the same name as the original method name but prefixed with "async_". An asynchronous method will invoke to original method in a new thread and immediately return a proxy object that looks and acts just like the result from calling the actual method. When this proxy object is accessed for the first time, it will only then wait for the thread executing the method to finish.
|
8
|
+
|
9
|
+
If you add fragment caching to your views and the cache returns a value and bypasses your view code, the method will never be invoked. Thanks to the magic of Ruby the proxy object will even act like the class it is proxying in class to class and kind_of?
|
10
|
+
|
11
|
+
A simple example:
|
12
|
+
|
13
|
+
The normal way to do it:
|
14
|
+
|
15
|
+
def index
|
16
|
+
@record_1 = MyResource.load(:first, :conditions => {:name => params[:name_1]})
|
17
|
+
@record_2 = MyResource.load(:first, :conditions => {:name => params[:name_2]})
|
18
|
+
@record_3 = MyResource.load(:first, :conditions => {:name => params[:name_3]})
|
19
|
+
end
|
20
|
+
|
21
|
+
If the calls to load the resource each takes an average of 0.1 seconds, loading all three will take 0.3 seconds. In a web application this can start adding up quickly, especially under a heavy load. However, by using asynchronous methods like this, all three calls will happen in parallel and they should all complete in 0.1 seconds.
|
22
|
+
|
23
|
+
def index
|
24
|
+
@record_1 = MyResource.async_load(:first, :conditions => {:name => params[:name_1]})
|
25
|
+
@record_2 = MyResource.async_load(:first, :conditions => {:name => params[:name_2]})
|
26
|
+
@record_3 = MyResource.async_load(:first, :conditions => {:name => params[:name_3]})
|
27
|
+
end
|
28
|
+
|
29
|
+
== Be Careful
|
30
|
+
|
31
|
+
Because underneath it all new threads are being spawned, you must be careful to make sure that the code you are calling is thread safe. For example, the default configuration for ActiveRecord is not thread safe so loading several calls from the database at once would cause you problems. This plugin was originally written to speed up parallel loads of ActiveResource records, so that should be safe to do.
|
32
|
+
|
33
|
+
== Testing
|
34
|
+
|
35
|
+
Since the proxy object looks and acts just like the real result object, all your view tests should still pass. Your controller tests should pass will little or no tweaking.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'spec/rake/spectask'
|
10
|
+
desc 'Test the gem.'
|
11
|
+
Spec::Rake::SpecTask.new(:test) do |t|
|
12
|
+
t.spec_files = FileList.new('spec/**/*_spec.rb')
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
tast :test do
|
16
|
+
STDERR.puts "You must have rspec >= 1.3.0 to run the tests"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Generate documentation for the gem.'
|
21
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.options << '--title' << 'Async Methods' << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
|
24
|
+
rdoc.rdoc_files.include('README.rdoc')
|
25
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'jeweler'
|
30
|
+
Jeweler::Tasks.new do |gem|
|
31
|
+
gem.name = "async_methods"
|
32
|
+
gem.summary = %Q{Gem that adds asynchronous method calls for all methods on every object to aid in throughput on I/O bound processes.}
|
33
|
+
gem.description = %Q(Gem that adds asynchronous method calls for all methods on every object to aid in throughput on I/O bound processes. This is intended to improve throughput on I/O bound processes like making several HTTP calls in row.)
|
34
|
+
gem.email = "brian@embellishedvisions.com"
|
35
|
+
gem.homepage = "http://github.com/bdurand/acts_as_revisionable"
|
36
|
+
gem.authors = ["Brian Durand"]
|
37
|
+
gem.rdoc_options = ["--charset=UTF-8", "--main", "README.rdoc"]
|
38
|
+
|
39
|
+
gem.add_development_dependency('rspec', '>= 1.3.0')
|
40
|
+
gem.add_development_dependency('jeweler')
|
41
|
+
end
|
42
|
+
|
43
|
+
Jeweler::GemcutterTasks.new
|
44
|
+
rescue LoadError
|
45
|
+
end
|
46
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{async_methods}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Brian Durand"]
|
12
|
+
s.date = %q{2010-06-22}
|
13
|
+
s.description = %q{Gem that adds asynchronous method calls for all methods on every object to aid in throughput on I/O bound processes. This is intended to improve throughput on I/O bound processes like making several HTTP calls in row.}
|
14
|
+
s.email = %q{brian@embellishedvisions.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"async_methods.gemspec",
|
25
|
+
"lib/async_methods.rb",
|
26
|
+
"lib/async_methods/async_methods.rb",
|
27
|
+
"spec/async_method_spec.rb",
|
28
|
+
"spec/method_tester.rb",
|
29
|
+
"spec/spec_helper.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/bdurand/acts_as_revisionable}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8", "--main", "README.rdoc"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.7}
|
35
|
+
s.summary = %q{Gem that adds asynchronous method calls for all methods on every object to aid in throughput on I/O bound processes.}
|
36
|
+
s.test_files = [
|
37
|
+
"spec/async_method_spec.rb",
|
38
|
+
"spec/method_tester.rb",
|
39
|
+
"spec/spec_helper.rb"
|
40
|
+
]
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
48
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
49
|
+
else
|
50
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
51
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
52
|
+
end
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
55
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Including this module will provide the asynchronous method handling for the class where any method can be
|
2
|
+
# prefixed with async_ to continue execution without waiting for results. By default, the plugin includes
|
3
|
+
# it in Object so it is universally available.
|
4
|
+
module AsyncMethods
|
5
|
+
|
6
|
+
module InstanceMethods
|
7
|
+
def self.included (base)
|
8
|
+
base.send :alias_method, :method_missing_without_async, :method_missing
|
9
|
+
base.send :alias_method, :method_missing, :method_missing_with_async
|
10
|
+
end
|
11
|
+
|
12
|
+
# Override missing method to add the async method handling
|
13
|
+
def method_missing_with_async (method, *args, &block)
|
14
|
+
if method.to_s[0, 6] == 'async_'
|
15
|
+
method = method.to_s
|
16
|
+
return Proxy.new(self, method[6 , method.length].to_sym, args, &block)
|
17
|
+
else
|
18
|
+
# Keep track of the current missing method calls to keep out of an infinite loop
|
19
|
+
stack = Thread.current[:async_method_missing_methods] ||= []
|
20
|
+
sig = MethodSignature.new(self, method)
|
21
|
+
raise NoMethodError.new("undefined method `#{method}' for #{self}") if stack.include?(sig)
|
22
|
+
begin
|
23
|
+
stack.push(sig)
|
24
|
+
return method_missing_without_async(method, *args, &block)
|
25
|
+
ensure
|
26
|
+
stack.pop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Call a block asynchronously.
|
32
|
+
def asynchronous_block (&block)
|
33
|
+
Proxy.new(nil, nil, nil, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# This class is used to keep track of methods being called.
|
38
|
+
class MethodSignature
|
39
|
+
|
40
|
+
attr_reader :object, :method
|
41
|
+
|
42
|
+
def initialize (obj, method)
|
43
|
+
@object = obj
|
44
|
+
@method = method.to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
def eql? (sig)
|
48
|
+
sig.kind_of(MethodSignature) and sig.object == @object and sig.method == @method
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
# The proxy object does all the heavy lifting.
|
54
|
+
class Proxy
|
55
|
+
# These methods we don't want to override. All other existing methods will be redefined.
|
56
|
+
PROTECTED_METHODS = %w(initialize __proxy_result__ __proxy_loaded__ method_missing)
|
57
|
+
|
58
|
+
def initialize (obj, method, args = [], &block)
|
59
|
+
# Override already defined methods on Object to proxy them to the result object
|
60
|
+
methods.each do |m|
|
61
|
+
eval "def self.#{m} (*args, &block); __proxy_result__.send(:#{m}, *args, &block); end" unless PROTECTED_METHODS.include?(m)
|
62
|
+
end
|
63
|
+
|
64
|
+
@thread = Thread.new do
|
65
|
+
begin
|
66
|
+
if obj and method
|
67
|
+
@proxy_result = obj.send(method, *args, &block)
|
68
|
+
else
|
69
|
+
@proxy_result = block.call
|
70
|
+
end
|
71
|
+
rescue Object => e
|
72
|
+
@proxy_exception = e
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Get the result of the original method call. The original method will only be called once.
|
78
|
+
def __proxy_result__
|
79
|
+
@thread.join if @thread && @thread.alive?
|
80
|
+
@thread = nil
|
81
|
+
raise @proxy_exception if @proxy_exception
|
82
|
+
return @proxy_result
|
83
|
+
end
|
84
|
+
|
85
|
+
def __proxy_loaded__
|
86
|
+
!(@thread && @thread.alive?)
|
87
|
+
end
|
88
|
+
|
89
|
+
# All missing methods are proxied to the original result object.
|
90
|
+
def method_missing (method, *args, &block)
|
91
|
+
__proxy_result__.send(method, *args, &block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'async_methods', 'async_methods'))
|
2
|
+
Object.send(:include, AsyncMethods::InstanceMethods) unless Object.include?(AsyncMethods::InstanceMethods)
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/method_tester')
|
4
|
+
|
5
|
+
context "AsyncMethods InstanceMethods" do
|
6
|
+
|
7
|
+
let(:object) { AsyncMethods::Tester.new }
|
8
|
+
|
9
|
+
specify "should inject async method handling" do
|
10
|
+
proxy = object.async_test("arg")
|
11
|
+
proxy.to_s.should == "ARG"
|
12
|
+
proxy.__proxy_loaded__.should == true
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "should return a proxy object that has not been invoked yet" do
|
16
|
+
proxy = object.async_test("arg", 1)
|
17
|
+
proxy.__proxy_loaded__.should == false
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should be able to run a block asynchronously" do
|
21
|
+
proxy = asynchronous_block{object.test("arg", 0.1)}
|
22
|
+
proxy.__proxy_loaded__.should == false
|
23
|
+
proxy.to_s.should == "ARG"
|
24
|
+
proxy.__proxy_loaded__.should == true
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context "AsyncMethods Proxy" do
|
30
|
+
|
31
|
+
let(:object) { AsyncMethods::Tester.new }
|
32
|
+
|
33
|
+
specify "should be able to wrap a method without waiting for it to finish" do
|
34
|
+
proxy = object.async_test("arg", 1)
|
35
|
+
object.test_called.should == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "should execute the wrapped method when it needs to" do
|
39
|
+
proxy = object.async_test("arg")
|
40
|
+
proxy.to_s
|
41
|
+
object.test_called.should == 1
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "should only execute the wrapped method once" do
|
45
|
+
proxy = object.async_test("arg")
|
46
|
+
proxy.to_s
|
47
|
+
proxy.to_s
|
48
|
+
object.test_called.should == 1
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "should allow nil as a valid proxied value" do
|
52
|
+
proxy = object.async_test(nil)
|
53
|
+
proxy.should_not
|
54
|
+
object.test_called.should == 1
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "should allow blocks in the async method" do
|
58
|
+
n = 1
|
59
|
+
proxy = object.async_test("arg", 0.1) do
|
60
|
+
n = 2
|
61
|
+
end
|
62
|
+
n.should == 1
|
63
|
+
proxy.to_s
|
64
|
+
n.should == 2
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "should be indistinguishable from the real object" do
|
68
|
+
proxy = object.async_test("arg")
|
69
|
+
proxy.class.should == String
|
70
|
+
proxy.kind_of?(String).should == true
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "should proxy core methods on Object" do
|
74
|
+
proxy = "xxx".async_to_s
|
75
|
+
proxy.should == "xxx"
|
76
|
+
end
|
77
|
+
|
78
|
+
specify "should proxy missing methods" do
|
79
|
+
proxy = object.async_find_test
|
80
|
+
proxy.to_s.should == "FINDER"
|
81
|
+
end
|
82
|
+
|
83
|
+
specify "should allow blocks in the async missing methods" do
|
84
|
+
n = 1
|
85
|
+
proxy = object.async_find_test do
|
86
|
+
n = 2
|
87
|
+
end
|
88
|
+
n.should == 2
|
89
|
+
end
|
90
|
+
|
91
|
+
specify "should not interfere with the proxied object's method_missing" do
|
92
|
+
real = object.find_test
|
93
|
+
real.to_s.should == "FINDER"
|
94
|
+
end
|
95
|
+
|
96
|
+
specify "should not interfere with real methods that begin with async_" do
|
97
|
+
object.async_real_method_called.should == false
|
98
|
+
object.async_real_method
|
99
|
+
object.async_real_method_called.should == true
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# This class is used for testing the async_methods plugin functionality.
|
2
|
+
|
3
|
+
class AsyncMethods::Tester
|
4
|
+
|
5
|
+
attr_reader :test_called, :async_real_method_called
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@test_called = 0
|
9
|
+
@async_real_method_called = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def test (arg, delay = 0)
|
13
|
+
sleep(delay) if delay > 0
|
14
|
+
@test_called += 1
|
15
|
+
yield if block_given?
|
16
|
+
arg.upcase if arg
|
17
|
+
end
|
18
|
+
|
19
|
+
def async_real_method
|
20
|
+
@async_real_method_called = true
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing (method, *args, &block)
|
24
|
+
if method.to_s[0, 5] == 'find_'
|
25
|
+
yield if block_given?
|
26
|
+
"FINDER"
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
|
2
|
+
# from the project root directory.
|
3
|
+
ENV["RAILS_ENV"] ||= "test"
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
|
5
|
+
require 'spec/rails'
|
6
|
+
|
7
|
+
Spec::Runner.configure do |config|
|
8
|
+
config.use_transactional_fixtures = true
|
9
|
+
config.use_instantiated_fixtures = false
|
10
|
+
config.fixture_path = RAILS_ROOT + '/spec/fixtures'
|
11
|
+
config.before(:each, :behaviour_type => :controller) do
|
12
|
+
raise_controller_errors
|
13
|
+
end
|
14
|
+
|
15
|
+
# You can declare fixtures for each behaviour like this:
|
16
|
+
# describe "...." do
|
17
|
+
# fixtures :table_a, :table_b
|
18
|
+
#
|
19
|
+
# Alternatively, if you prefer to declare them only once, you can
|
20
|
+
# do so here, like so ...
|
21
|
+
#
|
22
|
+
# config.global_fixtures = :table_a, :table_b
|
23
|
+
#
|
24
|
+
# If you declare global fixtures, be aware that they will be declared
|
25
|
+
# for all of your examples, even those that don't use them.
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: async_methods
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Brian Durand
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-22 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 27
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 3
|
33
|
+
- 0
|
34
|
+
version: 1.3.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: jeweler
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
description: Gem that adds asynchronous method calls for all methods on every object to aid in throughput on I/O bound processes. This is intended to improve throughput on I/O bound processes like making several HTTP calls in row.
|
52
|
+
email: brian@embellishedvisions.com
|
53
|
+
executables: []
|
54
|
+
|
55
|
+
extensions: []
|
56
|
+
|
57
|
+
extra_rdoc_files:
|
58
|
+
- README.rdoc
|
59
|
+
files:
|
60
|
+
- .gitignore
|
61
|
+
- MIT-LICENSE
|
62
|
+
- README.rdoc
|
63
|
+
- Rakefile
|
64
|
+
- VERSION
|
65
|
+
- async_methods.gemspec
|
66
|
+
- lib/async_methods.rb
|
67
|
+
- lib/async_methods/async_methods.rb
|
68
|
+
- spec/async_method_spec.rb
|
69
|
+
- spec/method_tester.rb
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
has_rdoc: true
|
72
|
+
homepage: http://github.com/bdurand/acts_as_revisionable
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options:
|
77
|
+
- --charset=UTF-8
|
78
|
+
- --main
|
79
|
+
- README.rdoc
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
hash: 3
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
hash: 3
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
requirements: []
|
101
|
+
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 1.3.7
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Gem that adds asynchronous method calls for all methods on every object to aid in throughput on I/O bound processes.
|
107
|
+
test_files:
|
108
|
+
- spec/async_method_spec.rb
|
109
|
+
- spec/method_tester.rb
|
110
|
+
- spec/spec_helper.rb
|