tty 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -2
  3. data/.travis.yml +15 -4
  4. data/CHANGELOG.md +22 -0
  5. data/Gemfile +4 -7
  6. data/README.md +648 -58
  7. data/appveyor.yml +3 -4
  8. data/exe/teletype +18 -0
  9. data/lib/tty.rb +7 -4
  10. data/lib/tty/cli.rb +140 -0
  11. data/lib/tty/cmd.rb +132 -0
  12. data/lib/tty/commands/add.rb +321 -0
  13. data/lib/tty/commands/new.rb +256 -0
  14. data/lib/tty/gemspec.rb +30 -0
  15. data/lib/tty/licenses.rb +34 -0
  16. data/lib/tty/path_helpers.rb +38 -0
  17. data/lib/tty/plugins.rb +20 -12
  18. data/lib/tty/templater.rb +54 -0
  19. data/lib/tty/templates/add/command.rb.tt +31 -0
  20. data/lib/tty/templates/add/gitkeep.tt +1 -0
  21. data/lib/tty/templates/add/namespace.rb.tt +17 -0
  22. data/lib/tty/templates/add/spec/integration/command_spec.rb.tt +20 -0
  23. data/lib/tty/templates/add/spec/integration/sub_command_spec.rb.tt +16 -0
  24. data/lib/tty/templates/add/spec/unit/command_spec.rb.tt +15 -0
  25. data/lib/tty/templates/add/spec/unit/sub_command_spec.rb.tt +15 -0
  26. data/lib/tty/templates/add/test/integration/command_test.rb.tt +23 -0
  27. data/lib/tty/templates/add/test/integration/sub_command_test.rb.tt +19 -0
  28. data/lib/tty/templates/add/test/unit/command_test.rb.tt +16 -0
  29. data/lib/tty/templates/add/test/unit/sub_command_test.rb.tt +16 -0
  30. data/lib/tty/templates/new/agplv3_LICENSE.txt.tt +555 -0
  31. data/lib/tty/templates/new/apache_LICENSE.txt.tt +157 -0
  32. data/lib/tty/templates/new/bsd2_LICENSE.txt.tt +22 -0
  33. data/lib/tty/templates/new/bsd3_LICENSE.txt.tt +26 -0
  34. data/lib/tty/templates/new/exe/newcli.tt +18 -0
  35. data/lib/tty/templates/new/gitkeep.tt +1 -0
  36. data/lib/tty/templates/new/gplv2_LICENSE.txt.tt +255 -0
  37. data/lib/tty/templates/new/gplv3_LICENSE.txt.tt +543 -0
  38. data/lib/tty/templates/new/lgplv3_LICENSE.txt.tt +143 -0
  39. data/lib/tty/templates/new/lib/newcli/cli.rb.tt +24 -0
  40. data/lib/tty/templates/new/lib/newcli/command.rb.tt +124 -0
  41. data/lib/tty/templates/new/mit_LICENSE.txt.tt +20 -0
  42. data/lib/tty/templates/new/mplv2_LICENSE.txt.tt +277 -0
  43. data/lib/tty/version.rb +1 -1
  44. data/spec/fixtures/foo-0.0.1.gemspec +4 -4
  45. data/spec/integration/add_desc_args_spec.rb +341 -0
  46. data/spec/integration/add_force_spec.rb +98 -0
  47. data/spec/integration/add_namespaced_spec.rb +291 -0
  48. data/spec/integration/add_spec.rb +535 -0
  49. data/spec/integration/add_subcommand_spec.rb +259 -0
  50. data/spec/integration/new_author_spec.rb +19 -0
  51. data/spec/integration/new_license_spec.rb +39 -0
  52. data/spec/integration/new_namespaced_spec.rb +228 -0
  53. data/spec/integration/new_spec.rb +354 -0
  54. data/spec/integration/new_test_spec.rb +21 -0
  55. data/spec/integration/start_spec.rb +21 -0
  56. data/spec/spec_helper.rb +47 -16
  57. data/spec/unit/gemspec_spec.rb +17 -0
  58. data/spec/{tty/plugins/load_spec.rb → unit/plugins/activate_spec.rb} +2 -4
  59. data/spec/unit/plugins/load_from_spec.rb +28 -0
  60. data/spec/{tty → unit}/plugins/plugin/load_spec.rb +1 -3
  61. data/spec/{tty → unit}/plugins/plugin/new_spec.rb +1 -3
  62. data/spec/{tty → unit}/tty_spec.rb +1 -3
  63. data/tty.gemspec +25 -15
  64. metadata +186 -49
  65. data/spec/tty/plugins/find_spec.rb +0 -20
  66. data/tasks/metrics/cane.rake +0 -14
  67. data/tasks/metrics/flog.rake +0 -17
  68. data/tasks/metrics/heckle.rake +0 -15
  69. data/tasks/metrics/reek.rake +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45114097bee0b394b6ed154cffaadbf5611a1049
4
- data.tar.gz: 718b5f44f5390caff017ae31acf186c99bb5e5c4
3
+ metadata.gz: fadf60f672e1f406309e7a026b181e0672b104a3
4
+ data.tar.gz: 5052f53049b8d32d32b8e17cd0d46a55815ed3f2
5
5
  SHA512:
6
- metadata.gz: 3769ed6a9226548f2c18398d9942d8886c547fc50cc3a6e00d066f548b5341da67d039c1b466a9699d0feeefd76807c43b8f3dc5dec44c8198345a51c175ae6e
7
- data.tar.gz: e751e71398166c48c5de6f6d31f3f53049dc93d44f54a9f6ff3090c8416b950352e1ea3b7476f8776a8f7e9435a7258ae4bf951cf2cdd886ae0d00a8ea827139
6
+ metadata.gz: 55da8f56e48079e9b195dd1c0bf3f45e8ab5e3ba449a4723075463e3761124c78b880607a93acd6cac2254925765926d0e168c0a43d0030a8c29c1bf57fcee69
7
+ data.tar.gz: 6d0f13a347de0903b1940dd6e75f4e3431b22075dd8002ca8d98c3faac7285c4b0f60183f53ecc33c07155b6c3c6d770b8f40a06c01ef0724d1f8b33ccc2e921
data/.rspec CHANGED
@@ -1,4 +1,4 @@
1
1
  --color
2
- --format progress
2
+ --require spec_helper
3
+ --format documentation
3
4
  --order random
4
- --warnings
@@ -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.6
11
- - 2.3.3
12
- - 2.4.0
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
@@ -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 'rspec', '~> 3.5.0'
7
- gem 'yard', '~> 0.8.7'
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 'coveralls', '~> 0.8.1'
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 'benchmark_suite', '~> 1.0.0'
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
- [![Code Climate](https://codeclimate.com/github/piotrmurach/tty/badges/gpa.svg)][codeclimate]
10
- [![Coverage Status](https://coveralls.io/repos/piotrmurach/tty/badge.svg?branch=master)][coveralls]
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
- [coveralls]: https://coveralls.io/r/piotrmurach/tty
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. It provides a fluid interface for gathering input from the user, querying system and terminal and displaying information back. It is not another command line options parser, rather a plumbing library that helps in common tasks.
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 command line 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?
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
- Even more so, any command line application needs a clear way of communicating its results back to terminal whether in tabular form, column form or colorfully indented text. Our time and energy should be spent in creating the tools not the foundation.
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](#2-components) to suit your needs.
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. Components](#2-components)
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 tools to get the job done in terminal.
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 ask for user input use `TTY::Prompt`:
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
- require 'tty'
103
+ $ teletype new app
104
+ ```
68
105
 
69
- prompt = TTY::Prompt.new
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
- # or ask to select from list
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
- prompt.select("Choose your destiny?", %w(Scorpion Kano Jax))
76
- # =>
77
- # Choose your destiny? (Use arrow keys, press Enter to select)
78
- # ‣ Scorpion
79
- # Kano
80
- # Jax
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
- To print tabular output use `TTY::Table`:
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
- table = TTY::Table[['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']]
87
- table.to_s
88
- # => a1 a2 a3
89
- b1 b2 b3
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
- To create a progress bar use `TTY::ProgressBar`:
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
- bar = TTY::ProgressBar.new("downloading [:bar]", total: 30)
96
- 30.times { bar.advance }
164
+ App::CLI.start
97
165
  ```
98
166
 
99
- To create a spinner use `TTY::Spinner`:
167
+ Run the new command with `--help` or `-h` flag to see all available options:
100
168
 
101
169
  ```ruby
102
- spinner = TTY::Spinner.new('Loading ... ', format: :spin_2)
103
- 30.times { spinner.spin }
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
- To colorize your strings use `Pastel`:
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
- pastel = Pastel.new
110
- pastel.green.on_red.bold('Piotr')
198
+ $ teletype new app --license bsd3
111
199
  ```
112
200
 
113
- To page very long input use `TTY::Pager`:
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
- pager = TTY::Pager.new
117
- pager.page('Very long text...')
206
+ $ teletype new app --test=minitest
207
+ $ teletype new app -t=minitest
118
208
  ```
119
209
 
120
- To run external commands with output logging, capturing stdout and stderr use `TTY::Command`:
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
- cmd = TTY::Command.new
124
- out, err = cmd.run('cat ~/.bashrc | grep alias')
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
- To measure screen size use `TTY::Screen`:
234
+ Then you will be able to call the new commands like so:
128
235
 
129
236
  ```ruby
130
- screen = TTY::Screen.new
131
- screen.size # => [51, 280]
132
- screen.width # => 280
133
- screen.height # => 51
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
- `TTY::Color` allows you to check if terminal supports color and the color mode:
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
- TTY::Color.supports? # => true
140
- TTY::Color.mode # => 64
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
- For instance, to find out if `less` utility is actually supported by the system do:
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
- TTY::Which.which('less') # => '/usr/bin/less'
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
- To move cursor around the terminal use `TTY::Cursor`:
437
+ which will append `...` to the argument description:
150
438
 
151
439
  ```ruby
152
- cursor = TTY::Cursor
153
- print cursor.up(5) + cursor.forward(2)
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
- ## 2. Components
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-2017 Piotr Murach. See LICENSE for further details.
779
+ Copyright (c) 2012-2018 Piotr Murach. See LICENSE.txt for further details.