iprocess 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -4,7 +4,7 @@ __OVERVIEW__
4
4
  | Project | IProcess
5
5
  |:----------------|:--------------------------------------------------
6
6
  | Homepage | https://github.com/robgleeson/IProcess
7
- | Documentation | http://rubydoc.info/gems/IProcess/frames
7
+ | Documentation | http://rubydoc.info/gems/iprocess/frames
8
8
  | Author | Rob Gleeson
9
9
 
10
10
 
@@ -21,13 +21,21 @@ __WHY?__
21
21
 
22
22
  I wanted to be able to:
23
23
 
24
- * Spawn a subprocess, apply restrictions to that subprocess, then collect
25
- and send Ruby objects back to the parent process.
26
- (that was for a IRC bot evaluating Ruby code).
27
-
28
- * Spawn multiple parallel jobs, then collect and send back Ruby objects to the
29
- parent process.
24
+ * Share Ruby objects between a subprocess and its parent process.
25
+ * Share Ruby objects between multiple subprocesses running in parallel and their parent.
30
26
 
27
+
28
+ __COST?__
29
+
30
+ If you're using IProcess for parallelism, a subprocess will cost you more than
31
+ a thread (in terms of time to create the subprocess, and the memory it consumes
32
+ - no implementation IProcess supports has a CoW-friendly garbage collector).
33
+
34
+ Despite the GIL on CRuby, for IO bound operations it can run threads in
35
+ parallel and may perform better. For long running non-IO bound operations,
36
+ though, parallel subprocesses usually outperform CRuby threads. You should
37
+ profile and benchmark IProcess and threads for your use-case before choosing
38
+ either. IProcess may be better, or it may be worse.
31
39
 
32
40
  __EXAMPLES__
33
41
 
@@ -15,6 +15,26 @@ class IProcess::Channel
15
15
  end
16
16
  end
17
17
 
18
+ #
19
+ # Is the channel closed?
20
+ #
21
+ # @return [Boolean]
22
+ # Returns true if the channel is closed.
23
+ #
24
+ def closed?
25
+ @reader.closed? && @writer.closed?
26
+ end
27
+
28
+ #
29
+ # Is the channel open?
30
+ #
31
+ # @return [Boolean]
32
+ # Returns true if the channel is open.
33
+ #
34
+ def open?
35
+ !closed?
36
+ end
37
+
18
38
  #
19
39
  # Write a object to the channel.
20
40
  #
@@ -22,9 +42,11 @@ class IProcess::Channel
22
42
  # A object to add to the channel.
23
43
  #
24
44
  def write object
25
- @reader.close
26
- @writer.write Marshal.dump(object)
27
- @writer.close
45
+ if open?
46
+ @reader.close
47
+ @writer.write Marshal.dump(object)
48
+ @writer.close
49
+ end
28
50
  end
29
51
 
30
52
  #
@@ -34,10 +56,12 @@ class IProcess::Channel
34
56
  # The object added to the channel.
35
57
  #
36
58
  def recv
37
- @writer.close
38
- obj = Marshal.load(@reader.read)
39
- @reader.close
40
- obj
59
+ if open?
60
+ @writer.close
61
+ obj = Marshal.load(@reader.read)
62
+ @reader.close
63
+ obj
64
+ end
41
65
  end
42
66
 
43
67
  end
@@ -1,4 +1,4 @@
1
- class IProcess::Delegate
1
+ class IProcess::Delegator
2
2
 
3
3
  #
4
4
  # @param [IProcess] delegate
data/lib/iprocess/job.rb CHANGED
@@ -1,21 +1,25 @@
1
1
  class IProcess::Job
2
2
 
3
3
  #
4
- # Spawn one or more jobs to be run in parallel.
4
+ # @overload spawn(number_of_jobs = 1, worker)
5
5
  #
6
- # @param [Integer] number_of_jobs
7
- # The number of jobs to spawn.
6
+ # Spawn one or more jobs to be run in parallel.
8
7
  #
9
- # @param [Proc] worker
10
- # The unit of work to execute in one or more jobs.
8
+ # @param [Integer] number_of_jobs
9
+ # The number of jobs to spawn.
11
10
  #
12
- # @return [Array<Object>]
13
- # The return value of one or more workers.
11
+ # @param [#call] worker
12
+ # The unit of work to execute in one or more jobs.
14
13
  #
15
- def self.spawn number_of_jobs = 1, &worker
14
+ # @return [Array<Object>]
15
+ # The return value of one or more workers.
16
+ #
17
+ def self.spawn number_of_jobs = 1, obj = nil, &worker
18
+ worker = obj || worker
19
+
16
20
  jobs =
17
21
  Array.new(number_of_jobs) do
18
- job = IProcess::Job.new(&worker)
22
+ job = IProcess::Job.new(worker)
19
23
  job.execute
20
24
  job
21
25
  end
@@ -26,7 +30,7 @@ class IProcess::Job
26
30
  end
27
31
 
28
32
  #
29
- # @param [Proc] worker
33
+ # @param [#call] worker
30
34
  # The unit of work to execute in a subprocess.
31
35
  #
32
36
  # @raise [ArgumentError]
@@ -35,14 +39,15 @@ class IProcess::Job
35
39
  # @return [IProcess::Job]
36
40
  # Returns self.
37
41
  #
38
- def initialize &worker
39
- unless block_given?
40
- raise ArgumentError, 'No block given.'
41
- end
42
-
42
+ def initialize worker
43
43
  @worker = worker
44
44
  @channel = nil
45
45
  @pid = nil
46
+
47
+ unless @worker.respond_to?(:call)
48
+ raise ArgumentError,
49
+ "Expected worker to implement #{@worker.class}#call"
50
+ end
46
51
  end
47
52
 
48
53
  #
@@ -1,3 +1,3 @@
1
1
  class IProcess
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'
3
3
  end
data/lib/iprocess.rb CHANGED
@@ -5,12 +5,11 @@ class IProcess
5
5
  #
6
6
  def initialize &block
7
7
  @variables = SortedSet.new
8
+ @scope = nil
8
9
 
9
10
  if block_given?
10
11
  @scope = block.binding
11
- IProcess::Delegate.new(self).instance_eval(&block)
12
- else
13
- @scope = nil
12
+ IProcess::Delegator.new(self).instance_eval(&block)
14
13
  end
15
14
  end
16
15
 
@@ -85,6 +84,7 @@ class IProcess
85
84
  scope.eval("#{channel.name} = Thread.current[:__iprocess_obj__]")
86
85
  end
87
86
 
87
+ Thread.current[:__iprocess_obj__] = nil
88
88
  pid
89
89
  end
90
90
 
@@ -94,4 +94,4 @@ require 'set'
94
94
  require 'iprocess/version'
95
95
  require 'iprocess/channel'
96
96
  require 'iprocess/job'
97
- require 'iprocess/delegate'
97
+ require 'iprocess/delegator'
@@ -4,6 +4,30 @@ context IProcess::Job do
4
4
  topic = IProcess::Job.spawn(2) { :ok }
5
5
  topic.must_equal([:ok, :ok])
6
6
  end
7
+
8
+ it 'must spawn non-Proc workers and return the result of each.' do
9
+ worker = Class.new do
10
+ def call
11
+ :ok
12
+ end
13
+ end
14
+
15
+ topic = IProcess::Job.spawn(2, worker.new)
16
+ topic.must_equal([:ok, :ok])
17
+ end
18
+
19
+ it 'must accept any object responding to #call.' do
20
+ mock = MiniTest::Mock.new
21
+ mock.expect(:call, :ok)
22
+
23
+ IProcess::Job.spawn(1, mock)
24
+ end
25
+ end
26
+
27
+ context 'initialize' do
28
+ it "must raise a ArgumentError if not given a object responding to #call" do
29
+ proc { IProcess::Job.new("") }.must_raise(ArgumentError)
30
+ end
7
31
  end
8
32
  end
9
33
 
@@ -44,8 +44,10 @@ context IProcess do
44
44
  end
45
45
 
46
46
  it 'must raise a ArgumentError if a block is not given.' do
47
+ obj = IProcess.new
48
+
47
49
  assert_raises ArgumentError do
48
- IProcess.new.fork
50
+ obj.fork
49
51
  end
50
52
  end
51
53
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iprocess
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-09 00:00:00.000000000 Z
12
+ date: 2012-03-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yard
16
- requirement: &70367004931520 !ruby/object:Gem::Requirement
16
+ requirement: &70154156887500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0.7'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70367004931520
24
+ version_requirements: *70154156887500
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redcarpet
27
- requirement: &70367004931060 !ruby/object:Gem::Requirement
27
+ requirement: &70154156887040 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.17'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70367004931060
35
+ version_requirements: *70154156887040
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: minitest
38
- requirement: &70367004930600 !ruby/object:Gem::Requirement
38
+ requirement: &70154156886580 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '2.6'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70367004930600
46
+ version_requirements: *70154156886580
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &70367004930140 !ruby/object:Gem::Requirement
49
+ requirement: &70154156886120 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: 0.9.2
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70367004930140
57
+ version_requirements: *70154156886120
58
58
  description: A Domain Specific Language(DSL) for sharing Ruby objectsbetween processes
59
59
  on UNIX-like operating systems.
60
60
  email: rob@flowof.info
@@ -73,7 +73,7 @@ files:
73
73
  - iprocess.gemspec
74
74
  - lib/iprocess.rb
75
75
  - lib/iprocess/channel.rb
76
- - lib/iprocess/delegate.rb
76
+ - lib/iprocess/delegator.rb
77
77
  - lib/iprocess/job.rb
78
78
  - lib/iprocess/version.rb
79
79
  - test/setup.rb