Can thor accept unix-like options (such as -lv)? - ruby

I've recently started using thor. I've set my script up with some global options, such as -l --logging and -v --verbose. I'd like users to be able to call my thor task with -lv rather than -l -v, but this doesn't seem possible.

There are several items in the standard library and should help you support Unixy flags/command-line arguments:
getoptlong is reminiscent of Perl's GetOpt library, so if you've used that (or one of the many clones in other languages) that may be easy for you.
Otherwise, optparse is more Ruby-ish, and thus might feel more natural to use.

Related

Why shebang `env <executable>` instead of `executable`, even when there is no need to pre-set environment variables?

Why it is recommended to use /usr/bin/env python as opposed to /usr/bin/python.
This was inspired from reading the responses here:
What do I use on linux to make a python program executable
I think both would do exactly the same thing, but the answer that mentions both equally has 2 votes, rather than 88 votes for the answer that says to use env. People seem to really agree with using env, but don't explain why. Does env help you find any executable named "python", rather than just the one in a specific path which the user could have customized?
I'm really interested to know the various advantages and use cases for using env, and man env didn't explain it. man env only says that you can use env to set environment variables before running, NAME=VALUE, but we aren't doing that in the linked example.
I feel the community clearly is recommending to use env, but my own research has not hinted at a reason, so if you have ideas why it's good or good style to do so, please answer.
Using #!/usr/bin/env python ensures that the first Python interpreter in the currently-defined PATH is used, honoring any user overrides (which, for Python, includes virtualenvs and the like).
This is particularly important for environments such as MacOS, where OS-vendor packages are often out-of-date (for instance, /bin/bash is 3.2 -- a release series from 2006 -- whereas if the user has MacPorts or Homebrew, /opt/local/bin/bash or /usr/local/bin/bash may be a modern 4.x; thus, #!/usr/bin/env bash will gain the benefit of any updated bash interpreter a user has installed, whether system-wide or under their home directory, so long as the location of that interpreter is present in their PATH at runtime).

Where to find the ruby executable documentation?

I was trying to find the list of command-line arguments available for the ruby executable in http://ruby-doc.com/ but I could not find anything. After a Google search for "ruby interpreter command line options" I could only find this page, which applies to Ruby 1.4 only. Where can I find the documentation for the ruby executable in an 'official' source, like ruby-doc.com? Thanks!
Easiest option is to run man ruby. It will show your locally installed interpreter options.
Definitive option is the ruby repository on GitHub. Navigate to the version you need in the releases and locate man/ruby.1 file in the tree. The file contains definitions for CLI arguments.
Example: Ruby 2.3.0 interpreter CLI arguments definitions are here.
There is no such thing as "the Ruby executable". Every Ruby implementation has their own commandline executable. (Actually, come to think of it, SmallRuby and BlueRuby didn't have a commandline executable at all.)
And every Ruby implementation has their own commandline flags. That's why there cannot be a document explaining all the options: which implementation's options would that document?
For example, JRuby's --jdb flag to run under the Java Debugger simply doesn't make sense for IronRuby, Rubinius, MacRuby, Topaz, Cardinal, MRuby, or YARV. Rubinius's flag to turn on the sampling profiler doesn't make sense for implementations that don't have a sampling profiler. Rubinius's flag to turn on the native code JIT compiler doesn't make sense for implementations that don't have a native code JIT compiler. And so on.
However, there are a couple of options that most implementations agree on:
-0
-a
-c
-C
-d
-e
-E
-F
-i
-I
-l
-n
-p
-r
-s
-S
-T
-v
-w
-W
-x
BUT!!!
If you look at MRuby, which is the Ruby implementation written by Yukihiro "matz" Matsumoto, Ruby's creator, which is intended to be a lightweight implementation of the minimum core that can still be called "Ruby", it only supports these options:
-b load and execute RiteBinary (mrb) file
-c check syntax only
-e 'command' one line of script
-v print version number, then run in verbose mode
--verbose run in verbose mode
--version print the version
--copyright print the copyright
Of these, -b is clearly implementation specific, and -c, -v, --version, and --copyright have no runtime impact, so we can interpret this as meaning that -e is the only option that must be supported by a conforming Ruby implementation … after all, it is the only option supported by the Ruby implementation written by the only person who can legitimately have a say in what it means to be "a Ruby implementation".

Can zsh complete command flags?

Is there some way to get zsh to complete long flag names on the command line?
$ command --reall<tab>
$ command --really-long-flag-name
Seems like a zshy thing to do.
The short answer is yes, or course it can.
To turn on zsh’s completion system, you need to do the following – probably in a startup file like your ~/.zshrc:
autoload -U compinit && compinit
On most modern Unix-like systems, once you do that you ought to find that many commands already have their flags and parameters completed, because zsh ships with a library of completion functions for common Unix commands and utilities. This library ought to be installed in a location like /usr/local/share/zsh/function (or similar, depending on your system) and consists of a bunch of scripts with filenames starting in a _ character, each of which defines the completion for a specific command.
If a command or utility you’re interested in is not yet completed correctly by zsh, you have several options:
Look into the zsh-completions package. (It may well be installable by your operating system or distribution’s package manager.)
Read the documentation for the tool you wish to have completion. Many Unix utilities ship with completion scripts for bash and/or zsh, or with some way of generating completion scripts.
If all else fails, read the documentation on zsh’s completion system (or find a good book or online tutorial) and write it yourself. This can — obviously — be non-trivial!
Reading that zsh documentation might also show you how to do other things that you may not even know yet that you want, like turning on menu-based completion.

Compilation using 3rd party libraries

I'm using Getopt to parse commandline arguments in commands.ml. So the first line of commands.ml looks like this:
open Getopt
I can't seem to figure out how I compile commands.ml with this module. I've tried so many things and I always get the following error:
File "commands.ml", line 1, characters 5-11:
Error: Unbound module Getopt
I have added #require "Getopt" to my .ocamlinit file.
You say you're using Getopt, "so" you have open Getopt in your code. But there's no direct connection there. It's more usual (and in my opinion usually better) to use modules without opening them.
The use of open only controls the names available in the containing module. It doesn't tell the compiler where to look for the opened modules.
There's no Getopt module in the standard OCaml library. The standard module for parsing command lines is named Arg. If you're using an external library, you need to use the -I flag to tell the compiler where to look for it.
The .ocamlinit file controls the behavior of the OCaml toplevel (the read-eval-print interpreter). It doesn't affect the behavior of compilers.
If you're using a building tool, there are probably easier ways to set things up. But you'll need to explain your build environment more carefully.
The problem, that there're lots of answers to your question. Depending on what build system you chose, there will be different commands. And that is the reason, why we are asking. But it looks like, that you have no preference, so let me try to give you some answers.
With ocamlbuild
$ ocamlbuild -package getopt commands.native
With ocamlfind
$ ocamlfind ocamlopt -package getopt commands.ml -o commands.native
For more explanation read the following.
Personal advice: if you're unsure on what to choose, then use ocamlbuild.
Use ocamlfind with your preferred compiler (I'm using ocamlopt below), like so:
ocamlfind ocamlopt -package getopt -linkpkg commands.ml -o commands
This will still fail if you don't have getopt installed. Getopt may be installed with opam:
opam install getopt
I would like to suggest that you use Arg instead. It's part of OCaml's standard library, and is generally pleasant to work with.

Ruby Script to Command Line Tool

I am trying to make a command line tool. I already have a ruby script (one file). But I want to project it as a normal command line command.
Right now I have to go into the directory where the script is and type ruby script.rb for it to function but i want to make a command such as script [option] from directory and it should process the required option in the script.
Do I need to make an independent ruby gem for this? I have read about some gems like thor and commander but I am not able to use them properly.
How can I make this command line tool?
PS: An example can be the twitter gem and a command line tool 't' which is also a gem.
Ruby, because it's a general-programming language, makes it easy to create command-line scripts. Here's a basic script you can build upon:
#!/usr/bin/env ruby
require 'optparse'
args = {}
OptionParser.new do |opt|
opt.on('-i', '--input FILE', 'File to read') { |o| args[:file_in] = o }
opt.on('-o', '--output FILE', 'File to write') { |o| args[:file_out] = o }
end.parse!
abort "Missing input or output file" unless (args[:file_in] && args[:file_out])
File.write(args[:file_out], File.read(args[:file_in]))
Here's what's happening:
#!/usr/bin/env ruby is commonly called a "bang line". The shell will look for this line at the top of a file to determine what application can read the file and execute/interpret it. env is an application that will look through the user's PATH environment variable and return the first Ruby found as the Ruby to execute the script. Using this makes the script work with Rubies in the normal /usr/bin, /usr/local/bin or when managed by rbenv or RVM.
require 'opt parse' pulls in Ruby's command-line parser class OptionParser, which makes it easy to set up traditional flags, such as -i path/to/file/to/read, -o path/to/file/to/write, or long parameters, like --input or --output. It also automatically supplies the -h and --help flags to return formatted help text for the script. OptionParser is a bit of a learning-curve, so play with the complete example and you'll figure it out.
The rest should be pretty self-explanatory.
Traditionally, executables that are installed by the system go in /usr/bin. Executables we write, or add, go in /usr/local/bin, and I highly recommend sticking with that.
Some OSes don't automatically supply an entry for /usr/local/bin in the PATH, so you might need to modify your PATH setting in your ~/.bashrc, ~/.bash_profile or ~/.profile to allow the shell to locate the script.
Executable scripts need to have their executable flag set: chmod +x /path/to/executable is the basic command. See man chmod for more information.
I tend to leave the script's extension in place; Ruby scripts are "foo.rb", Python are "bar.py", etc. I do that because I prefer to have that extension as a hint of the language it's written in, but YMMV. The extension isn't necessary so go with what works for you.
Beyond all that, you might want to provide logging output, or output to the system's syslog. In the first case use Ruby's built-in Logger class, or the Syslog class in the second case.
Actually there's two great gems for command line apps in Ruby.
First is methadone which is for simpler command line apps.
Another is gli which is for apps with multiple commands, for example something like bundler.
If you want to know more, you can check out book about creating command line apps build awesome command-line apps in ruby by author of these gems.
You do not need to make it a gem, the following suffices:
Change its name from script.rb to script
Add #!/usr/bin/env ruby as the first line of script
Put it somewhere in PATH (e.g. $HOME/bin, making sure it is in PATH), or execute by giving path explicitly, e.g. $HOME/myscriptdir/script

Resources