ruby thor command line

Créer une application en ligne de commande en Ruby avec Thor

Partagez sur:

Thor un outil pour créer des excellent pour créer des interfaces en ligne de commande en Ruby, Il est utilisé dans Vagrant, Ruby On Rails, Bundler etc.

Thor se présente sous forme de gem que vous pouvez installer et inclure dans votre projet.Une simple class Thor expose un exécutable et des sous-commandes comme git, bundler ou rails…

Une fois que vous incluez Thor dans votre classe, les méthodes publiques de votre classe deviennent des commandes.

Exemple:

# Require thor library.
require "thor"

class MyCLI < Thor
  desc "hello NAME", "say hello to NAME"
  def hello(name)
    puts "Hello #{name}"
  end
end

# Start CLI
MyCLI.start(ARGV)

A la fin de votre classe il faudra imperativement demarrer votre CLI (Interface de Ligne de Commande). Typiquement vous pouvez faire cela dans le repertoire d’excutable « bin » de votre gem.

Si l’argument passé à la méthode « start » est vide, Thor affiche une d’aide de votre class.

Appel à la méthode ci-dessus sans argument :

$ ruby ./cli
Tasks:
  cli hello NAME   # say hello to NAME
  cli help [TASK]  # Describe available tasks or one specific task

Appel à la méthode ci-dessus avec argument :

$ ruby ./cli hello Yehuda
Hello Yehuda

Vous pouvez aussi utilisé des arguments optionnel de ruby, pour rendre les arguments de votre programme optionnels :

class MyCLI < Thor
  desc "hello NAME", "say hello to NAME"
  def hello(name, from=nil)
    puts "from: #{from}" if from
    puts "Hello #{name}"
  end
end

Quand vous exécutez ce code, vous obtenez :

$ ruby ./cli hello "Yehuda Katz"
Hello Yehuda Katz
$ ruby ./cli hello "Yehuda Katz" "Carl Lerche"
from: Carl Lerche
Hello Yehuda Katz

Long Description

Par défaut Thor utilise la description courte pour vos commande en utilisant la méthode de class « desc » qui reçoit deux paramètres au minimum, le premier étant l’usage de la commande et le second la description courte de la commande.

$ ruby ./cli help hello
Usage:
  test.rb hello NAME
 
say hello to NAME

Souvent, vous avez besoin d’afficher une description un peu long pour vos commandes, dans cas vous pouvez utiliser la méthode de class « long_desc » fournie par Thor.

class MyCLI < Thor
  desc "hello NAME", "say hello to NAME"
  long_desc <<-LONGDESC
    `cli hello` will print out a message to a person of your
    choosing.
 
    You can optionally specify a second parameter, which will print
    out a from message as well.
 
    > $ cli hello "Yehuda Katz" "Carl Lerche"
 
    > from: Carl Lerche
  LONGDESC
  def hello(name, from=nil)
    puts "from: #{from}" if from
    puts "Hello #{name}"
  end
end

Options et Flags

Thor rend facile l’utilisation des options et flags comme métadonnées.

class MyCLI < Thor
  desc "hello NAME", "say hello to NAME"
  option :from
  def hello(name)
    puts "from: #{options[:from]}" if options[:from]
    puts "Hello #{name}"
  end
end

Maintenant vos utilisateurs peuvent spécifier l’option « from » comme un flag.

$ ruby ./cli hello --from "Carl Lerche" Yehuda
from: Carl Lerche
Hello Yehuda
$ ruby ./cli hello Yehuda --from "Carl Lerche"
from: Carl Lerche
Hello Yehuda
$ ruby ./cli hello Yehuda --from="Carl Lerche"
from: Carl Lerche
Hello Yehuda

Il faut noter que par défaut, les options sont des chaines de caractères « String », mais vous pouvez spécifier les types alternative pour chaque commande.

class MyCLI < Thor
  option :from
  option :yell, :type => :boolean
  desc "hello NAME", "say hello to NAME"
  def hello(name)
    output = []
    output << "from: #{options[:from]}" if options[:from]
    output << "Hello #{name}"
    output = output.join("\n")
    puts options[:yell] ? output.upcase : output
  end
end

Quand vous exécutez ce code vous obtiendrez :

$ ./cli hello --yell Yehuda --from "Carl Lerche"
FROM: CARL LERCHE
HELLO YEHUDA
$ ./cli hello Yehuda --from "Carl Lerche" --yell
FROM: CARL LERCHE
HELLO YEHUDA

Il faut noter que vous spécifier si une option est requise avec la fonction « required » lors de la declaration de l’option.

class MyCLI < Thor
  option :from, :required => true
  option :yell, :type => :boolean
  desc "hello NAME", "say hello to NAME"
  def hello(name)
    output = []
    output << "from: #{options[:from]}" if options[:from]
    output << "Hello #{name}"
    output = output.join("\n")
    puts options[:yell] ? output.upcase : output
  end
end

Si vous essayez d’exécuter ce code sans l’option requise :

$ ./cli hello Yehuda
No value provided for required options '--from'

Sous-commandes

Comme votre CLI devient un peu plus complexe, vous pouvez vouloir utiliser des sous-commandes. Comme par exemple pour la command « git remote » qui contient des sous commandes : add, rename, rm, prune, set-head etc.

Dans Thor vous pouvez faire la meme chose facilement en créant des classes pour chaque sous-commandes et pointer apres ces sous-commandes dans la commande principale.

Exemple :

module GitCLI
  class Remote < Thor
    desc "add <name> <url>", "Adds a remote named <name> for the repository at <url>"
    long_desc <<-LONGDESC
      Adds a remote named <name> for the repository at <url>. The command git fetch <name> can then be used to create and update
      remote-tracking branches <name>/<branch>.
 
      With -f option, git fetch <name> is run immediately after the remote information is set up.
 
      With --tags option, git fetch <name> imports every tag from the remote repository.
 
      With --no-tags option, git fetch <name> does not import tags from the remote repository.
 
      With -t <branch> option, instead of the default glob refspec for the remote to track all branches under $GIT_DIR/remotes/<name>/, a
      refspec to track only <branch> is created. You can give more than one -t <branch> to track multiple branches without grabbing all
      branches.
 
      With -m <master> option, $GIT_DIR/remotes/<name>/HEAD is set up to point at remote's <master> branch. See also the set-head
      command.
 
      When a fetch mirror is created with --mirror=fetch, the refs will not be stored in the refs/remotes/ namespace, but rather
      everything in refs/ on the remote will be directly mirrored into refs/ in the local repository. This option only makes sense in
      bare repositories, because a fetch would overwrite any local commits.
 
      When a push mirror is created with --mirror=push, then git push will always behave as if --mirror was passed.
    LONGDESC
    option :t, :banner => "<branch>"
    option :m, :banner => "<master>"
    options :f => :boolean, :tags => :boolean, :mirror => :string
    def add(name, url)
      # implement git remote add
    end
 
    desc "rename <old> <new>", "Rename the remote named <old> to <new>"
    def rename(old, new)
    end
  end
 
  class Git < Thor
    desc "fetch <repository> [<refspec>...]", "Download objects and refs from another repository"
    options :all => :boolean, :multiple => :boolean
    option :append, :type => :boolean, :aliases => :a
    def fetch(respository, *refspec)
      # implement git fetch here
    end
 
    desc "remote SUBCOMMAND ...ARGS", "manage set of tracked repositories"
    subcommand "remote", Remote
  end
end

Vous pouvez avoir accès aux options de la commande parente dans les sous-commandes en utilisant la méthode de class « parent_options » fournie par Thor.

NB : ce tuto est inspiré du officiel sur le site de Thor « http://whatisthor.com/ », qui est disponible en Anglais.

http://whatisthor.com/

Amonce DEMBELE

 

LIRE AUSSI:  Comment programmer des tâches Cron en Ruby On Rails ?


Partagez sur: