Module: Terminalwire::V2::Server

Defined in:
lib/terminalwire/v2/server/io.rb,
lib/terminalwire/v2/server/flow.rb,
lib/terminalwire/v2/server/rack.rb,
lib/terminalwire/v2/server/thor.rb,
lib/terminalwire/v2/server/context.rb,
lib/terminalwire/v2/server/handler.rb,
lib/terminalwire/v2/server/runtime.rb,
lib/terminalwire/v2/server/session.rb,
lib/terminalwire/v2/server/redirect.rb,
lib/terminalwire/v2/server/terminal.rb,
lib/terminalwire/v2/server/dual_thor.rb,
lib/terminalwire/v2/server/connection.rb,
lib/terminalwire/v2/server/stream_router.rb

Defined Under Namespace

Modules: DualThor, Thor Classes: Connection, Context, FlowController, Handler, IO, Rack, Runtime, Session, StreamRouter, Terminal

Constant Summary collapse

STDOUT_KEY =
:terminalwire_stdout
STDERR_KEY =
:terminalwire_stderr
STDIN_KEY =
:terminalwire_stdin

Class Method Summary collapse

Class Method Details

.dualize(klass, seen = {}) ⇒ Object

Walk a Thor class + its subcommand tree, making every command class respond to both protocols. Idempotent. Returns the class so it reads as a transform.



40
41
42
43
44
45
46
# File 'lib/terminalwire/v2/server/dual_thor.rb', line 40

def self.dualize(klass, seen = {})
  return klass if seen[klass]
  seen[klass] = true
  klass.include(DualThor) unless klass.include?(DualThor)
  klass.subcommand_classes.each_value { |sub| dualize(sub, seen) } if klass.respond_to?(:subcommand_classes)
  klass
end

.install!Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/terminalwire/v2/server/redirect.rb', line 33

def install!
  @install_mutex.synchronize do
    return if @installed

    $stdout = StreamRouter.new(STDOUT_KEY, $stdout)
    $stderr = StreamRouter.new(STDERR_KEY, $stderr)
    $stdin  = StreamRouter.new(STDIN_KEY, $stdin)
    @installed = true
  end
end

.installed?Boolean

Returns:

  • (Boolean)


44
# File 'lib/terminalwire/v2/server/redirect.rb', line 44

def installed? = @installed == true

.redirect(context, argv: nil) ⇒ Object

Run the block with this fiber's standard streams pointed at context.

argv: is accepted for convenience but ARGV / $PROGRAM_NAME are genuinely process-global (Ruby has no fiber-local ARGV), so we pass the arguments to the block instead of mutating ARGV — the Handler hands them to your CLI directly. We deliberately do NOT mutate global ARGV here, to avoid the exact cross-command races this method exists to prevent.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/terminalwire/v2/server/redirect.rb', line 53

def redirect(context, argv: nil)
  install!

  out = IO.new(context, :stdout)
  err = IO.new(context, :stderr)
  in_ = IO.new(context, :stdin)

  prev_out = $stdout.__bind__(out)
  prev_err = $stderr.__bind__(err)
  prev_in  = $stdin.__bind__(in_)

  yield(out: out, err: err, in: in_, argv: argv)
ensure
  $stdout.__restore__(prev_out)
  $stderr.__restore__(prev_err)
  $stdin.__restore__(prev_in)
end

.terminalize(klass, seen = {}) ⇒ Object

Walk a Thor class + its subcommand tree, making every command class speak v2 NATIVELY — it includes Terminalwire::V2::Server::Thor (whose terminalwire dispatches with the v2 shell, no v1 super). This is the v2-only path: the app loads only the v2 gem. dualize is the transitional both-protocols path. Idempotent. Returns the class.



53
54
55
56
57
58
59
# File 'lib/terminalwire/v2/server/dual_thor.rb', line 53

def self.terminalize(klass, seen = {})
  return klass if seen[klass]
  seen[klass] = true
  klass.include(Terminalwire::V2::Server::Thor) unless klass.include?(Terminalwire::V2::Server::Thor)
  klass.subcommand_classes.each_value { |sub| terminalize(sub, seen) } if klass.respond_to?(:subcommand_classes)
  klass
end