On Ruby's Thor, How to show the command usage from within the application - ruby

I'm building a CLI using Ruby and Thor and I would like to print on the screen the command usage if no option is passed.
Something on the line of the pseudo code bellow:
Class Test < Thor
desc 'test', 'test'
options :run_command
def run_command
if options.empty?
# Print Usage
end
end
end
Im currently using the following hack (and I'm not proud of it! =P):
Class Test < Thor
desc 'test', 'test'
options :run_command
def run_command
if options.empty?
puts `my_test_command help run_command`
end
end
end
What would be the proper way to do this?

You can use command_help to display the help information for the command:
require 'thor'
class Test < Thor
desc 'run_command --from=FROM', 'test usage help'
option :from
def run_command
unless options[:from]
Test.command_help(Thor::Base.shell.new, 'run_command')
return
end
puts "Called command from #{options[:from]}"
end
end
Test.start
and then running with no options:
$ ruby example.rb run_command
Usage:
example.rb run_command --from=FROM
Options:
[--from=FROM]
test usage help
and running with the option:
$ ruby example.rb run_command --from=somewhere
Called command from somewhere

Related

Accessing the PWD inside a thor task

In my main thor file, I call this code
script.rb
# this works
current_dir = Dir.getwd
# this changes directory into the tasks
Dir.chdir(#{pwd}/tasks) {
IO.popen("thor #{ARGV * ' '}") do |io|
while (line = io.gets) do
puts line
end
io.close
end
}
tasks/example.rb
require 'thor'
class Git < Thor
include Thor::Actions
desc 'test', 'test'
def test
puts Dir.getwd # this is showing my tasks folder
end
end
Inside example.rb How can I get access to the Dir.getwd value of the script.rb and not of the example.rb (this is wrong since it is running inside the Dir.chdir).
I tried global variables and such but it doesn't seem to be working.

Ruby - Print with color output

I have a ruby script (Guardfile) that executes a rake command.
guard :shell do
watch(%r{^manifests\/.+\.pp$}) do |m|
spec = `rake spec`
retval = $?.to_i
case retval
when 0
if spec.length > 0 then
puts spec
n "#{m[0]} Tests Failed!", 'Rake Spec', :pending
else
puts spec
n "#{m[0]} Tests Passed!", 'Rake Spec', :pending
end
end
end
When I run a 'rake spec' from the command line, outputs are colorized.
How could I make it so the output of the ruby script is also colorized?
From command line:
From ruby script:
Update
I was able to sort-of work around the problem by using script
bash command preserve color when piping
spec = `script -q /dev/null rake spec`
This still has the downside of not scrolling the text in real time. While it does preserve the colors, it does not output anything until the very end.
Is there a more native way to do this that will allow for scrolling?
First, rake spec --color won't work, because you're passing --color to rake, and not rspec.
Jay Mitchell's suggestion for color should work - by putting this in your .rspec file:
--color
As for having "live" output, guard-shell has an eager command for this:
https://github.com/guard/guard-shell/blob/master/lib/guard/shell.rb#L37-L51
Unfortunately, guard-shell has 2 important shortcomings:
it doesn't give you access to the exit code
it doesn't properly report failures in Guard (which causes other tasks to run)
So the eager method of Guard::Shell is useless for our needs here.
Instead, the following should work:
# a version of Guard::Shell's 'eager()' which returns the result
class InPty
require 'pty'
def self.run(command)
PTY.spawn(command) do |r, w, pid|
begin
$stdout.puts
r.each {|line| $stdout.print line }
rescue Errno::EIO
end
Process.wait(pid)
end
$?.success?
rescue PTY::ChildExited
end
end
# A hack so that Guard::Shell properly throws :task_has_failed
class ProperGuardPluginFailure
def to_s
throw :task_has_failed
end
end
guard :shell, any_return: true do
watch(%r{^manifests\/.+\.pp$}) do |m|
ok = InPty.run('rake spec')
status, type = ok ? ['Passed', :success] : ['Failed', :failed]
n "#{m[0]} Tests #{status}!", 'Rake Spec', type
ok ? nil : ProperGuardPluginFailure.new
end
end
The above looks ideal for a new guard plugin - good idea?
I am unfamiliar with Guardfiles. Can you use gems? The colorize gem is great.
https://github.com/fazibear/colorize
Install it:
$ sudo gem install colorize
Use it:
require 'colorize'
puts "Tests failed!".red
puts "Tests passed!".green

Get path of parent requiring file, Ruby

Is it possible to get the location of the file which requires another file in Ruby?
I have a project where I spawn some processes and I would love to be able, in the code, to determine which file is the parent of the required file. This is nice when debugging.
Example:
#initial.rb:
require "./my_file.rb"
fork do
require "./my_file2.rb"
end
-
#my_file.rb:
puts "Required from file: #{?????}"
-
#my_file2.rb:
require "./my_file.rb"
I would expect to get something like:
#=> Required from file: /path/to/initial.rb
#=> Required from file: /path/to/my_file2.rb
Based on Jacobs answer I ended with this redefinition of require_relative and require:
alias :old_require_relative :require_relative
def require_relative(arg)
#~ puts caller.map{|x| "\t#{x}"}
puts "%s requires %s" % [ caller.first.split(/:\d+/,2).first, arg]
old_require_relative arg
end
alias :old_require :require
def require(arg)
#~ puts caller.map{|x| "\t#{x}"}
puts "%s requires %s" % [ caller.first.split(/:\d+/,2).first, arg]
old_require arg
end
In a test test scenario with the following load sequence:
test.rb
+- test1.rb
+- test1_a.rb
+ test2.rb
The following calls
require './test1'
require './test2'
or
require_relative 'test1'
require_relative 'test2'
result in:
test.rb requires ./test1
C:/Temp/test1.rb requires test1_a
test.rb requires ./test2
You could also include the line of the requirement in the output.
You should never need to do this, but you can examine the call stack from Kernel#caller. You'll have to filter out require methods (especially if you use any libraries that override require).

How can I use a flag as a command with Thor

Given a Ruby program using Thor, how can I implement a method that gets called when an argument that looks like a flag is called.
For example, if I run this on the command line:
mycmd --version
I would like to execute the code:
desc 'version', 'Print version number'
def version
puts "mycmd version #{Mycmd::VERSION}"
end
You can make a "top level" default task, which examines its arguments and outputs the correct thing:
class MyThing < Thor
desc "meta", "Information about the task itself"
argument :name
def meta
if name == "--version"
puts "v 1.1.1"
elsif name == "--author"
puts "meagar"
end
end
default_task :meta
end

Namespacing thor commands in a standalone ruby executable

When calling thor commands on the command line, the methods are namespaced by their module/class structure, e.g.
class App < Thor
desc 'hello', 'prints hello'
def hello
puts 'hello'
end
end
would be run with the command
thor app:hello
However, if you make that self executable by putting
App.start
at the bottom you can run the command like:
app hello
Is there any way to namespace those commands? So that you could call, for example
app say:hello
app say:goodbye
Another way of doing this is to use register:
class CLI < Thor
register(SubTask, 'sub', 'sub <command>', 'Description.')
end
class SubTask < Thor
desc "bar", "..."
def bar()
# ...
end
end
CLI.start
Now - assuming your executable is called foo - you can call:
$ foo sub bar
In the current thor version (0.15.0.rc2) there is a bug though, which causes the help texts to skip the namespace of sub commands:
$ foo sub
Tasks:
foo help [COMMAND] # Describe subcommands or one specific subcommand
foo bar #
You can fix that by overriding self.banner and explicitly setting the namespace.
class SubTask < Thor
namespace :sub
def bar ...
def self.banner(task, namespace = true, subcommand = false)
"#{basename} #{task.formatted_usage(self, true, subcommand)}"
end
end
The second parameter of formatted_usage is the only difference to the original implemtation of banner. You can also do this once and have other sub command thor classes inherit from SubTask. Now you get:
$ foo sub
Tasks:
foo sub help [COMMAND] # Describe subcommands or one specific subcommand
foo sub bar #
Hope that helps.
This is one way with App as the default namespace (quite hacky though):
#!/usr/bin/env ruby
require "rubygems"
require "thor"
class Say < Thor
# ./app say:hello
desc 'hello', 'prints hello'
def hello
puts 'hello'
end
end
class App < Thor
# ./app nothing
desc 'nothing', 'does nothing'
def nothing
puts 'doing nothing'
end
end
begin
parts = ARGV[0].split(':')
namespace = Kernel.const_get(parts[0].capitalize)
parts.shift
ARGV[0] = parts.join
namespace.start
rescue
App.start
end
Or, also not ideal:
define_method 'say:hello'

Resources