tty-command 0.7.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +49 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +134 -64
  5. data/lib/tty-command.rb +1 -3
  6. data/lib/tty/command.rb +19 -18
  7. data/lib/tty/command/child_process.rb +23 -16
  8. data/lib/tty/command/cmd.rb +16 -12
  9. data/lib/tty/command/dry_runner.rb +4 -5
  10. data/lib/tty/command/exit_error.rb +1 -2
  11. data/lib/tty/command/printers/abstract.rb +11 -9
  12. data/lib/tty/command/printers/null.rb +1 -4
  13. data/lib/tty/command/printers/pretty.rb +29 -22
  14. data/lib/tty/command/printers/progress.rb +3 -8
  15. data/lib/tty/command/printers/quiet.rb +18 -8
  16. data/lib/tty/command/process_runner.rb +90 -67
  17. data/lib/tty/command/result.rb +0 -1
  18. data/lib/tty/command/truncator.rb +3 -4
  19. data/lib/tty/command/version.rb +2 -2
  20. metadata +24 -64
  21. data/.gitignore +0 -9
  22. data/.rspec +0 -4
  23. data/.travis.yml +0 -28
  24. data/CODE_OF_CONDUCT.md +0 -49
  25. data/Gemfile +0 -14
  26. data/Rakefile +0 -10
  27. data/appveyor.yml +0 -24
  28. data/benchmarks/memory.rb +0 -11
  29. data/bin/console +0 -6
  30. data/bin/setup +0 -6
  31. data/examples/bash.rb +0 -12
  32. data/examples/basic.rb +0 -9
  33. data/examples/cli +0 -4
  34. data/examples/env.rb +0 -9
  35. data/examples/logger.rb +0 -10
  36. data/examples/output.rb +0 -10
  37. data/examples/pty.rb +0 -7
  38. data/examples/redirect_stderr.rb +0 -10
  39. data/examples/redirect_stdin.rb +0 -16
  40. data/examples/redirect_stdout.rb +0 -10
  41. data/examples/stdin_input.rb +0 -10
  42. data/examples/threaded.rb +0 -12
  43. data/examples/timeout.rb +0 -7
  44. data/examples/wait.rb +0 -21
  45. data/tasks/console.rake +0 -11
  46. data/tasks/coverage.rake +0 -11
  47. data/tasks/spec.rake +0 -29
  48. data/tty-command.gemspec +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fb721a5620ec91bddc77643358783a38fb76631f
4
- data.tar.gz: b0f3485e21f80e9172d1651eb661360fb3972d6f
2
+ SHA256:
3
+ metadata.gz: efe5adcd3fe993ed0b35a1d640b77e50d42611e4c87efd296656c82680bbe19e
4
+ data.tar.gz: 91276213aee2b1a56b3b983e3779d47da9c2de4b2f16fd9fa1603173d12ec522
5
5
  SHA512:
6
- metadata.gz: 3184987586dff4f957bbeee34cf0811f60c10db0f533fe48e957f171a3a1b22485f1e4970a7b4867466deb73ad95e9b3ae30c4194753724471756aece30446de
7
- data.tar.gz: 1500b854c1a69a788e49226d28403f92ee28258b608939596e1da92296ff815623ef70885e0c54751e3a8769539fc5f6c8dfd973f69c43c87f112cbf575707ce
6
+ metadata.gz: 3d3159b1a53f1649a220c6cd41f00fe8c9621c26460715d2352c1ff010c84de2f8ced1a06ce4de998da16f43a9d254429b37f825a370059dad1828b820c28060
7
+ data.tar.gz: '094d9b3afbc63cb7b94888873e602badf0dc2dd6dee3c2a13c79d2865ee7c1270f52136df5472c9c080f1f157778808033ffe3a4989b72cba6dbcf5d83d57c3c'
@@ -1,5 +1,49 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.10.0] - 2020-10-22
4
+
5
+ ### Changed
6
+ * Change :chdir option to escape directory location path
7
+ * Change gemspec to add metadata and remove test artefacts
8
+ * Change to update pastel dependency and restrict version to minor only
9
+ * Remove bundler as a dev dependency and relax rspec's upper boundary
10
+
11
+ ### Fixed
12
+ * Fix Ruby 2.7 keyword conversion errors
13
+ * Fix error when environment variable contains % character
14
+
15
+ ## [v0.9.0] - 2019-09-28
16
+
17
+ ### Changed
18
+ * Change gemspec to require Ruby >= 2.0.0
19
+
20
+ ## [v0.8.2] - 2018-08-07
21
+
22
+ ### Changed
23
+ * Change gemspec to load only required files
24
+
25
+ ### Fixed
26
+ * Fix issue with Ruby greater than 2.5.0 displaying thread error traceback by default
27
+
28
+ ## [v0.8.1] - 2018-05-20
29
+
30
+ ### Changed
31
+ * Change ProcessRunner#write_stream to handle all writing logic
32
+
33
+ ## [v0.8.0] - 2018-04-22
34
+
35
+ ### Added
36
+ * Add :output_only_on_error option by Iulian Onofrei(@revolter)
37
+ * Add :verbose flag to toggle warnings
38
+
39
+ ### Changed
40
+ * Change ProcessRunner to use waitpid2 api for direct status
41
+ * Change ProcessRunner stdout & stderr reading to use IO.select and be non-blocking
42
+
43
+ ### Fixed
44
+ * Fix :timeout to raise when long running without input or output
45
+ * Fix ProcessRunner to ensure no zombie processes on timeouts
46
+
3
47
  ## [v0.7.0] - 2017-11-19
4
48
 
5
49
  ### Added
@@ -96,6 +140,11 @@
96
140
 
97
141
  * Initial implementation and release
98
142
 
143
+ [v0.10.0]: https://github.com/piotrmurach/tty-command/compare/v0.9.0...v0.10.0
144
+ [v0.9.0]: https://github.com/piotrmurach/tty-command/compare/v0.8.2...v0.9.0
145
+ [v0.8.2]: https://github.com/piotrmurach/tty-command/compare/v0.8.1...v0.8.2
146
+ [v0.8.1]: https://github.com/piotrmurach/tty-command/compare/v0.8.0...v0.8.1
147
+ [v0.8.0]: https://github.com/piotrmurach/tty-command/compare/v0.7.0...v0.8.0
99
148
  [v0.7.0]: https://github.com/piotrmurach/tty-command/compare/v0.6.0...v0.7.0
100
149
  [v0.6.0]: https://github.com/piotrmurach/tty-command/compare/v0.5.0...v0.6.0
101
150
  [v0.5.0]: https://github.com/piotrmurach/tty-command/compare/v0.4.0...v0.5.0
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016 Piotr Murach
3
+ Copyright (c) 2016 Piotr Murach (https://piotrmurach.com)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ <div align="center">
2
+ <a href="https://ttytoolkit.org"><img width="130" src="https://github.com/piotrmurach/tty/blob/master/images/tty.png" alt="TTY Toolkit logo"/></a>
3
+ </div>
4
+
1
5
  # TTY::Command [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
2
6
 
3
7
  [![Gem Version](https://badge.fury.io/rb/tty-command.svg)][gem]
@@ -32,7 +36,7 @@ Why should we be handcuffed to `sh` or `bash` for these scripts when we could be
32
36
  Add this line to your application's Gemfile:
33
37
 
34
38
  ```ruby
35
- gem 'tty-command'
39
+ gem "tty-command"
36
40
  ```
37
41
 
38
42
  And then execute:
@@ -52,6 +56,8 @@ Or install it yourself as:
52
56
  * [2.3. Logging](#23-logging)
53
57
  * [2.3.1. Color](#231-color)
54
58
  * [2.3.2. UUID](#232-uuid)
59
+ * [2.3.3. Only output on error](#233-only-output-on-error)
60
+ * [2.3.4. Verbose](#234-verbose)
55
61
  * [2.4. Dry run](#24-dry-run)
56
62
  * [2.5. Wait](#25-wait)
57
63
  * [2.6. Test](#26-test)
@@ -82,9 +88,11 @@ Or install it yourself as:
82
88
  Create a command instance and then run some commands:
83
89
 
84
90
  ```ruby
91
+ require "tty-command"
92
+
85
93
  cmd = TTY::Command.new
86
- cmd.run('ls -la')
87
- cmd.run('echo Hello!')
94
+ cmd.run("ls -la")
95
+ cmd.run("echo Hello!")
88
96
  ```
89
97
 
90
98
  Note that `run` will throw an exception if the command fails. This is already an improvement over ordinary shell scripts, which just keep on going when things go bad. That usually makes things worse.
@@ -92,7 +100,7 @@ Note that `run` will throw an exception if the command fails. This is already an
92
100
  You can use the return value to capture stdout and stderr:
93
101
 
94
102
  ```ruby
95
- out, err = cmd.run('cat ~/.bashrc | grep alias')
103
+ out, err = cmd.run("cat ~/.bashrc | grep alias")
96
104
  ```
97
105
 
98
106
  Instead of using a plain old string, you can break up the arguments and they'll get escaped if necessary:
@@ -119,13 +127,13 @@ The `env`, `command` and `options` arguments are described in the following sect
119
127
  For example, to display file contents:
120
128
 
121
129
  ```ruby
122
- cmd.run('cat file.txt')
130
+ cmd.run("cat file.txt")
123
131
  ```
124
132
 
125
133
  If the command succeeds, a `TTY::Command::Result` is returned that records stdout and stderr:
126
134
 
127
135
  ```ruby
128
- out, err = cmd.run('date')
136
+ out, err = cmd.run("date")
129
137
  puts "The date is #{out}"
130
138
  # => "The date is Tue 10 May 2016 22:30:15 BST\n"
131
139
  ```
@@ -133,7 +141,7 @@ puts "The date is #{out}"
133
141
  You can also pass a block that gets invoked anytime stdout and/or stderr receive output:
134
142
 
135
143
  ```ruby
136
- cmd.run('long running script') do |out, err|
144
+ cmd.run("long running script") do |out, err|
137
145
  output << out if out
138
146
  errors << err if err
139
147
  end
@@ -153,8 +161,8 @@ If the error output is very long, the stderr may contain only a prefix, number o
153
161
  If you expect a command to fail occasionally, use `run!` instead. Then you can detect failures and respond appropriately. For example:
154
162
 
155
163
  ```ruby
156
- if cmd.run!('which xyzzy').failure?
157
- cmd.run('brew install xyzzy')
164
+ if cmd.run!("which xyzzy").failure?
165
+ cmd.run("brew install xyzzy")
158
166
  end
159
167
  ```
160
168
 
@@ -176,7 +184,7 @@ cmd = TTY::Command.new(printer: :progress)
176
184
  By default the printers log to `stdout` but this can be changed by passing an object that responds to `<<` message:
177
185
 
178
186
  ```ruby
179
- logger = Logger.new('dev.log')
187
+ logger = Logger.new("dev.log")
180
188
  cmd = TTY::Command.new(output: logger)
181
189
  ```
182
190
 
@@ -186,18 +194,75 @@ You can force the printer to always in print in color by passing the `:color` op
186
194
  cmd = TTY::Command.new(color: true)
187
195
  ```
188
196
 
197
+ If the default printers don't meet your needs you can always create [a custom printer](#34-custom-printer)
198
+
189
199
  #### 2.3.1 Color
190
200
 
191
- When using printers you can switch off coloring by using `color` option set to `false`.
201
+ When using printers you can switch off coloring by using `:color` option set to `false`.
202
+
203
+ #### 2.3.2 UUID
204
+
205
+ By default, when logging is enabled and `pretty` printer is used, each log entry is prefixed by specific command run uuid number. This number can be switched off using the `:uuid` option at initialization:
206
+
207
+ ```ruby
208
+ cmd = TTY::Command.new(uuid: false)
209
+ cmd.run("rm -R all_my_files")
210
+ # =>
211
+ # Running rm -r all_my_files
212
+ # ...
213
+ # Finished in 6 seconds with exit status 0 (successful)
214
+ ```
215
+
216
+ or individually per command run:
192
217
 
193
- #### 2.3.2 Uuid
218
+ ```rub
219
+ cmd = TTY::Command.new
220
+ cmd.run("echo hello", uuid: false)
221
+ # =>
222
+ # Running echo hello
223
+ # hello
224
+ # Finished in 0.003 seconds with exit status 0 (successful)
225
+ ```
194
226
 
195
- By default when logging is enabled each log entry is prefixed by specific command run uuid number. This number can be switched off using `uuid` option:
227
+ #### 2.3.3 Only output on error
228
+
229
+ When using a command that can fail, setting `:only_output_on_error` option to `true` hides the output if the command succeeds:
196
230
 
197
231
  ```ruby
198
- cmd = TTY::Command.new uuid: false
199
- cmd.run('rm -R all_my_files')
200
- # => rm -r all_my_files
232
+ cmd = TTY::Command.new
233
+ cmd.run("non_failing_command", only_output_on_error: true)
234
+ ```
235
+
236
+ This will only print the `Running` and `Finished` lines, while:
237
+
238
+ ```ruby
239
+ cmd.run("non_failing_command")
240
+ ```
241
+
242
+ will also print any output that the `non_failing_command` might generate.
243
+
244
+ Running either:
245
+
246
+ ```ruby
247
+ cmd.run("failing_command", only_output_on_error: true)
248
+ ```
249
+
250
+ either:
251
+
252
+ ```ruby
253
+ cmd.run("failing_command")
254
+ ```
255
+
256
+ will also print the output.
257
+
258
+ *Setting this option will cause the output to show at once, at the end of the command.*
259
+
260
+ #### 2.3.4 Verbose
261
+
262
+ By default commands will produce warnings when, for example `pty` option is not supported on a given platform. You can switch off such warnings with `:verbose` option set to `false`.
263
+
264
+ ```ruby
265
+ cmd.run("echo '\e[32mColors!\e[0m'", pty: true, verbose: false)
201
266
  ```
202
267
 
203
268
  ### 2.4 Dry run
@@ -206,7 +271,7 @@ Sometimes it can be useful to put your script into a "dry run" mode that prints
206
271
 
207
272
  ```ruby
208
273
  cmd = TTY::Command.new(dry_run: true)
209
- cmd.run(:rm, 'all_my_files')
274
+ cmd.run(:rm, "all_my_files")
210
275
  # => [123abc] (dry run) rm all_my_files
211
276
  ```
212
277
 
@@ -221,7 +286,7 @@ cmd.dry_run? # => true
221
286
  If you need to wait for a long running script and stop it when a given pattern has been matched use `wait` like so:
222
287
 
223
288
  ```ruby
224
- cmd.wait 'tail -f /var/log/production.log', /something happened/
289
+ cmd.wait "tail -f /var/log/production.log", /something happened/
225
290
  ```
226
291
 
227
292
  ### 2.6 Test
@@ -229,7 +294,7 @@ cmd.wait 'tail -f /var/log/production.log', /something happened/
229
294
  To simulate classic bash test command you case use `test` method with expression to check as a first argument:
230
295
 
231
296
  ```ruby
232
- if cmd.test '-e /etc/passwd'
297
+ if cmd.test "-e /etc/passwd"
233
298
  puts "Sweet..."
234
299
  else
235
300
  puts "Ohh no! Where is it?"
@@ -252,24 +317,24 @@ cmd.ruby %q{-e "puts 'Hello world'"}
252
317
  The environment variables need to be provided as hash entries, that can be set directly as a first argument:
253
318
 
254
319
  ```ruby
255
- cmd.run({'RAILS_ENV' => 'PRODUCTION'}, :rails, 'server')
320
+ cmd.run({"RAILS_ENV" => "PRODUCTION"}, :rails, "server")
256
321
  ```
257
322
 
258
323
  or as an option with `:env` key:
259
324
 
260
325
  ```ruby
261
- cmd.run(:rails, 'server', env: {rails_env: :production})
326
+ cmd.run(:rails, "server", env: {rails_env: :production})
262
327
  ```
263
328
 
264
329
  When a value in env is nil, the variable is unset in the child process:
265
330
 
266
331
  ```ruby
267
- cmd.run(:echo, 'hello', env: {foo: 'bar', baz: nil})
332
+ cmd.run(:echo, "hello", env: {foo: "bar", baz: nil})
268
333
  ```
269
334
 
270
335
  ### 3.2 Options
271
336
 
272
- When a hash is given in the last argument (options), it allows to specify a current directory, umask, user, group and and zero or more fd redirects for the child process.
337
+ When a hash is given in the last argument (options), it allows to specify a current directory, umask, user, group and zero or more fd redirects for the child process.
273
338
 
274
339
  #### 3.2.1 Redirection
275
340
 
@@ -302,27 +367,27 @@ The hash key and value specify a file descriptor in the child process (stderr &
302
367
  You can also redirect to a file:
303
368
 
304
369
  ```ruby
305
- cmd.run(:cat, :in => 'file')
306
- cmd.run(:cat, :in => open('/etc/passwd'))
307
- cmd.run(:ls, :out => 'log')
370
+ cmd.run(:cat, :in => "file")
371
+ cmd.run(:cat, :in => open("/etc/passwd"))
372
+ cmd.run(:ls, :out => "log")
308
373
  cmd.run(:ls, :out => "/dev/null")
309
- cmd.run(:ls, :out => 'out.log', :err => "err.log")
374
+ cmd.run(:ls, :out => "out.log", :err => "err.log")
310
375
  cmd.run(:ls, [:out, :err] => "log")
311
- cmd.run("ls 1>&2", :err => 'log')
376
+ cmd.run("ls 1>&2", :err => "log")
312
377
  ```
313
378
 
314
379
  It is possible to specify flags and permissions of file creation explicitly by passing an array value:
315
380
 
316
381
  ```ruby
317
- cmd.run(:ls, :out => ['log', 'w']) # 0664 assumed
318
- cmd.run(:ls, :out => ['log', 'w', 0600])
319
- cmd.run(:ls, :out => ['log', File::WRONLY|File::EXCL|File::CREAT, 0600])
382
+ cmd.run(:ls, :out => ["log", "w"]) # 0664 assumed
383
+ cmd.run(:ls, :out => ["log", "w", 0600])
384
+ cmd.run(:ls, :out => ["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
320
385
  ```
321
386
 
322
387
  You can, for example, read data from one source and output to another:
323
388
 
324
389
  ```ruby
325
- cmd.run("cat", :in => "Gemfile", :out => 'gemfile.log')
390
+ cmd.run("cat", :in => "Gemfile", :out => "gemfile.log")
326
391
  ```
327
392
 
328
393
  #### 3.2.2 Handling Input
@@ -337,7 +402,7 @@ puts "Your name: #{name}"
337
402
  In order to execute `cli` with name input do:
338
403
 
339
404
  ```ruby
340
- cmd.run('cli', input: "Piotr\n")
405
+ cmd.run("cli", input: "Piotr\n")
341
406
  # => Your name: Piotr
342
407
  ```
343
408
 
@@ -356,7 +421,7 @@ cmd.run("my_cli_program", "login", in: in_stream).out
356
421
 
357
422
  #### 3.2.3 Timeout
358
423
 
359
- You can timeout command execuation by providing the `:timeout` option in seconds:
424
+ You can timeout command execution by providing the `:timeout` option in seconds:
360
425
 
361
426
  ```ruby
362
427
  cmd.run("while test 1; sleep 1; done", timeout: 5)
@@ -386,7 +451,7 @@ cmd = TTY::Command.new(binmode: true)
386
451
 
387
452
  #### 3.2.5 Signal
388
453
 
389
- You can specify process termination signal other than the defaut `SIGTERM`:
454
+ You can specify process termination signal other than the default `SIGTERM`:
390
455
 
391
456
  ```ruby
392
457
  cmd.run("whilte test1; sleep1; done", timeout: 5, signal: :KILL)
@@ -394,42 +459,44 @@ cmd.run("whilte test1; sleep1; done", timeout: 5, signal: :KILL)
394
459
 
395
460
  #### 3.2.6 PTY(pseudo terminal)
396
461
 
397
- The `:pty` configuration option causes the command to be executed in subprocess where each stream is a pseudo terminal. By default this options is set to `false`. However, some comamnds may require a terminal like device to work correctly. For example, a command may emit colored output only if it is running via terminal.
462
+ The `:pty` configuration option causes the command to be executed in subprocess where each stream is a `pseudo terminal`. By default this options is set to `false`.
463
+
464
+ If you require to interface with interactive subprocess then setting this option to `true` will enable a `pty` terminal device. For example, a command may emit colored output only if it is running via terminal device. You may also wish to run a program that waits for user input, and simulates typing in commands and reading responses.
465
+
466
+ This option will only work on systems that support BSD pty devices such as Linux or OS X, and it will gracefully fallback to non-pty device on all the other.
398
467
 
399
- In order to run command in pseudo terminal, either set the flag globally for all commands:
468
+ In order to run command in `pseudo terminal`, either set the flag globally for all commands:
400
469
 
401
470
  ```ruby
402
471
  cmd = TTY::Command.new(pty: true)
403
472
  ```
404
473
 
405
- or for each executed command individually:
474
+ or individually for each executed command:
406
475
 
407
476
  ```ruby
408
477
  cmd.run("echo 'hello'", pty: true)
409
478
  ```
410
479
 
411
- Please note though, that setting `:pty` to `true` may change how the command behaves. For instance, on unix like systems the line feed character `\n` in output will be prefixed with carriage return `\r`:
480
+ Please note that setting `:pty` to `true` may change how the command behaves. It's important to understand the difference between `interactive` and `non-interactive` modes. For example, executing `git log` to view the commit history in default `non-interactive` mode:
412
481
 
413
482
  ```ruby
414
- out, _ = cmd.run("echo 'hello'")
415
- out # => "hello\n"
483
+ cmd.run("git log") # => finishes and produces full output
416
484
  ```
417
485
 
418
- and with `:pty` option:
486
+ However, in `interactive` mode with `pty` flag on:
419
487
 
420
488
  ```ruby
421
- out, _ = cmd.run("echo 'hello'", pty: true)
422
- out # => "hello\r\n"
489
+ cmd.run("git log", pty: true) # => uses pager and waits for user input (never returns)
423
490
  ```
424
491
 
425
- In addition, any input to command may be echoed to the standard output.
492
+ In addition, when pty device is used, any input to command may be echoed to the standard output, as well as some redirects may not work.
426
493
 
427
494
  #### 3.2.7 Current directory
428
495
 
429
496
  To change directory in which the command is run pass the `:chdir` option:
430
497
 
431
498
  ```ruby
432
- cmd.run(:echo, 'hello', chdir: '/var/tmp')
499
+ cmd.run(:echo, "hello", chdir: "/var/tmp")
433
500
  ```
434
501
 
435
502
  #### 3.2.8 User
@@ -437,7 +504,7 @@ cmd.run(:echo, 'hello', chdir: '/var/tmp')
437
504
  To run command as a given user do:
438
505
 
439
506
  ```ruby
440
- cmd.run(:echo, 'hello', user: 'piotr')
507
+ cmd.run(:echo, "hello", user: "piotr")
441
508
  ```
442
509
 
443
510
  #### 3.2.9 Group
@@ -445,7 +512,7 @@ cmd.run(:echo, 'hello', user: 'piotr')
445
512
  To run command as part of group do:
446
513
 
447
514
  ```ruby
448
- cmd.run(:echo, 'hello', group: 'devs')
515
+ cmd.run(:echo, "hello", group: "devs")
449
516
  ```
450
517
 
451
518
  #### 3.2.10 Umask
@@ -453,7 +520,7 @@ cmd.run(:echo, 'hello', group: 'devs')
453
520
  To run command with umask do:
454
521
 
455
522
  ```ruby
456
- cmd.run(:echo, 'hello', umask: '007')
523
+ cmd.run(:echo, "hello", umask: "007")
457
524
  ```
458
525
 
459
526
  ### 3.3 Result
@@ -461,13 +528,13 @@ cmd.run(:echo, 'hello', umask: '007')
461
528
  Each time you run command the stdout and stderr are captured and return as result. The result can be examined directly by casting it to tuple:
462
529
 
463
530
  ```ruby
464
- out, err = cmd.run(:echo, 'Hello')
531
+ out, err = cmd.run(:echo, "Hello")
465
532
  ```
466
533
 
467
534
  However, if you want to you can defer reading:
468
535
 
469
536
  ```ruby
470
- result = cmd.run(:echo, 'Hello')
537
+ result = cmd.run(:echo, "Hello")
471
538
  result.out
472
539
  result.err
473
540
  ```
@@ -477,7 +544,7 @@ result.err
477
544
  To check if command exited successfully use `success?`:
478
545
 
479
546
  ```ruby
480
- result = cmd.run(:echo, 'Hello')
547
+ result = cmd.run(:echo, "Hello")
481
548
  result.success? # => true
482
549
  ```
483
550
 
@@ -486,7 +553,7 @@ result.success? # => true
486
553
  To check if command exited unsuccessfully use `failure?` or `failed?`:
487
554
 
488
555
  ```ruby
489
- result = cmd.run(:echo, 'Hello')
556
+ result = cmd.run(:echo, "Hello")
490
557
  result.failure? # => false
491
558
  result.failed? # => false
492
559
  ```
@@ -496,7 +563,7 @@ result.failed? # => false
496
563
  To check if command ran to completion use `exited?` or `complete?`:
497
564
 
498
565
  ```ruby
499
- result = cmd.run(:echo, 'Hello')
566
+ result = cmd.run(:echo, "Hello")
500
567
  result.exited? # => true
501
568
  result.complete? # => true
502
569
  ```
@@ -506,7 +573,7 @@ result.complete? # => true
506
573
  The result itself is an enumerable and allows you to iterate over the stdout output:
507
574
 
508
575
  ```ruby
509
- result = cmd.run(:ls, '-1')
576
+ result = cmd.run(:ls, "-1")
510
577
  result.each { |line| puts line }
511
578
  # =>
512
579
  # CHANGELOG.md
@@ -529,26 +596,29 @@ TTY::Command.record_separator = "\n\r"
529
596
  or configured per `each` call by passing delimiter as an argument:
530
597
 
531
598
  ```ruby
532
- cmd.run(:ls, '-1').each("\t") { ... }
599
+ cmd.run(:ls, "-1").each("\t") { ... }
533
600
  ```
534
601
 
535
602
  ### 3.4 Custom printer
536
603
 
537
- If the built-in printers do not meet your requirements you can create your own. At the very minimum you need to specify the `write` method that will be called during the lifecycle of command execution:
604
+ If the built-in printers do not meet your requirements you can create your own. A printer is a regular Ruby class that can be registered through `:printer` option to receive notifications about received command data.
605
+
606
+ As the command runs the custom printer will be notified when the command starts, when data is printed to stdout, when data is printed to stderr and when the command exits.
607
+
608
+ Please see [lib/tty/command/printers/abstract.rb](https://github.com/piotrmurach/tty-command/blob/master/lib/tty/command/printers/abstract.rb) for a full set of methods that you can override.
609
+
610
+ At the very minimum you need to specify the `write` method that will be called during the lifecycle of command execution. The `write` accepts two arguments, first the currently run command instance and second the message to be printed:
538
611
 
539
612
  ```ruby
540
613
  CustomPrinter < TTY::Command::Printers::Abstract
541
- def write(message)
542
- puts message
614
+ def write(cmd, message)
615
+ puts cmd.to_command + message
543
616
  end
544
617
  end
545
618
 
546
- printer = CustomPrinter
547
-
548
- cmd = TTY::Command.new(printer: printer)
619
+ cmd = TTY::Command.new(printer: CustomPrinter)
549
620
  ```
550
621
 
551
-
552
622
  ## 4. Example
553
623
 
554
624
  Here's a slightly more elaborate example to illustrate how tty-command can improve on plain old shell scripts. This example installs a new version of Ruby on an Ubuntu machine.
@@ -588,4 +658,4 @@ The gem is available as open source under the terms of the [MIT License](http://
588
658
 
589
659
  ## Copyright
590
660
 
591
- Copyright (c) 2016-2017 Piotr Murach. See LICENSE for further details.
661
+ Copyright (c) 2016 Piotr Murach. See LICENSE for further details.