rexe 1.0.3 → 1.5.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 +40 -0
- data/README.md +93 -82
- data/exe/rexe +118 -80
- data/rexe.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7477c149efa64d0b00e4127d5219546c7ef1559fb7708ca8b389a9ef48c7348
|
4
|
+
data.tar.gz: 76114118d28be5a81561f8c67af9727fca5201a5ca443d0cdc6d60f5431451a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 615ff910e6a79cdc38b574503253871e5141bf027f6753aaa2375a4b8e2a4108f2ebdd6eb4532dbd46daf655212ac8f6583b538f103164abcc1264e84ae71450
|
7
|
+
data.tar.gz: 6cd017a263416d521de4c1a8b55cdba5fb55605a053d3bb39e019c1521f19c1549eeed715cc9c8c37e90dbe7109681a27de56ee8ef6e53ffa41c337ebd2fb29a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,45 @@
|
|
1
1
|
## rexe -- Ruby Command Line Executor/Filter
|
2
2
|
|
3
|
+
### 1.5.0
|
4
|
+
|
5
|
+
* Switch from AwesomePrint to AmazingPrint, and change all references in text, help, etc.
|
6
|
+
|
7
|
+
|
8
|
+
### 1.4.1
|
9
|
+
|
10
|
+
* As of later versions of Ruby, `stringio` is a gem and must be required. Fixed.
|
11
|
+
|
12
|
+
|
13
|
+
### 1.4.0
|
14
|
+
|
15
|
+
* Handle Bundler deprecation of `with_clean_env` method.
|
16
|
+
* Mark entire file frozen_string_literal: true.
|
17
|
+
|
18
|
+
|
19
|
+
### 1.3.1
|
20
|
+
|
21
|
+
* Add Awesome Print and Pretty Print output formats to help.
|
22
|
+
|
23
|
+
|
24
|
+
### 1.3.0
|
25
|
+
|
26
|
+
* Document --project-url option.
|
27
|
+
* Add undocumented option --open-project to output Github project URL.
|
28
|
+
* Simplify test as per @davetron5000's array based approach.
|
29
|
+
* Fix context do/end in test code.
|
30
|
+
* Froze strings: VERSION, PROJECT_URL, help_text.
|
31
|
+
|
32
|
+
|
33
|
+
### 1.2.0
|
34
|
+
|
35
|
+
* Add --project-url option to output project URL on Github, then exit
|
36
|
+
|
37
|
+
|
38
|
+
### 1.1.0
|
39
|
+
|
40
|
+
* Enable specifying different output formats for tty and block devices. (#4)
|
41
|
+
* Outputs exception text on error instead of just exception class.
|
42
|
+
|
3
43
|
|
4
44
|
### 1.0.3
|
5
45
|
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
__Rexe__ is a Ruby script and gem that multiplies Ruby's usefulness and conciseness on the command line by:
|
4
4
|
|
5
|
-
* automating parsing and formatting using JSON, YAML, Ruby marshalling,
|
5
|
+
* automating parsing and formatting using JSON, YAML, Ruby marshalling, Amazing Print, and others
|
6
6
|
* simplifying the use of Ruby as a shell filter, optionally predigesting input as lines, an enumerator, or one big string
|
7
7
|
* extracting the plumbing from the command line; requires and other options can be set in an environment variable
|
8
8
|
* enabling the loading of Ruby helper files to keep your code DRY and your command line code high level
|
@@ -24,8 +24,8 @@ Sometimes a good solution is to combine Ruby and shell scripting on the same com
|
|
24
24
|
Let's start by seeing what the Ruby interpreter already provides. Here we use `ruby` on the command line, using an intermediate environment variable to simplify the logic and save the data for use by future commands. An excerpt of the output follows the code:
|
25
25
|
|
26
26
|
```bash
|
27
|
-
|
28
|
-
|
27
|
+
$ export EUR_RATES_JSON=`curl https://api.exchangeratesapi.io/latest`
|
28
|
+
$ echo $EUR_RATES_JSON | ruby -r json -r yaml -e 'puts JSON.parse(STDIN.read).to_yaml'
|
29
29
|
```
|
30
30
|
```yaml
|
31
31
|
---
|
@@ -45,13 +45,13 @@ Unfortunately, the configuration setup (the `require`s) along with the reading,
|
|
45
45
|
Rexe [see footnote ^1 regarding its origin] can simplify such commands. Among other things, rexe provides switch-activated input parsing and output formatting so that converting from one format to another is trivial. The previous `ruby` command can be expressed in `rexe` as:
|
46
46
|
|
47
47
|
```bash
|
48
|
-
|
48
|
+
$ echo $EUR_RATES_JSON | rexe -mb -ij -oy self
|
49
49
|
```
|
50
50
|
|
51
51
|
Or, even more concisely (`self` is the default Ruby source code for rexe commands):
|
52
52
|
|
53
53
|
```bash
|
54
|
-
|
54
|
+
$ echo $EUR_RATES_JSON | rexe -mb -ij -oy
|
55
55
|
```
|
56
56
|
|
57
57
|
The command options may seem cryptic, but they're logical so it shouldn't take long to learn them:
|
@@ -63,7 +63,7 @@ The command options may seem cryptic, but they're logical so it shouldn't take l
|
|
63
63
|
If input comes from a JSON or YAML file, rexe determines the input format from the file's extension, and it's even simpler:
|
64
64
|
|
65
65
|
```bash
|
66
|
-
|
66
|
+
$ rexe -f eur_rates.json -oy
|
67
67
|
```
|
68
68
|
|
69
69
|
Rexe is at https://github.com/keithrbennett/rexe and can be installed with `gem install rexe`. Rexe provides several ways to simplify Ruby on the command line, tipping the scale so that it is practical to do it more often.
|
@@ -73,7 +73,7 @@ Rexe is at https://github.com/keithrbennett/rexe and can be installed with `gem
|
|
73
73
|
Here is rexe's help text as of the time of this writing:
|
74
74
|
|
75
75
|
```
|
76
|
-
rexe -- Ruby Command Line Executor/Filter -- v1.0
|
76
|
+
rexe -- Ruby Command Line Executor/Filter -- v1.5.0 -- https://github.com/keithrbennett/rexe
|
77
77
|
|
78
78
|
Executes Ruby code on the command line,
|
79
79
|
optionally automating management of standard input and standard output,
|
@@ -107,14 +107,18 @@ Options:
|
|
107
107
|
-n, --[no-]noop Do not execute the code (useful with -g);
|
108
108
|
For true: yes, true, y, +; for false: no, false, n
|
109
109
|
-o, --output_format FORMAT Output format, defaults to -on (no output):
|
110
|
+
-oa Amazing Print
|
110
111
|
-oi Inspect
|
111
112
|
-oj JSON
|
112
113
|
-oJ Pretty JSON
|
113
114
|
-om Marshal
|
114
115
|
-on No Output (default)
|
115
116
|
-op Puts
|
117
|
+
-oP Pretty Print
|
116
118
|
-os to_s
|
117
119
|
-oy YAML
|
120
|
+
If 2 letters are provided, 1st is for tty devices, 2nd for block
|
121
|
+
--project-url Outputs project URL on Github, then exits
|
118
122
|
-r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
|
119
123
|
! to clear all, or precede a name with '-' to remove
|
120
124
|
-v, --version Prints version and exits
|
@@ -131,7 +135,7 @@ before processing the input.
|
|
131
135
|
|
132
136
|
If there is a REXE_OPTIONS environment variable, its content will be prepended
|
133
137
|
to the command line so that you can specify options implicitly
|
134
|
-
(e.g. `export REXE_OPTIONS="-r
|
138
|
+
(e.g. `export REXE_OPTIONS="-r amazing_print,yaml"`)
|
135
139
|
```
|
136
140
|
|
137
141
|
### Simplifying the Rexe Invocation
|
@@ -150,15 +154,15 @@ The `REXE_OPTIONS` environment variable can contain command line options that wo
|
|
150
154
|
Instead of this:
|
151
155
|
|
152
156
|
```bash
|
153
|
-
|
157
|
+
$ rexe -r wifi-wand -oa WifiWand::MacOsModel.new.wifi_info
|
154
158
|
```
|
155
159
|
|
156
160
|
you can do this:
|
157
161
|
|
158
162
|
```bash
|
159
|
-
|
160
|
-
|
161
|
-
|
163
|
+
$ export REXE_OPTIONS="-r wifi-wand -oa"
|
164
|
+
$ rexe WifiWand::MacOsModel.new.wifi_info
|
165
|
+
$ # [more rexe commands with the same options]
|
162
166
|
```
|
163
167
|
|
164
168
|
Putting configuration options in `REXE_OPTIONS` effectively creates custom defaults, and is useful when you use the same options in most or all of your commands. Any options specified on the rexe command line will override the environment variable options.
|
@@ -185,7 +189,7 @@ To digress a bit, why would you want this? You might want to be able to go to an
|
|
185
189
|
Here is an example of how you might use the `valkyries` method, assuming the above configuration is loaded from your `~/.rexerc` file or an explicitly loaded file:
|
186
190
|
|
187
191
|
```bash
|
188
|
-
|
192
|
+
$ tar czf /tmp/my-whole-user-space.tar.gz ~ ; rexe valkyries
|
189
193
|
```
|
190
194
|
|
191
195
|
(Note that `;` is used rather than `&&` because we want to hear the music whether or not the command succeeds.)
|
@@ -209,7 +213,7 @@ end
|
|
209
213
|
...which you could then call like this:
|
210
214
|
|
211
215
|
```bash
|
212
|
-
|
216
|
+
$ tar czf /tmp/my-whole-user-space.tar.gz ~ ; rexe 'play(:hallelujah)'
|
213
217
|
```
|
214
218
|
|
215
219
|
(You need to quote the `play` call because otherwise the shell will process and remove the parentheses. Alternatively you could escape the parentheses with backslashes.)
|
@@ -222,27 +226,29 @@ One of the examples at the end of this articles shows how you could have differe
|
|
222
226
|
A log entry is optionally output to standard error after completion of the code. This entry is a hash representation (to be precise, `to_h`) of the `$RC` OpenStruct described in the $RC section below. It contains the version, date/time of execution, source code to be evaluated, options (after parsing both the `REXE_OPTIONS` environment variable and the command line), and the execution time of your Ruby code:
|
223
227
|
|
224
228
|
```bash
|
225
|
-
|
229
|
+
$ echo $EUR_RATES_JSON | rexe -gy -ij -mb -oa -n self
|
226
230
|
```
|
227
231
|
```yaml
|
228
232
|
---
|
229
233
|
:count: 0
|
230
|
-
:rexe_version: 1.
|
231
|
-
:start_time: '2019-
|
234
|
+
:rexe_version: 1.3.1
|
235
|
+
:start_time: '2019-09-11T13:28:46+07:00'
|
232
236
|
:source_code: self
|
233
237
|
:options:
|
234
238
|
:input_filespec:
|
235
239
|
:input_format: :json
|
236
240
|
:input_mode: :one_big_string
|
237
241
|
:loads: []
|
238
|
-
:output_format: :
|
242
|
+
:output_format: :amazing_print
|
243
|
+
:output_format_tty: :amazing_print
|
244
|
+
:output_format_block: :amazing_print
|
239
245
|
:requires:
|
240
|
-
-
|
246
|
+
- amazing_print
|
241
247
|
- json
|
242
248
|
- yaml
|
243
249
|
:log_format: :yaml
|
244
250
|
:noop: true
|
245
|
-
:duration_secs: 0.
|
251
|
+
:duration_secs: 0.095705
|
246
252
|
```
|
247
253
|
|
248
254
|
We specified `-gy` for YAML format; there are other formats as well (see the help output or this document) and the default is `-gn`, which means don't output the log entry at all.
|
@@ -254,7 +260,7 @@ This extra output is sent to standard error (_stderr_) instead of standard outpu
|
|
254
260
|
If you would like to append this informational output to a file(e.g. `rexe.log`), you could do something like this:
|
255
261
|
|
256
262
|
```bash
|
257
|
-
|
263
|
+
$ rexe ... -gy 2>>rexe.log
|
258
264
|
```
|
259
265
|
|
260
266
|
|
@@ -263,12 +269,13 @@ If you would like to append this informational output to a file(e.g. `rexe.log`)
|
|
263
269
|
Rexe tries to make it simple and convenient for you to handle standard input, and in different ways. Here is the help text relating to input modes:
|
264
270
|
|
265
271
|
```
|
266
|
-
-m, --input_mode MODE Input preprocessing mode (determines what `self` will be)
|
272
|
+
-m, --input_mode MODE Input preprocessing mode (determines what `self` will be)
|
273
|
+
defaults to -mn (none)
|
267
274
|
-ml line; each line is ingested as a separate string
|
268
275
|
-me enumerator (each_line on STDIN or File)
|
269
276
|
-mb big string; all lines combined into one string
|
270
|
-
-mn none (default); no input preprocessing;
|
271
|
-
self is an Object.new
|
277
|
+
-mn none (default); no input preprocessing;
|
278
|
+
self is an Object.new
|
272
279
|
```
|
273
280
|
|
274
281
|
The first three are _filter_ modes; they make standard input available to your code as `self`.
|
@@ -281,7 +288,7 @@ The last (and default) is the _executor_ mode. It merely assists you in executin
|
|
281
288
|
In this mode, your code would be called once per line of input, and in each call, `self` would evaluate to each line of text:
|
282
289
|
|
283
290
|
```bash
|
284
|
-
|
291
|
+
$ echo "hello\ngoodbye" | rexe -ml puts reverse
|
285
292
|
olleh
|
286
293
|
eybdoog
|
287
294
|
```
|
@@ -303,7 +310,7 @@ Dealing with input as an enumerator enables you to use the wealth of `Enumerable
|
|
303
310
|
Here is an example of using `-me` to add line numbers to the first 3 files in the directory listing:
|
304
311
|
|
305
312
|
```bash
|
306
|
-
|
313
|
+
$ ls / | rexe -me "first(3).each_with_index { |ln,i| puts '%5d %s' % [i, ln] }"
|
307
314
|
|
308
315
|
0 AndroidStudioProjects
|
309
316
|
1 Applications
|
@@ -356,7 +363,7 @@ The input format option is ignored if the input _mode_ is `-mn` ("no input" exec
|
|
356
363
|
|
357
364
|
Several output formats are provided for your convenience:
|
358
365
|
|
359
|
-
* `-oa` -
|
366
|
+
* `-oa` - Amazing Print - calls `.ai` on the object to get the string that `ap` would print
|
360
367
|
* `-oi` - Inspect - calls `inspect` on the object
|
361
368
|
* `-oj` - JSON - calls `to_json` on the object
|
362
369
|
* `-oJ` - Pretty JSON calls `JSON.pretty_generate` with the object
|
@@ -369,6 +376,8 @@ All formats will implicitly `require` anything needed to accomplish their task (
|
|
369
376
|
|
370
377
|
The default is `-on` to produce no output at all (unless explicitly coded to do so). If you prefer a different default such as `-op` for _puts_ mode, you can specify that in your `REXE_OPTIONS` environment variable.
|
371
378
|
|
379
|
+
If two letters are provided, the first will be used for tty devices (e.g. the terminal when not redirected or piped), and the second for block devices (e.g. when redirected or piped to another process).
|
380
|
+
|
372
381
|
You may wonder why these formats are provided, given that their functionality could be included in the custom code instead. Here's why:
|
373
382
|
|
374
383
|
* The savings in command line length goes a long way to making these commands more readable and feasible.
|
@@ -381,12 +390,12 @@ You may wonder why these formats are provided, given that their functionality co
|
|
381
390
|
Rexe also simplifies getting input from a file rather than standard input. The `-f` option takes a filespec and does with its content exactly what it would have done with standard input. This shortens:
|
382
391
|
|
383
392
|
```bash
|
384
|
-
|
393
|
+
$ cat filename.ext | rexe ...
|
385
394
|
```
|
386
395
|
...to...
|
387
396
|
|
388
397
|
```bash
|
389
|
-
|
398
|
+
$ rexe -f filename.ext ...
|
390
399
|
```
|
391
400
|
|
392
401
|
This becomes even more useful if you are using files whose extensions are `.yml`, `.yaml`, or `.json` (case insensitively). In this case the input format and mode will be set automatically for you to:
|
@@ -397,14 +406,14 @@ This becomes even more useful if you are using files whose extensions are `.yml`
|
|
397
406
|
So the example we gave above:
|
398
407
|
|
399
408
|
```bash
|
400
|
-
|
401
|
-
|
409
|
+
$ export EUR_RATES_JSON=`curl https://api.exchangeratesapi.io/latest`
|
410
|
+
$ echo $EUR_RATES_JSON | rexe -mb -ij -oy self
|
402
411
|
```
|
403
412
|
...could be changed to:
|
404
413
|
|
405
414
|
```bash
|
406
|
-
|
407
|
-
|
415
|
+
$ curl https://api.exchangeratesapi.io/latest > eur_rates.json
|
416
|
+
$ rexe -f eur_rates.json -oy self
|
408
417
|
```
|
409
418
|
|
410
419
|
Another possible win for using `-f` is that since it is a command line option, it could be specified in `REXE_OPTIONS`. This could be useful if you are doing many operations on the same file.
|
@@ -412,7 +421,7 @@ Another possible win for using `-f` is that since it is a command line option, i
|
|
412
421
|
If you need to override the input mode and format automatically configured for file input, you can simply specify the desired options on the command line _after_ the `-f`:
|
413
422
|
|
414
423
|
```bash
|
415
|
-
|
424
|
+
$ rexe -f eur_rates.json -mb -in 'puts self.class, self[0..20]'
|
416
425
|
String
|
417
426
|
{"base":"EUR","rates"
|
418
427
|
```
|
@@ -443,21 +452,23 @@ This feature is probably only useful in the filter modes, since in the executor
|
|
443
452
|
For your convenience, the information displayed in verbose mode is available to your code at runtime by accessing the `$RC` global variable, which contains an OpenStruct. Let's print out its contents using YAML:
|
444
453
|
|
445
454
|
```bash
|
446
|
-
|
455
|
+
$ rexe -oy '$RC'
|
447
456
|
```
|
448
457
|
```yaml
|
449
458
|
--- !ruby/object:OpenStruct
|
450
459
|
table:
|
451
460
|
:count: 0
|
452
|
-
:rexe_version: 1.
|
453
|
-
:start_time: '2019-
|
461
|
+
:rexe_version: 1.3.1
|
462
|
+
:start_time: '2019-09-11T13:25:53+07:00'
|
454
463
|
:source_code: "$RC"
|
455
464
|
:options:
|
456
|
-
:input_filespec:
|
465
|
+
:input_filespec:
|
457
466
|
:input_format: :none
|
458
467
|
:input_mode: :none
|
459
468
|
:loads: []
|
460
469
|
:output_format: :yaml
|
470
|
+
:output_format_tty: :yaml
|
471
|
+
:output_format_block: :yaml
|
461
472
|
:requires:
|
462
473
|
- yaml
|
463
474
|
:log_format: :none
|
@@ -468,7 +479,7 @@ modifiable: true
|
|
468
479
|
Probably most useful in that object at runtime is the record count, accessible with both `$RC.count` and `$RC.i`. This is only really useful in line mode, because in the others it will always be 0 or 1. Here is an example of how you might use it as a kind of progress indicator:
|
469
480
|
|
470
481
|
```bash
|
471
|
-
|
482
|
+
$ find / | rexe -ml -on \
|
472
483
|
'if $RC.i % 1000 == 0; puts %Q{File entry ##{$RC.i} is #{self}}; end'
|
473
484
|
```
|
474
485
|
```
|
@@ -487,22 +498,22 @@ Note that a single quote was used for the Ruby code here; if a double quote were
|
|
487
498
|
Defining methods in your loaded files enables you to effectively define a [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) for your command line use. You could use different load files for different projects, domains, or contexts, and define aliases or one line scripts to give them meaningful names. For example, if you had Ansible helper code in `~/projects/ansible-tools/rexe-ansible.rb`, you could define an alias in your startup script:
|
488
499
|
|
489
500
|
```bash
|
490
|
-
|
501
|
+
$ alias rxans="rexe -l ~/projects/ansible-tools/rexe-ansible.rb $*"
|
491
502
|
```
|
492
503
|
...and then you would have an Ansible DSL available for me to use by calling `rxans`.
|
493
504
|
|
494
505
|
In addition, since you can also call `pry` on the context of any object, you can provide a DSL in a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) (shell) trivially easily. Just to illustrate, here's how you would open a REPL on the File class:
|
495
506
|
|
496
507
|
```bash
|
497
|
-
|
508
|
+
$ ruby -r pry -e File.pry
|
498
509
|
# or
|
499
|
-
|
510
|
+
$ rexe -r pry File.pry
|
500
511
|
```
|
501
512
|
|
502
513
|
`self` would evaluate to the `File` class, so you could call class methods using only their names:
|
503
514
|
|
504
515
|
```bash
|
505
|
-
|
516
|
+
$ rexe -r pry File.pry
|
506
517
|
```
|
507
518
|
```
|
508
519
|
[6] pry(File)> size '/etc/passwd'
|
@@ -516,7 +527,7 @@ true
|
|
516
527
|
This could be really handy if you call `pry` on a custom object that has methods especially suited to your task:
|
517
528
|
|
518
529
|
```bash
|
519
|
-
|
530
|
+
$ rexe -r wifi-wand,pry WifiWand::MacOsModel.new.pry
|
520
531
|
```
|
521
532
|
```
|
522
533
|
[1] pry(#<WifiWand::MacOsModel>)> random_mac_address
|
@@ -537,25 +548,25 @@ Personally, I find single quotes more useful since I usually don't want special
|
|
537
548
|
Sometimes it doesn't matter:
|
538
549
|
|
539
550
|
```bash
|
540
|
-
|
551
|
+
$ rexe 'puts "hello"'
|
541
552
|
hello
|
542
|
-
|
553
|
+
$ rexe "puts 'hello'"
|
543
554
|
hello
|
544
555
|
```
|
545
556
|
|
546
557
|
We can also use `%q` or `%Q`, and sometimes this eliminates the needs for the outer quotes altogether:
|
547
558
|
|
548
559
|
```bash
|
549
|
-
|
560
|
+
$ rexe puts %q{hello}
|
550
561
|
hello
|
551
|
-
|
562
|
+
$ rexe puts %Q{hello}
|
552
563
|
hello
|
553
564
|
```
|
554
565
|
|
555
566
|
Sometimes the quotes to use on the outside (quoting your command in the shell) need to be chosen based on which quotes are needed on the inside. For example, in the following command, we need double quotes in Ruby in order for interpolation to work, so we use single quotes on the outside:
|
556
567
|
|
557
568
|
```bash
|
558
|
-
|
569
|
+
$ rexe puts '"The time is now #{Time.now}"'
|
559
570
|
```
|
560
571
|
```
|
561
572
|
The time is now 2019-03-29 16:41:26 +0800
|
@@ -564,7 +575,7 @@ The time is now 2019-03-29 16:41:26 +0800
|
|
564
575
|
In this case we also need to use single quotes on the outside, because we need literal double quotes in a `%Q{}` expression:
|
565
576
|
|
566
577
|
```bash
|
567
|
-
|
578
|
+
$ rexe 'puts %Q{The operating system name is "#{`uname`.chomp}".}'
|
568
579
|
```
|
569
580
|
```
|
570
581
|
The operating system name is "Darwin".
|
@@ -573,7 +584,7 @@ The operating system name is "Darwin".
|
|
573
584
|
We can eliminate the need for any quotes in the Ruby code using `%Q{}`:
|
574
585
|
|
575
586
|
```bash
|
576
|
-
|
587
|
+
$ rexe puts '%Q{The time is now #{Time.now}}'
|
577
588
|
```
|
578
589
|
```
|
579
590
|
The time is now 2019-03-29 17:06:13 +0800
|
@@ -604,7 +615,7 @@ AUD BGN BRL CAD CHF CNY CZK DKK GBP HKD HRK HUF IDR ILS INR ISK JPY KRW MXN MYR
|
|
604
615
|
The codes output are the legal arguments that could be sent to rexe's stdin as an argument in the command below. Let's find out the Euro exchange rate for _PHP_, Philippine Pesos:
|
605
616
|
|
606
617
|
```bash
|
607
|
-
|
618
|
+
$ echo PHP | rexe -ml -op -rjson \
|
608
619
|
"rate = JSON.parse(ENV['EUR_RATES_JSON'])['rates'][self];\
|
609
620
|
%Q{1 EUR = #{rate} #{self}}"
|
610
621
|
|
@@ -636,13 +647,13 @@ AUD BGN BRL PHP TRY USD ZAR
|
|
636
647
|
We could manually select that text and use system menu commands or keys to copy it to the clipboard, or we could do this:
|
637
648
|
|
638
649
|
```bash
|
639
|
-
|
650
|
+
$ echo AUD BGN BRL PHP TRY USD ZAR | pbcopy
|
640
651
|
```
|
641
652
|
|
642
653
|
After copying this line to the clipboard, we could run this:
|
643
654
|
|
644
655
|
```bash
|
645
|
-
|
656
|
+
$ pbpaste | rexe -ml -op \
|
646
657
|
"split.map(&:downcase).map { |s| %Q{ #{s}: '',} }.join(%Q{\n})"
|
647
658
|
aud: '',
|
648
659
|
bgn: '',
|
@@ -661,7 +672,7 @@ Although rexe is cleanest with short one liners, you may want to use it to inclu
|
|
661
672
|
What might not be so obvious is that you will often need to use semicolons as statement separators. For example, here is an example without a semicolon:
|
662
673
|
|
663
674
|
```bash
|
664
|
-
|
675
|
+
$ cowsay hello | rexe -me "print %Q{\u001b[33m} \
|
665
676
|
puts to_a"
|
666
677
|
```
|
667
678
|
```
|
@@ -673,13 +684,13 @@ rexe: (eval):1: syntax error, unexpected tIDENTIFIER, expecting '}'
|
|
673
684
|
The shell combines all backslash terminated lines into a single line of text, so when the Ruby interpreter sees your code, it's all in a single line:
|
674
685
|
|
675
686
|
```bash
|
676
|
-
|
687
|
+
$ cowsay hello | rexe -me "print %Q{\u001b[33m} puts to_a"
|
677
688
|
```
|
678
689
|
|
679
690
|
Adding the semicolon fixes the problem:
|
680
691
|
|
681
692
|
```bash
|
682
|
-
|
693
|
+
$ cowsay hello | rexe -me "print %Q{\u001b[33m}; \
|
683
694
|
puts to_a"
|
684
695
|
```
|
685
696
|
```
|
@@ -703,7 +714,7 @@ There may be times when you have specified a load or require on the command line
|
|
703
714
|
2) Unspecify individual requires or loads by preceding the name with `-`, e.g. `-r -rails`. Array subtraction is used, and array subtraction removes _all_ occurrences of each element of the subtracted (subtrahend) array, so:
|
704
715
|
|
705
716
|
```bash
|
706
|
-
|
717
|
+
$ rexe -n -r rails,rails,rails,-rails -gP
|
707
718
|
...
|
708
719
|
:requires=>["pp"],
|
709
720
|
...
|
@@ -714,7 +725,7 @@ There may be times when you have specified a load or require on the command line
|
|
714
725
|
We could have also extracted the requires list programmatically using `$RC` (described above) by doing this:
|
715
726
|
|
716
727
|
```bash
|
717
|
-
|
728
|
+
$ rexe -oP -r rails,rails,rails,-rails '$RC[:options][:requires]'
|
718
729
|
["pp"]
|
719
730
|
```
|
720
731
|
|
@@ -729,9 +740,9 @@ You can also clear _all_ options specified up to a certain point in time with th
|
|
729
740
|
For consistency with the `ruby` interpreter, rexe supports requires with the `-r` option, but also allows grouping them together using commas:
|
730
741
|
|
731
742
|
```bash
|
732
|
-
|
733
|
-
|
734
|
-
|
743
|
+
vvvvvvvvvvvvvvvvvv
|
744
|
+
$ echo $EUR_RATES_JSON | rexe -r json,amazing_print 'ap JSON.parse(STDIN.read)'
|
745
|
+
^^^^^^^^^^^^^^^^^^
|
735
746
|
```
|
736
747
|
|
737
748
|
Files loaded with the `-l` option are treated the same way.
|
@@ -742,9 +753,9 @@ Files loaded with the `-l` option are treated the same way.
|
|
742
753
|
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 consumed. For example, we can find out that rails takes about 0.63 seconds to load on one system by observing and comparing the execution times with and without the require (output has been abbreviated using `grep`):
|
743
754
|
|
744
755
|
```bash
|
745
|
-
|
756
|
+
$ rexe -gy -r rails 2>&1 | grep duration
|
746
757
|
:duration_secs: 0.660138
|
747
|
-
|
758
|
+
$ rexe -gy 2>&1 | grep duration
|
748
759
|
:duration_secs: 0.027781
|
749
760
|
```
|
750
761
|
(For the above to work, the `rails` gem and its dependencies need to be installed.)
|
@@ -766,29 +777,29 @@ Here are some more examples to illustrate the use of rexe.
|
|
766
777
|
To output the result to stdout, you can either call `puts` or specify the `-op` option:
|
767
778
|
|
768
779
|
```bash
|
769
|
-
|
780
|
+
$ rexe puts 1 / 3.0
|
770
781
|
0.3333333333333333
|
771
782
|
```
|
772
783
|
|
773
784
|
or:
|
774
785
|
|
775
786
|
```bash
|
776
|
-
|
787
|
+
$ rexe -op 1 / 3.0
|
777
788
|
0.3333333333333333
|
778
789
|
```
|
779
790
|
|
780
791
|
Since `*` is interpreted by the shell, if we do multiplication, we need to quote the expression:
|
781
792
|
|
782
793
|
```bash
|
783
|
-
|
794
|
+
$ rexe -op '2 * 7'
|
784
795
|
14
|
785
796
|
```
|
786
797
|
|
787
798
|
Of course, if you put the `-op` in the `REXE_OPTIONS` environment variable, you don't need to be explicit about the output:
|
788
799
|
|
789
800
|
```bash
|
790
|
-
|
791
|
-
|
801
|
+
$ export REXE_OPTIONS=-op
|
802
|
+
$ rexe '2 * 7'
|
792
803
|
14
|
793
804
|
```
|
794
805
|
|
@@ -797,10 +808,10 @@ Of course, if you put the `-op` in the `REXE_OPTIONS` environment variable, you
|
|
797
808
|
|
798
809
|
#### Outputting ENV
|
799
810
|
|
800
|
-
Output the contents of `ENV` using
|
811
|
+
Output the contents of `ENV` using AmazingPrint [see footnote ^4 regarding ENV.to_s]:
|
801
812
|
|
802
813
|
```bash
|
803
|
-
|
814
|
+
$ rexe -oa ENV
|
804
815
|
```
|
805
816
|
```
|
806
817
|
{
|
@@ -819,7 +830,7 @@ Output the contents of `ENV` using AwesomePrint [see footnote ^4 regarding ENV.t
|
|
819
830
|
Show disk space used/free on a Mac's main hard drive's main partition:
|
820
831
|
|
821
832
|
```bash
|
822
|
-
|
833
|
+
$ df -h | grep disk1s1 | rexe -ml \
|
823
834
|
"x = split; puts %Q{#{x[4]} Used: #{x[2]}, Avail: #{x[3]}}"
|
824
835
|
91% Used: 412Gi, Avail: 44Gi
|
825
836
|
```
|
@@ -833,7 +844,7 @@ Show disk space used/free on a Mac's main hard drive's main partition:
|
|
833
844
|
Show the 3 longest file names of the current directory, with their lengths, in descending order:
|
834
845
|
|
835
846
|
```bash
|
836
|
-
|
847
|
+
$ ls | rexe -ml -op "%Q{[%4d] %s} % [length, self]" | sort -r | head -3
|
837
848
|
[ 50] Agoda_Booking_ID_9999999 49_–_RECEIPT_enclosed.pdf
|
838
849
|
[ 40] 679a5c034994544aab4635ecbd50ab73-big.jpg
|
839
850
|
[ 28] 2018-abc-2019-01-16-2340.zip
|
@@ -848,11 +859,11 @@ When you right align numbers using printf formatting, sorting the lines alphabet
|
|
848
859
|
This uses an [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code) to output text to the terminal in yellow:
|
849
860
|
|
850
861
|
```bash
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
862
|
+
$ cowsay hello | rexe -me "print %Q{\u001b[33m}; puts to_a"
|
863
|
+
$ # or
|
864
|
+
$ cowsay hello | rexe -mb "print %Q{\u001b[33m}; puts self"
|
865
|
+
$ # or
|
866
|
+
$ cowsay hello | rexe "print %Q{\u001b[33m}; puts STDIN.read"
|
856
867
|
```
|
857
868
|
```
|
858
869
|
_______
|
@@ -901,13 +912,13 @@ end
|
|
901
912
|
Then when we issue a command that succeeds, the Hallelujah Chorus is played [see footnote ^2]:
|
902
913
|
|
903
914
|
```bash
|
904
|
-
|
915
|
+
$ uname; echo $? | rexe play_result_by_exit_code
|
905
916
|
```
|
906
917
|
|
907
918
|
...but when the command fails, in this case, with an executable which is not found, it plays Rick Astley's "Never Gonna Give You Up":
|
908
919
|
|
909
920
|
```bash
|
910
|
-
|
921
|
+
$ uuuuu; echo $? | rexe play_result_by_exit_code
|
911
922
|
```
|
912
923
|
|
913
924
|
----
|
@@ -929,7 +940,7 @@ Another formatting example...I wanted to reformat this source code...
|
|
929
940
|
...into something more suitable for my help text. Admittedly, the time it took to do this with rexe probably exceeded the time to do it manually, but it was an interesting exercise and made it easy to try different formats. Here it is, after copying the original text to the clipboard:
|
930
941
|
|
931
942
|
```bash
|
932
|
-
|
943
|
+
$ pbpaste | rexe -ml -op "sub(%q{'}, '-o').sub(%q{' =>}, %q{ })"
|
933
944
|
-oi Inspect
|
934
945
|
-oj JSON
|
935
946
|
-oJ Pretty JSON
|
@@ -986,7 +997,7 @@ lib/rock_books/documents/journal_entry.rb:
|
|
986
997
|
So this is what worked well for me:
|
987
998
|
|
988
999
|
```bash
|
989
|
-
|
1000
|
+
$ grep Struct **/*.rb | grep -v OpenStruct | rexe -ml -op \
|
990
1001
|
"a = \
|
991
1002
|
gsub('lib/rock_books/', '') \
|
992
1003
|
.gsub('< Struct.new', '') \
|
data/exe/rexe
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Inspired by https://github.com/thisredone/rb
|
6
6
|
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
|
7
10
|
require 'bundler'
|
8
11
|
require 'date'
|
9
12
|
require 'optparse'
|
@@ -12,7 +15,7 @@ require 'shellwords'
|
|
12
15
|
|
13
16
|
class Rexe
|
14
17
|
|
15
|
-
VERSION = '1.0
|
18
|
+
VERSION = '1.5.0'
|
16
19
|
|
17
20
|
PROJECT_URL = 'https://github.com/keithrbennett/rexe'
|
18
21
|
|
@@ -25,7 +28,7 @@ class Rexe
|
|
25
28
|
yield
|
26
29
|
rescue Exception => e
|
27
30
|
unless e.class == SystemExit
|
28
|
-
$stderr.puts(
|
31
|
+
$stderr.puts("rexe: #{e}")
|
29
32
|
$stderr.puts("Use the -h option to get help.")
|
30
33
|
exit(-1)
|
31
34
|
end
|
@@ -40,6 +43,8 @@ class Rexe
|
|
40
43
|
:input_mode,
|
41
44
|
:loads,
|
42
45
|
:output_format,
|
46
|
+
:output_format_tty,
|
47
|
+
:output_format_block,
|
43
48
|
:requires,
|
44
49
|
:log_format,
|
45
50
|
:noop)
|
@@ -53,13 +58,15 @@ class Rexe
|
|
53
58
|
|
54
59
|
def clear
|
55
60
|
self.input_filespec = nil
|
56
|
-
self.input_format
|
57
|
-
self.input_mode
|
58
|
-
self.output_format
|
59
|
-
self.
|
60
|
-
self.
|
61
|
-
self.
|
62
|
-
self.
|
61
|
+
self.input_format = :none
|
62
|
+
self.input_mode = :none
|
63
|
+
self.output_format = :none
|
64
|
+
self.output_format_tty = :none
|
65
|
+
self.output_format_block = :none
|
66
|
+
self.loads = []
|
67
|
+
self.requires = []
|
68
|
+
self.log_format = :none
|
69
|
+
self.noop = false
|
63
70
|
end
|
64
71
|
end
|
65
72
|
|
@@ -100,7 +107,7 @@ class Rexe
|
|
100
107
|
|
101
108
|
def output_formats
|
102
109
|
@output_formats ||= {
|
103
|
-
'a' => :
|
110
|
+
'a' => :amazing_print,
|
104
111
|
'i' => :inspect,
|
105
112
|
'j' => :json,
|
106
113
|
'J' => :pretty_json,
|
@@ -116,14 +123,14 @@ class Rexe
|
|
116
123
|
|
117
124
|
def formatters
|
118
125
|
@formatters ||= {
|
119
|
-
|
126
|
+
amazing_print: ->(obj) { obj.ai << "\n" },
|
120
127
|
inspect: ->(obj) { obj.inspect + "\n" },
|
121
128
|
json: ->(obj) { obj.to_json },
|
122
129
|
marshal: ->(obj) { Marshal.dump(obj) },
|
123
130
|
none: ->(_obj) { nil },
|
124
131
|
pretty_json: ->(obj) { JSON.pretty_generate(obj) },
|
125
132
|
pretty_print: ->(obj) { obj.pretty_inspect },
|
126
|
-
puts: ->(obj) { sio = StringIO.new; sio.puts(obj); sio.string },
|
133
|
+
puts: ->(obj) { require 'stringio'; sio = StringIO.new; sio.puts(obj); sio.string },
|
127
134
|
to_s: ->(obj) { obj.to_s + "\n" },
|
128
135
|
yaml: ->(obj) { obj.to_yaml },
|
129
136
|
}
|
@@ -134,7 +141,7 @@ class Rexe
|
|
134
141
|
@format_requires ||= {
|
135
142
|
json: 'json',
|
136
143
|
pretty_json: 'json',
|
137
|
-
|
144
|
+
amazing_print: 'amazing_print',
|
138
145
|
pretty_print: 'pp',
|
139
146
|
yaml: 'yaml'
|
140
147
|
}
|
@@ -173,69 +180,79 @@ class Rexe
|
|
173
180
|
|
174
181
|
|
175
182
|
private def help_text
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
183
|
+
unless @help_text
|
184
|
+
@help_text ||= <<~HEREDOC
|
185
|
+
|
186
|
+
rexe -- Ruby Command Line Executor/Filter -- v#{VERSION} -- #{PROJECT_URL}
|
187
|
+
|
188
|
+
Executes Ruby code on the command line,
|
189
|
+
optionally automating management of standard input and standard output,
|
190
|
+
and optionally parsing input and formatting output with YAML, JSON, etc.
|
191
|
+
|
192
|
+
rexe [options] [Ruby source code]
|
193
|
+
|
194
|
+
Options:
|
195
|
+
|
196
|
+
-c --clear_options Clear all previous command line options specified up to now
|
197
|
+
-f --input_file Use this file instead of stdin for preprocessed input;
|
198
|
+
if filespec has a YAML and JSON file extension,
|
199
|
+
sets input format accordingly and sets input mode to -mb
|
200
|
+
-g --log_format FORMAT Log format, logs to stderr, defaults to -gn (none)
|
201
|
+
(see -o for format options)
|
202
|
+
-h, --help Print help and exit
|
203
|
+
-i, --input_format FORMAT Input format, defaults to -in (None)
|
204
|
+
-ij JSON
|
205
|
+
-im Marshal
|
206
|
+
-in None (default)
|
207
|
+
-iy YAML
|
208
|
+
-l, --load RUBY_FILE(S) Ruby file(s) to load, comma separated;
|
209
|
+
! to clear all, or precede a name with '-' to remove
|
210
|
+
-m, --input_mode MODE Input preprocessing mode (determines what `self` will be)
|
211
|
+
defaults to -mn (none)
|
212
|
+
-ml line; each line is ingested as a separate string
|
213
|
+
-me enumerator (each_line on STDIN or File)
|
214
|
+
-mb big string; all lines combined into one string
|
215
|
+
-mn none (default); no input preprocessing;
|
216
|
+
self is an Object.new
|
217
|
+
-n, --[no-]noop Do not execute the code (useful with -g);
|
218
|
+
For true: yes, true, y, +; for false: no, false, n
|
219
|
+
-o, --output_format FORMAT Output format, defaults to -on (no output):
|
220
|
+
-oa Amazing Print
|
221
|
+
-oi Inspect
|
222
|
+
-oj JSON
|
223
|
+
-oJ Pretty JSON
|
224
|
+
-om Marshal
|
225
|
+
-on No Output (default)
|
226
|
+
-op Puts
|
227
|
+
-oP Pretty Print
|
228
|
+
-os to_s
|
229
|
+
-oy YAML
|
230
|
+
If 2 letters are provided, 1st is for tty devices, 2nd for block
|
231
|
+
--project-url Outputs project URL on Github, then exits
|
232
|
+
-r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
|
233
|
+
! to clear all, or precede a name with '-' to remove
|
234
|
+
-v, --version Prints version and exits
|
235
|
+
|
236
|
+
---------------------------------------------------------------------------------------
|
237
|
+
|
238
|
+
In many cases you will need to enclose your source code in single or double quotes.
|
239
|
+
|
240
|
+
If source code is not specified, it will default to 'self',
|
241
|
+
which is most likely useful only in a filter mode (-ml, -me, -mb).
|
242
|
+
|
243
|
+
If there is a .rexerc file in your home directory, it will be run as Ruby code
|
244
|
+
before processing the input.
|
245
|
+
|
246
|
+
If there is a REXE_OPTIONS environment variable, its content will be prepended
|
247
|
+
to the command line so that you can specify options implicitly
|
248
|
+
(e.g. `export REXE_OPTIONS="-r amazing_print,yaml"`)
|
237
249
|
|
238
250
|
HEREDOC
|
251
|
+
|
252
|
+
@help_text.freeze
|
253
|
+
end
|
254
|
+
|
255
|
+
@help_text
|
239
256
|
end
|
240
257
|
|
241
258
|
|
@@ -348,10 +365,11 @@ class Rexe
|
|
348
365
|
|
349
366
|
parser.on('-o', '--output_format FORMAT',
|
350
367
|
'Mode with which to format values for output (`-o` + [aijJmnpsy])') do |v|
|
351
|
-
|
352
|
-
options.
|
353
|
-
|
354
|
-
|
368
|
+
options.output_format_tty = lookups.output_formats[v[0]]
|
369
|
+
options.output_format_block = lookups.output_formats[v[-1]]
|
370
|
+
options.output_format = ($stdout.tty? ? options.output_format_tty : options.output_format_block)
|
371
|
+
if [options.output_format_tty, options.output_format_block].include?(nil)
|
372
|
+
raise("Bad output mode '#{v}'; each must be one of #{lookups.output_formats.keys}.")
|
355
373
|
end
|
356
374
|
end
|
357
375
|
|
@@ -375,12 +393,17 @@ class Rexe
|
|
375
393
|
exit(0)
|
376
394
|
end
|
377
395
|
|
378
|
-
# Undocumented feature
|
396
|
+
# Undocumented feature: open Github project with default web browser on a Mac
|
379
397
|
parser.on('', '--open-project') do
|
380
398
|
open_resource(PROJECT_URL)
|
381
399
|
exit(0)
|
382
400
|
end
|
383
401
|
|
402
|
+
parser.on('', '--project-url') do
|
403
|
+
puts PROJECT_URL
|
404
|
+
exit(0)
|
405
|
+
end
|
406
|
+
|
384
407
|
end.parse!
|
385
408
|
|
386
409
|
# We want to do this after all options have been processed because we don't want any clearing of the
|
@@ -528,4 +551,19 @@ class Rexe
|
|
528
551
|
end
|
529
552
|
end
|
530
553
|
|
531
|
-
|
554
|
+
|
555
|
+
def bundler_run(&block)
|
556
|
+
# This used to be an unconditional call to with_clean_env but that method is now deprecated:
|
557
|
+
# [DEPRECATED] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`.
|
558
|
+
# If you instead want the environment before bundler was originally loaded,
|
559
|
+
# use `Bundler.with_original_env`
|
560
|
+
|
561
|
+
if Bundler.respond_to?(:with_unbundled_env)
|
562
|
+
Bundler.with_unbundled_env { block.call }
|
563
|
+
else
|
564
|
+
Bundler.with_clean_env { block.call }
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
|
569
|
+
bundler_run { Rexe::Main.new.call }
|
data/rexe.gemspec
CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
39
39
|
spec.require_paths = ["lib"]
|
40
40
|
|
41
|
-
spec.add_dependency "
|
41
|
+
spec.add_dependency "amazing_print"
|
42
42
|
|
43
43
|
spec.add_development_dependency "bundler", "~> 2.0"
|
44
44
|
spec.add_development_dependency "os"
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rexe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Bennett
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: amazing_print
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
requirements: []
|
128
|
-
rubygems_version: 3.
|
128
|
+
rubygems_version: 3.1.2
|
129
129
|
signing_key:
|
130
130
|
specification_version: 4
|
131
131
|
summary: Ruby Command Line Executor
|