multi_process 0.4.0 → 1.1.0

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