iprocess 1.0.1 → 1.0.2

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/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