require 'optparse'
params = ARGV.getopts("a:", "AA")
ruby a.rb -a shows:
a.rb:3:in `<main>': missing argument: -a (OptionParser::MissingArgument)
ruby a.rb -b shows:
a.rb:3:in `<main>': invalid option: -b (OptionParser::InvalidOption)
I want to show my help message, how do I do that?
Actually you can use on_tail inside the block of OptionParser.new.
But since you're simply trying with ARGV.getopts, a hack to show your own help message would be rescuing exceptions:
require 'optparse'
help_msg = <<EOM
This is help message:
Hello buddy, you may do something wrong
...
EOM
begin
params = ARGV.getopts("a:", "AA")
rescue => e
puts e.message
puts '=' * 80
puts help_msg
end
Output:
ruby a.rb -a
#=>
missing argument: -a
================================================================================
This is help message:
Hello buddy, you may do something wrong
...
ruby a.rb -b
#=>
invalid option: -b
================================================================================
This is help message:
Hello buddy, you may do something wrong
...
Related
I'm new to ruby . I'm trying to source my shell script in ruby and execute functions in sourced shell script.
below is my shell script /tmp/test.sh
#!/bin/bash
function hello {
echo "hello, this script is being called from ruby"
}
below is my ruby script test.rb
#!/usr/bin/ruby
system("source /tmp/test.sh")
puts $?.exitstatus
system("hello")
puts $?.exitstatus
output using system
[root#localhost ~]# ruby test.rb
127
127
I even tried the back tick approach, but i got below error
code :
#!/usr/bin/ruby
status=`source /root/test.sh`
puts status
status2=`hello`
puts status2
error:
ruby test.rb
test.rb:3:in ``': No such file or directory - source (Errno::ENOENT)
from test.rb:3:in `<main>'
can anyone tell what is wrong in my code.
You can use session gem, or write a solution yourself.
script.sh:
#!/bin/bash
function hello() {
echo "Hello, World!"
}
Ruby file:
IO.popen('bash', 'r+') do |sh|
sh.puts 'source script.sh'
sh.puts 'hello'
sh.close_write
puts sh.gets
end
# => Hello, World!
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...
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.
I'm running into an issue with OptionParser's make_switch.
My code parses three arguments and runs a test to see if my MANDATORY argument is here:
#!/usr/bin/env ruby
require 'optparse'
require 'ostruct'
options = OpenStruct.new
#argv = ARGV
optparse = OptionParser.new do |opts|
#opts=opts
usage = "USAGE: ./#{File.basename($0)} [-v] -p xxxxxx"
#opts.banner = usage
#opts.on( '-p', '--pdu [PDU]', 'Specify a PDU to configure') do |res|
options.pdu = true
$pdu_name = res
end
#opts.on( '-v', '--[no-]verbose', 'Run verbosely') do
options.verbose = true
end
#opts.on( '-?', '-help','Show this message') do
puts "Help Me!"
puts #opts
exit 1
end
end
begin
if not #argv.empty?
optparse.order!(#argv)
if !options.pdu
$stderr.puts "Options -p missing."
$stderr.puts "#{#opts}\n\n"
exit 1
end
else
$stderr.puts "ERROR: Arguments Required."
$stderr.puts "#{#opts}\n\n"
exit 1
end
rescue OptionParser::InvalidOption
$stderr.puts "ERROR: Invalid option."
$stderr.puts "#{#opts}\n\n"
exit 1
end
Everything works except -?:
xxx$ ./myscript.rb -?
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:451:in
`parse': missing argument: -? (OptionParser::MissingArgument)
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1295:in `parse_in_order'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1254:in `catch'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1254:in `parse_in_order'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/optparse.rb:1248:in `order!'
blabla
However -help works perfectly:
xxxx$ ./myscript.rb -help
Help me!
USAGE: ./myscript.rb [-v] -p xxxxxx
-p, --pdu [PDU] Specify a PDU to configure
-v, --[no-]verbose Run verbosely
-?, -help Show this message
More surprisingly, -? -v works too:
xxxx$ ./myscript.rb -? -v
Help Me!
USAGE: ./myscript.rb [-v] -p xxxxxx
-p, --pdu [PDU] Specify a PDU to configure
-v, --[no-]verbose Run verbosely
-?, -help Show this message
What did I do wrong?
The same issue occurs if I replace -? with -h in the code.
Perhaps a quick look at the (somewhat confusing) documentation would shed some light on the situation. If you look at the docs, you'll end up at OptionParser#make_switch where you'll find an explanation of what the opt.on arguments look like:
Long style switch:
Specifies a long style switch which takes a mandatory, optional or no argument. It’s a string of the following form:
"--switch=MANDATORY" or "--switch MANDATORY"
"--switch[=OPTIONAL]"
"--switch"
Short style switch:
Specifies short style switch which takes a mandatory, optional or no argument. It’s a string of the following form:
"-xMANDATORY"
"-x[OPTIONAL]"
"-x"
Note the -xMANDATORY and then look closer at your #opts.on call:
#opts.on( '-?', '-help','Show this message') do
# ---------------^^^^^
That -help defines a -h option with a required elp argument. Presumably the option parser is interpreting that to mean that -h is an alias for -? and since -h is defined with a required argument, -? also requires an argument. If you use --help (i.e. a long style switch) then you'll probably have a better time:
#opts.on('-?', '--help', 'Show this message') do
I working from the Ruby 2.0 version but I doubt much has changed in the option parser since the older version of Ruby that you appear to be using.
In my executable Ruby file I have the following:
#!/usr/bin/env ruby
require 'thor'
include Thor::Actions
class UI < Thor
# def self.source_root
# File.dirname(__FILE__)
# end
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcalmakecal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
In the terminal when I run the file as is I get an empty line as Thor's run command is returning a NilClass.
However, when I un-comment the puts `ls ~` and comment out Thor's run method I get an output of my home directory as expected.
I'm having trouble figuring out why I can't get Thor's run method to work like Ruby's ticks.
Any ideas where I may have went wrong?
Thanks for looking
I didn't put the include statement inside my class and that messed things up. The code should be:
#!/usr/bin/env ruby
require 'makecal'
class UI < Thor
include Thor::Actions
# def self.source_root
# File.dirname(__FILE__)
# end
#
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
Thor's documentation on this method is actually wrong and incomplete. It documents that it returns the "contents of the command" (which I assume means the standard output), but it, by defualt, does nothing.
But, you can, apparently, use the :capture option to get what you want:
unless options[:pretend]
config[:capture] ? `#{command}` : system("#{command}")
end
So, try doing
puts run("ls ~", :capture => true)
And see if that does it.