multi_process 0.4.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0ed246c253f6ea4749f55ee0fecb88362b14f4ee
4
- data.tar.gz: 3dc45356e8af8de981bf7aa55ba01e15d0e94af5
2
+ SHA256:
3
+ metadata.gz: 72585d4ab91c2cabcab27ece73e7759bc9ae7d9825564736583b551467dc480d
4
+ data.tar.gz: 27d863d2702517f16a7cb35de0f9e6823dbe32212b11465ba509fb91a3565bd9
5
5
  SHA512:
6
- metadata.gz: a1d41519fa0047ed43402b2999183dcf5a38f75a1ed21081d81c3720877c4186d60fc66e845050bc28a4b3e1d9d2edae05f68cc4e57376a5e1601dd0adf5d471
7
- data.tar.gz: b12e9cd8912107d2e0cf63401c7c11dbd0a20c92573ecf5a1c9191e8191dcccecaba7742049f85d5ee49b64e3b39b576ded43e903ca7417528c98c1bb5b9f3b6
6
+ metadata.gz: 8c1d02ed6a2ea5d5c08a7776ba4e9ad777f4d15454fc91d711e98cf52c430ef2faf51b2f3a83c40fe0ee3b688368c32e4e69102d65414dfcd12814d17b9b8f5e
7
+ data.tar.gz: ed7f3357d64c532b39271affe9156aaf58bc20ed59b73778d8bbdbfd73ac503aa44babd0b80c08e7d6f03a1cc1f33b848d57b1b237cdd408effbff7fe1f5d259
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## 1.1.0 - 2020-11-19
10
+ ### Feature
11
+ - Add support for IPv6 by using the hostname instead of the loopback IPv4 address (#2)
12
+
13
+ ## 1.0.0 - 2019-05-13
14
+ ### Fixed
15
+ - Possible concurrent hash modification while iterating (#1)
16
+
17
+ [Unreleased]: https://github.com/jgraichen/multi_process/compare/v1.0.0...HEAD
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MultiProcess
2
2
 
3
- Handle multiple processes.
3
+ Handle multiple processes. Ruby >= 2.0.
4
4
 
5
5
  TODO: Just experiment.
6
6
 
@@ -39,7 +39,7 @@ group.stop # Stop processes
39
39
  (23314) rubyC | Output from C
40
40
  (23311) rubyB | Output from B
41
41
  (23308) rubyA | Output from A
42
- ``
42
+ ```
43
43
 
44
44
  ## Contributing
45
45
 
@@ -51,7 +51,7 @@ group.stop # Stop processes
51
51
 
52
52
  ## License
53
53
 
54
- Copyright (C) 2014 Jan Graichen
54
+ Copyright (C) 2019 Jan Graichen
55
55
 
56
56
  This program is free software: you can redistribute it and/or modify
57
57
  it under the terms of the GNU General Public License as published by
data/Rakefile CHANGED
@@ -2,4 +2,4 @@ require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
- task :default => :spec
5
+ task default: :spec
@@ -4,6 +4,7 @@ require 'childprocess'
4
4
  module MultiProcess
5
5
  DEFAULT_TIMEOUT = 60
6
6
 
7
+ require 'multi_process/loop'
7
8
  require 'multi_process/group'
8
9
  require 'multi_process/receiver'
9
10
  require 'multi_process/nil_receiver'
@@ -1,9 +1,9 @@
1
1
  module MultiProcess
2
-
2
+ #
3
3
  # Store and run a group of processes.
4
4
  #
5
5
  class Group
6
-
6
+ #
7
7
  # Return list of processes.
8
8
  attr_reader :processes
9
9
 
@@ -22,10 +22,10 @@ module MultiProcess
22
22
  # @option otps [ Receiver ] :receiver Receiver to use for new added
23
23
  # processes. Defaults to `MultiProcess::Logger.global`.
24
24
  #
25
- def initialize(opts = {})
25
+ def initialize(receiver: nil, partition: nil)
26
26
  @processes = []
27
- @receiver = opts[:receiver] ? opts[:receiver] : MultiProcess::Logger.global
28
- @partition = opts[:partition] ? opts[:partition].to_i : 0
27
+ @receiver = receiver ? receiver : MultiProcess::Logger.global
28
+ @partition = partition ? partition.to_i : 0
29
29
  @mutex = Mutex.new
30
30
  end
31
31
 
@@ -35,14 +35,12 @@ module MultiProcess
35
35
  #
36
36
  # @param process [Process, Array<Process>] New process or processes.
37
37
  #
38
- def <<(process)
39
- Array(process).flatten.each do |process|
38
+ def <<(procs)
39
+ Array(procs).flatten.each do |process|
40
40
  processes << process
41
41
  process.receiver = receiver
42
42
 
43
- if started?
44
- start process
45
- end
43
+ start process if started?
46
44
  end
47
45
  end
48
46
 
@@ -50,15 +48,14 @@ module MultiProcess
50
48
  #
51
49
  # Call blocks until all processes are started.
52
50
  #
53
- # @param opts [ Hash ] Options.
54
- # @option opts [ Integer ] :delay Delay in seconds between starting processes.
51
+ # @option delay [Integer] Delay in seconds between starting processes.
55
52
  #
56
- def start(opts = {})
53
+ def start(delay: nil)
57
54
  processes.each do |process|
58
- unless process.started?
59
- process.start
60
- sleep opts[:delay] if opts[:delay]
61
- end
55
+ next if process.started?
56
+
57
+ process.start
58
+ sleep delay if delay
62
59
  end
63
60
  end
64
61
 
@@ -67,15 +64,13 @@ module MultiProcess
67
64
  # @return [ Boolean ] True if group was already started.
68
65
  #
69
66
  def started?
70
- processes.any? &:started?
67
+ processes.any?(&:started?)
71
68
  end
72
69
 
73
70
  # Stop all processes.
74
71
  #
75
72
  def stop
76
- processes.each do |process|
77
- process.stop
78
- end
73
+ processes.each(&:stop)
79
74
  end
80
75
 
81
76
  # Wait until all process terminated.
@@ -84,11 +79,11 @@ module MultiProcess
84
79
  # @option opts [ Integer ] :timeout Timeout in seconds to wait before
85
80
  # raising {Timeout::Error}.
86
81
  #
87
- def wait(opts = {})
88
- opts[:timeout] ||= 30
89
-
90
- ::Timeout::timeout(opts[:timeout]) do
91
- processes.each{|p| p.wait}
82
+ def wait(timeout: nil)
83
+ if timeout
84
+ ::Timeout.timeout(timeout) { wait }
85
+ else
86
+ processes.each(&:wait)
92
87
  end
93
88
  end
94
89
 
@@ -100,20 +95,18 @@ module MultiProcess
100
95
  # If timeout is given process will be terminated using {#stop}
101
96
  # when timeout error is raised.
102
97
  #
103
- def run(opts = {})
98
+ def run(delay: nil, timeout: nil)
104
99
  if partition > 0
105
- threads = Array.new
106
- partition.times do
107
- threads << Thread.new do
100
+ partition.times.map do
101
+ Thread.new do
108
102
  while (process = next_process)
109
103
  process.run
110
104
  end
111
105
  end
112
- end
113
- threads.each &:join
106
+ end.each(&:join)
114
107
  else
115
- start opts
116
- wait opts
108
+ start delay: delay
109
+ wait timeout: timeout
117
110
  end
118
111
  ensure
119
112
  stop
@@ -124,14 +117,14 @@ module MultiProcess
124
117
  # @return [ Boolean ] True if group is alive.
125
118
  #
126
119
  def alive?
127
- processes.any? &:alive?
120
+ processes.any?(&:alive?)
128
121
  end
129
122
 
130
123
  # Check if group is available. The group is available if all
131
124
  # processes are available.
132
125
  #
133
126
  def available?
134
- !processes.any?{|p| !p.available? }
127
+ processes.all?(:available?)
135
128
  end
136
129
 
137
130
  # Wait until group is available. This implies waiting until
@@ -143,15 +136,14 @@ module MultiProcess
143
136
  # @option opts [ Integer ] :timeout Timeout in seconds to wait for processes
144
137
  # to become available. Defaults to {MultiProcess::DEFAULT_TIMEOUT}.
145
138
  #
146
- def available!(opts = {})
147
- timeout = opts[:timeout] ? opts[:timeout].to_i : MultiProcess::DEFAULT_TIMEOUT
148
-
139
+ def available!(timeout: MultiProcess::DEFAULT_TIMEOUT)
149
140
  Timeout.timeout timeout do
150
- processes.each{|p| p.available! }
141
+ processes.each(&:available!)
151
142
  end
152
143
  end
153
144
 
154
145
  private
146
+
155
147
  def next_process
156
148
  @mutex.synchronize do
157
149
  @index ||= 0
@@ -1,11 +1,9 @@
1
1
  module MultiProcess
2
-
3
2
  # Can create pipes and multiplex pipe content to put into
4
3
  # given IO objects e.g. multiple output from multiple
5
4
  # processes to current stdout.
6
5
  #
7
6
  class Logger < Receiver
8
-
9
7
  # Create new logger.
10
8
  #
11
9
  # @param out [IO] IO to push formatted output from
@@ -14,10 +12,12 @@ module MultiProcess
14
12
  # error sources.
15
13
  #
16
14
  def initialize(*args)
17
- @opts = Hash === args.last ? args.pop : Hash.new
15
+ @opts = Hash === args.last ? args.pop : {}
18
16
  @out = args[0] || $stdout
19
17
  @err = args[1] || $stderr
20
18
 
19
+ @colwidth = 0
20
+
21
21
  super()
22
22
  end
23
23
 
@@ -34,6 +34,10 @@ module MultiProcess
34
34
  end
35
35
  end
36
36
 
37
+ def connected(process, _)
38
+ @colwidth = [process.title.to_s.length, @colwidth].max
39
+ end
40
+
37
41
  def read(pipe)
38
42
  pipe.gets
39
43
  end
@@ -43,32 +47,34 @@ module MultiProcess
43
47
  end
44
48
 
45
49
  private
46
- def output(process, line, opts = {})
47
- @mutex.synchronize do
48
- opts[:delimiter] ||= ' |'
49
- name = if opts[:name]
50
- opts[:name].to_s.dup
51
- else
52
- max = @readers.values.map{|h| h[:process] ? h[:process].title.length : 0 }.max
53
- process ? process.title.to_s.rjust(max, ' ') : (' ' * max)
54
- end
55
50
 
56
- io = opts[:io] || @out
57
- if @last_name == name && collapse?
58
- io.print " #{' ' * name.length} #{opts[:delimiter]} "
59
- else
60
- io.print " #{name} #{opts[:delimiter]} "
61
- end
62
- io.puts line
63
- io.flush
51
+ def output(process, line, opts = {})
52
+ opts[:delimiter] ||= ' |'
53
+ name = if opts[:name]
54
+ opts[:name].to_s.dup
55
+ else
56
+ if process
57
+ process.title.to_s.rjust(@colwidth, ' ')
58
+ else
59
+ (' ' * @colwidth)
60
+ end
61
+ end
64
62
 
65
- @last_name = name
63
+ io = opts[:io] || @out
64
+ if @last_name == name && collapse?
65
+ io.print " #{' ' * name.length} #{opts[:delimiter]} "
66
+ else
67
+ io.print " #{name} #{opts[:delimiter]} "
66
68
  end
69
+ io.puts line
70
+ io.flush
71
+
72
+ @last_name = name
67
73
  end
68
74
 
69
75
  class << self
70
76
  def global
71
- @global ||= self.new $stdout, $stderr
77
+ @global ||= new $stdout, $stderr
72
78
  end
73
79
  end
74
80
  end
@@ -0,0 +1,39 @@
1
+ require 'nio'
2
+
3
+ module MultiProcess
4
+ class Loop
5
+ def initialize
6
+ @selector = ::NIO::Selector.new
7
+
8
+ Thread.new do
9
+ loop do
10
+ @selector.select(30.0) do |monitor|
11
+ if monitor.io.eof?
12
+ @selector.deregister(monitor.io)
13
+ monitor.value.call(:eof, monitor)
14
+ else
15
+ monitor.value.call(:ready, monitor)
16
+ end
17
+ end
18
+
19
+ # Wait very short time to allow scheduling another thread
20
+ sleep(0.001)
21
+ end
22
+ end
23
+ end
24
+
25
+ def watch(io, &block)
26
+ @selector.wakeup
27
+ @selector.register(io, :r).tap do |monitor|
28
+ monitor.value = block
29
+ monitor.value.call(:registered, monitor)
30
+ end
31
+ end
32
+
33
+ class << self
34
+ def instance
35
+ @instance ||= new
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,12 +1,10 @@
1
1
  module MultiProcess
2
-
3
2
  # Receiver implementation that does nothing on every input.
4
3
  #
5
4
  class NilReceiver < Receiver
6
-
7
5
  # Do nothing.
8
6
  #
9
- def received(process, name, message)
7
+ def received(_process, _name, _message)
10
8
  nil
11
9
  end
12
10
  end
@@ -1,13 +1,13 @@
1
1
  require 'active_support/core_ext/module/delegation'
2
2
 
3
3
  module MultiProcess
4
-
4
+ #
5
5
  # Describes a single process that can be configured and run.
6
6
  #
7
7
  # {Process} basically is just a thin wrapper around {ChildProcess}.
8
8
  #
9
9
  class Process
10
- #@!group Process
10
+ # @!group Process
11
11
 
12
12
  # Process title used in e.g. logger
13
13
  attr_reader :title
@@ -23,7 +23,7 @@ module MultiProcess
23
23
  opts = (Hash === args.last ? args.pop : {})
24
24
 
25
25
  @title = opts[:title].to_s || args.first.to_s.strip.split(/\s+/, 2)[0]
26
- @command = args.map{ |arg| (arg =~ /\A[\s"']+\z/ ? arg.inspect : arg).gsub '"', '\"' }.join(' ')
26
+ @command = args.map { |arg| (arg =~ /\A[\s"']+\z/ ? arg.inspect : arg).gsub '"', '\"' }.join(' ')
27
27
  @childprocess = create_childprocess *args
28
28
 
29
29
  @env = opts[:env] if Hash === opts[:env]
@@ -63,7 +63,7 @@ module MultiProcess
63
63
  return false if started?
64
64
 
65
65
  at_exit { stop }
66
- receiver.message(self, :sys, self.command) if receiver
66
+ receiver.message(self, :sys, command) if receiver
67
67
  start_childprocess
68
68
  @started = true
69
69
  end
@@ -116,7 +116,7 @@ module MultiProcess
116
116
  wait opts
117
117
  end
118
118
 
119
- #@!group Working Directory
119
+ # @!group Working Directory
120
120
 
121
121
  # Working directory for child process.
122
122
  attr_reader :dir
@@ -126,10 +126,10 @@ module MultiProcess
126
126
  #
127
127
  def dir=(dir)
128
128
  @dir = ::File.expand_path(dir.to_s)
129
- self.env['PWD'] = @dir
129
+ env['PWD'] = @dir
130
130
  end
131
131
 
132
- #@!group Environment
132
+ # @!group Environment
133
133
 
134
134
  # Check if environment will be cleaned up for process.
135
135
  #
@@ -144,17 +144,17 @@ module MultiProcess
144
144
  # Return current environment.
145
145
  #
146
146
  def env
147
- @env ||= Hash.new
147
+ @env ||= {}
148
148
  end
149
149
 
150
150
  # Set environment.
151
151
  #
152
152
  def env=(env)
153
- raise ArgumentError.new 'Environment must be a Hash.' unless hash === env
153
+ fail ArgumentError.new 'Environment must be a Hash.' unless hash === env
154
154
  @env = env
155
155
  end
156
156
 
157
- #@!group Receiver
157
+ # @!group Receiver
158
158
 
159
159
  # Current receiver. Defaults to `MultiProcess::Logger.global`.
160
160
  #
@@ -186,7 +186,7 @@ module MultiProcess
186
186
  # Can be used to hook in subclasses and modules.
187
187
  #
188
188
  def start_childprocess
189
- env.each{|k, v| childprocess.environment[k.to_s] = v.to_s }
189
+ env.each { |k, v| childprocess.environment[k.to_s] = v.to_s }
190
190
  childprocess.cwd = dir
191
191
 
192
192
  if clean_env?
@@ -1,12 +1,10 @@
1
1
  class MultiProcess::Process
2
-
3
2
  # Provides functionality to wrap command in with bundle
4
3
  # execute.
5
4
  #
6
5
  module BundleExec
7
-
8
6
  def initialize(*args)
9
- opts = Hash === args.last ? args.pop : Hash.new
7
+ opts = Hash === args.last ? args.pop : {}
10
8
  super %w(bundle exec) + args, opts
11
9
  end
12
10
  end
@@ -1,5 +1,4 @@
1
1
  class MultiProcess::Process
2
-
3
2
  # Provides functionality for a process that is a rails server
4
3
  # process.
5
4
  #
@@ -9,7 +8,6 @@ class MultiProcess::Process
9
8
  # availability check based on if server socket is reachable.
10
9
  #
11
10
  module Rails
12
-
13
11
  # Server wrapper given as argument to `server` action.
14
12
  #
15
13
  attr_reader :server
@@ -44,9 +42,9 @@ class MultiProcess::Process
44
42
  end
45
43
 
46
44
  def available?
47
- raise ArgumentError.new "Cannot check availability for port #{port}." if port == 0
45
+ fail ArgumentError.new "Cannot check availability for port #{port}." if port == 0
48
46
 
49
- TCPSocket.new('127.0.0.1', port).close
47
+ TCPSocket.new('localhost', port).close
50
48
  true
51
49
  rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
52
50
  false
@@ -69,7 +67,7 @@ class MultiProcess::Process
69
67
 
70
68
  def free_port
71
69
  socket = Socket.new(:INET, :STREAM, 0)
72
- socket.bind(Addrinfo.tcp("127.0.0.1", 0))
70
+ socket.bind(Addrinfo.tcp('localhost', 0))
73
71
  socket.local_address.ip_port
74
72
  ensure
75
73
  socket.close if socket
@@ -1,40 +1,8 @@
1
1
  module MultiProcess
2
-
3
2
  # Can handle input from multiple processes and run custom
4
3
  # actions on event and output.
5
4
  #
6
5
  class Receiver
7
-
8
- # Mutex to synchronize operations.
9
- #
10
- attr_reader :mutex
11
-
12
- def initialize
13
- @mutex = Mutex.new
14
- @readers = {}
15
-
16
- Thread.new do
17
- begin
18
- loop do
19
- io = IO.select(@readers.keys, nil, nil, 0.1)
20
- (io.nil? ? [] : io.first).each do |reader|
21
- op = @readers[reader]
22
-
23
- if reader.eof?
24
- @readers.delete_if { |key, value| key == reader }
25
- removed op[:process], op[:name]
26
- else
27
- received op[:process], op[:name], read(reader)
28
- end
29
- end
30
- end
31
- rescue Exception => ex
32
- puts ex.message
33
- puts ex.backtrace
34
- end
35
- end
36
- end
37
-
38
6
  # Request a new pipe writer for given process and name.
39
7
  #
40
8
  # @param process [ Process ] Process requesting pipe.
@@ -43,8 +11,18 @@ module MultiProcess
43
11
  #
44
12
  def pipe(process, name)
45
13
  reader, writer = IO.pipe
46
- @readers[reader] = {name: name, process: process}
47
- connected process, name
14
+
15
+ Loop.instance.watch(reader) do |action, monitor|
16
+ case action
17
+ when :registered
18
+ connected(process, name)
19
+ when :ready
20
+ received(process, name, read(monitor.io))
21
+ when :eof
22
+ removed(process, name)
23
+ end
24
+ end
25
+
48
26
  writer
49
27
  end
50
28
 
@@ -61,8 +39,8 @@ module MultiProcess
61
39
  #
62
40
  # Must be overridden by subclass.
63
41
  #
64
- def received(process, name, message)
65
- raise NotImplementedError.new 'Subclass responsibility.'
42
+ def received(_process, _name, _message)
43
+ fail NotImplementedError.new 'Subclass responsibility.'
66
44
  end
67
45
 
68
46
  # Read content from pipe. Can be used to provide custom reading
@@ -77,14 +55,12 @@ module MultiProcess
77
55
  # Called after pipe for process and name was removed because it
78
56
  # reached EOF.
79
57
  #
80
- def removed(process, name)
81
-
58
+ def removed(_process, _name)
82
59
  end
83
60
 
84
61
  # Called after new pipe for process and name was created.
85
62
  #
86
- def connected(process, name)
87
-
63
+ def connected(_process, _name)
88
64
  end
89
65
  end
90
66
  end
@@ -1,17 +1,15 @@
1
1
  module MultiProcess
2
-
3
2
  # Receiver implementation storing process output
4
3
  # in string.
5
4
  #
6
5
  class StringReceiver < Receiver
7
-
8
- def received(process, name, message)
6
+ def received(_process, name, message)
9
7
  get(name) << message
10
8
  end
11
9
 
12
10
  def get(name)
13
- @strings ||= Hash.new
14
- @strings[name.to_s] ||= String.new
11
+ @strings ||= {}
12
+ @strings[name.to_s] ||= ''
15
13
  end
16
14
  end
17
15
  end
@@ -1,11 +1,13 @@
1
1
  module MultiProcess
2
2
  module VERSION
3
- MAJOR = 0
4
- MINOR = 4
3
+ MAJOR = 1
4
+ MINOR = 1
5
5
  PATCH = 0
6
6
  STAGE = nil
7
7
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.')
8
8
 
9
- def self.to_s; STRING end
9
+ def self.to_s
10
+ STRING
11
+ end
10
12
  end
11
13
  end
@@ -4,22 +4,23 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'multi_process/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "multi_process"
7
+ spec.name = 'multi_process'
8
8
  spec.version = MultiProcess::VERSION
9
- spec.authors = ["Jan Graichen"]
10
- spec.email = ["jg@altimos.de"]
11
- spec.summary = %q{Handle multiple child processes.}
12
- spec.description = %q{Handle multiple child processes.}
13
- spec.homepage = "https://github.com/jgraichen/multi_process"
14
- spec.license = "GPLv3"
9
+ spec.authors = ['Jan Graichen']
10
+ spec.email = ['jg@altimos.de']
11
+ spec.summary = 'Handle multiple child processes.'
12
+ spec.description = 'Handle multiple child processes.'
13
+ spec.homepage = 'https://github.com/jgraichen/multi_process'
14
+ spec.license = 'GPLv3'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_runtime_dependency 'activesupport', '>= 3.1'
22
22
  spec.add_runtime_dependency 'childprocess'
23
+ spec.add_runtime_dependency 'nio4r', '~> 2.0'
23
24
 
24
- spec.add_development_dependency "bundler", "~> 1.5"
25
+ spec.add_development_dependency 'bundler'
25
26
  end
@@ -1,24 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe MultiProcess do
4
-
5
4
  it 'should run processes' do
6
5
  reader, writer = IO.pipe
7
6
 
8
7
  logger = MultiProcess::Logger.new writer, collapse: false
9
8
  group = MultiProcess::Group.new receiver: logger
10
9
  group << MultiProcess::Process.new(%w(ruby spec/files/test.rb A), title: 'rubyA')
11
- group << MultiProcess::Process.new(%w(ruby spec/files/test.rb B), title: 'rubyB')
12
- group << MultiProcess::Process.new(%w(ruby spec/files/test.rb C), title: 'rubyC')
10
+ group << MultiProcess::Process.new(%w(ruby spec/files/test.rb B), title: 'rubyBB')
11
+ group << MultiProcess::Process.new(%w(ruby spec/files/test.rb C), title: 'rubyCCC')
13
12
  group.run
14
13
 
15
- expect(reader.read_nonblock(4096).split("\n")).to match_array <<-EOF.gsub(/^\s+/, ' ').split("\n")
16
- rubyB | Output from B
17
- rubyA | Output from A
18
- rubyA | Output from A
19
- rubyC | Output from C
20
- rubyC | Output from C
21
- rubyB | Output from B
14
+ expect(reader.read_nonblock(4096).split("\n")).to match_array <<-EOF.gsub(/^\s+\./, '').split("\n")
15
+ . rubyBB | Output from B
16
+ . rubyA | Output from A
17
+ . rubyA | Output from A
18
+ . rubyCCC | Output from C
19
+ . rubyCCC | Output from C
20
+ . rubyBB | Output from B
22
21
  EOF
23
22
  end
24
23
 
@@ -57,7 +56,7 @@ describe MultiProcess do
57
56
 
58
57
  it 'should env processes' do
59
58
  receiver = MultiProcess::StringReceiver.new
60
- process = MultiProcess::Process.new(%w(ruby spec/files/env.rb TEST), env: {'TEST' => "abc"}, receiver: receiver)
59
+ process = MultiProcess::Process.new(%w(ruby spec/files/env.rb TEST), env: { 'TEST' => 'abc' }, receiver: receiver)
61
60
  process.run
62
61
 
63
62
  expect(receiver.get(:out)).to eq "ENV: abc\n"
@@ -5,7 +5,7 @@ Bundler.require
5
5
 
6
6
  require 'multi_process'
7
7
 
8
- Dir[File.expand_path('spec/support/**/*.rb')].each {|f| require f}
8
+ Dir[File.expand_path('spec/support/**/*.rb')].each { |f| require f }
9
9
 
10
10
  RSpec.configure do |config|
11
11
  # ## Mock Framework
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_process
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-16 00:00:00.000000000 Z
11
+ date: 2020-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -39,19 +39,33 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: nio4r
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.5'
48
- type: :development
47
+ version: '2.0'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.5'
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Handle multiple child processes.
56
70
  email:
57
71
  - jg@altimos.de
@@ -60,6 +74,7 @@ extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
62
76
  - ".gitignore"
77
+ - CHANGELOG.md
63
78
  - Gemfile
64
79
  - LICENSE.txt
65
80
  - README.md
@@ -67,6 +82,7 @@ files:
67
82
  - lib/multi_process.rb
68
83
  - lib/multi_process/group.rb
69
84
  - lib/multi_process/logger.rb
85
+ - lib/multi_process/loop.rb
70
86
  - lib/multi_process/nil_receiver.rb
71
87
  - lib/multi_process/process.rb
72
88
  - lib/multi_process/process/bundle_exec.rb
@@ -99,8 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
115
  - !ruby/object:Gem::Version
100
116
  version: '0'
101
117
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.2.1
118
+ rubygems_version: 3.0.8
104
119
  signing_key:
105
120
  specification_version: 4
106
121
  summary: Handle multiple child processes.