tty 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -2
- data/.travis.yml +15 -4
- data/CHANGELOG.md +22 -0
- data/Gemfile +4 -7
- data/README.md +648 -58
- data/appveyor.yml +3 -4
- data/exe/teletype +18 -0
- data/lib/tty.rb +7 -4
- data/lib/tty/cli.rb +140 -0
- data/lib/tty/cmd.rb +132 -0
- data/lib/tty/commands/add.rb +321 -0
- data/lib/tty/commands/new.rb +256 -0
- data/lib/tty/gemspec.rb +30 -0
- data/lib/tty/licenses.rb +34 -0
- data/lib/tty/path_helpers.rb +38 -0
- data/lib/tty/plugins.rb +20 -12
- data/lib/tty/templater.rb +54 -0
- data/lib/tty/templates/add/command.rb.tt +31 -0
- data/lib/tty/templates/add/gitkeep.tt +1 -0
- data/lib/tty/templates/add/namespace.rb.tt +17 -0
- data/lib/tty/templates/add/spec/integration/command_spec.rb.tt +20 -0
- data/lib/tty/templates/add/spec/integration/sub_command_spec.rb.tt +16 -0
- data/lib/tty/templates/add/spec/unit/command_spec.rb.tt +15 -0
- data/lib/tty/templates/add/spec/unit/sub_command_spec.rb.tt +15 -0
- data/lib/tty/templates/add/test/integration/command_test.rb.tt +23 -0
- data/lib/tty/templates/add/test/integration/sub_command_test.rb.tt +19 -0
- data/lib/tty/templates/add/test/unit/command_test.rb.tt +16 -0
- data/lib/tty/templates/add/test/unit/sub_command_test.rb.tt +16 -0
- data/lib/tty/templates/new/agplv3_LICENSE.txt.tt +555 -0
- data/lib/tty/templates/new/apache_LICENSE.txt.tt +157 -0
- data/lib/tty/templates/new/bsd2_LICENSE.txt.tt +22 -0
- data/lib/tty/templates/new/bsd3_LICENSE.txt.tt +26 -0
- data/lib/tty/templates/new/exe/newcli.tt +18 -0
- data/lib/tty/templates/new/gitkeep.tt +1 -0
- data/lib/tty/templates/new/gplv2_LICENSE.txt.tt +255 -0
- data/lib/tty/templates/new/gplv3_LICENSE.txt.tt +543 -0
- data/lib/tty/templates/new/lgplv3_LICENSE.txt.tt +143 -0
- data/lib/tty/templates/new/lib/newcli/cli.rb.tt +24 -0
- data/lib/tty/templates/new/lib/newcli/command.rb.tt +124 -0
- data/lib/tty/templates/new/mit_LICENSE.txt.tt +20 -0
- data/lib/tty/templates/new/mplv2_LICENSE.txt.tt +277 -0
- data/lib/tty/version.rb +1 -1
- data/spec/fixtures/foo-0.0.1.gemspec +4 -4
- data/spec/integration/add_desc_args_spec.rb +341 -0
- data/spec/integration/add_force_spec.rb +98 -0
- data/spec/integration/add_namespaced_spec.rb +291 -0
- data/spec/integration/add_spec.rb +535 -0
- data/spec/integration/add_subcommand_spec.rb +259 -0
- data/spec/integration/new_author_spec.rb +19 -0
- data/spec/integration/new_license_spec.rb +39 -0
- data/spec/integration/new_namespaced_spec.rb +228 -0
- data/spec/integration/new_spec.rb +354 -0
- data/spec/integration/new_test_spec.rb +21 -0
- data/spec/integration/start_spec.rb +21 -0
- data/spec/spec_helper.rb +47 -16
- data/spec/unit/gemspec_spec.rb +17 -0
- data/spec/{tty/plugins/load_spec.rb → unit/plugins/activate_spec.rb} +2 -4
- data/spec/unit/plugins/load_from_spec.rb +28 -0
- data/spec/{tty → unit}/plugins/plugin/load_spec.rb +1 -3
- data/spec/{tty → unit}/plugins/plugin/new_spec.rb +1 -3
- data/spec/{tty → unit}/tty_spec.rb +1 -3
- data/tty.gemspec +25 -15
- metadata +186 -49
- data/spec/tty/plugins/find_spec.rb +0 -20
- data/tasks/metrics/cane.rake +0 -14
- data/tasks/metrics/flog.rake +0 -17
- data/tasks/metrics/heckle.rake +0 -15
- data/tasks/metrics/reek.rake +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fadf60f672e1f406309e7a026b181e0672b104a3
|
4
|
+
data.tar.gz: 5052f53049b8d32d32b8e17cd0d46a55815ed3f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55da8f56e48079e9b195dd1c0bf3f45e8ab5e3ba449a4723075463e3761124c78b880607a93acd6cac2254925765926d0e168c0a43d0030a8c29c1bf57fcee69
|
7
|
+
data.tar.gz: 6d0f13a347de0903b1940dd6e75f4e3431b22075dd8002ca8d98c3faac7285c4b0f60183f53ecc33c07155b6c3c6d770b8f40a06c01ef0724d1f8b33ccc2e921
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -1,15 +1,25 @@
|
|
1
1
|
---
|
2
|
+
env:
|
3
|
+
global:
|
4
|
+
- CC_TEST_REPORTER_ID=76c3cb8a84b67e1e18aadacbe5a77861bc723dc1448f044bae995795b261569b
|
2
5
|
language: ruby
|
3
6
|
sudo: false
|
4
|
-
cache: bundler
|
5
7
|
bundler_args: --without yard guard benchmarks
|
8
|
+
before_install: "gem install bundler -v 1.16.0"
|
9
|
+
before_script:
|
10
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
11
|
+
- chmod +x ./cc-test-reporter
|
12
|
+
- ./cc-test-reporter before-build
|
6
13
|
script: "bundle exec rake ci"
|
14
|
+
after_script:
|
15
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
7
16
|
rvm:
|
8
17
|
- 2.0.0
|
9
18
|
- 2.1.10
|
10
|
-
- 2.2.
|
11
|
-
- 2.3.
|
12
|
-
- 2.4.
|
19
|
+
- 2.2.8
|
20
|
+
- 2.3.6
|
21
|
+
- 2.4.3
|
22
|
+
- 2.5.0
|
13
23
|
- ruby-head
|
14
24
|
- jruby-9000
|
15
25
|
- jruby-head
|
@@ -17,6 +27,7 @@ matrix:
|
|
17
27
|
allow_failures:
|
18
28
|
- rvm: ruby-head
|
19
29
|
- rvm: jruby-head
|
30
|
+
- rvm: jruby-9000
|
20
31
|
fast_finish: true
|
21
32
|
branches:
|
22
33
|
only: master
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
This file documents notable changes in reverse chronological order.
|
4
|
+
|
5
|
+
## [v0.8.0] - 2018-05-31
|
6
|
+
|
7
|
+
### Added
|
8
|
+
* Add teletype executable for jump starting new CLI apps
|
9
|
+
* Add TTY::CLI for scaffolding new console applications
|
10
|
+
* Add Commands::New for generating new command line applications
|
11
|
+
* Add Commands::Add for adding new commands & subcommands
|
12
|
+
* Add Plugins#load_from to allow loading dependencies from gemspec
|
13
|
+
* Add tty-tree component
|
14
|
+
* Add tty-markdown component
|
15
|
+
* Add tty-font component
|
16
|
+
* Add tty-config component
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
* Remove Plugins#find
|
20
|
+
* Change Plugins#load to Plugins#activate
|
21
|
+
* Remove metrics rake tasks
|
22
|
+
* Update dependencies
|
23
|
+
|
3
24
|
## [v0.7.0] - 2017-03-26
|
4
25
|
|
5
26
|
### Changed
|
@@ -122,6 +143,7 @@
|
|
122
143
|
|
123
144
|
* Initial release
|
124
145
|
|
146
|
+
[v0.8.0]: https://github.com/piotrmurach/tty/compare/v0.7.0...v0.8.0
|
125
147
|
[v0.7.0]: https://github.com/piotrmurach/tty/compare/v0.6.1...v0.7.0
|
126
148
|
[v0.6.1]: https://github.com/piotrmurach/tty/compare/v0.6.0...v0.6.1
|
127
149
|
[v0.6.0]: https://github.com/piotrmurach/tty/compare/v0.5.0...v0.6.0
|
data/Gemfile
CHANGED
@@ -3,18 +3,15 @@ source 'https://rubygems.org'
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
group :development do
|
6
|
-
gem '
|
7
|
-
gem '
|
8
|
-
gem 'timecop', '~> 0.7.1'
|
6
|
+
gem 'yard', '~> 0.9.12'
|
7
|
+
gem 'timecop', '~> 0.9.1'
|
9
8
|
end
|
10
9
|
|
11
10
|
group :metrics do
|
12
|
-
gem '
|
13
|
-
gem 'simplecov', '~> 0.10.0'
|
11
|
+
gem 'simplecov', '~> 0.16.1'
|
14
12
|
gem 'yardstick', '~> 0.9.9'
|
15
|
-
gem 'term-ansicolor', '=1.3.2'
|
16
13
|
end
|
17
14
|
|
18
15
|
group :benchmarks do
|
19
|
-
gem '
|
16
|
+
gem 'benchmark-ips', '~> 2.7.2'
|
20
17
|
end
|
data/README.md
CHANGED
@@ -6,31 +6,31 @@
|
|
6
6
|
[![Gem Version](https://badge.fury.io/rb/tty.svg)][gem]
|
7
7
|
[![Build Status](https://secure.travis-ci.org/piotrmurach/tty.svg?branch=master)][travis]
|
8
8
|
[![Build status](https://ci.appveyor.com/api/projects/status/0a85w6yr40lmuo3o?svg=true)][appveyor]
|
9
|
-
[![
|
10
|
-
[![Coverage
|
9
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/b7656caaf3bdb1fd4c04/maintainability)][codeclimate]
|
10
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/b7656caaf3bdb1fd4c04/test_coverage)][coverage]
|
11
11
|
[![Inline docs](http://inch-ci.org/github/piotrmurach/tty.svg?branch=master)][inchpages]
|
12
12
|
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
|
13
13
|
|
14
14
|
[gem]: http://badge.fury.io/rb/tty
|
15
15
|
[travis]: http://travis-ci.org/piotrmurach/tty
|
16
16
|
[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty
|
17
|
-
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty
|
18
|
-
[
|
17
|
+
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty/maintainability
|
18
|
+
[coverage]: https://codeclimate.com/github/piotrmurach/tty/test_coverage
|
19
19
|
[inchpages]: http://inch-ci.org/github/piotrmurach/tty
|
20
20
|
[gitter]: https://gitter.im/piotrmurach/tty
|
21
21
|
|
22
|
-
> TTY is a toolbox for developing beautiful command line clients in Ruby
|
22
|
+
> 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.
|
23
23
|
|
24
24
|
## Motivation
|
25
25
|
|
26
|
-
All too often libraries that interact with
|
26
|
+
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?
|
27
27
|
|
28
|
-
|
28
|
+
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.
|
29
29
|
|
30
30
|
## Features
|
31
31
|
|
32
|
-
* Jump-start development of your command line app the Unix way.
|
33
|
-
* Fully modular, choose out of many [components](#
|
32
|
+
* Jump-start development of your command line app the Unix way with scaffold provided by [teletype](#2-bootstrapping).
|
33
|
+
* Fully modular, choose out of many [components](#3-components) to suit your needs or use any 3rd party ones.
|
34
34
|
* All tty components are small packages that do one thing well.
|
35
35
|
* Fully tested with major ruby interpreters.
|
36
36
|
|
@@ -55,105 +55,691 @@ Or install it yourself as:
|
|
55
55
|
## Contents
|
56
56
|
|
57
57
|
* [1. Overview](#1-overview)
|
58
|
-
* [2.
|
58
|
+
* [2. Bootstrapping](#2-bootstrapping)
|
59
|
+
* [2.1 new command](#21-new-command)
|
60
|
+
* [2.1.1 --author, -a flag](#211---author--a-flag)
|
61
|
+
* [2.1.2 --ext flag](#212---ext-flag)
|
62
|
+
* [2.1.3 --license, -l flag](#213---license--l-flag)
|
63
|
+
* [2.1.4 --test, -t flag](#214---test--t-flag)
|
64
|
+
* [2.2 add command](#22-add-command)
|
65
|
+
* [2.2.1 --args flag](#221---args-flag)
|
66
|
+
* [2.2.2 --desc flag](#222---desc-flag)
|
67
|
+
* [2.2.3 --force flag](#223---desc-flag)
|
68
|
+
* [2.3 Working with Commands](#23-working-with-commands)
|
69
|
+
* [2.4 Arguments](#24-arguments)
|
70
|
+
* [2.5 Description](#25-description)
|
71
|
+
* [2.6 Options and Flags](#26-options-and-flags)
|
72
|
+
* [2.7 Global Flags](#27-global-flags)
|
73
|
+
* [2.8 Working with Subcommands](#28-working-with-subcommands)
|
74
|
+
* [3. Components](#3-components)
|
59
75
|
|
60
76
|
## 1. Overview
|
61
77
|
|
62
|
-
**TTY** provides you with many
|
78
|
+
**TTY** provides you with commands and many components to get you onto the path of bulding awesome terminal applications in next to no time.
|
63
79
|
|
64
|
-
To
|
80
|
+
To simply jump start a new command line application use `teletype` executable:
|
81
|
+
|
82
|
+
```bash
|
83
|
+
$ teletype new app
|
84
|
+
```
|
85
|
+
|
86
|
+
and then to add more commands:
|
87
|
+
|
88
|
+
```bash
|
89
|
+
$ teletype add config
|
90
|
+
```
|
91
|
+
|
92
|
+
Throughout the rest of this guide, I will assume a generated application called `app` and a newly created bare command `config`.
|
93
|
+
|
94
|
+
## 2. Bootstrapping
|
95
|
+
|
96
|
+
### 2.1 `new` command
|
97
|
+
|
98
|
+
Running `teletype new [app-name]` will bootstrap an entire project file structure based on the bundler `gem` command setup enhanced by additional files and folders related to command application development.
|
99
|
+
|
100
|
+
For example, to create a new command line application called `app` do:
|
65
101
|
|
66
102
|
```ruby
|
67
|
-
|
103
|
+
$ teletype new app
|
104
|
+
```
|
68
105
|
|
69
|
-
|
70
|
-
prompt.yes?('Do you like Ruby?')
|
71
|
-
# => Do you like Ruby? (Y/n)
|
106
|
+
The output will contain all the files that have been created during setup:
|
72
107
|
|
73
|
-
|
108
|
+
```
|
109
|
+
Creating gem 'app'
|
110
|
+
create app/Gemfile
|
111
|
+
create app/.gitignore
|
112
|
+
create app/lib/app.rb
|
113
|
+
create app/lib/app/version.rb
|
114
|
+
...
|
115
|
+
```
|
74
116
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
117
|
+
In turn, the following files and directories will be generated in the `app` folder familiar to anyone who has created a gem beforehand:
|
118
|
+
|
119
|
+
```
|
120
|
+
▾ app/
|
121
|
+
├── ▾ exe/
|
122
|
+
│ └── app
|
123
|
+
├── ▾ lib/
|
124
|
+
│ ├── ▾ app/
|
125
|
+
│ │ ├── ▸ commands/
|
126
|
+
│ │ ├── ▸ templates/
|
127
|
+
│ │ ├── cli.rb
|
128
|
+
│ │ ├── command.rb
|
129
|
+
│ │ └── version.rb
|
130
|
+
│ └── app.rb
|
131
|
+
├── CODE_OF_CONDUCT.md
|
132
|
+
├── Gemfile
|
133
|
+
├── LICENSE.txt
|
134
|
+
├── README.md
|
135
|
+
├── Rakefile
|
136
|
+
└── app.gemspec
|
81
137
|
```
|
82
138
|
|
83
|
-
|
139
|
+
By convention the file `lib/app/cli.rb` provides the main entry point to your command line application:
|
84
140
|
|
85
141
|
```ruby
|
86
|
-
|
87
|
-
|
88
|
-
#
|
89
|
-
|
142
|
+
module App
|
143
|
+
class CLI < Thor
|
144
|
+
# Error raised by this runner
|
145
|
+
Error = Class.new(StandardError)
|
146
|
+
|
147
|
+
desc 'version', 'app version'
|
148
|
+
def version
|
149
|
+
require_relative 'version'
|
150
|
+
puts "v#{App::VERSION}"
|
151
|
+
end
|
152
|
+
map %w(--version -v) => :version
|
153
|
+
end
|
154
|
+
end
|
90
155
|
```
|
91
156
|
|
92
|
-
|
157
|
+
This is where all your application commands and subcommands will be defined.
|
158
|
+
|
159
|
+
Teletype uses `Thor` as an option parsing library by directly inheriting from it.
|
160
|
+
|
161
|
+
And also by convention the `start` method is used to parse the command line arguments inside the `app` executable:
|
93
162
|
|
94
163
|
```ruby
|
95
|
-
|
96
|
-
30.times { bar.advance }
|
164
|
+
App::CLI.start
|
97
165
|
```
|
98
166
|
|
99
|
-
|
167
|
+
Run the new command with `--help` or `-h` flag to see all available options:
|
100
168
|
|
101
169
|
```ruby
|
102
|
-
|
103
|
-
|
170
|
+
$ teletype new --help
|
171
|
+
$ teletype new -h
|
172
|
+
```
|
173
|
+
|
174
|
+
Execute `teletype` to see all available commands.
|
175
|
+
|
176
|
+
#### 2.1.1 `--author`, `-a` flag
|
177
|
+
|
178
|
+
The `teletype` generator can inject name into documentation for you:
|
179
|
+
|
180
|
+
```bash
|
181
|
+
$ teletype new app --author 'Piotr Murach'
|
104
182
|
```
|
105
183
|
|
106
|
-
|
184
|
+
#### 2.1.2 `--ext` flag
|
185
|
+
|
186
|
+
To specify that `teletype` should create a binary executable (as `exe/GEM_NAME`) in the generated project use the `--ext` flag. This binary will also be included in the `GEM_NAME.gemspec` manifest. This is disabled by default, to enable do:
|
187
|
+
|
188
|
+
```bash
|
189
|
+
$ teletype new app --ext
|
190
|
+
```
|
191
|
+
|
192
|
+
#### 2.1.3 `--license`, `-l` flag
|
193
|
+
|
194
|
+
The `teletype` generator comes prepackaged with most popular open source licenses:
|
195
|
+
`agplv3`, `apache`, `bsd2`, `bsd3`, `gplv2`, `gplv3`, `lgplv3`, `mit`, `mplv2`, `custom`. By default the `mit` license is used. To change that do:
|
107
196
|
|
108
197
|
```ruby
|
109
|
-
|
110
|
-
pastel.green.on_red.bold('Piotr')
|
198
|
+
$ teletype new app --license bsd3
|
111
199
|
```
|
112
200
|
|
113
|
-
|
201
|
+
#### 2.1.4 `--test`, `-t` flag
|
202
|
+
|
203
|
+
The `teletype` comes configured to work with `rspec` and `minitest` frameworks which are the only two acceptables values. The `GEM_NAME.gemspec` will be configured will be configured and appropriate testing directory setup. By default the `RSpec` framework is used.
|
114
204
|
|
115
205
|
```ruby
|
116
|
-
|
117
|
-
|
206
|
+
$ teletype new app --test=minitest
|
207
|
+
$ teletype new app -t=minitest
|
118
208
|
```
|
119
209
|
|
120
|
-
|
210
|
+
### 2.2 `add` command
|
211
|
+
|
212
|
+
Once application has been initialized, you can create additional command by using `teletype add [command-name]` task:
|
121
213
|
|
122
214
|
```ruby
|
123
|
-
|
124
|
-
|
215
|
+
$ teletype add config
|
216
|
+
$ teletype add create
|
217
|
+
```
|
218
|
+
|
219
|
+
This will add `create.rb` and `config.rb` commands to the CLI client:
|
220
|
+
|
221
|
+
```
|
222
|
+
▾ app/
|
223
|
+
├── ▾ commands/
|
224
|
+
│ ├── config.rb
|
225
|
+
│ └── create.rb
|
226
|
+
├── ▸ templates/
|
227
|
+
│ ├── ▸ config/
|
228
|
+
│ └── ▸ create/
|
229
|
+
├── command.rb
|
230
|
+
├── cli.rb
|
231
|
+
└── version.rb
|
125
232
|
```
|
126
233
|
|
127
|
-
|
234
|
+
Then you will be able to call the new commands like so:
|
128
235
|
|
129
236
|
```ruby
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
237
|
+
$ app config
|
238
|
+
$ app create
|
239
|
+
```
|
240
|
+
|
241
|
+
The commands require you to specify the actual logic in their `execute` methods.
|
242
|
+
|
243
|
+
Please note that command names should be provided as `camelCase` or `snake_case`. For example:
|
244
|
+
|
134
245
|
```
|
246
|
+
$ teletype add addConfigCommand # => correct
|
247
|
+
$ teletype add add_config_command # => correct
|
248
|
+
$ teletype add add-config-command # => incorrect
|
249
|
+
```
|
250
|
+
|
251
|
+
#### 2.2.1 `--args` flag
|
252
|
+
|
253
|
+
You can specify that `teletype` 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 pass `name = nil` enclosed in quote marks and any variable number of arguments needs to be preceeded by asterisk:
|
254
|
+
|
255
|
+
```bash
|
256
|
+
$ teletype add config --args name # required argument
|
257
|
+
$ teletype add config --args "name = nil" # optional argument
|
258
|
+
$ teletype add config --args *names # variadic argument
|
259
|
+
```
|
260
|
+
|
261
|
+
For more in-depth usage see [2.4 Arguments](#24-arguments).
|
262
|
+
|
263
|
+
#### 2.2.2 `--desc` flag
|
264
|
+
|
265
|
+
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:
|
266
|
+
|
267
|
+
```bash
|
268
|
+
$ teletype add config --desc 'Set and get configuration options'
|
269
|
+
```
|
270
|
+
|
271
|
+
For more in-depth usage see [2.5 Description](#25-description).
|
272
|
+
|
273
|
+
#### 2.2.3 `--force` flag
|
135
274
|
|
136
|
-
|
275
|
+
If you wish to overwrite currently implemented command use `--force` flag:
|
276
|
+
|
277
|
+
```bash
|
278
|
+
$ teletype add config --force
|
279
|
+
```
|
280
|
+
|
281
|
+
### 2.3 Working with Commands
|
282
|
+
|
283
|
+
Running
|
284
|
+
|
285
|
+
```
|
286
|
+
teletype add config
|
287
|
+
```
|
288
|
+
|
289
|
+
a new command `config` will be added to `commands` folder creating the following files structure inside the `lib` folder:
|
290
|
+
|
291
|
+
```shell
|
292
|
+
▾ app/
|
293
|
+
├── ▾ commands/
|
294
|
+
│ └── config.rb
|
295
|
+
├── ▾ templates/
|
296
|
+
│ └── ▸ config/
|
297
|
+
├── cli.rb
|
298
|
+
├── command.rb
|
299
|
+
└── version.rb
|
300
|
+
```
|
301
|
+
|
302
|
+
The `lib/app/cli.rb` file will contain generated command entry which handles the case where the user asked for the `config` command help or invokes the actual command:
|
303
|
+
|
304
|
+
```ruby
|
305
|
+
module App
|
306
|
+
class CLI < Thor
|
307
|
+
desc 'config', 'Command description...'
|
308
|
+
def config(*)
|
309
|
+
if options[:help]
|
310
|
+
invoke :help, ['config']
|
311
|
+
else
|
312
|
+
require_relative 'commands/config'
|
313
|
+
App::Commands::Config.new(options).execute
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
```
|
319
|
+
|
320
|
+
And the `lib/app/commands/config.rb` will allow you to specify all the command logic. In the `Config` class which by convention matches the command name, the `execute` method provids place to implement the command logic:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
module App
|
324
|
+
module Commands
|
325
|
+
class Config < App::Command
|
326
|
+
def initialize(options)
|
327
|
+
@options = options
|
328
|
+
end
|
329
|
+
|
330
|
+
def execute
|
331
|
+
# Command logic goes here ...
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
```
|
337
|
+
|
338
|
+
Notice that `Config` inherits from `App::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 many [tty components](#3-components) inside helper methods which you have access to by opening up the `lib/app/command.rb` file.
|
339
|
+
|
340
|
+
For example in the `lib/app/command.rb` file, you have access to `prompt` helper for gathering user input:
|
341
|
+
|
342
|
+
```ruby
|
343
|
+
# The interactive prompt
|
344
|
+
#
|
345
|
+
# @see http://www.rubydoc.info/gems/tty-prompt
|
346
|
+
#
|
347
|
+
# @api public
|
348
|
+
def prompt(**options)
|
349
|
+
require 'tty-prompt'
|
350
|
+
TTY::Prompt.new(options)
|
351
|
+
end
|
352
|
+
```
|
353
|
+
|
354
|
+
or a `command` helper for running external commands:
|
355
|
+
|
356
|
+
```ruby
|
357
|
+
# The external commands runner
|
358
|
+
#
|
359
|
+
# @see http://www.rubydoc.info/gems/tty-command
|
360
|
+
#
|
361
|
+
# @api public
|
362
|
+
def command(**options)
|
363
|
+
require 'tty-command'
|
364
|
+
TTY::Command.new(options)
|
365
|
+
end
|
366
|
+
```
|
367
|
+
|
368
|
+
You have full control of the file, so you can use only the [tty components](#3-components) that you require. Please bear in mind that all the components are added by default in your `app.gemspec` which you can change to suite your needs and pick only `tty` components that fit your case.
|
369
|
+
|
370
|
+
### 2.4 Arguments
|
371
|
+
|
372
|
+
A command may accept a variable number of arguments.
|
373
|
+
|
374
|
+
For example, if we wish to have a `config` command that accepts a location of configuration file, then we can run `teletype add` command passing `--args` flag:
|
375
|
+
|
376
|
+
```bash
|
377
|
+
$ teletype add config --args file
|
378
|
+
```
|
379
|
+
|
380
|
+
which will include the required `file` as an argument to the `config` method:
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
module App
|
384
|
+
class CLI < Thor
|
385
|
+
desc 'config FILE', 'Set and get configuration options'
|
386
|
+
def config(file)
|
387
|
+
...
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
```
|
392
|
+
|
393
|
+
Similarly, if we want to generate command with two required arguments, we run `teletype add` command with `--args` flag that can accept variable names delimited by space character:
|
394
|
+
|
395
|
+
```bash
|
396
|
+
$ teletype add set --args name value
|
397
|
+
```
|
398
|
+
|
399
|
+
will generate the following:
|
137
400
|
|
138
401
|
```ruby
|
139
|
-
|
140
|
-
|
402
|
+
module App
|
403
|
+
class CLI < Thor
|
404
|
+
desc 'set NAME VALUE', 'Set configuration option'
|
405
|
+
def config(name, value)
|
406
|
+
...
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
```
|
411
|
+
|
412
|
+
If we want to have a command that has an optional argument, for example, the `file` argument is an optional argument in the `config` command, then you need to enclose `--args` argument in parentheses:
|
413
|
+
|
414
|
+
```bash
|
415
|
+
$ teletype add config --args 'file = nil'
|
141
416
|
```
|
142
417
|
|
143
|
-
|
418
|
+
In well behaved command line application, any optional argument in a command will be enclosed in square brackets:
|
144
419
|
|
145
420
|
```ruby
|
146
|
-
|
421
|
+
module App
|
422
|
+
class CLI < Thor
|
423
|
+
desc 'config [FILE]', 'Set and get configuration options'
|
424
|
+
def config(file = nil)
|
425
|
+
...
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
```
|
430
|
+
|
431
|
+
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:
|
432
|
+
|
433
|
+
```bash
|
434
|
+
$ teletype add get --args *names
|
147
435
|
```
|
148
436
|
|
149
|
-
|
437
|
+
which will append `...` to the argument description:
|
150
438
|
|
151
439
|
```ruby
|
152
|
-
|
153
|
-
|
440
|
+
module App
|
441
|
+
class CLI < Thor
|
442
|
+
desc 'get NAMES...', 'Get configuration options'
|
443
|
+
def config(*names)
|
444
|
+
...
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
154
448
|
```
|
155
449
|
|
156
|
-
|
450
|
+
You can mix and match all the above styles of arguments definitions:
|
451
|
+
|
452
|
+
```bash
|
453
|
+
$ teletype add config --args file *names
|
454
|
+
```
|
455
|
+
|
456
|
+
### 2.5 Description
|
457
|
+
|
458
|
+
Use the `desc` 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.
|
459
|
+
|
460
|
+
For example, given the command `config` generated in [add command](#22-add-command) section, we can add description like so:
|
461
|
+
|
462
|
+
```ruby
|
463
|
+
module App
|
464
|
+
class CLI < Thor
|
465
|
+
desc 'config [FILE]', 'Set and get configuration options'
|
466
|
+
def config(file = nil)
|
467
|
+
...
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
```
|
472
|
+
|
473
|
+
Running `app` executable will include the new description:
|
474
|
+
|
475
|
+
```
|
476
|
+
Commands:
|
477
|
+
app config [FILE] # Set and get configuration options
|
478
|
+
```
|
479
|
+
|
480
|
+
To provide long form description of your command use `long_desc` method.
|
481
|
+
|
482
|
+
```ruby
|
483
|
+
module App
|
484
|
+
class CLI < Thor
|
485
|
+
desc 'config [FILE]', 'Set and get configuration options'
|
486
|
+
long_desc <<-DESC
|
487
|
+
You can query/set/replace/unset options with this command.
|
488
|
+
|
489
|
+
The name is is an option key separated by a dot, and the value will be escaped.
|
490
|
+
|
491
|
+
This command will fail with non-zero status upon error.
|
492
|
+
DESC
|
493
|
+
def config(file = nil)
|
494
|
+
...
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
```
|
499
|
+
|
500
|
+
Running `app config --help` will produce the following output:
|
501
|
+
|
502
|
+
```
|
503
|
+
Usage:
|
504
|
+
app config
|
505
|
+
|
506
|
+
You can query/set/replace/unset options with this command.
|
507
|
+
|
508
|
+
The name is is an option key separated by a dot, and the value will be escaped.
|
509
|
+
|
510
|
+
This command will fail with non-zero status upon error.
|
511
|
+
```
|
512
|
+
|
513
|
+
### 2.6 Options and Flags
|
514
|
+
|
515
|
+
Flags and options allow to customize how particular command is invoked and provide additional configuration.
|
516
|
+
|
517
|
+
To specify individual flag or option use `method_option` before the command method. All the flags and options can be accessed inside method body via the `options` hash.
|
518
|
+
|
519
|
+
Available metadata for an option are:
|
520
|
+
|
521
|
+
* `:aliases` - A list of aliases for this option.
|
522
|
+
* `:banner` — A description of the value if the option accepts one.
|
523
|
+
* `:default` - The default value of this option if it is not provided.
|
524
|
+
* `:lazy_default` — A default that is only passed if the cli option is passed without a value.
|
525
|
+
* `:desc` - The short description of the option, printed out in the usage description.
|
526
|
+
* `:required` — Indicates that an option is required.
|
527
|
+
* `:type` - `:string`, `:hash`, `:array`, `:numeric`, `:boolean`
|
528
|
+
* `:enum` — A list of allowed values for this option.
|
529
|
+
|
530
|
+
The values for `:type` option are:
|
531
|
+
|
532
|
+
* `:boolean` is parsed as `--option`
|
533
|
+
* `:string` is parsed as `--option=VALUE` or `--option VALUE`
|
534
|
+
* `:numeric` is parsed as `--option=N` or `--option N`
|
535
|
+
* `:array` is parsed as `--option=one two three` or `--option one two three`
|
536
|
+
* `:hash` is parsed as `--option=name:string age:integer`
|
537
|
+
|
538
|
+
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 run `app 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:
|
539
|
+
|
540
|
+
```ruby
|
541
|
+
method_option :add, type: :array, banner: "name value", desc: "Adds a new line the config file. "
|
542
|
+
```
|
543
|
+
|
544
|
+
The above option would be included in the `config` method like so:
|
545
|
+
|
546
|
+
```ruby
|
547
|
+
module App
|
548
|
+
class CLI < Thor
|
549
|
+
desc 'config [<file>]', 'Set and get configuration options'
|
550
|
+
method_option :add, type: :array, banner: "name value",
|
551
|
+
desc: "Adds a new line the config file. "
|
552
|
+
def config(*)
|
553
|
+
...
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
```
|
558
|
+
|
559
|
+
Running `app help config` will output new option:
|
560
|
+
|
561
|
+
```
|
562
|
+
Usage:
|
563
|
+
app config [<file>]
|
564
|
+
|
565
|
+
Options:
|
566
|
+
[--add=name value] # Adds a new line the config file.
|
567
|
+
```
|
568
|
+
|
569
|
+
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 running `app config --edit` or `app config -e`. This can be achieved by adding the following option:
|
570
|
+
|
571
|
+
```ruby
|
572
|
+
method_option :edit, type: :boolean, aliases: ['-e'],
|
573
|
+
desc: "Opens an editor to modify the specified config file."
|
574
|
+
```
|
575
|
+
|
576
|
+
And adding it to the `config` method:
|
577
|
+
|
578
|
+
```ruby
|
579
|
+
module App
|
580
|
+
class CLI < Thor
|
581
|
+
desc 'config [<file>]', 'Set and get configuration options'
|
582
|
+
method_option :edit, type: :boolean, aliases: ['-e'],
|
583
|
+
desc: "Opens an editor to modify the specified config file."
|
584
|
+
def config(*)
|
585
|
+
...
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
```
|
590
|
+
|
591
|
+
Next, running `app help config` will produce:
|
592
|
+
|
593
|
+
```
|
594
|
+
Usage:
|
595
|
+
app config [<file>]
|
596
|
+
|
597
|
+
Options:
|
598
|
+
[--add=name value] # Adds a new line the config file.
|
599
|
+
-e, [--edit], [--no-edit] # Opens an editor to modify the specified config file.
|
600
|
+
```
|
601
|
+
|
602
|
+
You can use `method_options` as a shorthand for specifying multiple options at once.
|
603
|
+
|
604
|
+
```ruby
|
605
|
+
method_options %w(list -l) => :boolean, :system => :boolean, :local => :boolean
|
606
|
+
```
|
607
|
+
|
608
|
+
Once all the command options and flags have been setup, you can access them via `options` hash in command file `lib/app/commands/config.rb`:
|
609
|
+
|
610
|
+
```ruby
|
611
|
+
module App
|
612
|
+
module Commands
|
613
|
+
class Config < App::Command
|
614
|
+
def initialize(options)
|
615
|
+
@options = options
|
616
|
+
end
|
617
|
+
|
618
|
+
def execute
|
619
|
+
if options[:edit]
|
620
|
+
editor.open('path/to/config/file')
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
end
|
626
|
+
```
|
627
|
+
|
628
|
+
### 2.7 Global Flags
|
629
|
+
|
630
|
+
You can specify an option or a flag that is applicable to all commands and subcommands within a given class by using the `class_option` method. This method takes exactly the same parameters as `method_option` for an individual command. The `options` hash in a given command will always include a global level flag information.
|
631
|
+
|
632
|
+
For example, if you want a global flag `debug` that is visible to all commands in your tool then you need to add it to your `CLI` class like so:
|
633
|
+
|
634
|
+
```ruby
|
635
|
+
module App
|
636
|
+
class CLI < Thor
|
637
|
+
class_option :debug, type: :boolean, default: false, desc: 'Run in debug mode'
|
638
|
+
|
639
|
+
...
|
640
|
+
end
|
641
|
+
end
|
642
|
+
```
|
643
|
+
|
644
|
+
### 2.8. Working with Subcommands
|
645
|
+
|
646
|
+
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 its `git remote` command have various subcommands `add`, `rename`, `remove`, `set-url`, `prune` and so on that themselves accept many options and arguments.
|
647
|
+
|
648
|
+
The `teletype` executable allows you to easily create new subcommands by issuing the same `add` command for generating commands. The only difference is that you need to provide the original command name and a new subcommand name. For example, let say we want the `config` command and we want to add `set` subcommand with a description and two positional arguments `name` and `value`:
|
649
|
+
|
650
|
+
```bash
|
651
|
+
$ teletype add config set --desc 'Set configuration option' --args name value
|
652
|
+
```
|
653
|
+
|
654
|
+
This will add `set.rb` command to the `commands/config` folder:
|
655
|
+
|
656
|
+
```
|
657
|
+
▾ app/
|
658
|
+
├── ▾ commands/
|
659
|
+
│ ├── ▾ config/
|
660
|
+
│ │ └── set.rb
|
661
|
+
│ └── config.rb
|
662
|
+
├── ▾ templates/
|
663
|
+
│ └── ▾ config/
|
664
|
+
│ └── ▸ set/
|
665
|
+
├── cli.rb
|
666
|
+
├── command.rb
|
667
|
+
└── version.rb
|
668
|
+
```
|
669
|
+
|
670
|
+
The `lib/app/cli.rb` will contain code that registers config namespace with our `CLI` root application:
|
671
|
+
|
672
|
+
```ruby
|
673
|
+
module App
|
674
|
+
class CLI < Thor
|
675
|
+
require_relative 'commands/config'
|
676
|
+
register App::Commands::Config, 'config', 'config [SUBCOMMAND]', 'Set configuration option'
|
677
|
+
end
|
678
|
+
end
|
679
|
+
```
|
680
|
+
|
681
|
+
The `lib/app/commands/config.rb` will contain code that handles dispatching subcommands to the `Config` instance:
|
682
|
+
|
683
|
+
```ruby
|
684
|
+
# frozen_string_literal: true
|
685
|
+
|
686
|
+
require 'thor'
|
687
|
+
|
688
|
+
module App
|
689
|
+
module Commands
|
690
|
+
class Config < Thor
|
691
|
+
|
692
|
+
namespace :config
|
693
|
+
|
694
|
+
desc 'set NAME VALUE', 'Set configuration option'
|
695
|
+
def set(name, value)
|
696
|
+
if options[:help]
|
697
|
+
invoke :help, ['set']
|
698
|
+
else
|
699
|
+
require_relative 'config/set'
|
700
|
+
App::Commands::Config::Set.new(name, value, options).execute
|
701
|
+
end
|
702
|
+
end
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
```
|
707
|
+
|
708
|
+
And finally, the `lib/app/commands/config/set.rb` will contain the actual `set` command implementation:
|
709
|
+
|
710
|
+
```ruby
|
711
|
+
# frozen_string_literal: true
|
712
|
+
|
713
|
+
require_relative '../../command'
|
714
|
+
|
715
|
+
module App
|
716
|
+
module Commands
|
717
|
+
class Config
|
718
|
+
class Set < App::Command
|
719
|
+
def initialize(name, value, options)
|
720
|
+
@name = name
|
721
|
+
@value = value
|
722
|
+
@options = options
|
723
|
+
end
|
724
|
+
|
725
|
+
def execute
|
726
|
+
# Command logic goes here ...
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
730
|
+
end
|
731
|
+
end
|
732
|
+
```
|
733
|
+
|
734
|
+
You can now run your command in terminal:
|
735
|
+
|
736
|
+
```ruby
|
737
|
+
bundle exec app config set debug true
|
738
|
+
```
|
739
|
+
|
740
|
+
## 3. Components
|
741
|
+
|
742
|
+
The **TTY** allows you to mix & match any components you need to get your job done. The command line applications generated with `teletype` executable references all of the below components.
|
157
743
|
|
158
744
|
| Component | Description | API docs |
|
159
745
|
| ------------ | ----------- | -------- |
|
@@ -163,13 +749,17 @@ print cursor.up(5) + cursor.forward(2)
|
|
163
749
|
| [tty-cursor](https://github.com/piotrmurach/tty-cursor) | Move terminal cursor around. | [docs](http://www.rubydoc.info/gems/tty-cursor) |
|
164
750
|
| [tty-editor](https://github.com/piotrmurach/tty-editor) | Open a file or text in the user preferred editor. | [docs](http://www.rubydoc.info/gems/tty-editor) |
|
165
751
|
| [tty-file](https://github.com/piotrmurach/tty-file) | File manipulation utility methods. | [docs](http://www.rubydoc.info/gems/tty-file) |
|
752
|
+
| [tty-font](https://github.com/piotrmurach/tty-font) | Write text in large stylized characters using a variety of terminal fonts. | [docs](http://www.rubydoc.info/gems/tty-font) |
|
753
|
+
| [tty-markdown](https://github.com/piotrmurach/tty-markdown) | Convert a markdown document or text into a terminal friendly output. | [docs](http://www.rubydoc.info/gems/tty-markdown) |
|
166
754
|
| [tty-pager](https://github.com/piotrmurach/tty-pager) | Terminal output paging in a cross-platform way. | [docs](http://www.rubydoc.info/gems/tty-pager) |
|
167
755
|
| [tty-platform](https://github.com/piotrmurach/tty-platform) | Detecting different operating systems. | [docs](http://www.rubydoc.info/gems/tty-platform) |
|
168
756
|
| [tty-progressbar](https://github.com/piotrmurach/tty-progressbar) | A flexible progress bars drawing in terminal emulators. | [docs](http://www.rubydoc.info/gems/tty-progressbar) |
|
169
757
|
| [tty-prompt](https://github.com/piotrmurach/tty-prompt) | A beautiful and powerful interactive command line prompt. | [docs](http://www.rubydoc.info/gems/tty-prompt) |
|
758
|
+
| [tty-reader](https://github.com/piotrmurach/tty-reader) | A set of methods for processing keyboard input in character, line and multiline modes. | [docs](http://www.rubydoc.info/gems/tty-reader) |
|
170
759
|
| [tty-screen](https://github.com/piotrmurach/tty-screen) | Terminal screen properties detection. | [docs](http://www.rubydoc.info/gems/tty-screen)
|
171
760
|
| [tty-spinner](https://github.com/piotrmurach/tty-spinner) | A terminal spinner for tasks with non-deterministic time.| [docs](http://www.rubydoc.info/gems/tty-spinner) |
|
172
761
|
| [tty-table](https://github.com/piotrmurach/tty-table) | A flexible and intuitive table output generator. | [docs](http://www.rubydoc.info/gems/tty-table) |
|
762
|
+
| [tty-tree](https://github.com/piotrmurach/tty-tree) | Print directory or structured data in a tree like format. | [docs](http://www.rubydoc.info/gems/tty-tree) |
|
173
763
|
| [tty-which](https://github.com/piotrmurach/tty-which) | Platform independent implementation of Unix which command. | [docs](http://www.rubydoc.info/gems/tty-which) |
|
174
764
|
|
175
765
|
## Contributing
|
@@ -186,4 +776,4 @@ This project is intended to be a safe, welcoming space for collaboration, and co
|
|
186
776
|
|
187
777
|
## Copyright
|
188
778
|
|
189
|
-
Copyright (c) 2012-
|
779
|
+
Copyright (c) 2012-2018 Piotr Murach. See LICENSE.txt for further details.
|