Class: Holder::Tenant
- Inherits:
-
Object
- Object
- Holder::Tenant
- Defined in:
- lib/holder/tenant.rb
Overview
Builds and launches a child process, returning a Handle that owns its teardown.
in:, out:, and err: each accept an IO (or nil) to redirect that stream
to; any other keyword (+chdir+, umask, ...) is forwarded to the spawn. The
child always runs in its own process group so the whole group can be torn down
together -- this is not overridable.
Instance Attribute Summary collapse
-
#handle ⇒ Object
readonly
Returns the value of attribute handle.
-
#kwargs ⇒ Object
readonly
Returns the value of attribute kwargs.
-
#pgroup ⇒ Object
readonly
Returns the value of attribute pgroup.
Instance Method Summary collapse
-
#initialize(*args, in: nil, out: nil, err: nil, **kwargs) ⇒ Tenant
constructor
A new instance of Tenant.
-
#run ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/MethodLength.
Constructor Details
#initialize(*args, in: nil, out: nil, err: nil, **kwargs) ⇒ Tenant
Returns a new instance of Tenant.
16 17 18 19 20 21 |
# File 'lib/holder/tenant.rb', line 16 def initialize(*args, in: nil, out: nil, err: nil, **kwargs) @args = args @io_defs = { in:, out:, err: } @pgroup = true @kwargs = kwargs end |
Instance Attribute Details
#handle ⇒ Object
Returns the value of attribute handle.
12 13 14 |
# File 'lib/holder/tenant.rb', line 12 def handle @handle end |
#kwargs ⇒ Object (readonly)
Returns the value of attribute kwargs.
12 13 14 |
# File 'lib/holder/tenant.rb', line 12 def kwargs @kwargs end |
#pgroup ⇒ Object (readonly)
Returns the value of attribute pgroup.
12 13 14 |
# File 'lib/holder/tenant.rb', line 12 def pgroup @pgroup end |
Instance Method Details
#run ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/MethodLength
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/holder/tenant.rb', line 23 def run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength # Validate the three streams up front. The one-line pattern match checks each # is an IO or nil (in: is a keyword, so it can't be named as a local); we then # read the values out by key. A bad stream raises ArgumentError here rather # than slipping through and detonating later inside a pump. unless @io_defs in { in: StreamType | nil, out: StreamType | nil, err: StreamType | nil } raise ArgumentError, "in:, out:, and err: must each be an IO object or nil" end u_sin, u_sout, u_serr = @io_defs.values_at(:in, :out, :err) # Open3 ALWAYS pipes stdin and stdout, so in:/out: are always pumped; err is # the only stream that can go direct, and only via popen2. So the entire # 8-case dispatch is just this, and the only thing handed to spawn directly # is a redirected err:. Any extra kwargs (chdir, umask, unsetenv_others, # close_others, ...) are forwarded to spawn; they go in first so our # pgroup: true and err redirect win on collision and the group-teardown # invariant is never overridden. meth = u_serr ? :popen2 : :popen3 spawn_redirects = u_serr ? { err: u_serr } : {} # Each form uses its matching Open3 form: block -> Open3's block form (its # close+reap is a backstop under our kill); no-block -> Open3's non-block # form (the handle owns teardown). if block_given? Open3.public_send(meth, *args, **kwargs, pgroup:, **spawn_redirects) do |*streams| self.handle = build_handle(streams, meth, u_sin, u_sout, u_serr) begin yield handle ensure handle.terminate end end else streams = Open3.public_send(meth, *args, **kwargs, pgroup:, **spawn_redirects) self.handle = build_handle(streams, meth, u_sin, u_sout, u_serr) end end |