Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Toolkit for developing sleek command line apps.

License

NotificationsYou must be signed in to change notification settings

piotrmurach/tty

Repository files navigation

TTY Toolkit logo

Gem VersionActions CIBuild statusMaintainabilityTest CoverageInline docsGitter

TTY is a toolbox for developing beautiful command line clients in Ruby with a fluid interface for gathering input, querying terminal properties and displaying information.

Motivation

All too often libraries that interact with terminals create their own interface logic that gathers input from users and displays information back. Many times utility files are created that contain methods for reading system or terminal properties. Shouldn't we focus our energy on building the actual client?

Building terminal tools takes time. I believe that modular components put together in a single package with project scaffolding will help people build things faster and produce higher quality results. It is easy to jump start a new project with available scaffolding and mix and match components to create new tooling.

Features

  • Jump-start development of your command line app the Unix way with scaffold provided byteletype.
  • Fully modular, choose out of manycomponents to suit your needs or use any 3rd party ones.
  • All tty components are small packages that do one thing well.
  • Fully tested with major ruby interpreters.

Installation

Add this line to your application's Gemfile to install all components:

gem 'tty'

or install a particular component:

gem 'tty-*'

And then execute:

$ bundle

Or install it yourself as:

$ gem install tty

Contents

1. Overview

TTY provides you with commands and many components to get you onto the path of building awesome terminal applications in next to no time.

To simply jump start a new command line application useteletype executable:

$ teletype new app

Move in to your new app, and then add more commands:

$cd app$ teletype add config

Throughout the rest of this guide, I will assume a generated application calledapp, that you are in the working directory of 'app/', and a newly created bare commandconfig.

2. Bootstrapping

2.1new command

Runningteletype new [app-name] will bootstrap an entire project file structure based on the bundlergem command setup enhanced by additional files and folders related to command application development.

For example, to create a new command line application calledapp do:

$teletypenewapp

The output will contain all the files that have been created during setup:

Creating gem 'app'    create app/Gemfile    create app/.gitignore    create app/lib/app.rb    create app/lib/app/version.rb    ...

In turn, the following files and directories will be generated in theapp folder familiar to anyone who has created a gem beforehand:

▾ app/├── ▾ exe/│   └── app├── ▾ lib/│   ├── ▾ app/│   │   ├── ▸ commands/│   │   ├── ▸ templates/│   │   ├── cli.rb│   │   ├── command.rb│   │   └── version.rb│   └── app.rb├── CODE_OF_CONDUCT.md├── Gemfile├── LICENSE.txt├── README.md├── Rakefile└── app.gemspec

By convention the filelib/app/cli.rb provides the main entry point to your command line application:

moduleAppclassCLI <Thor# Error raised by this runnerError=Class.new(StandardError)desc'version','app version'defversionrequire_relative'version'puts"v#{App::VERSION}"endmap%w(--version-v)=>:versionendend

This is where all your application commands and subcommands will be defined.

Teletype usesThor as an option parsing library by directly inheriting from it.

And also by convention thestart method is used to parse the command line arguments inside theapp executable:

App::CLI.start

Run the new command with--help or-h flag to see all available options:

$teletypenew --help$teletypenew -h

Executeteletype to see all available commands.

2.1.1--author,-a flag

Theteletype generator can inject name into documentation for you:

$ teletype new app --author'Piotr Murach'

2.1.2--ext flag

To specify thatteletype should create a binary executable (asexe/GEM_NAME) in the generated project use the--ext flag. This binary will also be included in theGEM_NAME.gemspec manifest. This is disabled by default, to enable do:

$ teletype new app --ext

2.1.3--license,-l flag

Theteletype generator comes prepackaged with most popular open source licenses:agplv3,apache,bsd2,bsd3,gplv2,gplv3,lgplv3,mit,mplv2,custom. By default themit license is used. To change that do:

$teletypenewapp --licensebsd3

2.1.4--test,-t flag

Theteletype comes configured to work withrspec andminitest frameworks which are the only two acceptable values. TheGEM_NAME.gemspec will be configured and appropriate testing directory setup. By default theRSpec framework is used.

$teletypenewapp --test=minitest$teletypenewapp -t=minitest

2.2add command

Once application has been initialized, you can create additional command by usingteletype add [command-name] task:

$teletypeaddconfig$teletypeaddcreate

This will addcreate.rb andconfig.rb commands to the CLI client:

▾ app/├── ▾ commands/│   ├── config.rb│   └── create.rb├── ▸ templates/│   ├── ▸ config/│   └── ▸ create/├── command.rb├── cli.rb└── version.rb

Then you will be able to call the new commands like so:

$appconfig$appcreate

The commands require you to specify the actual logic in theirexecute methods.

Please note that command names should be provided ascamelCase orsnake_case. For example:

$ teletype add addConfigCommand   # => correct$ teletype add add_config_command # => correct$ teletype add add-config-command # => incorrect

2.2.1--args flag

You can specify thatteletype should add a command with a variable number of arguments using the--args flag. The--args flag accepts space delimited variable names. To specify required argument use a string name, for an optional argument passname = nil enclosed in quote marks and any variable number of arguments needs to be preceded by asterisk:

$ teletype add config --args name# required argument$ teletype add config --args"name = nil"# optional argument$ teletype add config --args*names# variadic argument

For more in-depth usage see2.4 Arguments.

2.2.2--desc flag

Every generated command will have a default description 'Command description...', however whilst generating a command you can and should specify a custom description to provide more context with--desc flag:

$ teletype add config --desc'Set and get configuration options'

For more in-depth usage see2.5 Description.

2.2.3--force flag

If you wish to overwrite currently implemented command use--force flag:

$ teletype add config --force

2.3 Working with Commands

Running

teletype add config

a new commandconfig will be added tocommands folder creating the following files structure inside thelib folder:

▾ app/├── ▾ commands/│   └── config.rb├── ▾ templates/│   └── ▸ config/├── cli.rb├── command.rb└── version.rb

Thelib/app/cli.rb file will contain generated command entry which handles the case where the user asks for theconfig command help or invokes the actual command:

moduleAppclassCLI <Thordesc'config','Command description...'defconfig(*)ifoptions[:help]invoke:help,['config']elserequire_relative'commands/config'App::Commands::Config.new(options).executeendendendend

And thelib/app/commands/config.rb will allow you to specify all the command logic. In theConfig class which by convention matches the command name, theexecute method provides a place to implement the command logic:

moduleAppmoduleCommandsclassConfig <App::Commanddefinitialize(options)@options=optionsenddefexecute# Command logic goes here ...endendendend

Notice thatConfig inherits fromApp::Cmd class which you have full access to. This class is meant to provide all the convenience methods to lay foundation for any command development. It will lazy load manytty components inside helper methods which you have access to by opening up thelib/app/command.rb file.

For example in thelib/app/command.rb file, you have access toprompt helper for gathering user input:

# The interactive prompt## @see http://www.rubydoc.info/gems/tty-prompt## @api publicdefprompt(**options)require'tty-prompt'TTY::Prompt.new(options)end

or acommand helper for running external commands:

# The external commands runner## @see http://www.rubydoc.info/gems/tty-command## @api publicdefcommand(**options)require'tty-command'TTY::Command.new(options)end

You have full control of the file, so you can use only thetty components that you require. Please bear in mind that all the components are added by default in yourapp.gemspec which you can change to suite your needs and pick onlytty components that fit your case.

2.4 Arguments

A command may accept a variable number of arguments.

For example, if we wish to have aconfig command that accepts a location of configuration file, then we can runteletype add command passing--args flag:

$ teletype add config --args file

which will include the requiredfile as an argument to theconfig method:

moduleAppclassCLI <Thordesc'config FILE','Set and get configuration options'defconfig(file)      ...endendend

Similarly, if we want to generate command with two required arguments, we runteletype add command with--args flag that can accept variable names delimited by space character:

$ teletype addset --args name value

will generate the following:

moduleAppclassCLI <Thordesc'set NAME VALUE','Set configuration option'defset(name,value)      ...endendend

If we want to have a command that has an optional argument, for example, thefile argument is an optional argument in theconfig command, then you need to enclose--args argument in parentheses:

$ teletype add config --args'file = nil'

In well behaved command line application, any optional argument in a command will be enclosed in square brackets:

moduleAppclassCLI <Thordesc'config [FILE]','Set and get configuration options'defconfig(file=nil)      ...endendend

If you intend for your command to accept any number of arguments, you need to prefix such argument with an asterisk. For example, if we wish to accept many configuration names:

$ teletype add get --args*names

which will append... to the argument description:

moduleAppclassCLI <Thordesc'get NAMES...','Get configuration options'defget(*names)      ...endendend

You can mix and match all the above styles of arguments definitions:

$ teletype add config --args file*names

2.5 Description

Use thedesc method call to describe your command when displayed in terminal. There are two arguments to this method. First, specifies the command name and the actual positional arguments it will accept. The second argument is an actual text description of what the command does.

For example, given the commandconfig generated inadd command section, we can add description like so:

moduleAppclassCLI <Thordesc'config [FILE]','Set and get configuration options'defconfig(file=nil)      ...endendend

Runningapp executable will include the new description:

Commands:  app config [FILE]  # Set and get configuration options

To provide long form description of your command uselong_desc method.

moduleAppclassCLI <Thordesc'config [FILE]','Set and get configuration options'long_desc<<-DESC      You can query/set/replace/unset options with this command.      The name is an optional key separated by a dot, and the value will be escaped.      This command will fail with non-zero status upon error.    DESCdefconfig(file=nil)      ...endendend

Runningapp config --help will produce the following output:

Usage:  app configYou can query/set/replace/unset options with this command.The name is an optional key separated by a dot, and the value will be escaped.This command will fail with non-zero status upon error.

2.6 Options and Flags

Flags and options allow to customize how particular command is invoked and provide additional configuration.

To specify individual flag or option usemethod_option before the command method. All the flags and options can be accessed inside method body via theoptions hash.

Available metadata for an option are:

  • :aliases - A list of aliases for this option.
  • :banner — A description of the value if the option accepts one.
  • :default - The default value of this option if it is not provided.
  • :lazy_default — A default that is only passed if the cli option is passed without a value.
  • :desc - The short description of the option, printed out in the usage description.
  • :required — Indicates that an option is required.
  • :type -:string,:hash,:array,:numeric,:boolean
  • :enum — A list of allowed values for this option.

The values for:type option are:

  • :boolean is parsed as--option
  • :string is parsed as--option=VALUE or--option VALUE
  • :numeric is parsed as--option=N or--option N
  • :array is parsed as--option=one two three or--option one two three
  • :hash is parsed as--option=name:string age:integer

For example, you wish to add an option that allows you to add a new line to a configuration file for a given key with a value thus being able to runapp config --add name value. To do this, you would need to specify:array type for accepting more than one value and:banner to provide meaningful description of values:

method_option:add,type::array,banner:"name value",desc:"Adds a new line the config file. "

The above option would be included in theconfig method like so:

moduleAppclassCLI <Thordesc'config [<file>]','Set and get configuration options'method_option:add,type::array,banner:"name value",desc:"Adds a new line the config file. "defconfig(*)      ...endendend

Runningapp help config will output new option:

Usage:  app config [<file>]  Options:    [--add=name value]  # Adds a new line the config file.

You can also specify an option as a flag without an associated value. Let us assume you want to be able to open a configuration file in your system editor when runningapp config --edit orapp config -e. This can be achieved by adding the following option:

method_option:edit,type::boolean,aliases:['-e'],desc:"Opens an editor to modify the specified config file."

And adding it to theconfig method:

moduleAppclassCLI <Thordesc'config [<file>]','Set and get configuration options'method_option:edit,type::boolean,aliases:['-e'],desc:"Opens an editor to modify the specified config file."defconfig(*)      ...endendend

Next, runningapp help config will produce:

Usage:  app config [<file>]Options:      [--add=name value]     # Adds a new line the config file.  -e, [--edit], [--no-edit]  # Opens an editor to modify the specified config file.

You can usemethod_options as a shorthand for specifying multiple options at once.

method_options%w(list-l)=>:boolean,:system=>:boolean,:local=>:boolean

Once all the command options and flags have been setup, you can access them viaoptions hash in command filelib/app/commands/config.rb:

moduleAppmoduleCommandsclassConfig <App::Commanddefinitialize(options)@options=optionsenddefexecuteifoptions[:edit]editor.open('path/to/config/file')endendendendend

2.7 Global Flags

You can specify an option or a flag that is applicable to all commands and subcommands within a given class by using theclass_option method. This method takes exactly the same parameters asmethod_option for an individual command. Theoptions hash in a given command will always include a global level flag information.

For example, if you want a global flagdebug that is visible to all commands in your tool then you need to add it to yourCLI class like so:

moduleAppclassCLI <Thorclass_option:debug,type::boolean,default:false,desc:'Run in debug mode'    ...endend

2.8. Working with Subcommands

If your tool grows in complexity you may want to add more refined behaviour for each individual command, a subcommand is a great choice to accomplish this. For example,git utility and itsgit remote command have various subcommandsadd,rename,remove,set-url,prune and so on that themselves accept many options and arguments.

Theteletype executable allows you to easily create new subcommands by issuing the sameadd command that is also used for generating commands. The only difference is that you need to provide a command name together with a subcommand name. For example, let's say we want theconfig with aset subcommand with a description and two positional argumentsname andvalue:

$ teletype add configset --desc'Set configuration option' --args name value

This will addset.rb command to thecommands/config folder:

▾ app/├── ▾ commands/│   ├── ▾ config/│   │   └── set.rb│   └── config.rb├── ▾ templates/│   └── ▾ config/│       └── ▸ set/├── cli.rb├── command.rb└── version.rb

Thelib/app/cli.rb will contain code that registers config namespace with ourCLI root application:

moduleAppclassCLI <Thorrequire_relative'commands/config'registerApp::Commands::Config,'config','config [SUBCOMMAND]','Set configuration option'endend

Thelib/app/commands/config.rb will contain code that handles dispatching subcommands to theConfig instance:

# frozen_string_literal: truerequire'thor'moduleAppmoduleCommandsclassConfig <Thornamespace:configdesc'set NAME VALUE','Set configuration option'defset(name,value)ifoptions[:help]invoke:help,['set']elserequire_relative'config/set'App::Commands::Config::Set.new(name,value,options).executeendendendendend

And finally, thelib/app/commands/config/set.rb will contain the actualset command implementation:

# frozen_string_literal: truerequire_relative'../../command'moduleAppmoduleCommandsclassConfigclassSet <App::Commanddefinitialize(name,value,options)@name=name@value=value@options=optionsenddefexecute# Command logic goes here ...endendendendend

You can now run your command in terminal:

bundleexecappconfigsetdebugtrue

Note that it is not possible to add subcommands to an existing command. Attempting to do so will currently causeteletype to crash. The reason why it is not possible to add subcommands to existing commands is that it is impossible fortty to distinguish between normal arguments to a command, and subcommands for that command. However, you may very well add multiple subcommands one after another.

3. Components

TheTTY allows you to mix & match any components you need to get your job done. The command line applications generated withteletype executable references all of the below components.

ComponentDescriptionAPI docs
pastelTerminal strings styling with intuitive and clean API.docs
tty-boxDraw various frames and boxes in your terminal.docs
tty-colorTerminal color capabilities detection.docs
tty-commandExecute shell commands with pretty logging and capture stdout, stderr and exit status.docs
tty-configDefine, read and write any Ruby app configurations with a penchant for terminal clients.docs
tty-cursorMove terminal cursor around.docs
tty-editorOpen a file or text in the user preferred editor.docs
tty-fileFile manipulation utility methods.docs
tty-fontWrite text in large stylized characters using a variety of terminal fonts.docs
tty-linkHyperlinks in your terminal.docs
tty-loggerA readable and structured logging for the terminal.docs
tty-markdownConvert a markdown document or text into a terminal friendly output.docs
tty-optionParser for command line arguments, keywords and options.docs
tty-pagerTerminal output paging in a cross-platform way.docs
tty-pieDraw pie charts in your terminal window.docs
tty-platformDetecting different operating systems.docs
tty-progressbarA flexible progress bars drawing in terminal emulators.docs
tty-promptA beautiful and powerful interactive command line prompt.docs
tty-readerA set of methods for processing keyboard input in character, line and multiline modes.docs
tty-screenTerminal screen properties detection.docs
tty-spinnerA terminal spinner for tasks with non-deterministic time.docs
tty-tableA flexible and intuitive table output generator.docs
tty-treePrint directory or structured data in a tree like format.docs
tty-whichPlatform independent implementation of Unix which command.docs

4. Contributing

You can contribute by postingfeature requests, evaluating the APIs or simply by hacking on TTY components:

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to theContributor Covenant code of conduct.

This project usesEditorConfig to maintain consistent tabbing and file formats. Considerinstalling the plugin for your editor to help maintain proper code formatting.

Copyright

Copyright (c) 2012 Piotr Murach. See LICENSE.txt for further details.

About

Toolkit for developing sleek command line apps.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors18

Languages


[8]ページ先頭

©2009-2025 Movatter.jp