Skip to content

Add stderr, stdin, and stdout support for Dry::CLI #151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions lib/dry/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ def initialize(command_or_registry = nil, &block)
# Invoke the CLI
#
# @param arguments [Array<string>] the command line arguments (defaults to `ARGV`)
# @param out [IO] the standard output (defaults to `$stdout`)
# @param err [IO] the error output (defaults to `$stderr`)
# @param stderr [IO] the error output (defaults to `$stderr`)
# @param stdin [IO] the standard input (defaults to `$stdin`)
# @param stdout [IO] the standard output (defaults to `$stdout`)
#
# @since 0.1.0
def call(arguments: ARGV, out: $stdout, err: $stderr)
@out, @err = out, err
def call(arguments: ARGV, stderr: $stderr, stdin: $stdin, stdout: $stdout)
@stderr, @stdin, @stdout = stderr, stdin, stdout
kommand ? perform_command(arguments) : perform_registry(arguments)
rescue SignalException => e
signal_exception(e)
Expand All @@ -82,11 +83,15 @@ def call(arguments: ARGV, out: $stdout, err: $stderr)

# @since 0.6.0
# @api private
attr_reader :out
attr_reader :stderr

# @since unreleased
# @api private
attr_reader :stdin

# @since 0.6.0
# @api private
attr_reader :err
attr_reader :stdout

# Invoke the CLI if singular command passed
#
Expand Down Expand Up @@ -145,29 +150,29 @@ def parse(command, arguments, names)
# @since 0.6.0
# @api private
def build_command(command)
command.is_a?(Class) ? command.new : command
command.is_a?(Class) ? command.new(stderr: stderr, stdin: stdin, stdout: stdout) : command
end

# @since 0.6.0
# @api private
def help(command, prog_name)
out.puts Banner.call(command, prog_name)
stdout.puts Banner.call(command, prog_name)
exit(0) # Successful exit
end

# @since 0.6.0
# @api private
def error(result)
err.puts(result.error)
stderr.puts(result.error)
exit(1)
end

# @since 1.1.1
def spell_checker(result, arguments)
spell_checker = SpellChecker.call(result, arguments)
err.puts spell_checker if spell_checker
stderr.puts spell_checker if spell_checker
puts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timriley is this a bug? Should this be stderr.puts and if so would you like me to fix it in this PR?

err.puts Usage.call(result)
stderr.puts Usage.call(result)
exit(1)
end

Expand Down
54 changes: 54 additions & 0 deletions lib/dry/cli/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,14 @@ def self.superclass_options
superclass_variable_dup(:@options)
end

# @since unreleased
# @api private
def initialize(stderr: $stderr, stdin: $stdin, stdout: $stdout)
@stderr = stderr
@stdin = stdin
@stdout = stdout
end

extend Forwardable

delegate %i[
Expand All @@ -379,6 +387,52 @@ def self.superclass_options
optional_arguments
subcommands
] => "self.class"

protected

# The error output used to print error messaging
#
# @example
# class MyCommand
# def call
# stdout.puts "Hello World!"
# exit(0)
# rescue StandardError => e
# stderr.puts "Uh oh: #{e.message}"
# exit(1)
# end
# end
#
# @since unreleased
# @return [IO]
attr_reader :stderr

# The standard input stream used for reading input
#
# @example
# class MyCommand
# def call
# name = stdin.gets.chomp
# stdout.puts "Hello #{name}!"
# end
# end
#
# @since unreleased
# @return [IO]
attr_reader :stdin

# The standard output stream used for normal output
#
# @example
# class MyCommand
# def call
# stdout.puts "Hello World!"
# end
# end
#
# @since unreleased
# @return [IO]
attr_reader :stdout
end
end
end
6 changes: 3 additions & 3 deletions lib/dry/cli/inline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class CLI
# methods below
#
# DSL consists of 5 methods:
# `desc`, `example`, `argument`, `option` 
# `desc`, `example`, `argument`, `option`
# — are similar to methods from Command class
#
# `run` accepts a block to execute
Expand Down Expand Up @@ -60,13 +60,13 @@ module Inline
# end
#
# @since 0.6.0
def run(arguments: ARGV, out: $stdout)
def run(arguments: ARGV, stdout: $stdout)
command = AnonymousCommand
command.define_method(:call) do |**args|
yield(**args)
end

Dry.CLI(command).call(arguments: arguments, out: out)
Dry.CLI(command).call(arguments: arguments, stdout: stdout)
end
end
end
Expand Down