parallizer 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +45 -29
- data/VERSION +1 -1
- data/lib/parallizer.rb +38 -34
- data/lib/parallizer/proxy.rb +21 -10
- data/parallizer.gemspec +4 -4
- data/test/{test_helper.rb → helper.rb} +0 -0
- data/test/parallizer/method_call_notifier_test.rb +1 -1
- data/test/parallizer/proxy_test.rb +55 -24
- data/test/parallizer_test.rb +24 -28
- metadata +4 -4
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Parallizer - Execute your service layer in parallel
|
2
2
|
|
3
|
-
Parallizer executes service methods in parallel, stores the method results,
|
3
|
+
Parallizer executes service methods in parallel, stores the method results, and creates a proxy of your service with those results. Your application then uses the short-lived service proxy (think of a single request for a web application) and calls your methods without again executing the underlying implementation. For applications that make considerable use of web service calls, Parallizer can give you a considerable performance boost.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -13,51 +13,60 @@ Parallizer executes service methods in parallel, stores the method results, then
|
|
13
13
|
Here's an example service.
|
14
14
|
|
15
15
|
```ruby
|
16
|
+
require 'rubygems'
|
16
17
|
require 'net/http'
|
18
|
+
require 'nokogiri'
|
17
19
|
|
18
20
|
class SearchService
|
19
|
-
def
|
20
|
-
Net::HTTP.get('www.google.com', '
|
21
|
+
def top_urls_for_foo
|
22
|
+
parse_search_result_for_urls(Net::HTTP.get('www.google.com', '/search?q=foo'))
|
21
23
|
end
|
22
24
|
|
23
|
-
def
|
24
|
-
Net::HTTP.get('www.google.com', '
|
25
|
+
def top_urls_for_bar
|
26
|
+
parse_search_result_for_urls(Net::HTTP.get('www.google.com', '/search?q=bar'))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse_search_result_for_urls(content)
|
32
|
+
Nokogiri::HTML.parse(content).search('h3.r > a').collect(&:attributes).collect{ |attrs| attrs['href'].value }
|
25
33
|
end
|
26
34
|
end
|
27
35
|
|
28
36
|
$search_service = SearchService.new
|
29
37
|
```
|
30
38
|
|
31
|
-
Now create a Parallizer for that service and add all of the methods you intend to call.
|
39
|
+
Now create a Parallizer for that service and add all of the methods you intend to call. This begins the execution of the service methods in worker threads. Then create a service proxy that uses the stored results of the method calls.
|
32
40
|
|
33
41
|
```ruby
|
34
42
|
require 'parallizer'
|
35
43
|
|
36
44
|
parallizer = Parallizer.new($search_service)
|
37
|
-
parallizer.add.
|
38
|
-
parallizer.add.
|
39
|
-
search_service = parallizer.
|
45
|
+
parallizer.add.top_urls_for_foo
|
46
|
+
parallizer.add.top_urls_for_bar
|
47
|
+
search_service = parallizer.create_proxy
|
40
48
|
```
|
41
49
|
|
42
|
-
Now use that service proxy in your application logic.
|
50
|
+
Now use that service proxy in your application logic. Calls to these methods will not make an HTTP request
|
51
|
+
and will not parse HTML. That was done by the parallel worker threads.
|
43
52
|
|
44
53
|
```ruby
|
45
|
-
puts search_service.
|
46
|
-
puts search_service.
|
54
|
+
puts search_service.top_urls_for_foo
|
55
|
+
puts search_service.top_urls_for_bar
|
47
56
|
```
|
48
57
|
|
49
58
|
Additional calls in your application logic will not result in an additional call to the underlying service.
|
50
59
|
|
51
60
|
```ruby
|
52
61
|
# Called twice, but no extra service call. (Be careful not to mutate the returned object!)
|
53
|
-
puts search_service.
|
54
|
-
puts search_service.
|
62
|
+
puts search_service.top_urls_for_foo
|
63
|
+
puts search_service.top_urls_for_foo
|
55
64
|
```
|
56
65
|
|
57
66
|
If there are additional methods on your service that were not parallized, you can still call them.
|
58
67
|
|
59
68
|
```ruby
|
60
|
-
puts search_service.
|
69
|
+
puts search_service.top_urls_for_foobar # makes an HTTP request and parses result
|
61
70
|
```
|
62
71
|
|
63
72
|
### Parallizing methods with parameters
|
@@ -66,11 +75,18 @@ Parallizing also works on service methods with parameters.
|
|
66
75
|
|
67
76
|
```ruby
|
68
77
|
require 'net/http'
|
78
|
+
require 'nokogiri'
|
69
79
|
require 'cgi'
|
70
80
|
|
71
81
|
class SearchService
|
72
|
-
def
|
73
|
-
Net::HTTP.get('www.google.com', "
|
82
|
+
def top_urls(search_term)
|
83
|
+
parse_search_result_for_urls(Net::HTTP.get('www.google.com', "/search?q=#{CGI.escape(search_term)}"))
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def parse_search_result_for_urls(content)
|
89
|
+
Nokogiri::HTML.parse(content).search('h3.r > a').collect(&:attributes).collect{ |attrs| attrs['href'].value }
|
74
90
|
end
|
75
91
|
end
|
76
92
|
|
@@ -83,17 +99,17 @@ The parallel execution and proxy creation.
|
|
83
99
|
require 'parallizer'
|
84
100
|
|
85
101
|
parallizer = Parallizer.new($search_service)
|
86
|
-
parallizer.add.
|
87
|
-
parallizer.add.
|
88
|
-
search_service = parallizer.
|
102
|
+
parallizer.add.top_urls('foo')
|
103
|
+
parallizer.add.top_urls('bar')
|
104
|
+
search_service = parallizer.create_proxy
|
89
105
|
```
|
90
106
|
|
91
107
|
Using the service proxy in your application logic.
|
92
108
|
|
93
109
|
```ruby
|
94
|
-
puts search_service.
|
95
|
-
puts search_service.
|
96
|
-
puts search_service.
|
110
|
+
puts search_service.top_urls('foo') # returns stored value
|
111
|
+
puts search_service.top_urls('bar') # returns stored value
|
112
|
+
puts search_service.top_urls('foobar') # makes an HTTP request and parses result
|
97
113
|
```
|
98
114
|
|
99
115
|
|
@@ -108,24 +124,24 @@ require 'parallizer'
|
|
108
124
|
parallizer = Parallizer.new(Net::HTTP)
|
109
125
|
parallizer.add.get('www.google.com', '/?q=foo')
|
110
126
|
parallizer.add.get('www.google.com', '/?q=bar')
|
111
|
-
http_service = parallizer.
|
127
|
+
http_service = parallizer.create_proxy
|
112
128
|
```
|
113
129
|
|
114
130
|
Use the service proxy.
|
115
131
|
|
116
132
|
```ruby
|
117
133
|
# use your service proxy
|
118
|
-
http_service.get('www.google.com', '
|
119
|
-
http_service.get('www.google.com', '
|
120
|
-
http_service.get('www.google.com', '
|
134
|
+
http_service.get('www.google.com', '/search?q=foo') # returns stored value
|
135
|
+
http_service.get('www.google.com', '/search?q=bar') # returns stored value
|
136
|
+
http_service.get('www.google.com', '/search?q=foobar') # makes an HTTP request and parses result
|
121
137
|
```
|
122
138
|
|
123
139
|
|
124
140
|
# Credits
|
125
141
|
|
126
|
-
[Parallizer](https://github.com/michaelgpearce/parallizer) is maintained by [Michael Pearce](http://github.com/michaelgpearce) and is funded by [
|
142
|
+
[Parallizer](https://github.com/michaelgpearce/parallizer) is maintained by [Michael Pearce](http://github.com/michaelgpearce) and is funded by [Rafter](http://www.rafter.com "Rafter").
|
127
143
|
|
128
|
-
![
|
144
|
+
![Rafter Logo](http://rafter-logos.s3.amazonaws.com/rafter_github_logo.png "Rafter")
|
129
145
|
|
130
146
|
# Copyright
|
131
147
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/parallizer.rb
CHANGED
@@ -1,56 +1,60 @@
|
|
1
|
-
require 'set'
|
2
1
|
require 'work_queue'
|
3
2
|
require 'parallizer/proxy'
|
4
3
|
require 'parallizer/method_call_notifier'
|
5
4
|
|
6
5
|
class Parallizer
|
7
|
-
|
6
|
+
attr_reader :calls, :call_infos, :client, :proxy
|
8
7
|
|
9
8
|
def initialize(client)
|
10
|
-
|
11
|
-
|
9
|
+
@client = client
|
10
|
+
@call_infos = {}
|
12
11
|
end
|
13
12
|
|
14
13
|
def add
|
15
14
|
MethodCallNotifier.new do |*args|
|
16
|
-
|
15
|
+
add_call(*args)
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
|
-
def
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def execute
|
25
|
-
Parallizer.execute_all(self).first
|
19
|
+
def calls
|
20
|
+
@call_infos.keys
|
26
21
|
end
|
27
22
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
23
|
+
def add_call(method_name, *args)
|
24
|
+
raise ArgumentError, "Cannot add calls after proxy has been generated" if @proxy
|
25
|
+
|
26
|
+
method_name_and_args = [method_name.to_sym, *args]
|
27
|
+
|
28
|
+
call_info = {
|
29
|
+
:complete? => false,
|
30
|
+
:result => nil,
|
31
|
+
:exception => nil,
|
32
|
+
:condition_variable => ConditionVariable.new,
|
33
|
+
:mutex => Mutex.new
|
34
|
+
}
|
35
|
+
call_infos[method_name_and_args] = call_info
|
36
|
+
|
37
|
+
Parallizer.work_queue.enqueue_b do
|
38
|
+
call_info[:mutex].synchronize do
|
39
|
+
begin
|
40
|
+
call_info[:result] = client.send(*method_name_and_args)
|
41
|
+
rescue Exception => e
|
42
|
+
call_info[:exception] = e
|
43
|
+
ensure
|
44
|
+
call_info[:complete?] = true
|
45
|
+
call_info[:condition_variable].signal
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_proxy
|
52
|
+
raise ArgumentError, "Cannot create another proxy" if @proxy
|
49
53
|
|
50
|
-
Parallizer.
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
Parallizer::Proxy.new(client, call_infos)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.work_queue
|
58
|
+
@parallizer_work_queue ||= WorkQueue.new(10)
|
55
59
|
end
|
56
60
|
end
|
data/lib/parallizer/proxy.rb
CHANGED
@@ -1,27 +1,38 @@
|
|
1
|
+
require 'thread'
|
1
2
|
require 'set'
|
2
3
|
|
3
4
|
class Parallizer
|
4
5
|
class Proxy
|
5
|
-
def initialize(client,
|
6
|
+
def initialize(client, call_infos)
|
6
7
|
@client = client
|
7
|
-
@
|
8
|
+
@call_infos = call_infos
|
8
9
|
end
|
9
10
|
|
10
11
|
def method_missing(name, *args, &block)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
value = nil
|
13
|
+
|
14
|
+
if call_info = @call_infos[[name, *args]]
|
15
|
+
call_info[:mutex].synchronize do
|
16
|
+
if !call_info[:complete?]
|
17
|
+
# not done, so lets wait for signal of completion
|
18
|
+
call_info[:condition_variable].wait(call_info[:mutex])
|
19
|
+
end
|
20
|
+
# we now have our result from the worker thread
|
21
|
+
|
22
|
+
raise call_info[:exception] if call_info[:exception]
|
23
|
+
|
24
|
+
value = call_info[:result]
|
17
25
|
end
|
18
26
|
else
|
19
|
-
|
27
|
+
# pass through to client since not added
|
28
|
+
value = @client.send(*[name, *args], &block)
|
20
29
|
end
|
30
|
+
|
31
|
+
value
|
21
32
|
end
|
22
33
|
|
23
34
|
def respond_to?(name, include_private = false, &block)
|
24
|
-
@execution_methods ||= Set.new(@
|
35
|
+
@execution_methods ||= Set.new(@call_infos.keys.collect(&:first))
|
25
36
|
|
26
37
|
if @execution_methods.include?(name.to_sym)
|
27
38
|
true
|
data/parallizer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "parallizer"
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Michael Pearce"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-08-04"
|
13
13
|
s.description = "Execute your service layer in parallel."
|
14
14
|
s.email = "michael.pearce@bookrenter.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -27,10 +27,10 @@ Gem::Specification.new do |s|
|
|
27
27
|
"lib/parallizer/method_call_notifier.rb",
|
28
28
|
"lib/parallizer/proxy.rb",
|
29
29
|
"parallizer.gemspec",
|
30
|
+
"test/helper.rb",
|
30
31
|
"test/parallizer/method_call_notifier_test.rb",
|
31
32
|
"test/parallizer/proxy_test.rb",
|
32
|
-
"test/parallizer_test.rb"
|
33
|
-
"test/test_helper.rb"
|
33
|
+
"test/parallizer_test.rb"
|
34
34
|
]
|
35
35
|
s.homepage = "http://github.com/michaelgpearce/parallizer"
|
36
36
|
s.licenses = ["MIT"]
|
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
class Parallizer::ProxyTest < Test::Unit::TestCase
|
4
4
|
DEFAULT_RETURN_VALUE = "return value"
|
@@ -12,53 +12,82 @@ class Parallizer::ProxyTest < Test::Unit::TestCase
|
|
12
12
|
context ".method_missing" do
|
13
13
|
setup do
|
14
14
|
@client = TestObject.new
|
15
|
+
@call_key = []
|
16
|
+
@call_info = {:result => nil, :exception => nil, :complete? => true,
|
17
|
+
:condition_variable => ConditionVariable.new, :mutex => Mutex.new }
|
18
|
+
end
|
19
|
+
|
20
|
+
execute do
|
21
|
+
call_infos = { @call_key => @call_info }
|
22
|
+
proxy = Parallizer::Proxy.new(@client, call_infos)
|
23
|
+
proxy.send(*@call_key) rescue $!
|
15
24
|
end
|
16
25
|
|
17
26
|
context "with method that exists on client" do
|
18
|
-
context "with method and arg
|
27
|
+
context "with method and arg call info" do
|
19
28
|
setup do
|
20
|
-
@
|
21
|
-
@method_arg = "some arg"
|
22
|
-
@execution_results = {[:a_method, @method_arg] => {:result => @method_result}}
|
29
|
+
@call_key += [:a_method, "some value"]
|
23
30
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
31
|
+
|
32
|
+
context "with not complete?" do
|
33
|
+
setup do
|
34
|
+
@call_info[:complete?] = false
|
35
|
+
@call_info[:condition_variable].expects(:wait).with(@call_info[:mutex])
|
36
|
+
@call_info[:result] = 'this is a value'
|
37
|
+
end
|
38
|
+
|
39
|
+
should do
|
40
|
+
assert_equal @call_info[:result], @execute_result
|
41
|
+
end
|
27
42
|
end
|
28
|
-
|
29
|
-
context "with
|
43
|
+
|
44
|
+
context "with complete? call info" do
|
30
45
|
setup do
|
31
|
-
@
|
46
|
+
@call_info[:complete?] = true
|
32
47
|
end
|
33
48
|
|
34
|
-
|
35
|
-
|
36
|
-
|
49
|
+
context "with an exception" do
|
50
|
+
setup do
|
51
|
+
@call_info[:exception] = StandardError.new('An Exception')
|
52
|
+
end
|
53
|
+
|
54
|
+
should "raise exception" do
|
55
|
+
assert_equal @call_info[:exception], @execute_result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with a result" do
|
60
|
+
setup do
|
61
|
+
@call_info[:result] = "a result"
|
62
|
+
end
|
63
|
+
|
64
|
+
should "return result" do
|
65
|
+
assert_equal @call_info[:result], @execute_result
|
37
66
|
end
|
38
67
|
end
|
39
68
|
end
|
40
69
|
end
|
41
70
|
|
42
|
-
context "with method and arg not in execute result" do
|
71
|
+
context "with no method and arg not in execute result" do
|
43
72
|
setup do
|
44
|
-
@
|
73
|
+
@call_key += [:a_method, "some parameter"]
|
74
|
+
@call_info = nil
|
45
75
|
end
|
46
|
-
|
76
|
+
|
47
77
|
should "return value from client object" do
|
48
|
-
assert_equal DEFAULT_RETURN_VALUE,
|
78
|
+
assert_equal DEFAULT_RETURN_VALUE, @execute_result
|
49
79
|
end
|
50
80
|
end
|
51
81
|
end
|
52
82
|
|
53
83
|
context "with method that does not exist on client" do
|
54
84
|
setup do
|
55
|
-
@
|
85
|
+
@call_key += [:unknown_method, "some parameter"]
|
86
|
+
@call_info = nil
|
56
87
|
end
|
57
88
|
|
58
89
|
should "raise exception" do
|
59
|
-
|
60
|
-
Parallizer::Proxy.new(@client, @execution_results).unknown_method()
|
61
|
-
end
|
90
|
+
assert_equal NoMethodError, @execute_result.class
|
62
91
|
end
|
63
92
|
end
|
64
93
|
end
|
@@ -66,8 +95,10 @@ class Parallizer::ProxyTest < Test::Unit::TestCase
|
|
66
95
|
context ".respond_to?" do
|
67
96
|
setup do
|
68
97
|
client = TestObject.new
|
69
|
-
|
70
|
-
|
98
|
+
call_key = [:a_method, 'valid argument']
|
99
|
+
call_info = {:result => nil, :exception => nil, :complete? => true,
|
100
|
+
:condition_variable => ConditionVariable.new, :mutex => Mutex.new }
|
101
|
+
@proxy = Parallizer::Proxy.new(client, { call_key => call_info })
|
71
102
|
end
|
72
103
|
|
73
104
|
should "respond to proxy method as symbol" do
|
data/test/parallizer_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
class ParallizerTest < Test::Unit::TestCase
|
4
4
|
class TestObject
|
@@ -43,7 +43,17 @@ class ParallizerTest < Test::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
|
45
45
|
execute do
|
46
|
-
@parallizer.add_call(@method, 'arg')
|
46
|
+
@parallizer.add_call(@method, 'arg') rescue $!
|
47
|
+
end
|
48
|
+
|
49
|
+
context "with proxy already created" do
|
50
|
+
setup do
|
51
|
+
@parallizer.instance_variable_set(:@proxy, mock('proxy'))
|
52
|
+
end
|
53
|
+
|
54
|
+
should "raise ArgumentError" do
|
55
|
+
assert_equal ArgumentError, @execute_result.class
|
56
|
+
end
|
47
57
|
end
|
48
58
|
|
49
59
|
context "with string method name added" do
|
@@ -67,14 +77,14 @@ class ParallizerTest < Test::Unit::TestCase
|
|
67
77
|
end
|
68
78
|
end
|
69
79
|
|
70
|
-
context ".
|
80
|
+
context ".create_proxy" do
|
71
81
|
setup do
|
72
82
|
@client = TestObject.new
|
73
83
|
@parallizer = Parallizer.new(@client)
|
74
84
|
end
|
75
85
|
|
76
86
|
execute do
|
77
|
-
@proxy = @parallizer.
|
87
|
+
@proxy = @parallizer.create_proxy rescue $!
|
78
88
|
end
|
79
89
|
|
80
90
|
context "with existing method on client" do
|
@@ -90,30 +100,16 @@ class ParallizerTest < Test::Unit::TestCase
|
|
90
100
|
assert_equal Thread.current, @proxy.another_method
|
91
101
|
end
|
92
102
|
end
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
@parallizer2.add_call(:a_method)
|
103
|
-
end
|
104
|
-
|
105
|
-
execute do
|
106
|
-
@proxy1, @proxy2 = Parallizer.execute_all(@parallizer1, @parallizer2)
|
107
|
-
end
|
108
|
-
|
109
|
-
should "execute methods with add_call in a separate thread" do
|
110
|
-
assert_not_equal Thread.current, @proxy1.a_method('arg')
|
111
|
-
assert_not_equal Thread.current, @proxy2.a_method
|
112
|
-
end
|
113
|
-
|
114
|
-
should "execute methods not added with add_call in current thread" do
|
115
|
-
assert_equal Thread.current, @proxy1.another_method
|
116
|
-
assert_equal Thread.current, @proxy2.another_method
|
103
|
+
|
104
|
+
context "with proxy already created" do
|
105
|
+
setup do
|
106
|
+
@parallizer.instance_variable_set(:@proxy, mock('proxy'))
|
107
|
+
end
|
108
|
+
|
109
|
+
should "raise ArgumentError" do
|
110
|
+
assert_equal ArgumentError, @execute_result.class
|
111
|
+
end
|
117
112
|
end
|
113
|
+
|
118
114
|
end
|
119
115
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -109,10 +109,10 @@ files:
|
|
109
109
|
- lib/parallizer/method_call_notifier.rb
|
110
110
|
- lib/parallizer/proxy.rb
|
111
111
|
- parallizer.gemspec
|
112
|
+
- test/helper.rb
|
112
113
|
- test/parallizer/method_call_notifier_test.rb
|
113
114
|
- test/parallizer/proxy_test.rb
|
114
115
|
- test/parallizer_test.rb
|
115
|
-
- test/test_helper.rb
|
116
116
|
homepage: http://github.com/michaelgpearce/parallizer
|
117
117
|
licenses:
|
118
118
|
- MIT
|
@@ -128,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
128
|
version: '0'
|
129
129
|
segments:
|
130
130
|
- 0
|
131
|
-
hash: -
|
131
|
+
hash: -894887093549594031
|
132
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
133
|
none: false
|
134
134
|
requirements:
|