rexe 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +120 -47
- data/exe/rexe +6 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdd31e24705dfe69cc4f83f5529d1fd528401cb1a675e4203c037c92c4d88eae
|
4
|
+
data.tar.gz: '08e378d2729a9af62773deed3f4b653e702b97835e08ceb1b77622eda78d63be'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb5f6e5d5a8a19b18fd6ebdd6e5a12bdd6defe25638a91a9602697ba36057bbc905f1c0fb64ba30f830651bb825566eec455d94570f21751458e8c29ad371a0a
|
7
|
+
data.tar.gz: 676a94dfa2890c7711b6863dd9840c22cc402d09c940d4eace18832f78e254ff96fb1bf226e0f795c42da8c9f3c17f7630df68d54a7544bf54f8033a71cf2dfb
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,9 @@ title: The `rexe` Command Line Executor and Filter
|
|
3
3
|
date: 2019-02-15
|
4
4
|
---
|
5
5
|
|
6
|
+
[Caution: This is a long article! If you lose patience reading it, I suggest skimming the headings
|
7
|
+
and the source code, and at minimum, reading the Conclusion.]
|
8
|
+
|
6
9
|
I love the power of the command line, but not the awkwardness of shell scripting
|
7
10
|
languages. Sure, there's a lot that can be done with them, but it doesn't take
|
8
11
|
long before I get frustrated with their bluntness and verbosity.
|
@@ -21,24 +24,31 @@ An excerpt of the output follows the code:
|
|
21
24
|
|
22
25
|
```
|
23
26
|
➜ ~ export EUR_RATES_JSON=`curl https://api.exchangeratesapi.io/latest`
|
24
|
-
➜ ~ echo $EUR_RATES_JSON | ruby -r json -r
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}
|
27
|
+
➜ ~ echo $EUR_RATES_JSON | ruby -r json -r yaml -e 'puts JSON.parse(STDIN.read).to_yaml'
|
28
|
+
---
|
29
|
+
rates:
|
30
|
+
MXN: 21.96
|
31
|
+
AUD: 1.5964
|
32
|
+
HKD: 8.8092
|
33
|
+
...
|
34
|
+
base: EUR
|
35
|
+
date: '2019-03-08'
|
34
36
|
```
|
35
37
|
|
36
|
-
However, the configuration setup (the `require`s)
|
37
|
-
approach.
|
38
|
+
However, the configuration setup (the `require`s) along with the reading, parsing, and formatting
|
39
|
+
make the command long and tedious, discouraging this approach.
|
38
40
|
|
39
41
|
### Rexe
|
40
42
|
|
41
|
-
Enter the `rexe` script
|
43
|
+
Enter the `rexe` script: [^1]
|
44
|
+
|
45
|
+
Among other things, `rexe` provides switch-activated input parsing and output formatting so that converting
|
46
|
+
from one format to another is trivial.
|
47
|
+
This command does the same thing as the previous `ruby` command:
|
48
|
+
|
49
|
+
```
|
50
|
+
➜ ~ echo $EUR_RATES_JSON | rexe -mb -ij -oy self
|
51
|
+
```
|
42
52
|
|
43
53
|
`rexe` is at https://github.com/keithrbennett/rexe and can be installed with
|
44
54
|
`gem install rexe`. `rexe` provides several ways to simplify Ruby on the command
|
@@ -47,10 +57,12 @@ line, tipping the scale so that it is practical to do it more often.
|
|
47
57
|
Here is `rexe`'s help text as of the time of this writing:
|
48
58
|
|
49
59
|
```
|
50
|
-
rexe -- Ruby Command Line Executor/Filter -- v0.10.
|
60
|
+
rexe -- Ruby Command Line Executor/Filter -- v0.10.2 -- https://github.com/keithrbennett/rexe
|
51
61
|
|
52
62
|
Executes Ruby code on the command line, optionally taking standard input and writing to standard output.
|
53
63
|
|
64
|
+
rexe [options] 'Ruby source code'
|
65
|
+
|
54
66
|
Options:
|
55
67
|
|
56
68
|
-c --clear_options Clear all previous command line options specified up to now
|
@@ -65,7 +77,7 @@ Options:
|
|
65
77
|
-ml line mode; each line is ingested as a separate string
|
66
78
|
-me enumerator mode
|
67
79
|
-mb big string mode; all lines combined into single multiline string
|
68
|
-
-mn (default) no input mode; no special handling of input; self is
|
80
|
+
-mn (default) no input mode; no special handling of input; self is an Object.new
|
69
81
|
-n, --[no-]noop Do not execute the code (useful with -v); see note (1) below
|
70
82
|
-o, --output_format FORMAT Output format (puts is default):
|
71
83
|
-oi Inspect
|
@@ -76,7 +88,7 @@ Options:
|
|
76
88
|
-op Puts (default)
|
77
89
|
-os to_s
|
78
90
|
-oy YAML
|
79
|
-
-r, --require
|
91
|
+
-r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated, or ! to clear
|
80
92
|
-v, --[no-]verbose verbose mode (logs to stderr); see note (1) below
|
81
93
|
|
82
94
|
If there is an .rexerc file in your home directory, it will be run as Ruby code
|
@@ -89,16 +101,6 @@ so that you can specify options implicitly (e.g. `export REXE_OPTIONS="-r awesom
|
|
89
101
|
-v no, -v yes, -v false, -v true, -v n, -v y, -v +, but not -v -
|
90
102
|
```
|
91
103
|
|
92
|
-
For consistency with the `ruby` interpreter we called previously, `rexe` supports requires with the `-r` option, but as one tiny improvement it also allows grouping them together using commas:
|
93
|
-
|
94
|
-
```
|
95
|
-
vvvvvvvvvvvvvvvvvvvvv
|
96
|
-
➜ ~ echo $EUR_RATES_JSON | rexe -r json,awesome_print 'ap JSON.parse(STDIN.read)'
|
97
|
-
^^^^^^^^^^^^^^^^^^^^^
|
98
|
-
```
|
99
|
-
|
100
|
-
This command produces the same results as the previous `ruby` one.
|
101
|
-
|
102
104
|
### Simplifying the Rexe Invocation with Configuration
|
103
105
|
|
104
106
|
`rexe` provides two approaches to configuration:
|
@@ -271,9 +273,12 @@ eybdoog
|
|
271
273
|
`reverse` is implicitly called on each line of standard input. `self`
|
272
274
|
is the input line in each call (we could also have used `self.reverse` but the `self` would have been redundant.).
|
273
275
|
|
274
|
-
Be aware that
|
275
|
-
is
|
276
|
-
|
276
|
+
Be aware that although you can control the _content_ of output records,
|
277
|
+
there is no way to selectively _exclude_ records from being output. Even if the result of the code
|
278
|
+
is nil or the empty string, a newline will be output. If this is an issue, you could do one of the following:
|
279
|
+
|
280
|
+
* use Enumerator mode and call `select`, `filter`, `reject`, etc.
|
281
|
+
* use the `-on` _no output_ mode and call `puts` explicitly for the output you _do_ want
|
277
282
|
|
278
283
|
|
279
284
|
#### -me "Enumerator" Filter Mode
|
@@ -299,23 +304,21 @@ Since `self` is an enumerable, we can call `first` and then `each_with_index`.
|
|
299
304
|
|
300
305
|
#### -mb "Big String" Filter Mode
|
301
306
|
|
302
|
-
In this mode, all standard input is combined into a single, (possibly
|
303
|
-
large string, with newline characters joining the lines in the string.
|
307
|
+
In this mode, all standard input is combined into a single, (possibly
|
308
|
+
large) string, with newline characters joining the lines in the string.
|
304
309
|
|
305
|
-
A good example of when you would use this is when you parse JSON or YAML text;
|
310
|
+
A good example of when you would use this is when you parse JSON or YAML text;
|
311
|
+
you need to pass the entire (probably) multiline string to the parse method.
|
312
|
+
This is the mode that was used in the first `rexe` example in this article.
|
306
313
|
|
307
|
-
An earlier example would be more simply specified using this mode, since `STDIN.read` could be replaced with `self`:
|
308
|
-
|
309
|
-
```
|
310
|
-
➜ ~ echo $EUR_RATES_JSON | rexe -mb -r awesome_print,json 'ap JSON.parse(self)'
|
311
|
-
```
|
312
314
|
|
313
315
|
#### -mn "No Input" Executor Mode -- The Default
|
314
316
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
317
|
+
In this mode, no special handling of standard input is done at all;
|
318
|
+
if you want standard input you need to code it yourself (e.g. with `STDIN.read`).
|
319
|
+
|
320
|
+
`self` evaluates to a new instance of `Object`, which would be used
|
321
|
+
if you defined methods, constants, instance variables, etc., in your code.
|
319
322
|
|
320
323
|
|
321
324
|
#### Filter Input Mode Memory Considerations
|
@@ -325,9 +328,9 @@ If you may have more input than would fit in memory, you can do the following:
|
|
325
328
|
* use `-ml` (line) mode so you are fed only 1 line at a time
|
326
329
|
* use an Enumerator, either by specifying the `-me` (enumerator) mode option,
|
327
330
|
or using `-mn` (no input) mode in conjunction with something like `STDIN.each_line`. Then:
|
328
|
-
|
331
|
+
* Make sure not to call any methods (e.g. `map`, `select`)
|
329
332
|
that will produce an array of all the input because that will pull all the records into memory, or:
|
330
|
-
|
333
|
+
* use [lazy enumerators](https://www.honeybadger.io/blog/using-lazy-enumerators-to-work-with-large-files-in-ruby/)
|
331
334
|
|
332
335
|
|
333
336
|
|
@@ -396,7 +399,8 @@ so calls to your custom methods _look_ like built in language commands and keywo
|
|
396
399
|
|
397
400
|
One complication of using utilities like `rexe` where Ruby code is specified on the shell command line is that
|
398
401
|
you need to be careful about the shell's special treatment of certain characters. For this reason, it is often
|
399
|
-
necessary to quote the Ruby code. You can use single or double quotes
|
402
|
+
necessary to quote the Ruby code. You can use single or double quotes to have the shell treat your source code
|
403
|
+
as a single argument.
|
400
404
|
An excellent reference for how they differ is [here](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash).
|
401
405
|
|
402
406
|
Feel free to fall back on Ruby's super useful `%q{}` and `%Q{}`, equivalent to single and double quotes, respectively.
|
@@ -454,6 +458,70 @@ If I add `| pbcopy` to the rexe command, then that output text would be copied i
|
|
454
458
|
displayed in the terminal, and I could then paste it in my editor.
|
455
459
|
|
456
460
|
|
461
|
+
### Multiline Ruby Commands
|
462
|
+
|
463
|
+
Although `rexe` is cleanest with short one liners, you may want to use it to include nontrivial Ruby code
|
464
|
+
in your shell script as well. If you do this, you may need to:
|
465
|
+
|
466
|
+
* add trailing backslashes to lines of Ruby code
|
467
|
+
* use %q{} and %Q{} in your Ruby code instead of single and double quotes,
|
468
|
+
since the quotes have special meaning to the shell
|
469
|
+
|
470
|
+
|
471
|
+
### The Use of Semicolons
|
472
|
+
|
473
|
+
You will probably find yourself using semicolons much more often than usual when you use `rexe`.
|
474
|
+
Obviously you would need them to separate statements on the same line:
|
475
|
+
|
476
|
+
```
|
477
|
+
➜ ~ cowsay hello | rexe -me "print %Q{\u001b[33m}; puts to_a"
|
478
|
+
```
|
479
|
+
|
480
|
+
What might not be so obvious is that you _also_ need them if each statement is on its own line.
|
481
|
+
For example, here is an example without a semicolon:
|
482
|
+
|
483
|
+
```
|
484
|
+
➜ ~ cowsay hello | rexe -me "print %Q{\u001b[33m} \
|
485
|
+
puts to_a"
|
486
|
+
|
487
|
+
/Users/kbennett/.rvm/gems/ruby-2.6.0/gems/rexe-0.10.1/exe/rexe:256:in `eval':
|
488
|
+
(eval):1: syntax error, unexpected tIDENTIFIER, expecting '}' (SyntaxError)
|
489
|
+
...new { print %Q{\u001b[33m} puts to_a }
|
490
|
+
... ^~~~
|
491
|
+
```
|
492
|
+
|
493
|
+
The shell combines all backslash terminated lines into a single line of text, so when the Ruby
|
494
|
+
interpreter sees your code, it's all in a single line. Adding the semicolon fixes the problem:
|
495
|
+
|
496
|
+
```
|
497
|
+
➜ ~ cowsay hello | rexe -me "print %Q{\u001b[33m}; \
|
498
|
+
puts to_a"
|
499
|
+
|
500
|
+
eval_context_object: #<Enumerator:0x00007f92b1972840>
|
501
|
+
_______
|
502
|
+
< hello >
|
503
|
+
-------
|
504
|
+
\ ^__^
|
505
|
+
\ (oo)\_______
|
506
|
+
(__)\ )\/\
|
507
|
+
||----w |
|
508
|
+
|| ||
|
509
|
+
```
|
510
|
+
|
511
|
+
|
512
|
+
### Comma Separated Requires and Loads
|
513
|
+
|
514
|
+
For consistency with the `ruby` interpreter, `rexe` supports requires with the `-r` option, but
|
515
|
+
also allows grouping them together using commas:
|
516
|
+
|
517
|
+
```
|
518
|
+
vvvvvvvvvvvvvvvvvvvvv
|
519
|
+
➜ ~ echo $EUR_RATES_JSON | rexe -r json,awesome_print 'ap JSON.parse(STDIN.read)'
|
520
|
+
^^^^^^^^^^^^^^^^^^^^^
|
521
|
+
```
|
522
|
+
|
523
|
+
Files loaded with the `-l` option are treated the same way.
|
524
|
+
|
457
525
|
### More Examples
|
458
526
|
|
459
527
|
Here are some more examples to illustrate the use of `rexe`.
|
@@ -642,15 +710,20 @@ configuration from your command line so that you can focus on the high level
|
|
642
710
|
task at hand.
|
643
711
|
|
644
712
|
When we think of a new piece of software, we usually think "what would this be
|
645
|
-
helpful with now?". However, the power of `rexe` is not so much what can
|
646
|
-
with it in a single use case now, but rather what will
|
647
|
-
used to the concept and my supporting code and its uses evolve.
|
713
|
+
helpful with now?". However, for me, the power of `rexe` is not so much what I can do
|
714
|
+
with it in a single use case now, but rather what will I be able to do with it over time
|
715
|
+
as I get used to the concept and my supporting code and its uses evolve.
|
648
716
|
|
649
717
|
I suggest starting to use `rexe` even for modest improvements in workflow, even
|
650
718
|
if it doesn't seem compelling. There's a good chance that as you use it over
|
651
719
|
time, new ideas will come to you and the workflow improvements will increase
|
652
720
|
exponentially.
|
653
721
|
|
722
|
+
A word of caution though --
|
723
|
+
the complexity and difficulty of sharing your `rexe` scripts across systems
|
724
|
+
will be proportional to the extent to which you use environment variables
|
725
|
+
and loaded files for configuration and shared code.
|
726
|
+
Be responsible and disciplined in making this configuration as organized as possible.
|
654
727
|
|
655
728
|
#### Footnotes
|
656
729
|
|
data/exe/rexe
CHANGED
@@ -10,7 +10,7 @@ require 'shellwords'
|
|
10
10
|
|
11
11
|
class Rexe < Struct.new(:input_format, :input_mode, :loads, :output_format, :requires, :verbose, :noop)
|
12
12
|
|
13
|
-
VERSION = '0.10.
|
13
|
+
VERSION = '0.10.2'
|
14
14
|
|
15
15
|
def initialize
|
16
16
|
clear_options
|
@@ -19,6 +19,7 @@ class Rexe < Struct.new(:input_format, :input_mode, :loads, :output_format, :req
|
|
19
19
|
|
20
20
|
# Used as an initializer and also when `-!` is specified on the command line.
|
21
21
|
def clear_options
|
22
|
+
self.input_format = :none
|
22
23
|
self.input_mode = :no_input
|
23
24
|
self.output_format = :puts
|
24
25
|
self.loads = []
|
@@ -36,6 +37,8 @@ class Rexe < Struct.new(:input_format, :input_mode, :loads, :output_format, :req
|
|
36
37
|
|
37
38
|
Executes Ruby code on the command line, optionally taking standard input and writing to standard output.
|
38
39
|
|
40
|
+
rexe [options] 'Ruby source code'
|
41
|
+
|
39
42
|
Options:
|
40
43
|
|
41
44
|
-c --clear_options Clear all previous command line options specified up to now
|
@@ -50,7 +53,7 @@ class Rexe < Struct.new(:input_format, :input_mode, :loads, :output_format, :req
|
|
50
53
|
-ml line mode; each line is ingested as a separate string
|
51
54
|
-me enumerator mode
|
52
55
|
-mb big string mode; all lines combined into single multiline string
|
53
|
-
-mn (default) no input mode; no special handling of input; self is
|
56
|
+
-mn (default) no input mode; no special handling of input; self is an Object.new
|
54
57
|
-n, --[no-]noop Do not execute the code (useful with -v); see note (1) below
|
55
58
|
-o, --output_format FORMAT Output format (puts is default):
|
56
59
|
-oi Inspect
|
@@ -61,7 +64,7 @@ class Rexe < Struct.new(:input_format, :input_mode, :loads, :output_format, :req
|
|
61
64
|
-op Puts (default)
|
62
65
|
-os to_s
|
63
66
|
-oy YAML
|
64
|
-
-r, --require
|
67
|
+
-r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated, or ! to clear
|
65
68
|
-v, --[no-]verbose verbose mode (logs to stderr); see note (1) below
|
66
69
|
|
67
70
|
If there is an .rexerc file in your home directory, it will be run as Ruby code
|