Andrew Schutt
Thor: a toolkit for building powerful command-line interfaces
What is Thor?
What is Thor?
Thor is a simple and efficient tool for building self documenting command line utilities.
Why Thor?
Why Thor?
Getting Started
Getting Started
gem install thor
class Hello < Thor
desc "odinson", "Prince of Asgard"
def odinson
puts "It is I Thor!"
end
end
class Hello < Thor
desc "odinson", "Prince of Asgard"
def odinson
puts "It is I Thor!"
end
end
class Hello < Thor
desc "odinson", "Prince of Asgard"
def odinson
puts "It is I Thor!"
end
end
class Hello < Thor
desc "odinson", "Prince of Asgard"
def odinson
puts "It is I Thor!"
end
end
thor hello:odinson
It is I Thor!
thor list
thor list
hello
#----
thor hello:odinson # Prince of Asgard
thor help [COMMAND]
thor help hello:odinson
Usage:
thor hello:odinson
Prince of Asgard
Long Description
class Hello < Thor
desc "odinson", "Prince of Asgard"
long_desc <<-LONGDESC
`hello:odinson` will print out a lovely message
from Thor odinson himself.
The usage for this command is just invocation
using Thor.
`thor hello:odinson`
No additional option are available (yet!)
LONGDESC
def odinson
puts "It is I Thor!"
end
end
thor help hello:odinson
Usage:
thor hello:odinson
Description:
`hello:odinson` will print out a lovely message from Thor odinson himself.
The usage for this command is just invocation using Thor.
`thor hello:odinson`
No additional option are available (yet!)
Arguments
class Hello < Thor
desc "odinson", "says hello"
def odinson(name)
puts "It is I Thor! Hello #{name}"
end
end
class Hello < Thor
desc "odinson", "says hello"
def odinson(name)
puts "It is I Thor! Hello #{name}"
end
end
Task Options
Options
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose
def odinson
verbose_mode = options[:verbose]
if verbose_mode
puts "It is I Thor! Odinson! Prince of Asgard!"
else
puts "It is I Thor!"
end
end
end
Options
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose
def odinson
verbose_mode = options[:verbose]
if verbose_mode
puts "It is I Thor! Odinson! Prince of Asgard!"
else
puts "It is I Thor!"
end
end
end
thor help hello:odinson
Usage:
thor hello:odinson
Options:
[--verbose=VERBOSE]
Prince of Asgard
thor hello:odinson --verbose
Options for the options
-
:desc
-
:aliases
-
:banner
-
:default
-
:lazy_default
-
:required
-
:type
-
:string, :hash, :array, :numeric, or :boolean
-
-
:enum
:desc
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose,
:desc => "display Thor's full name"
def odinson
verbose_mode = options[:verbose]
if verbose_mode
puts "It is I Thor! Odinson! Prince of Asgard!"
else
puts "It is I Thor!"
end
end
end
:aliases
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose,
:desc => "display Thor's full name",
:aliases => "-v"
def odinson
verbose_mode = options[:verbose]
if verbose_mode
puts "It is I Thor! Odinson! Prince of Asgard!"
else
puts "It is I Thor!"
end
end
end
:banner
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose,
:desc => "display Thor's full name",
:banner => "to use this option append --verbose"
def odinson
verbose_mode = options[:verbose]
if verbose_mode
puts "It is I Thor! Odinson! Prince of Asgard!"
else
puts "It is I Thor!"
end
end
end
:default
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :hello_to,
:desc => "who to say hello to",
:default => "stranger"
def odinson
hello_to = options[:hello_to]
puts "It is I Thor! Hello #{hello_to}"
end
end
:lazy_default
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :hello_to,
:desc => "who to say hello to",
:lazy_default => "stranger"
def odinson
hello_to = options[:hello_to]
puts "It is I Thor! Hello #{hello_to}"
end
end
:required
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :hello_to,
:desc => "who to say hello to",
:required => true
def odinson
hello_to = options[:hello_to]
puts "It is I Thor! Hello #{hello_to}"
end
end
:type
-
:boolean
-
--option=true
-
-
:string
-
--option=value
-
-
:numeric
-
--option=1234
-
-
:array
-
--option=one two three
-
-
:hash
-
--option=name:string age:integer
-
:enum
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :hello_to,
:desc => "who to say hello to",
:enum => ['Loki', 'Hela', 'Hulk']
def odinson
hello_to = options[:hello_to]
puts "It is I Thor! Hello #{hello_to}"
end
end
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose, desc: "display full message from thor",
aliases: "-v",
default: false,
type: :boolean
method_option :family, desc: "display message for Thor family member",
aliases: "-f",
banner: "<family member name>",
default: "brother",
type: :string,
enum: ["Loki", "Hela", "Odin"]
method_option :no_name, desc: "display message without Thor addressing anyone",
aliases: "-nn",
banner: "Thor addesses no one"
def odinson(name)
hello_to = options[:family] ? option[:family] : name
if option[:no_name]
puts "Hello! It is I Thor!"
else
if options[:verbose]
puts "Hello #{name}. It is I Thor! Son of Odin and Prince of Asgard!"
else
puts "Hello #{name}. It is I Thor!"
end
end
end
end
class Hello < Thor
desc "odinson", "Prince of Asgard"
method_option :verbose, desc: "display full message from thor",
aliases: "-v",
default: false,
type: :boolean
method_option :family, desc: "display message for Thor family member",
aliases: "-f",
banner: "<family member name>",
default: "brother",
type: :string,
enum: ["Loki", "Hela", "Odin"]
method_option :no_name, desc: "display message without Thor addressing anyone",
aliases: "-nn",
banner: "Thor addesses no one"
def odinson(name)
hello_to = options[:family] ? option[:family] : name
if option[:no_name]
puts "Hello! It is I Thor!"
else
if options[:verbose]
puts "Hello #{name}. It is I Thor! Son of Odin and Prince of Asgard!"
else
puts "Hello #{name}. It is I Thor!"
end
end
end
end
thor help hello:odinson
Usage:
thor hello:odinson
Options:
-v, [--verbose], [--no-verbose] # display full message from thor
-f, [--family=<family member name>] # display message for Thor family member
# Default: brother
# Possible values: Loki, Hela, Odin
-nn, [--no-name=Thor addesses no one] # display message without Thor addressing anyone
Prince of Asgard
Class Options
class_option
class_option :yelling, type: :boolean,
default: false,
desc: "engage yelling mode"
class_option
class Volume < Thor
class_option :yelling, :type => :boolean,
:default => false,
:aliases => "-y"
desc "yell", "yell it!"
def yell
msg = "I am not yelling! You're yelling!"
if options[:yelling]
puts msg.upcase
end
puts msg
end
desc "whisper", "shhhh"
def whisper
if options[:yelling]
msg = "please stop yelling. whisper time"
else
msg = "shhh, whisper, whisper"
end
puts msg
end
end
thor help volume:yell
Usage:
thor volume:whisper
Options:
-y, [--yelling], [--no-yelling]
shhhh
thor help volume:whisper
Usage:
thor volume:yell
Options:
-y, [--yelling], [--no-yelling]
yell it!
Task Actions
Actions
class Quinjet < Thor
include Thor::Actions
desc "authenticate", "authenticates for quinjet access"
def authenticate
authenticated = false
run("say -v Moira Welcome. Authentication required.")
while !authenticated
username = ask "Welcome. Authentication required."
if username.upcase == "POINT BREAK"
authenticated = true
run("say -v Moira Welcome Point Break.")
else
run("say -v Moira Access Denied.")
end
end
end
end
Actions
class Quinjet < Thor
include Thor::Actions
desc "authenticate", "authenticates for quinjet access"
def authenticate
authenticated = false
run("say -v Moira Welcome. Authentication required.")
while !authenticated
username = ask "Welcome. Authentication required."
if username.upcase == "POINT BREAK"
authenticated = true
run("say -v Moira Welcome Point Break.")
else
run("say -v Moira Access Denied.")
end
end
end
end
Actions
class Quinjet < Thor
include Thor::Actions
desc "authenticate", "authenticates for quinjet access"
def authenticate
authenticated = false
run("say -v Moira Welcome. Authentication required.")
while !authenticated
username = ask "Welcome. Authentication required."
if username.upcase == "POINT BREAK"
authenticated = true
run("say -v Moira Welcome Point Break.")
else
run("say -v Moira Access Denied.")
end
end
end
end
Actions
-
:say
-
:ask
-
:yes?
-
:no?
-
:add_file, :remove_file, :copy_file
-
:template
-
:directory
-
:inside
-
:run
-
and more
Subcommands
Subcommands
module GitCLI
class Remote < Thor
desc "add <name> <url>", "Adds a remote"
def add(name, url)
# implement git remote add
end
desc "rename <old> <new>", "Rename the remote"
def rename(old, new)
# implement git remote rename
end
end
class Git < Thor
desc "remote SUBCOMMAND ...ARGS", "manage set repositories"
subcommand "remote", Remote
end
end
System Wide
thor install [.THOR FILE]
Thank you!
Thor CLI
By Andrew Schutt
Thor CLI
a presentation for Iowa Ruby Brigade around the Thor CLI tool with an example of creating a Magic the Gathering search CLI tool
- 1,207