This library officially supports the following Ruby versions:
- MRI
>= 2.4.0
- jruby
>= 9.4
(not tested on CI)
See LICENSE
file.
General purpose Command Line Interface (CLI) framework for Ruby
Home Page: https://dry-rb.org/gems/dry-cli
License: MIT License
This library officially supports the following Ruby versions:
>= 2.4.0
>= 9.4
(not tested on CI)See LICENSE
file.
When creating a subclass of a class, which inherits Dry::CLI::Command behaviour, options and arguments, that are declared in Base class are not inherited in children classes.
class Base < Dry::CLI::Command
option :debug
def call(**args); puts args.inspect; end
end
class Command1 < Base
end
module Commands
extend Dry::CLI::Registry
register 'run', Command1
end
Dry::CLI(Commands).call
$ ./cli run --debug=test
Error: "command" was called with arguments "--debug=test"
$ ./cli command --debug=test
{:debug=>"test"}
Oftentimes, it's tedious to find out which argument or option to pass. A nice feature would be to add the ability to use tty-prompt to select these options if they are not passed in. This would heavily improve the UX in my opinion.
Dry CLI doesn't parse negative numbers as arguments and command execution fails.
Lets imagine we have file cli.rb
with the following code:
require 'dry/cli'
module Commands
extend Dry::CLI::Registry
class Command < Dry::CLI::Command
argument :amount
option :rate
def call(**args)
puts args
end
end
register 'command', Command
end
Dry::CLI(Commands).call
Then we call it in the following way:
ruby cli.rb command -0.01 --rate -0.01
Current behavior is:
ERROR: "cli.rb command" was called with arguments "-0.01 --rate -0.01"
Expected behavior is to have the following output:
{:rate=>"-0.01", :amount=>"-0.01"}
Environment;
I think the problem is that Dry CLI uses Ruby OptionParser
which handles -0.01 as option. But is there any possibility to fix this incorrect behavior?
Keyword arguments for a command aren't passed correctly to commands that use callbacks.
I have two gems: hanami-cli
that depends on dry-cli
, and hanami-rspec
that depends on hanami-cli
.
The first gem (hanami-cli
) defines a command hanami generate slice NAME
, which loosely correspond to this implementation:
module Hanami
module CLI
module Generate
class Slice < Command
argument :name, required: true, desc: "The slice name"
def call(name: )
puts "generating slice: #{name}"
end
end
end
end
end
The second gem (hanami-rspec
) hooks into the invocation of hanami generate slice
with an after callback.
module Hanami
module RSpec
module Generate
class Slice < Command
def call(options, **)
puts "generating slice: #{options[:name]}"
end
end
end
end
end
I would have expected that Hanami::RSpec::Generate::Slice#call
would have accepted the :name
keyword argument. What it does instead, it passes a Hash.
When accessing Commands with subcommands and params in the documentation, it downloads a source file instead of displaying the page in the browser.
Click on the link above.
I saw the example in the README, where a command is registered as two separate words: generate configuration
โ see below:
#!/usr/bin/env ruby
require "bundler/setup"
require "hanami/cli"
module Foo
module CLI
module Commands
extend Hanami::CLI::Registry
module Generate
class Configuration < Hanami::CLI::Command
def call(*)
end
end
class Project < Hanami::CLI::Command
def call(*)
end
end
end
end
end
end
Foo::CLI::Commands.register "generate configuration", Foo::CLI::Commands::Generate::Configuration
Foo::CLI::Commands.register "generate project", Foo::CLI::Commands::Generate::Project
Hanami::CLI.new(Foo::CLI::Commands).call
However, when run with --help, this produces:
Commands:
hanami-test generate [SUBCOMMAND]
The word configuration
becomes a "subcommand", and is only visible if I run cli generate --help
Commands:
cli generate configuration
cli generate project
I would love to be able to see all options in a global help message. For instance:
cli generate configuration NAME
cli generate project NAME
cli build project NAME
cli deploy project NAME
cli deploy static NAME
Alternatively (albeit this does not work if arguments to the commands are different)
cli generate [ configuration NAME | project NAME ]
cli build project NAME
cli deploy [ project NAME | static NAME ]
Is it possible?
Is it desirable?
Going to illustrate this example with hanami/hanami
. It's an issue with this project though, not that one.
If you run: bundle exec hanami generate action web books#index
, files are generated.
Let's say you edit apps/web/controllers/books/index.rb
to look like this:
module Web::Controllers::Books
class Index
include Web::Action
def call(params)
# do some stuff
# like process params
# create some records maybe?
# return status codes
# maybe serialize a hash into JSON?
# doesn't really matter.
# These comments are just here for length, to show the odd behavior
end
end
end
Then run bundle exec hanami generate action web books#index
again, here's what it does to that file:
module Web::Controllers::Books
class Index
include Web::Action
def call(params)
end
end
end
uff
# like process params
# create some records maybe?
# return status codes
# maybe serialize a hash into JSON?
# doesn't really matter.
# These comments are just here for length, to show the odd behavior
end
end
end
(Yes, I pasted that correctly. The output is very strange, and not correct Ruby)
Instead we should ask the user if they want to replace or skip any existing files. And, if they replace, we obviously want to do it properly, by deleting the file first.
Hanami::CLI
seems to interpret options as values for the required args, when they're missing.
This is illustrated
Generating an action without a name for it (e.g. books#index
)
bundle exec hanami generate action web --url=no
Generates the following files:
create apps/web/controllers/--url=no.rb
create apps/web/views/--url=no.rb
create apps/web/templates/--url=no.html.erb
create spec/web/controllers/--url=no_spec.rb
create spec/web/views/--url=no_spec.rb
insert apps/web/config/routes.rb
Generating a mailer without a name for it (e.g. book_added
)
bundle exec hanami generate mailer [email protected]
Generates the following files:
create lib/blahtest/mailers/[email protected]
create spec/blahtest/mailers/[email protected]_spec.rb
create lib/blahtest/mailers/templates/[email protected]
create lib/blahtest/mailers/templates/[email protected]
Had there been an idea of sub-command autocompletion feature? If thats not on the roadmap, I could probably take a stab at that.
When global options are defined in a Base command class from which all other commands are derived, it is possible for an alias in the global space to be "re-used" in the command space. For example if "-v" is an alias for :verbose in the global space and a command implements and option :validate with a "-v" alias there is now a conflict. I'm not sure what the current functionality is when dealing with this kind of conflict. It might be the command options rule; or, the global options rule. My preference would be to add a notation to the help text that calls out the conflict as a warning.... or maybe something else.
Provide detailed steps to reproduce, an executable script would be best.
In my Github repo MadBomber/experiments/cli_options/dry-cli
The base command defines -x for :xyzzy, and :exec command defines -x for the :exit option.
If a ruby program is interrupted by Ctrl^C
or sent a SIGINT
signal, the Interrupt
exception is raised, causing an ugly backtrace to be printed. Ideally, Dry::CLI
should rescue Interrupt
and exit with a status of 130 (see: https://tldp.org/LDP/abs/html/exitcodes.html).
It would be nice to be able to add documentation to command prefixes. The way dry-cli
deals with subcommands disallows adding documentation to be shown calling --help
over the subcomand prefix.
Given the code on this example:
require "dry/cli"
module Foo
module Commands
extend Dry::CLI::Registry
module Generate
class App < Dry::CLI::Command
end
class Action < Dry::CLI::Command
end
end
register "generate", aliases: ["g"] do |prefix|
prefix.register "app", Generate::App
prefix.register "action", Generate::Action
end
end
end
It would be nice to be able to add documentation over the 'generate' subcommand. So its help will be shown like:
Description:
here you can include a general documentation about the subcommand.
Commands:
foo.rb generate action
foo.rb generate app
A possible implementation could be:
register "generate", aliases: ["g"] do |prefix|
prefix.desc 'HERE YOU CAN INCLUDE THE DOCUMENTATION OF THE COMMAND'
prefix.register "app", Generate::App
prefix.register "action", Generate::Action
end
I checked the code and saw that Prefix
class was just syntax sugar for self.register
, so no idea on how this could be implemented, or whether there is already a way of achieving what I'm looking for.
Thanks in advance! and thanks for dry-cli
!
Always adding --no-*
makes arguments like --skip-something
use double-negative (--no-skip-something
) and it might not make sense in all contexts
First of all, thank you everyone who participated in creating this tool. I'm using it now for the development of Shrine, the script automatizes setting up the S3 bucket with correct permissions. It's been a joy to use so far โค๏ธ
Onto the issue. I have an array option (in my case permissions
) which has a default value. When I print the page, the default value gets shown as a Ruby array:
module Commands
class S3
class Create < Dry::CLI::Command
DEFAULT_PERMISSIONS = %w[
GetObject
PutObject
PutObjectAcl
DeleteObject
ListMultipartUploadParts
AbortMultipartUpload
]
option :permissions, type: :array, default: DEFAULT_PERMISSIONS, desc: "list of S3 permissions"
# ...
end
end
$ shrine s3 create --help
Command:
shrine s3 create
Usage:
shrine s3 create
Options:
--permissions=VALUE # list of S3 permissions, default: ["GetObject", "PutObject", "PutObjectAcl", "DeleteObject", "ListMultipartUploadParts", "AbortMultipartUpload"]
...
--help, -h # Print this help
I think this might be a bit misleading, as the way to pass array arguments is via a comma-separated list. So, I think it would make sense that the default value is also displayed as a comma-separated list, to show the user how the input should look like.
When a ruby program is piped into | less
and less
is exited before the ruby program can exit, Ruby will raise a Errno::EPIPE
exception when stdio is accessed, causing an ugly backtrace to be printed. Dry::CLI
should rescue the Errno::EPIPE
exception and safely exit, calling any additional cleanup blocks/methods, with status code 0.
rescue Errno::EPIPE
begin
(0..Float::INFINITY).each do |i|
$stdout.puts i
$stdout.flush
end
rescue Interrupt
exit 130
end
$ ruby test.rb | less
q
Traceback (most recent call last):
3: from ./test.rb:4:in `<main>'
2: from ./test.rb:4:in `each'
1: from ./test.rb:6:in `block in <main>'
./test.rb:6:in `flush': Broken pipe (Errno::EPIPE)
$
rescue Errno::EPIPE
begin
(0..Float::INFINITY).each do |i|
$stdout.puts i
$stdout.flush
end
rescue Interrupt
exit 130
rescue Errno::EPIPE
end
$ ruby test.rb | less
q
$
When committing to this project (in my case, a fork), I'm not able to push new commits to the remote repo due to Rubocop failing. This happens because I always run Rubocop as a Git Hook in order to resolve issues before finding out via a failed CI build.
If you are serious about using Rubocop in this project (kudos for including it), it'd be a good idea to add it to the CI build process to ensure it is being used properly by this project. I might suggest this configuration as a good configuration to use. :)
Regardless of whether you auto-run Rubocop as a Git Hook or not, you can see the issues by running:
bundle exec rubocop
Delete this line:
gem 'rubocop', '0.49.1', require: false
...from the project Gemfile
. That allows my Git Hook to see that Rubocop isn't configured for the project and I can commit code successfully.
Feature request : In some cases it's required to have mutually-exclusive arguments or options.
For example if I have a program that will convert coordinates to a player name or a player name to its coordinates. I want to either have 1 argument (name) or two arguments (coodinate X and coordinate Y). Pseudo usage: program convert (name | coord_x coord_y)
.
Same for options, for example for git pull
you can't have --ff-only
and --no-ff
or --ff-only
and --rebase
at the same time.
Example with docopt:
The workaround that is heavy is to provide two sub-sub-commands to the convert
sub-command, one that converts from name to coords with one required argument and a second sub-sub-command that converts coords to name with 2 required arguments.
Another workaround is to use one unique and generic array argument name args
and then counts the number of entries in it, if only one it's the name if two those are the coords. But the description should explain logic and behavior as well as the description of all three arguments in one, that also wouldn't work if the two mutually exclusive arguments has the same number of entries.
Another workaround is to use three options instead with none as required but of course this will end into errors if none is provided or if only 1 coord is provided or if one corod and a name if provided.
Looking at the code it seems like you can pass already-filled-in options to #register, but man, I can't for the life of me figure out what's going on with that. I had thought I could do:
MyCLI.register 'staging deploy', MedInstaller::Remote::Deploy, target: "staging"
...and get an option named 'target'. But no combination of register
syntax and argument
or option
declarations in the target class is giving me anything useful. Any help appreciated.
The installation instructions should specify that you need the version number. Currently, if you follow the instructions it's installing v 0.0.0. Or rubygems needs to be fixed so that it picks up the latest version.
in Thor, I can specify an argument that is like many things, say DOMAINS...
, I would really like to be able to specify multiple arguments to my CLI app in this variable way. I dug into the source code a bit, and I didn't find any option to arguments that would make that happen, so logging the feature request.
Fantastic job on this library, I really like it!
./the_app one two three
would extract into the domains argument domains: ['one', 'two', 'three']
https://www.rubydoc.info/github/wycats/thor/Thor/Argument
If the argument type is an array, it'll grab all the arguments, I guess until the end of the line, which would conflict with the variadic arguments ability, but that could probably be supported also.
somecli --yes
won't work even with default value, but somecli --yes=no
works
Class should be named UnknownCommandError
instead
options are always considered having a value --mode=http2
or --mode http2
.
E.g. just having --color
, having the flag equals options.fetch(:color)
returning true, not having the flag equals options.fetch(:color)
returning false. It's better than having --color true
and --color false
with values: %w[true false]
and casting the string to a boolean.
It would be nice to have has many aliases as we want for an option.
E.g. -c, --color
or --color, --colour
.
It's often handy to have long flags that are mnemotechnic and short flags for those familiar with the tool that want to type faster.
Sometimes it is required to have mutually exclusive options, see #128.
As passed from the CLI, all values are strings, so it would be handy to have cast types for options.
E.g. --age 21
or --advanced true
. It's allows to cast type in the definition of the option, avoiding forgetting to cast it when the value is retrieved or to cast it several times if the option is used at multiple places.
Steps to reproduce:
Command
code: argument(
:output_file,
default: DEFAULT_HTML_FILE,
desc: "Specify HTML output file. Defaults to #{DEFAULT_HTML_FILE}"
)
option(
:sort_order,
aliases: ['-s'],
type: :string,
values: %w[alpha date],
default: 'alpha',
desc: 'Sorty by name-alpha (ascending), or date of last commit (descending)'
)
Help output
โค exe/codemonkey dig ../ -h
Command:
codemonkey dig
Usage:
codemonkey dig [OUTPUT_FILE]
Arguments:
OUTPUT_FILE # Specify HTML output file. Defaults to 'git_repos.hml'
Options:
--sort-order=VALUE, -s VALUE # Sort by name-alpha (ascending), or date of last commit (descending)
--help, -h # Print this help
codemonkey dig --sort-order=date
It will then assume the OUTPUT_FILE
is --sort-order=date
and create a file with that name.
i try:
hanami new laanz-backend --database=postgresql --test=rspec --aplication-name=api
And got error, that contains absolutely uninformative message:
Error: Invalid param provided
Not problem, i can find error, but can it be more informative?
Given the following example
:
#!/usr/bin/env ruby
require "bundler/setup"
require "dry/cli"
module Foo
module CLI
module Commands
extend Dry::CLI::Registry
class Start < Dry::CLI::Command
argument :arg, values: %w(one two)
option :opt, values: %w(one two)
def call(arg: nil, opt: nil, **)
puts "ARG: #{arg.inspect} / OPT: #{opt.inspect}"
end
end
register "start", Start
end
end
end
Dry::CLI.new(Foo::CLI::Commands).call
The following somewhat unexpected behaviour occurs:
example start --opt=one # ARG: nil / OPT: "one"
example start --opt=three # ERROR: was called with arguments "--opt=three"
example start one # ARG: "one" / OPT: nil
example start three # ARG: "three" / OPT: nil <-- OOPS
The last one should also result in an error IMO.
Dry::Core
enables us to add extensions to our libraries, which is a nice feature to have. Other than being nice, it enables us to make our own local patches to dry-rb libraries in a controlled fashion.
I'd love to be able use extensions with dry-cli too.
Here's my use-case: I'm writing a CLI which will prompt users for input. Naturally, I use tty-prompt
for that, and want a better integration with dry-cli: I don't want to write too much boilerplate across the whole project.
When looking at other CLI libraries, I found that Thor has a collection of similar methods, but they don't use an external dependency. Their interface is seamless: they just use say
and ask
on self
, with no intermediate object.
Right now, I've managed to devise a simple extension:
# lib/dry/cli/extensions/tty_prompt.rb
# frozen_string_literal: true
require 'dry/cli'
require 'tty-prompt'
module Dry
class CLI
class Command
def prompt
@prompt ||= TTY::Prompt.new
end
end
end
end
module Dry
class CLI
extend Dry::Core::Extensions
register_extension(:tty_prompt) do
require 'dry/cli/extensions/tty_prompt'
end
load_extensions(:tty_prompt)
end
end
Usage:
class Version < Dry::CLI::Command
def call(**)
prompt.say "Gem version #{MyGEM::VERSION}"
end
end
However, there's two major issues:
dry-core
manuallyDry::CLI
with Dry::Core::Extensions
So my proposal is to add dry-core
as a dependency and enable extensions as an out-of-the-box feature.
Would be even nicer to add a tty-prompt
integration, but it'll take a while
Why would a cli library need concurrency?
Hi hanami-cli maintainers,
First of all, thank you for making a CLI framework which works well for what we have been doing! The command registry and commands as classes have been working really well for us.
We wanted to add aliases for some common options that are used throughout the CLI that we are building, they aren't documented as being available on options, but they seemed to work in a quick test when hacking around with the code. However we've seen some strange behaviour with options in general, it looks to be a problem with some pattern matching somewhere?
Given the following CLI structure:
require 'hanami/cli'
module MyCommands
extend Hanami::CLI::Registry
class TheCommand < Hanami::CLI::Command
option :aaa, aliases: ['a'], default: 'aaa-default', desc: 'aaa'
option :abc, default: 'abc-default', desc: 'abc'
def call(**opts)
puts opts.inspect
end
end
register 'the-command', TheCommand
end
cli = Hanami::CLI.new(MyCommands)
cli.call
When running the following: bundle exec scratch.rb the-command -a hello
then we get the following error:
Error: "the-command" was called with arguments "-a hello"
However if we remove the first option
require 'hanami/cli'
module MyCommands
extend Hanami::CLI::Registry
class TheCommand < Hanami::CLI::Command
option :aaa, aliases: ['a'], default: 'aaa-default', desc: 'aaa'
def call(**opts)
puts opts.inspect
end
end
register 'the-command', TheCommand
end
cli = Hanami::CLI.new(MyCommands)
cli.call
Then everything seems to work. Running bundle exec scratch.rb the-command -a hello
we get the following (expected) output:
{:aaa=>"hello"}
I think this is by accident though, since if I remove the alias then the shorthand option...
require 'hanami/cli'
module MyCommands
extend Hanami::CLI::Registry
class TheCommand < Hanami::CLI::Command
option :aaa, default: 'aaa-default', desc: 'aaa'
def call(**opts)
puts opts.inspect
end
end
register 'the-command', TheCommand
end
cli = Hanami::CLI.new(MyCommands)
cli.call
Then everything seems to work, even though this time I don't think it should. Running bundle exec scratch.rb the-command -a hello
we get the following (unexpected) output:
{:aaa=>"hello"}
Then if I add back in the second option you get the following behaviour:
require 'hanami/cli'
module MyCommands
extend Hanami::CLI::Registry
class TheCommand < Hanami::CLI::Command
option :aaa, default: 'aaa-default', desc: 'aaa'
option :abc, default: 'abc-default', desc: 'abc'
def call(**opts)
puts opts.inspect
end
end
register 'the-command', TheCommand
end
cli = Hanami::CLI.new(MyCommands)
cli.call
Then if we run the same command again bundle exec scratch.rb the-command -a hello
we get an error again:
Error: "the-command" was called with arguments "-a hello"
Many thanks,
Michael
Latest documentation (0.6) is not aligned with latest release (0.7). As if this e.g. this page is outdated: https://dry-rb.org/gems/dry-cli/0.6/file-utilities/
Open https://dry-rb.org/gems/dry-cli
https://dry-rb.org/gems/dry-cli shows documentation for 1.0. https://dry-rb.org/gems/dry-cli/0.7/file-utilities page is gone.
Hi,
If I create a command and would like to automate the use of CLI, is there any way to return a non-zero exit status?
I tried the most intuitive way:
def call(*)
do_something
return 3
end
but doesn't work, any tip on this? ๐
#!/usr/bin/env ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'hanami-cli', github: 'hanami/cli'
end
require 'hanami/cli'
module HanamiTestCLI
extend Hanami::CLI::Registry
class TestCommand < Hanami::CLI::Command
option :only, type: :array
def call(**options)
puts options
end
end
register 'test', TestCommand
end
Hanami::CLI.new(HanamiTestCLI).call
โบ ruby hanami-cli-bug.rb test --only foo bar
{:only=>"foo"}
I think thor
allow to pass options separated by space as an array, but hanami-cli
no, @jodosha WDYT?
I would like to get your feedback whether you would accept a PR for shell autocompletion.
I am in the process of migrating a RubyGems from gli (GitHub) to dry-cli. gli generates output for bash and zsh autocompletion e.g. rubygem-command help -c
(see documentation).
I am pretty sure hanami-cli
would profit from such a feature as well.
Should I take a shot at this or is this something you are not interested?
Right now, --help
only goes one level deep. I think we should keep it that way, but it'd be nice to have another command that recursively prints out every command (that is, print the whole tree, including subcommands).
I could see it being useful for getting an idea of all the available commands, and also something someone could pipe to grep
to find the command they're looking for.
Right now:
hanami --help
Commands:
hanami assets [SUBCOMMAND]
hanami console # Starts Hanami console
hanami db [SUBCOMMAND]
...
Proposed:
hanami --help-all
(Not sure what the best name would be)
Commands:
hanami assets precompile # Precompile assets for deployment
hanami console # Starts Hanami console
hanami db apply # Migrate, dump the SQL schema, and delete the migrations (experimental)
hanami db console # Starts a database console
hanami db create # Create the database (only for development/test)
hanami db drop # Drop the database (only for development/test)
hanami db migrate [VERSION] # Migrate the database
hanami db prepare # Drop, create, and migrate the database (only for development/test)
hanami db rollback [STEPS] # Rollback migrations
hanami db version # Print the current migrated version
...
This request from @unrooty #55 (comment)
This request from @kigster #55 (comment)
Hello,
Firstly thanks for Hanami CLI! It is so much more elegant than Thor, which has been my goto tool up to this point.
On to business, I'm in the process of porting an old Thor based CLI to Hanami CLI and I found a dealbreaker missing feature for me - being able to parse and use a variable number of arguments to the CLI.
The use case here is something similar to ssh
, docker run
, and the like where the user provides a series of arguments that'll become the command our program will execute somewhere.
Example:
ssh [email protected] -- /bin/bash -c "echo '127.0.0.1 myapp.com' > /etc/hosts"
docker run -it --rm postgres:latest /bin/bash
docker run -it --rm postgres:latest -- psql postgres://user:pass@myhost/mydb -c "select * from users"
As you can see they can get pretty elaborate ;)
I've kind of hacked it in this way - but I'd rather make it official and do it more elegantly:
diff --git a/lib/hanami/cli/parser.rb b/lib/hanami/cli/parser.rb
index e9b7534..2cc18b1 100644
--- a/lib/hanami/cli/parser.rb
+++ b/lib/hanami/cli/parser.rb
@@ -27,6 +27,8 @@ module Hanami
end
end.parse!(arguments)
+ Hanami::CLI.define_singleton_method(:all_arguments) { arguments }
+
parsed_options = command.default_params.merge(parsed_options)
parse_required_params(command, arguments, names, parsed_options)
rescue ::OptionParser::ParseError
I'm happy to do the work on it but figured I'd ask first as to how it should be done - any opinions?
I noticed that failure Result
objects have ERROR:
hardcoded into their message. How errors are formatting or printed should be left up to the user or some print_error
method that can be overrode.
It would be nice to be able to specify global options that can apply to any command/sub command, say something like:
--debug
or --json
or --verbose
that would add that option to the options of any CLI out there.
I suppose it'd be handy to have something at the CLI Registry level that allowed you to specify the same arguments that apply to option
, but globally available to all commands.
#some classes for commands
global_option :profile, aliases: ['-p'], required: true, type: :string, desc: 'AWS Profile'
global_option :debug, required: false, type: :boolean, desc: 'enable debug output'
global_option :json, required: false, type: :boolean, desc: 'change output to JSON format'
register 'version', Version, aliases: %w[v -v --version]
Something similar to what the teletype
gem creates. There's some subcommands going on in here that I'm refactoring out, but --debug
and --json
are globally available options.
master> bundle exec exe/dns --help
Commands:
dns dns [SUBCOMMAND] # Command description...
dns help [COMMAND] # Describe available commands or one specific command
dns version # sparklint version
Options:
[--debug], [--no-debug] # enable debug logging
[--json], [--no-json] # output results as json
I would love to address the problem, that there is no way right now to create a single command executable. The easiest way for doing this IMO is to define DefaultCommand which will be called if there is nothing else in the Registry
.
But I'd love to suggest another approach. Let's think of the reasoning for using dry-cli
. I believe that the developer is looking for some gem to him drop-in syntax just to make a single command to do exactly one thing without many options.
And I really like the way how Sinatra
does it.
hellonamer
# /usr/bin/env ruby
require 'dry/cli/global'
argument :name, required: true, desc: "The name of the person to greet"
argument :age, desc: "The age of the person to greet"
run do |name:, age:|
result = "Hello, #{name}."
result = "#{result} You are #{age} years old." unless age.nil?
puts result
end
And then just run
$ chmod +x hellonamer
$ ./hellonamer Homer
If that is not enough, you are still free to use all the features with a registry, subcommands and sub-subcommands, running Dry::CLI::Core
instance
require "dry/cli/core"
module Commands
extend Dry::CLI::Registry
class Hello < Dry::CLI::Command
def call(*)
end
end
end
Commands.register "hi", Commands::Hello
Dry::CLI::Base.new(Foo::CLI::Commands).call
WDYT?
This is a feature I started working on long ago for Hanami: hanami/hanami#906
There could be two parts to this:
dry-cli
, like each command's help
and the list of subcommandssay
that users of the library can use to print in color (instead of using print
).e.g.
say "create", color: :red
This should probably be like print
rather than puts
(no trailing newline), since people should be able to print in several colors on one line.
The concrete use-case for this could be like hanami/hanami#906, being able to colorize the output of file generation for Hanami.
Is this something we'd be interested in adding to dry-cli
? Any thoughts on the API?
If I put a class that inherits from Hanami::CLI::Command in a different file to the file where I register the command...
eg
class Notice < Hanami::CLI::Command
# etc
def call(file:, **)
# etc
results in
app notice FILE FILE
not
app notice FILE
cheers, Mike (with thanks for your work on this and the usual caveat that it may be me screwing something up :-) )
Hi,
I'm new here. so, i'm trying to generate a project from the main page example.
http://hanamirb.org/#install
OS: ubuntu 16.04
Ruby: 2.3.0
Hanami: 1.2.0
Here is output:
hanami new test-project
wrong number of arguments (given 0, expected 2..3)
(erb):2:in `test'
(erb):2:in `binding'
/home/user/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/erb.rb:864:in `eval'
/home/user/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/erb.rb:864:in `result'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/command.rb:123:in `call'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/command.rb:149:in `render'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/command.rb:157:in `generate_file'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/new.rb:554:in `generate_file'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/new.rb:347:in `generate_application_templates'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/new.rb:315:in `block in call'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/new.rb:314:in `chdir'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/new.rb:314:in `call'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/lib/hanami/cli/commands/command.rb:85:in `call'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-cli-0.2.0/lib/hanami/cli.rb:57:in `call'
/home/user/.rvm/gems/ruby-2.3.0/gems/hanami-1.2.0/bin/hanami:6:in `<top (required)>'
/home/user/.rvm/gems/ruby-2.3.0/bin/hanami:23:in `load'
/home/user/.rvm/gems/ruby-2.3.0/bin/hanami:23:in `<main>'
/home/user/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `eval'
/home/user/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `<main>'
Thank you.
Let me know if you need more information
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.