How to Get the Name of the Command Called for Usage Prompts in Ruby

How can I get the name of the command called for usage prompts in Ruby?

Ruby has three ways of giving us the name of the called script:

#!/usr/bin/env ruby

puts "$0 : #{$0}"
puts "__FILE__ : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"

Saving that code as "test.rb" and calling it a couple ways shows that the script receives the name as it was passed to it by the OS. A script only knows what the OS tells it:

$ ./test.rb 
$0 : ./test.rb
__FILE__ : ./test.rb
$PROGRAM_NAME : ./test.rb

$ ~/Desktop/test.rb
$0 : /Users/ttm/Desktop/test.rb
__FILE__ : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb

$ /Users/ttm/Desktop/test.rb
$0 : /Users/ttm/Desktop/test.rb
__FILE__ : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb

Calling it using the ~ shortcut for $HOME in the second example shows the OS replacing it with the expanded path, matching what is in the third example. In all cases it's what the OS passed in.

Linking to the file using both hard and soft links shows consistent behavior. I created a hard link for test1.rb and a soft link for test2.rb:

$ ./test1.rb 
$0 : ./test1.rb
__FILE__ : ./test1.rb
$PROGRAM_NAME : ./test1.rb

$ ./test2.rb
$0 : ./test2.rb
__FILE__ : ./test2.rb
$PROGRAM_NAME : ./test2.rb

Launching ruby test.rb with any of the variations on the script name returns consistent results.

If you only want the called filename, you can use File's basename method with one of the variables or split on the delimiter and take the last element.

$0 and __FILE__ have some minor differences but for single scripts they're equivalent.

puts File.basename($0)

There are some benefits to using the File.basename,File.extname and File.dirname suite of methods. basename takes an optional parameter, which is the extension to strip, so if you need just the basename without the extension

File.basename($0, File.extname($0)) 

does it without reinventing the wheel or having to deal with variable-length or missing extensions or the possibility of incorrectly truncating extension chains ".rb.txt" for instance:

ruby-1.9.2-p136 :004 > filename = '/path/to/file/name.ext'
=> "/path/to/file/name.ext"
ruby-1.9.2-p136 :005 > File.basename(filename, File.extname(filename))
=> "name"
ruby-1.9.2-p136 :006 > filename = '/path/to/file/name.ext' << '.txt'
=> "/path/to/file/name.ext.txt"
ruby-1.9.2-p136 :007 > File.basename(filename, File.extname(filename))
=> "name.ext"

Use a command line option to call a method

There are a lot of ways to do this, depending on the use case. The below code is taken from the Ruby docs with the extra method added.

Realistically you'd probably want a class that handles the different options and encapsulates the method instead of having them at the file scope.

#!/usr/bin/env ruby

require 'optparse'

options = {}
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"

opts.on("-b", "Run method 'b'") do |v|
options[:b] = true
end
end.parse!

def b
puts "Hello Brian"
end

if options[:b]
b
end

I've also added a shebang at the top that will automatically call ruby. As long as your script file is executable you can call it directly (ie. ./mine.rb -b).

How can same program in ruby accept input from user as well as command line arguments

gets will only read from the real $stdin (ie the user) if there are no command line arguments. Otherwise it'll take those arguments as files to concatenate as a virtual $stdin.

You can use STDIN.gets to make sure you're always using the right function.

You can also delete the arguments from ARGV as you go (or remove them all in one go), your gets should work correctly.

One liner in Ruby for displaying a prompt, getting input, and assigning to a variable?

Check out highline:

require "highline/import"
input = ask "Input text: "

Call ruby function from command-line

First the name of the class needs to start with a capital letter, and since you really want to use a static method, the function name definition needs to start with self..

class TestClass
def self.test_function(someVar)
puts "I got the following variable: " + someVar
end
end

Then to invoke that from the command line you can do:

ruby -r "./test.rb" -e "TestClass.test_function 'hi'"

If you instead had test_function as an instance method, you'd have:

class TestClass
def test_function(someVar)
puts "I got the following variable: " + someVar
end
end

then you'd invoke it with:

ruby -r "./test.rb" -e "TestClass.new.test_function 'hi'"

Find declared function from user input

You can write a mapping for the different inputs in the form of a case:

case command
when "pwd"
Dir.pwd # or move it into another method and call it here
when "ls"
# etc
end

or a hash, which is slightly more concise

actions = {
pwd: -> { Dir.pwd },
ls: -> { <foobar> }
}
actions[command.to_sym].call

You can also make method names matching the commands and use send, but don't do this if the input is coming from strangers:

def pwd
Dir.pwd
end

command = command.to_sym
send(command)

Pre-Filled Prompt in Ruby

You can do it with RbReadline:

require 'rubygems'
require 'rb-readline'

module RbReadline
def self.prefill_prompt(str)
@rl_prefill = str
@rl_startup_hook = :rl_prefill_hook
end

def self.rl_prefill_hook
rl_insert_text @rl_prefill if @rl_prefill
@rl_startup_hook = nil
end
end

RbReadline.prefill_prompt("Previous query")
str = Readline.readline("Enter query: ", true)

puts "You entered: #{str}"

Using a different name for calling a ruby gem from the command line

Your gem name and the executables it bundles don't have to be the same at all. In your gemspec, you can define a list of executables via executables:

Gem::Specification.new do |s|
s.name = "super_awesome_gem"
# other gemspec stuff
s.executables = ["sup_awe"]
end

As long as sup_awe is listed in the gemspec's files list, and is executable, that will be in the user's path after they install your gem. Bundler, when bootstrapping your gemspec, makes this even simpler

s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }

Anything in bin/ will be treated as an executable.

That is the long way of saying that your exectuable/bin file can be named whatever you want, and doesn't have to be named for your gem.



Related Topics



Leave a reply



Submit