How to default to information if none is given using optparse - ruby

I have a program that creates emails, what I want to do is when the -t flag is given and no argument is given with the flag, default to something, instead it outputs the usual: <main>': missing argument: -t (OptionParser::MissingArgument)
So my question being, if I have this flag:
require 'optparse'
OPTIONS = {}
OptionParser.new do |opts|
opts.on('-t INPUT', '--type INPUT', 'Specify who to say hello to'){ |o| OPTIONS[:type] = o }
end.parse!
def say_hello
puts "Hello #{OPTIONS[:type]}"
end
case
when OPTIONS[:type]
say_hello
else
puts "Hello World"
end
and I run this flag without the required argument INPUThow do I get the program to out put the Hello World instead of the: <main>': missing argument: -t (OptionParser::MissingArgument)?
Examples:
C:\Users\bin\ruby\test_folder>ruby opt.rb -t hello
Hello hello
C:\Users\bin\ruby\test_folder>ruby opt.rb -t
opt.rb:7:in `<main>': missing argument: -t (OptionParser::MissingArgument)
C:\Users\bin\ruby\test_folder>

I figured out that by adding brackets around the INPUT I can provide the option to provide input examples:
require 'optparse'
OPTIONS = {}
OptionParser.new do |opts|
opts.on('-t [INPUT]', '--type [INPUT]', 'Specify the type of email to be generated'){ |o| OPTIONS[:type] = o }
end.parse!
def say_hello
puts "Hello #{OPTIONS[:type]}"
end
case
when OPTIONS[:type]
say_hello
else
puts "Hello World"
end
Output:
C:\Users\bin\ruby\test_folder>ruby opt.rb -t
Hello World
C:\Users\bin\ruby\test_folder>ruby opt.rb -t hello
Hello hello
So if I do this:
require 'optparse'
OPTIONS = {}
OptionParser.new do |opts|
opts.on('-t [INPUT]', '--type [INPUT]', 'Specify the type of email to be generated'){ |o| OPTIONS[:type] = o }
end.parse!
def say_hello
puts "Hello #{OPTIONS[:type]}"
puts
puts OPTIONS[:type]
end
case
when OPTIONS[:type]
say_hello
else
puts "Hello World"
puts OPTIONS[:type] unless nil; puts "No value given"
end
I can output the information provided, or when there's no information provided I can output No value given:
C:\Users\bin\ruby\test_folder>ruby opt.rb -t hello
Hello hello
hello
C:\Users\bin\ruby\test_folder>ruby opt.rb -t
Hello World
No value given

Related

Make Thor show message for top level command

Is there any way to make Thor show a general message for the top level command?
$my_command help
I'd like to show a welcome message here.
Commands:
my_command help [COMMAND]
The closest thing I can think of is adding a default task and using it to invoke the help task. You'd get this message when calling $my_command with no arguments
require 'thor'
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
desc "greeting", "this is just a greeting"
def greeting
puts "Welcome to MyCLI"
invoke :help
end
default_task :greeting
end
MyCLI.start(ARGV)
# $my_command
# output:
# Welcome to MyCLI
# Commands:
# test.rb greeting # this is just a greeting
# test.rb hello NAME # say hello to NAME
# test.rb help [COMMAND] # Describe available commands or one spec...

OptionParser, requiring subparameters

I'm trying to figure out how to define subparameters for one of my parameters. This is what I have that is NOT working:
require 'optparse'
options = {}
OptionParser.new do |parser|
parser.on("-r", "--require LIBRARY", "Require the LIBRARY before executing your script") do |lib|
parser.make_switch(["-p"], '--pop THING') do |o|
puts "You required #{o}!"
end
end
parser.on("-f", '--file FILE', 'File to be processed') do |file|
puts "This is the file: #{file}"
end
end.parse!
I'd like to do:
ruby myapp -r Library -p thing #<--required params
or
ruby myapp -f

OptionParser with subcommands

I'm trying to create a command line program with sub-commands using OptionParser. I'm following "ruby's OptionParser to get subcommands".
The problem is that it does not allow for a use case like this:
ruby main.rb --version
#=> main.rb in `<main>': undefined method `order!' for nil:NilClass (NoMethodError)
But it does allow for this:
ruby main.rb foo --options
ruby main.rb --options foo
ruby main.rb --options foo --options
How would I be properly handle command line arguments, in the case that no subcommand is given.
My example code is:
global = OptionParser.new do |opts|
opts.banner = "Usage: opt.rb [options] [subcommand [options]]"
opts.on("-v", "--version", "Print the version") do |v|
options[:version] = v
end
opts.separator ""
opts.separator subtext
end
The lines with the error:
global.order!
command = ARGV.shift
subcommands[command].order!
If global.order! uses all of ARGV, then command is nil. So... check for that.
global.order!
command = ARGV.shift
unless command
STDERR.puts "ERROR: no subcommand"
STDERR.puts global # prints usage
exit(-1)
end
subcommands[command].order!
Maybe this'll help:
require 'optparse'
VERSION = '1.0.0'
options = {}
OptionParser.new do |opt|
opt.on('-f', '--foo', 'Foo it') { |o| options[:foo] = o }
opt.on_tail('-v', '--version') do
puts VERSION
exit
end
end.parse!
puts options
Saving it as "test.rb" and running it with ruby test.rb returns:
{}
Running it with ruby test.rb -f or --foo returns:
{:foo=>true}
Running it with ruby test.rb -v or --version returns:
1.0.0
For more fun, running ruby test.rb -h or --help returns:
Usage: test [options]
-f, --foo Foo it
even though I didn't define -h or --help.
If I wanted the -v and --version flags to appear in the list then I'd change them from a on_tail method to a normal on method:
require 'optparse'
VERSION = '1.0.0'
options = {}
OptionParser.new do |opt|
opt.on('-f', '--foo', 'Foo it') { |o| options[:foo] = o }
opt.on('-v', '--version', 'Returns the version') do
puts VERSION
exit
end
end.parse!
puts options
which would return:
Usage: test [options]
-f, --foo Foo it
-v, --version Returns the version
I can add:
puts ARGV
to the end of the script and see that OptionParser is correctly handling flags and parameters:
>ruby test.rb bar --foo
{:foo=>true}
bar
>ruby test.rb --foo bar
{:foo=>true}
bar
See "Pass variables to Ruby script via command line" for more information.
There is no way your example code will handle your sample inputs using --options. No handler for --options is defined. Nor is subtext. Your code returns:
undefined local variable or method `subtext' for main:Object (NameError)
Stripping the block to:
global = OptionParser.new do |opts|
opts.on("-v", "--version", "Print the version") do |v|
options[:version] = v
end
end
and running again returns:
invalid option: --options (OptionParser::InvalidOption)
So, again, your example doesn't match the results you say you're getting.

Command Aliasing in Thor

Is it possible to create aliases for commands in Thor?
Much like command aliasing in Commander. https://github.com/tj/commander#command-aliasing
I am able to find aliases for options, but not for the command itself.
Using the example from Thor,
#!/usr/bin/env ruby
require 'thor'
# cli.rb
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
end
MyCLI.start(ARGV)
I should be able to run
$ ./cli.rb hello John
Hello John
I would like to alias the command "hello" to "hi" as well.
You can use map for this:
http://www.rubydoc.info/github/wycats/thor/master/Thor#map-class_method
#!/usr/bin/env ruby
require 'thor'
# cli.rb
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
map hi: :hello
end
MyCLI.start(ARGV)
Use method_option for aliases.
#!/usr/bin/env ruby
require 'thor'
# cli.rb
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
method_option :hello , :aliases => "-hello" , :desc => "Hello Command"
def hello(name)
puts "Hello #{name}"
end
end
MyCLI.start(ARGV)

How do I call help if path undefined using OptionParser?

I'm new to Ruby and am trying to code an elegant method for setting the working directory for the program. All file accesses with be relative to this path.
The program may or may not be run from within a Git repo. I also want to provide a method of overriding the path.
I'm using OptionParser and am having difficulty getting it to set the option correctly. It seems that work_area always gets set to the Git toplevel, regardless of whether or not I'm using the --work_area flag. I've tried using a || operator within the opts.on and that didn't work either.
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: mysprogram.rb [options]"
options[:work_area] = `git rev-parse --show-toplevel --quiet 2>/dev/null`
opts.on("-d", "--work_area", String, "Override default work area.") do |wa|
options[:work_area] = wa
end
if options[:work_area]
puts "Work area is " + options[:work_area]
else
puts "ERROR: Valid work directory not found or specified."
puts opts
exit
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
end.parse!
Any suggestions on what I'm doing wrong, or how to make this more Ruby-like, would be appreciated.
The block you pass to opts.on("-d" ...) is called after the block that's passed to OptionParser.new, so your puts statement is being executed before the argument parsing is actually happening. Try initializing it to the default (and testing it) outside of the OptionParser.new block entirely:
options = {}
opts = OptionParser.new do |opts|
opts.banner = "Usage: mysprogram.rb [options]"
opts.on("-d", "--work_area", String, "Override default work area.") do |wa|
options[:work_area] = wa
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
end
opts.parse!
# Notice the "||=" here; this means "set options[:work_area] to a new thing
# only if it's not nil or false."
options[:work_area] ||= `git rev-parse --show-toplevel --quiet 2>/dev/null`
if options[:work_area]
puts "Work area is " + options[:work_area]
else
puts "ERROR: Valid work directory not found or specified."
puts opts
exit
end
I've always used something like:
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.banner = "Usage: #{ File.basename($0) } [options]"
opt.on('--path PATH') { |o| options[:path] = o }
options[:help] = opt.help
end.parse!
puts options[:help] if !options[:path]
Saving that and running it with a --path foo option returns no output, as it should.
Running it without the --path foo option outputs:
Usage: test.rb [options]
--path PATH
Also, notice that OptionParser automatically supplies a -h or --help parameter for you if you don't define them. Calling the same code with -h results in the output you'd expect and are trying to code into your script.

Resources