rexe 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +233 -129
- data/exe/rexe +264 -224
- data/rexe.gemspec +2 -7
- metadata +13 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 982527b8b9d991102d3a3a1eb5ae83e7235cea0b77b782921ab6e203a5c70f42
|
4
|
+
data.tar.gz: a586d1f5c68beaf81692f23920e1c2e8c435e44e7095b38e90a70f4b113fa32c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffb97f15aae0ed61a2acabdfa2d330d15814d2c4ada682c1eae0099d8b5dd9262d1fa7e47142051d18ca5f5efddee2ef755efeb9b22d555bf2621327305e572c
|
7
|
+
data.tar.gz: ce5ae9551e7fad281a7505bb99c4749098eb9560fd377dc33ea3341ae29e5d4d490bfea807b426e36bf79f7cfbc597416da2cf50ab475343854908d49d131708
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
## rexe -- Ruby Command Line Executor
|
2
2
|
|
3
3
|
|
4
|
+
### 0.14.0
|
5
|
+
|
6
|
+
* The default output format has been changed from -op (:puts) to -on (:none).
|
7
|
+
* Support automatic input from file with -f option.
|
8
|
+
* Normalize load filespecs to eliminate duplication and to facilitate correct deletion.
|
9
|
+
|
10
|
+
|
4
11
|
### v0.13.0
|
5
12
|
|
6
13
|
* Much refactoring.
|
data/README.md
CHANGED
@@ -8,13 +8,13 @@ and the source code, and at minimum, reading the Conclusion.]_
|
|
8
8
|
|
9
9
|
----
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
Shell scripting is great for simple tasks but for anything nontrivial
|
12
|
+
it can easily get cryptic and awkward (pun intended!).
|
13
|
+
|
15
14
|
Often, I solve this problem by writing a Ruby script instead. Ruby gives me fine
|
16
|
-
grained control in a
|
17
|
-
|
15
|
+
grained control in a language that is all about clarity, conciseness, and expressiveness.
|
16
|
+
|
17
|
+
Unfortunately, when there are multiple OS commands to be called, then Ruby can be
|
18
18
|
awkward too.
|
19
19
|
|
20
20
|
### Using the Ruby Interpreter on the Command Line
|
@@ -50,6 +50,12 @@ The previous `ruby` command can be expressed in `rexe` as:
|
|
50
50
|
```
|
51
51
|
➜ ~ echo $EUR_RATES_JSON | rexe -mb -ij -oy self
|
52
52
|
```
|
53
|
+
|
54
|
+
The command options may seem cryptic, but they're logical so it shouldn't take long to learn them:
|
55
|
+
|
56
|
+
* `-mb` - __mode__ to consume all standard input as a single __big__ string
|
57
|
+
* `-ij` - parse that __input__ with __JSON__; `self` will be the parsed object
|
58
|
+
* `-oy` - __output__ the final value as __YAML__
|
53
59
|
|
54
60
|
`rexe` is at https://github.com/keithrbennett/rexe and can be installed with
|
55
61
|
`gem install rexe`. `rexe` provides several ways to simplify Ruby on the command
|
@@ -60,21 +66,24 @@ line, tipping the scale so that it is practical to do it more often.
|
|
60
66
|
Here is `rexe`'s help text as of the time of this writing:
|
61
67
|
|
62
68
|
```
|
63
|
-
rexe -- Ruby Command Line Executor/Filter -- v0.
|
69
|
+
rexe -- Ruby Command Line Executor/Filter -- v0.14.0 -- https://github.com/keithrbennett/rexe
|
64
70
|
|
65
|
-
Executes Ruby code on the command line, optionally
|
71
|
+
Executes Ruby code on the command line, optionally automating management of standard input
|
72
|
+
and standard output, and optionally parsing input and formatting output with YAML, JSON, etc.
|
66
73
|
|
67
74
|
rexe [options] 'Ruby source code'
|
68
75
|
|
69
76
|
Options:
|
70
77
|
|
71
78
|
-c --clear_options Clear all previous command line options specified up to now
|
79
|
+
-f --input_file Use this file instead of stdin; autodetects YAML and JSON file extensions
|
80
|
+
If YAML or JSON: parses file in that mode, sets input mode to -mb
|
72
81
|
-g --log_format FORMAT Log format, logs to stderr, defaults to none (see -o for format options)
|
73
82
|
-h, --help Print help and exit
|
74
|
-
-i, --input_format FORMAT Input format
|
83
|
+
-i, --input_format FORMAT Input format
|
75
84
|
-ij JSON
|
76
85
|
-im Marshal
|
77
|
-
-in None
|
86
|
+
-in None (default)
|
78
87
|
-iy YAML
|
79
88
|
-l, --load RUBY_FILE(S) Ruby file(s) to load, comma separated;
|
80
89
|
! to clear all, or precede a name with '-' to remove
|
@@ -90,8 +99,8 @@ Options:
|
|
90
99
|
-oj JSON
|
91
100
|
-oJ Pretty JSON
|
92
101
|
-om Marshal
|
93
|
-
-on No Output
|
94
|
-
-op Puts
|
102
|
+
-on No Output (default)
|
103
|
+
-op Puts
|
95
104
|
-os to_s
|
96
105
|
-oy YAML
|
97
106
|
-r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
|
@@ -118,11 +127,24 @@ There are two main ways we can make the `rexe` command line even more concise:
|
|
118
127
|
The `REXE_OPTIONS` environment variable can contain command line options that would otherwise
|
119
128
|
be specified on the `rexe` command line:
|
120
129
|
|
130
|
+
Instead of this:
|
131
|
+
|
121
132
|
```
|
122
|
-
➜ ~
|
123
|
-
➜ ~ echo $EUR_RATES_JSON | rexe 'ap JSON.parse(STDIN.read)'
|
133
|
+
➜ ~ rexe -r wifi-wand -oa WifiWand::MacOsModel.new.wifi_info
|
124
134
|
```
|
125
135
|
|
136
|
+
you can do this:
|
137
|
+
|
138
|
+
```
|
139
|
+
➜ ~ export REXE_OPTIONS="-r wifi-wand -oa"
|
140
|
+
➜ ~ rexe WifiWand::MacOsModel.new.wifi_info
|
141
|
+
➜ ~ # [more rexe commands with the same options]
|
142
|
+
```
|
143
|
+
|
144
|
+
Putting configuration options in `REXE_OPTIONS` effectively creates custom defaults,
|
145
|
+
and is useful when you use options in most or all of your commands. Any options specified on the `rexe`
|
146
|
+
command line will override the environment variable options.
|
147
|
+
|
126
148
|
Like any environment variable, `REXE_OPTIONS` could also be set in your startup script, input on a command line using `export`, or in another script loaded with `source` or `.`.
|
127
149
|
|
128
150
|
### Loading Files
|
@@ -155,14 +177,14 @@ You might be thinking that creating an alias or a minimal shell script for this
|
|
155
177
|
approach, and I would agree with you. However, over time the number of these could become unmanageable, whereas using Ruby
|
156
178
|
you could build a pretty extensive and well organized library of functionality. Moreover, that functionality could be made available to _all_ your Ruby code (for example, by putting it in a gem), and not just command line one liners.
|
157
179
|
|
158
|
-
For example, you could have something like this in a
|
180
|
+
For example, you could have something like this in a gem or loaded file:
|
159
181
|
|
160
182
|
```
|
161
183
|
def play(piece_code)
|
162
184
|
pieces = {
|
163
185
|
hallelujah: "https://www.youtube.com/watch?v=IUZEtVbJT5c&t=0m20s",
|
164
186
|
valkyries: "http://www.youtube.com/watch?v=P73Z6291Pt8&t=0m28s",
|
165
|
-
wm_tell: "https://www.youtube.com/watch?v=j3T8-aeOrbg"
|
187
|
+
wm_tell: "https://www.youtube.com/watch?v=j3T8-aeOrbg&t=0m1s",
|
166
188
|
# ... and many, many more
|
167
189
|
}
|
168
190
|
`open #{Shellwords.escape(pieces.fetch(piece_code))}`
|
@@ -178,6 +200,8 @@ end
|
|
178
200
|
(You need to quote the `play` call because otherwise the shell will process and remove the parentheses.
|
179
201
|
Alternatively you could escape the parentheses with backslashes.)
|
180
202
|
|
203
|
+
One of the examples at the end of this articles shows how you could have different music play for success and failure.
|
204
|
+
|
181
205
|
|
182
206
|
### Logging
|
183
207
|
|
@@ -187,12 +211,12 @@ to be evaluated, options (after parsing both the `REXE_OPTIONS` environment vari
|
|
187
211
|
and the execution time of your Ruby code:
|
188
212
|
|
189
213
|
```
|
190
|
-
➜ ~ echo $EUR_RATES_JSON | rexe -gy -
|
214
|
+
➜ ~ echo $EUR_RATES_JSON | rexe -gy -ij -oa self
|
191
215
|
...
|
192
216
|
---
|
193
217
|
:count: 0
|
194
|
-
:rexe_version: 0.
|
195
|
-
:start_time: '2019-03-
|
218
|
+
:rexe_version: 0.13.0
|
219
|
+
:start_time: '2019-03-21T20:58:51+08:00'
|
196
220
|
:source_code: ap JSON.parse(STDIN.read)
|
197
221
|
:options:
|
198
222
|
:input_format: :none
|
@@ -200,25 +224,26 @@ and the execution time of your Ruby code:
|
|
200
224
|
:loads: []
|
201
225
|
:output_format: :puts
|
202
226
|
:requires:
|
203
|
-
- json
|
204
227
|
- awesome_print
|
228
|
+
- json
|
205
229
|
- yaml
|
206
230
|
:log_format: :yaml
|
207
231
|
:noop: false
|
208
|
-
:duration_secs: 0.
|
232
|
+
:duration_secs: 0.070381
|
209
233
|
```
|
210
234
|
|
211
|
-
|
212
|
-
|
235
|
+
We specified `-gy` for YAML format; there are other formats as well (see the help output or this document)
|
236
|
+
and the default is `-gn`, which means don't output the log entry at all.
|
237
|
+
|
238
|
+
The requires you see were not explicitly specified but were automatically added because
|
239
|
+
`rexe` will add any requires needed for automatic parsing and formatting, and
|
240
|
+
we specified those formats in the command line options `-gy -ij -oa`.
|
213
241
|
|
214
242
|
This extra output is sent to standard error (_stderr_) instead of standard output
|
215
243
|
(_stdout_) so that it will not pollute the "real" data when stdout is piped to
|
216
244
|
another command.
|
217
245
|
|
218
|
-
|
219
|
-
use it programatically.
|
220
|
-
|
221
|
-
If you would like to append this informational output to a file, you could do something like this:
|
246
|
+
If you would like to append this informational output to a file(e.g. `rexe.log`), you could do something like this:
|
222
247
|
|
223
248
|
```
|
224
249
|
➜ ~ rexe ... -gy 2>>rexe.log
|
@@ -264,7 +289,7 @@ eybdoog
|
|
264
289
|
|
265
290
|
Be aware that, in this mode, although you can control the _content_ of output records,
|
266
291
|
there is no way to selectively _exclude_ records from being output. Even if the result of the code
|
267
|
-
is nil or the empty string, a newline will be output.
|
292
|
+
is nil or the empty string, a newline will be output. To prevent this, you can do one of the following:
|
268
293
|
|
269
294
|
* use `-me` Enumerator mode and call `select`, `filter`, `reject`, etc.
|
270
295
|
* use the `-on` _no output_ mode and call `puts` explicitly for the output you _do_ want
|
@@ -281,7 +306,7 @@ Here is an example of using `-me` to add line numbers to the first 3
|
|
281
306
|
files in the directory listing:
|
282
307
|
|
283
308
|
```
|
284
|
-
➜ ~ ls / | rexe -me "first(3).each_with_index { |ln,i| puts '%5d %s' % [i, ln] }
|
309
|
+
➜ ~ ls / | rexe -me -on "first(3).each_with_index { |ln,i| puts '%5d %s' % [i, ln] }"
|
285
310
|
|
286
311
|
0 AndroidStudioProjects
|
287
312
|
1 Applications
|
@@ -289,6 +314,7 @@ files in the directory listing:
|
|
289
314
|
```
|
290
315
|
|
291
316
|
Since `self` is an enumerable, we can call `first` and then `each_with_index`.
|
317
|
+
The `-on` says don't do any automatic output, just the output explicitly specified by `puts` in the source code.
|
292
318
|
|
293
319
|
|
294
320
|
#### -mb "Big String" Filter Mode
|
@@ -296,7 +322,7 @@ Since `self` is an enumerable, we can call `first` and then `each_with_index`.
|
|
296
322
|
In this mode, all standard input is combined into a single (possibly
|
297
323
|
large) string, with newline characters joining the lines in the string.
|
298
324
|
|
299
|
-
A good example of when you would use this is when you parse JSON or YAML
|
325
|
+
A good example of when you would use this is when you need to parse a multiline JSON or YAML representation of an object;
|
300
326
|
you need to pass the entire (probably) multiline string to the parse method.
|
301
327
|
This is the mode that was used in the first `rexe` example in this article.
|
302
328
|
|
@@ -362,16 +388,75 @@ could be included in the custom code instead. Here's why:
|
|
362
388
|
parameterization of the output format.
|
363
389
|
|
364
390
|
|
391
|
+
### Reading Input from a File
|
392
|
+
|
393
|
+
`rexe` also simplifies getting input from a file rather than standard input. The `-f` option takes a filespec
|
394
|
+
and does with exactly what it would have done with standard input. This shortens:
|
395
|
+
|
396
|
+
```
|
397
|
+
➜ ~ cat filename.ext | rexe ...
|
398
|
+
```
|
399
|
+
...to...
|
400
|
+
|
401
|
+
```
|
402
|
+
➜ ~ rexe -f filename.ext ...
|
403
|
+
```
|
404
|
+
|
405
|
+
This becomes even more useful if you are using files whose extensions are `.yml`, `.yaml`, or `.json` (case insensitively).
|
406
|
+
In this case the input format and mode will be set automatically for you to:
|
407
|
+
|
408
|
+
* `-iy` (YAML) or `-ij` (JSON) depending on the file extension
|
409
|
+
* `-mb` (one big string mode), which assumes that the most common use case will be to parse the entire file at once
|
410
|
+
|
411
|
+
So the example we gave above:
|
412
|
+
|
413
|
+
```
|
414
|
+
➜ ~ export EUR_RATES_JSON=`curl https://api.exchangeratesapi.io/latest`
|
415
|
+
➜ ~ echo $EUR_RATES_JSON | rexe -mb -ij -oy self
|
416
|
+
```
|
417
|
+
...could be changed to:
|
418
|
+
|
419
|
+
```
|
420
|
+
➜ ~ curl https://api.exchangeratesapi.io/latest > eur_rates.json
|
421
|
+
➜ ~ rexe -f eur_rates.json -oy self
|
422
|
+
```
|
423
|
+
|
424
|
+
Another possible win for using `-f` is that since it is a command line option, it could be specified in `REXE_OPTIONS`.
|
425
|
+
This could be useful if you are doing many operations on the same file.
|
426
|
+
|
365
427
|
### The $RC Global OpenStruct
|
366
428
|
|
367
429
|
For your convenience, the information displayed in verbose mode is available to your code at runtime
|
368
|
-
by accessing the `$RC` global variable, which contains an OpenStruct.
|
430
|
+
by accessing the `$RC` global variable, which contains an OpenStruct. Let's print out its contents using AwesomePrint:
|
431
|
+
|
432
|
+
```
|
433
|
+
➜ ~ rexe -oa '$RC'
|
434
|
+
OpenStruct {
|
435
|
+
:count => 0,
|
436
|
+
:rexe_version => "0.13.0",
|
437
|
+
:start_time => "2019-03-23T20:17:59+08:00",
|
438
|
+
:source_code => "$RC",
|
439
|
+
:options => {
|
440
|
+
:input_format => :none,
|
441
|
+
:input_mode => :no_input,
|
442
|
+
:loads => [],
|
443
|
+
:output_format => :awesome_print,
|
444
|
+
:requires => [
|
445
|
+
[0] "awesome_print"
|
446
|
+
],
|
447
|
+
:log_format => :none,
|
448
|
+
:noop => false
|
449
|
+
}
|
450
|
+
}
|
451
|
+
```
|
452
|
+
|
453
|
+
Probably most useful in that object
|
369
454
|
is the record count, accessible with both `$RC.count` and `$RC.i`.
|
370
455
|
This is only really useful in line mode, because in the others
|
371
456
|
it will always be 0 or 1. Here is an example of how you might use it as a kind of progress indicator:
|
372
457
|
|
373
458
|
```
|
374
|
-
➜ ~
|
459
|
+
➜ ~ find / | rexe -ml -on \
|
375
460
|
'if $RC.i % 1000 == 0; puts %Q{File entry ##{$RC.i} is #{self}}; end'
|
376
461
|
...
|
377
462
|
File entry #106000 is /usr/local/Cellar/go/1.11.5/libexec/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
|
@@ -404,10 +489,10 @@ trivially easily. Just to illustrate, here's how you would open a REPL on the Fi
|
|
404
489
|
➜ ~ rexe -r pry File.pry
|
405
490
|
```
|
406
491
|
|
407
|
-
`self` would evaluate to the `File` class, so you could call class methods
|
492
|
+
`self` would evaluate to the `File` class, so you could call class methods using only their names:
|
408
493
|
|
409
494
|
```
|
410
|
-
➜ ~ rexe
|
495
|
+
➜ ~ rexe -r pry File.pry
|
411
496
|
|
412
497
|
[6] pry(File)> size '/etc/passwd'
|
413
498
|
6804
|
@@ -420,7 +505,7 @@ true
|
|
420
505
|
This could be really handy if you call `pry` on a custom object that has methods especially suited to your task:
|
421
506
|
|
422
507
|
```
|
423
|
-
➜ ~ rexe
|
508
|
+
➜ ~ rexe -r wifi-wand,pry WifiWand::MacOsModel.new.pry
|
424
509
|
```
|
425
510
|
|
426
511
|
Ruby is supremely well suited for DSL's since it does not require parentheses for method calls,
|
@@ -435,8 +520,7 @@ necessary to quote the Ruby code. You can use single or double quotes to have th
|
|
435
520
|
as a single argument.
|
436
521
|
An excellent reference for how they differ is [here](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash).
|
437
522
|
|
438
|
-
Personally, I find single quotes more useful since special characters
|
439
|
-
not be disturbed.
|
523
|
+
Personally, I find single quotes more useful since I usually don't want special characters in my Ruby code like `$` to be processed by the shell.
|
440
524
|
|
441
525
|
When specifying the Ruby code, feel free to fall back on Ruby's super useful `%q{}` and `%Q{}`,
|
442
526
|
equivalent to single and double quotes, respectively.
|
@@ -520,20 +604,7 @@ when you change the content of the clipboard.
|
|
520
604
|
Although `rexe` is cleanest with short one liners, you may want to use it to include nontrivial Ruby code
|
521
605
|
in your shell script as well. If you do this, you may need to add trailing backslashes to the lines of Ruby code.
|
522
606
|
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
### The Use of Semicolons
|
527
|
-
|
528
|
-
You will probably find yourself using semicolons much more often than usual when you use `rexe`.
|
529
|
-
Obviously you would need them to separate statements on the same line:
|
530
|
-
|
531
|
-
```
|
532
|
-
➜ ~ cowsay hello | rexe -me "print %Q{\u001b[33m}; puts to_a"
|
533
|
-
```
|
534
|
-
|
535
|
-
What might not be so obvious is that you _also_ need them if each statement is on its own line.
|
536
|
-
For example, here is an example without a semicolon:
|
607
|
+
What might not be so obvious is that you will often need to use semicolons. For example, here is an example without a semicolon:
|
537
608
|
|
538
609
|
```
|
539
610
|
➜ ~ cowsay hello | rexe -me "print %Q{\u001b[33m} \
|
@@ -605,17 +676,15 @@ Files loaded with the `-l` option are treated the same way.
|
|
605
676
|
|
606
677
|
### Beware of Configured Requires
|
607
678
|
|
608
|
-
Requiring gems and modules for _all_ invocations of `rexe` will make your commands simpler and more concise, but will be a waste of execution time if they are not needed. You can inspect the execution times to see just how much time is being wasted. For example, we can find out that
|
679
|
+
Requiring gems and modules for _all_ invocations of `rexe` will make your commands simpler and more concise, but will be a waste of execution time if they are not needed. You can inspect the execution times to see just how much time is being wasted. For example, we can find out that rails takes about 0.63 seconds to load on my laptop by observing and comparing the execution times with and without the require (output has been abbreviated using the redirection and grep):
|
609
680
|
|
610
681
|
```
|
611
|
-
➜ ~
|
612
|
-
:duration_secs: 0.
|
613
|
-
|
614
|
-
|
615
|
-
:duration_secs: 0.148671
|
682
|
+
➜ ~ rexe -gy -r rails 123 2>&1 | grep duration
|
683
|
+
:duration_secs: 0.660138
|
684
|
+
➜ ~ rexe -gy 123 2>&1 | grep duration
|
685
|
+
:duration_secs: 0.027781
|
616
686
|
```
|
617
|
-
|
618
|
-
(For the above to work, the `nokogiri` gem needs to be installed.)
|
687
|
+
(For the above to work, the `rails` gem and its dependencies need to be installed.)
|
619
688
|
|
620
689
|
|
621
690
|
### Operating System Support
|
@@ -630,7 +699,33 @@ Windows non-Unix shells.
|
|
630
699
|
Here are some more examples to illustrate the use of `rexe`.
|
631
700
|
|
632
701
|
----
|
633
|
-
|
702
|
+
|
703
|
+
### Format Conversions -- JSON, YAML, AwesomePrint
|
704
|
+
|
705
|
+
You may work with YAML or JSON a lot and need to inspect files from time to time.
|
706
|
+
`rexe` makes it easy to convert from one format to another. For example, here's a
|
707
|
+
command to convert from `countries.yaml` to AwesomePrint:
|
708
|
+
|
709
|
+
```
|
710
|
+
cat countries.yaml | rexe -iy -oa -mb self
|
711
|
+
```
|
712
|
+
|
713
|
+
You can easily create a script that automates this. Using your favorite editor,
|
714
|
+
put this in a file:
|
715
|
+
|
716
|
+
```
|
717
|
+
cat $1 | rexe -iy -oa -mb self
|
718
|
+
```
|
719
|
+
|
720
|
+
I put mine in a file called `y2a` in my `~/bin` directory where I keep custom scripts like this.
|
721
|
+
|
722
|
+
Now you can call `y2a` to output any YAML file using AwesomePrint.
|
723
|
+
|
724
|
+
----
|
725
|
+
|
726
|
+
#### Outputting ENV
|
727
|
+
|
728
|
+
Output the contents of `ENV` using AwesomePrint [^3]:
|
634
729
|
|
635
730
|
```
|
636
731
|
➜ ~ rexe -oa ENV
|
@@ -645,6 +740,8 @@ Output the contents of `ENV` using AwesomePrint:
|
|
645
740
|
|
646
741
|
----
|
647
742
|
|
743
|
+
#### Reformatting a Command's Output
|
744
|
+
|
648
745
|
Show disk space used/free on a Mac's main hard drive's main partition:
|
649
746
|
|
650
747
|
```
|
@@ -657,7 +754,23 @@ Show disk space used/free on a Mac's main hard drive's main partition:
|
|
657
754
|
|
658
755
|
----
|
659
756
|
|
660
|
-
|
757
|
+
#### Formatting for Numeric Sort
|
758
|
+
|
759
|
+
Show the 3 longest file names of the current directory, with their lengths, in descending order:
|
760
|
+
|
761
|
+
```
|
762
|
+
➜ ~ ls | rexe -ml "%Q{[%4d] %s} % [length, self]" | sort -r | head -3
|
763
|
+
[ 50] Agoda_Booking_ID_9999999 49_–_RECEIPT_enclosed.pdf
|
764
|
+
[ 40] 679a5c034994544aab4635ecbd50ab73-big.jpg
|
765
|
+
[ 28] 2018-abc-2019-01-16-2340.zip
|
766
|
+
```
|
767
|
+
|
768
|
+
When you right align numbers using printf formatting, sorting the lines
|
769
|
+
alphabetically will result in sorting them numerically as well.
|
770
|
+
|
771
|
+
----
|
772
|
+
|
773
|
+
#### Print yellow (trust me!):
|
661
774
|
|
662
775
|
```
|
663
776
|
➜ ~ cowsay hello | rexe -me "print %Q{\u001b[33m}; puts to_a"
|
@@ -678,75 +791,9 @@ Print yellow (trust me!):
|
|
678
791
|
|
679
792
|
----
|
680
793
|
|
681
|
-
|
682
|
-
Show the 3 longest file names of the current directory, with their lengths, in descending order:
|
683
|
-
|
684
|
-
```
|
685
|
-
➜ ~ ls | rexe -ml "%Q{[%4d] %s} % [length, self]" | sort -r | head -3
|
686
|
-
[ 50] Agoda_Booking_ID_9999999 49_–_RECEIPT_enclosed.pdf
|
687
|
-
[ 40] 679a5c034994544aab4635ecbd50ab73-big.jpg
|
688
|
-
[ 28] 2018-abc-2019-01-16-2340.zip
|
689
|
-
```
|
690
|
-
|
691
|
-
Notice that when you right align numbers using printf formatting, sorting the lines
|
692
|
-
alphabetically will result in sorting them numerically as well.
|
693
|
-
|
694
794
|
----
|
695
795
|
|
696
|
-
|
697
|
-
The definition lines look like this one:
|
698
|
-
|
699
|
-
```
|
700
|
-
class JournalEntry < Struct.new(:date, :acct_amounts, :doc_short_name, :description, :receipts)
|
701
|
-
```
|
702
|
-
|
703
|
-
The `grep` command line utility prepends each of these matches with a string like this:
|
704
|
-
|
705
|
-
```
|
706
|
-
lib/rock_books/documents/journal_entry.rb:
|
707
|
-
```
|
708
|
-
|
709
|
-
So this is what worked well for me:
|
710
|
-
|
711
|
-
```
|
712
|
-
➜ ~ grep Struct **/*.rb | grep -v OpenStruct | rexe -ml \
|
713
|
-
"a = \
|
714
|
-
gsub('lib/rock_books/', '')\
|
715
|
-
.gsub('< Struct.new', '')\
|
716
|
-
.gsub('; end', '')\
|
717
|
-
.split('.rb:')\
|
718
|
-
.map(&:strip);\
|
719
|
-
\
|
720
|
-
%q{%-40s %-s} % [a[0] + %q{.rb}, a[1]]"
|
721
|
-
```
|
722
|
-
|
723
|
-
...which produced this output:
|
724
|
-
|
725
|
-
```
|
726
|
-
cmd_line/command_line_interface.rb class Command (:min_string, :max_string, :action)
|
727
|
-
documents/book_set.rb class BookSet (:run_options, :chart_of_accounts, :journals)
|
728
|
-
documents/journal.rb class Entry (:date, :amount, :acct_amounts, :description)
|
729
|
-
documents/journal_entry.rb class JournalEntry (:date, :acct_amounts, :doc_short_name, :description, :receipts)
|
730
|
-
documents/journal_entry_builder.rb class JournalEntryBuilder (:journal_entry_context)
|
731
|
-
reports/report_context.rb class ReportContext (:chart_of_accounts, :journals, :page_width)
|
732
|
-
types/account.rb class Account (:code, :type, :name)
|
733
|
-
types/account_type.rb class AccountType (:symbol, :singular_name, :plural_name)
|
734
|
-
types/acct_amount.rb class AcctAmount (:date, :code, :amount, :journal_entry_context)
|
735
|
-
types/journal_entry_context.rb class JournalEntryContext (:journal, :linenum, :line)
|
736
|
-
```
|
737
|
-
|
738
|
-
Although there's a lot going on here, the vertical and horizontal alignments and spacing make the code
|
739
|
-
straightforward to follow. Here's what it does:
|
740
|
-
|
741
|
-
* grep the code base for `"Struct"`
|
742
|
-
* exclude references to `"OpenStruct"` with `grep -v`
|
743
|
-
* remove unwanted text with `gsub`
|
744
|
-
* split the line into 1) a filespec relative to `lib/rockbooks`, and 2) the class definition
|
745
|
-
* strip unwanted space because that will mess up the horizontal alignment of the output.
|
746
|
-
* use C-style printf formatting to align the text into two columns
|
747
|
-
|
748
|
-
|
749
|
-
----
|
796
|
+
#### More YouTube: Differentiating Success and Failure
|
750
797
|
|
751
798
|
Let's go a little crazy with the YouTube example.
|
752
799
|
Let's have the video that loads be different for the success or failure
|
@@ -792,7 +839,9 @@ Then when I issue a command that succeeds, the Hallelujah Chorus is played:
|
|
792
839
|
|
793
840
|
----
|
794
841
|
|
795
|
-
|
842
|
+
#### Reformatting Source Code for Help Text
|
843
|
+
|
844
|
+
Another formatting example...I wanted to reformat this source code...
|
796
845
|
|
797
846
|
```
|
798
847
|
'i' => Inspect
|
@@ -820,7 +869,61 @@ but it was an interesting exercise and made it easy to try different formats. He
|
|
820
869
|
```
|
821
870
|
|
822
871
|
|
872
|
+
#### Reformatting Grep Output
|
823
873
|
|
874
|
+
I was recently asked to provide a schema for the data in my `rock_books` accounting gem. `rock_books` data is intended to be very small in size, and no data base is used. Instead, the input data is parsed on every run, and reports generated on demand. However, there are data structures (actually class instances) in memory at runtime, and their classes inherit from `Struct`.
|
875
|
+
The definition lines look like this one:
|
876
|
+
|
877
|
+
```
|
878
|
+
class JournalEntry < Struct.new(:date, :acct_amounts, :doc_short_name, :description, :receipts)
|
879
|
+
```
|
880
|
+
|
881
|
+
The `grep` command line utility prepends each of these matches with a string like this:
|
882
|
+
|
883
|
+
```
|
884
|
+
lib/rock_books/documents/journal_entry.rb:
|
885
|
+
```
|
886
|
+
|
887
|
+
So this is what worked well for me:
|
888
|
+
|
889
|
+
```
|
890
|
+
➜ ~ grep Struct **/*.rb | grep -v OpenStruct | rexe -ml \
|
891
|
+
"a = \
|
892
|
+
gsub('lib/rock_books/', '')\
|
893
|
+
.gsub('< Struct.new', '')\
|
894
|
+
.gsub('; end', '')\
|
895
|
+
.split('.rb:')\
|
896
|
+
.map(&:strip);\
|
897
|
+
\
|
898
|
+
%q{%-40s %-s} % [a[0] + %q{.rb}, a[1]]"
|
899
|
+
```
|
900
|
+
|
901
|
+
...which produced this output:
|
902
|
+
|
903
|
+
```
|
904
|
+
cmd_line/command_line_interface.rb class Command (:min_string, :max_string, :action)
|
905
|
+
documents/book_set.rb class BookSet (:run_options, :chart_of_accounts, :journals)
|
906
|
+
documents/journal.rb class Entry (:date, :amount, :acct_amounts, :description)
|
907
|
+
documents/journal_entry.rb class JournalEntry (:date, :acct_amounts, :doc_short_name, :description, :receipts)
|
908
|
+
documents/journal_entry_builder.rb class JournalEntryBuilder (:journal_entry_context)
|
909
|
+
reports/report_context.rb class ReportContext (:chart_of_accounts, :journals, :page_width)
|
910
|
+
types/account.rb class Account (:code, :type, :name)
|
911
|
+
types/account_type.rb class AccountType (:symbol, :singular_name, :plural_name)
|
912
|
+
types/acct_amount.rb class AcctAmount (:date, :code, :amount, :journal_entry_context)
|
913
|
+
types/journal_entry_context.rb class JournalEntryContext (:journal, :linenum, :line)
|
914
|
+
```
|
915
|
+
|
916
|
+
Although there's a lot going on here, the vertical and horizontal alignments and spacing make the code
|
917
|
+
straightforward to follow. Here's what it does:
|
918
|
+
|
919
|
+
* grep the code base for `"Struct"`
|
920
|
+
* exclude references to `"OpenStruct"` with `grep -v`
|
921
|
+
* remove unwanted text with `gsub`
|
922
|
+
* split the line into 1) a filespec relative to `lib/rockbooks`, and 2) the class definition
|
923
|
+
* strip unwanted space because that will mess up the horizontal alignment of the output.
|
924
|
+
* use C-style printf formatting to align the text into two columns
|
925
|
+
|
926
|
+
|
824
927
|
### Conclusion
|
825
928
|
|
826
929
|
`rexe` is not revolutionary technology, it's just plumbing that removes parsing,
|
@@ -873,3 +976,4 @@ Here is a _start_ at a method that opens a resource portably across operating sy
|
|
873
976
|
end
|
874
977
|
```
|
875
978
|
|
979
|
+
[^3]: It is an interesting quirk of the Ruby language that `ENV.to_s` returns `"ENV"` and not the contents of the `ENV` object. As a result, most of the other output formats will return some form of `"ENV"`. You can handle this by specifying `ENV.to_h`.
|