rexe 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +206 -105
  4. data/exe/rexe +40 -30
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 982527b8b9d991102d3a3a1eb5ae83e7235cea0b77b782921ab6e203a5c70f42
4
- data.tar.gz: a586d1f5c68beaf81692f23920e1c2e8c435e44e7095b38e90a70f4b113fa32c
3
+ metadata.gz: 3a85b226f2d7d337d03476286bbe79f7b594519f93370198f8ae0581cec3616c
4
+ data.tar.gz: 77e944cb23215f4ed522e5c13b8f4457f0cbefcac67b26da8218d700d729a079
5
5
  SHA512:
6
- metadata.gz: ffb97f15aae0ed61a2acabdfa2d330d15814d2c4ada682c1eae0099d8b5dd9262d1fa7e47142051d18ca5f5efddee2ef755efeb9b22d555bf2621327305e572c
7
- data.tar.gz: ce5ae9551e7fad281a7505bb99c4749098eb9560fd377dc33ea3341ae29e5d4d490bfea807b426e36bf79f7cfbc597416da2cf50ab475343854908d49d131708
6
+ metadata.gz: 4c88dd6b11138b9339f73439687a847332957cb50b66a1c7bde4e38d6fbc4cc4c9931e0e40111054d9b0e784ec7ac0201e172d6a1224b4aa72b5fde8593087f6
7
+ data.tar.gz: 30e2902d826c9f32b12a2508152039752bd0c0f9738aa792fbadf133f57a19af28b0f8ea0ebc8ea85a052678ec8a748b5b1974ef4ffe811243b33cd2b20abd4d
@@ -1,5 +1,10 @@
1
1
  ## rexe -- Ruby Command Line Executor
2
2
 
3
+ ### 0.15.0
4
+
5
+ * Source code now defaults to 'self' (#3).
6
+ * Change parse errors to not output help text and stack trace, but instead a short message with suggestion to use -h.
7
+
3
8
 
4
9
  ### 0.14.0
5
10
 
data/README.md CHANGED
@@ -3,8 +3,10 @@ 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.]_
6
+ [Caution: This is a long article!
7
+ You might want to skim the section headings and source code first.
8
+ Many sections can be skipped without sacrificing comprehensibility of the rest of them.
9
+ ]
8
10
 
9
11
  ----
10
12
 
@@ -42,7 +44,7 @@ make the command long and tedious, discouraging this approach.
42
44
 
43
45
  ### Rexe
44
46
 
45
- The `rexe` script [^1] can simplify such commands.
47
+ The `rexe` script [see footnote ^1] can simplify such commands.
46
48
  Among other things, `rexe` provides switch-activated input parsing and output formatting so that converting
47
49
  from one format to another is trivial.
48
50
  The previous `ruby` command can be expressed in `rexe` as:
@@ -66,7 +68,7 @@ line, tipping the scale so that it is practical to do it more often.
66
68
  Here is `rexe`'s help text as of the time of this writing:
67
69
 
68
70
  ```
69
- rexe -- Ruby Command Line Executor/Filter -- v0.14.0 -- https://github.com/keithrbennett/rexe
71
+ rexe -- Ruby Command Line Executor/Filter -- v0.15.0 -- https://github.com/keithrbennett/rexe
70
72
 
71
73
  Executes Ruby code on the command line, optionally automating management of standard input
72
74
  and standard output, and optionally parsing input and formatting output with YAML, JSON, etc.
@@ -106,6 +108,9 @@ Options:
106
108
  -r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
107
109
  ! to clear all, or precede a name with '-' to remove
108
110
 
111
+ If source code is not specified, it will default to 'self', which is most likely useful
112
+ only in a filter mode (-ml, -me, -mb).
113
+
109
114
  If there is an .rexerc file in your home directory, it will be run as Ruby code
110
115
  before processing the input.
111
116
 
@@ -160,7 +165,7 @@ def valkyries
160
165
  end
161
166
  ```
162
167
 
163
- To digress a bit, why would you want this? You might want to be able to go to another room until a long job completes, and be notified when it is done. The `valkyries` method will launch a browser window pointed to Richard Wagner's "Ride of the Valkyries" starting at a lively point in the music. (The `open` command is Mac specific and could be replaced with `start` on Windows, a browser command name, etc.) [^2]
168
+ To digress a bit, why would you want this? You might want to be able to go to another room until a long job completes, and be notified when it is done. The `valkyries` method will launch a browser window pointed to Richard Wagner's "Ride of the Valkyries" starting at a lively point in the music. (The `open` command is Mac specific and could be replaced with `start` on Windows, a browser command name, etc.) [see footnote ^2]
164
169
 
165
170
  If you like this kind of audio notification, you could download public domain audio files and use a command like player like `afplay` on Mac OS, or `mpg123` or `ogg123` on Linux. This approach is lighter weight, requires no network access, and will not leave an open browser window for you to close.
166
171
 
@@ -206,12 +211,13 @@ One of the examples at the end of this articles shows how you could have differe
206
211
  ### Logging
207
212
 
208
213
  A log entry is optionally output to standard error after completion of the code.
209
- The entry is a hash containing the version, date/time of execution, source code
214
+ This entry is a hash representation (to be precise, `to_h`) of the `$RC` OpenStruct described in the $RC section below.
215
+ It contains the version, date/time of execution, source code
210
216
  to be evaluated, options (after parsing both the `REXE_OPTIONS` environment variable and the command line),
211
217
  and the execution time of your Ruby code:
212
218
 
213
219
  ```
214
- ➜ ~  echo $EUR_RATES_JSON | rexe -gy -ij -oa self
220
+ ➜ ~  echo $EUR_RATES_JSON | rexe -gy -ij -mb -oa self
215
221
  ...
216
222
  ---
217
223
  :count: 0
@@ -268,9 +274,7 @@ to your code as `self`.
268
274
 
269
275
  The last (and default) is the _executor_ mode. It merely assists you in
270
276
  executing the code you provide without any special implicit handling of standard input.
271
-
272
- All input modes automatically output to standard output the last value evaluated by your code.
273
- You can suppress automatic output with the `-on` option.
277
+ Here is more detail on these modes:
274
278
 
275
279
 
276
280
  #### -ml "Line" Filter Mode
@@ -279,26 +283,29 @@ In this mode, your code would be called once per line of input,
279
283
  and in each call, `self` would evaluate to each line of text:
280
284
 
281
285
  ```
282
- ➜ ~  echo "hello\ngoodbye" | rexe -ms reverse
286
+ ➜ ~  echo "hello\ngoodbye" | rexe -ml puts reverse
283
287
  olleh
284
288
  eybdoog
285
289
  ```
286
290
 
287
291
  `reverse` is implicitly called on each line of standard input. `self`
288
- is the input line in each call (we could also have used `self.reverse` but the `self.` would have been redundant.).
292
+ is the input line in each call (we could also have used `self.reverse` but the `self.` would have been redundant).
289
293
 
290
- Be aware that, in this mode, although you can control the _content_ of output records,
294
+ Be aware that, in this mode, if you are using an automatic output mode
295
+ (anything other than the default `-on` no output mode),
296
+ although you can control the _content_ of output records,
291
297
  there is no way to selectively _exclude_ records from being output. Even if the result of the code
292
298
  is nil or the empty string, a newline will be output. To prevent this, you can do one of the following:
293
299
 
294
- * use `-me` Enumerator mode and call `select`, `filter`, `reject`, etc.
295
- * use the `-on` _no output_ mode and call `puts` explicitly for the output you _do_ want
300
+ * use `-me` Enumerator mode instead and call `select`, `filter`, `reject`, etc.
301
+ * use the (default) `-on` _no output_ mode and call `puts` explicitly for the output you _do_ want
296
302
 
297
303
 
298
304
  #### -me "Enumerator" Filter Mode
299
305
 
300
306
  In this mode, your code is called only once, and `self` is an enumerator
301
- dispensing all lines of standard input. To be more precise, it is the enumerator returned by `STDIN.each_line`.
307
+ dispensing all lines of standard input. To be more precise, it is the enumerator returned by the `each_line` method,
308
+ on `$stdin` or the input file, whichever is applicable.
302
309
 
303
310
  Dealing with input as an enumerator enables you to use the wealth of `Enumerable` methods such as `select`, `to_a`, `map`, etc.
304
311
 
@@ -306,7 +313,7 @@ Here is an example of using `-me` to add line numbers to the first 3
306
313
  files in the directory listing:
307
314
 
308
315
  ```
309
- ➜ ~  ls / | rexe -me -on "first(3).each_with_index { |ln,i| puts '%5d %s' % [i, ln] }"
316
+ ➜ ~  ls / | rexe -me "first(3).each_with_index { |ln,i| puts '%5d %s' % [i, ln] }"
310
317
 
311
318
  0 AndroidStudioProjects
312
319
  1 Applications
@@ -314,7 +321,8 @@ files in the directory listing:
314
321
  ```
315
322
 
316
323
  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.
324
+ We've used the default output mode `-on` (_no output_ mode), which says don't do any automatic output,
325
+ just the output explicitly specified by `puts` in the source code.
318
326
 
319
327
 
320
328
  #### -mb "Big String" Filter Mode
@@ -338,7 +346,8 @@ if you defined methods, constants, instance variables, etc., in your code.
338
346
 
339
347
  #### Filter Input Mode Memory Considerations
340
348
 
341
- If you may have more input than would fit in memory, you can do the following:
349
+ If you are using one of the filter modes, and may have more input than would fit in memory,
350
+ you can do one of the following:
342
351
 
343
352
  * use `-ml` (line) mode so you are fed only 1 line at a time
344
353
  * use an Enumerator, either by a) specifying the `-me` (enumerator) mode option,
@@ -373,7 +382,7 @@ Several output formats are provided for your convenience:
373
382
  * `-oi` - Inspect - calls `inspect` on the object
374
383
  * `-oj` - JSON - calls `to_json` on the object
375
384
  * `-oJ` - Pretty JSON calls `JSON.pretty_generate` with the object
376
- * `-on` - No Output - output is suppressed
385
+ * `-on` - (default) No Output - output is suppressed
377
386
  * `-op` - Puts - produces what `puts` would output
378
387
  * `-os` - To String - calls `to_s` on the object
379
388
  * `-oy` - YAML - calls `to_yaml` on the object
@@ -384,14 +393,14 @@ You may wonder why these formats are provided, given that their functionality
384
393
  could be included in the custom code instead. Here's why:
385
394
 
386
395
  * The savings in command line length goes a long way to making these commands more readable and feasible.
387
- * It's much simpler to switch formats, as there is no need to change the code itself. This also enables
388
- parameterization of the output format.
396
+ * It's much simpler to switch formats, as there is no need to change the code itself.
397
+ * This approach enables parameterization of the output format.
389
398
 
390
399
 
391
400
  ### Reading Input from a File
392
401
 
393
402
  `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:
403
+ and does with its content exactly what it would have done with standard input. This shortens:
395
404
 
396
405
  ```
397
406
  ➜ ~  cat filename.ext | rexe ...
@@ -424,6 +433,29 @@ So the example we gave above:
424
433
  Another possible win for using `-f` is that since it is a command line option, it could be specified in `REXE_OPTIONS`.
425
434
  This could be useful if you are doing many operations on the same file.
426
435
 
436
+
437
+ ### 'self' as Default Source Code
438
+
439
+ To make `rexe` even more concise, you do not need to specify any source code when you want that source code
440
+ to be `self`. This would be the case for simple format conversions, such as the following JSON to YAML conversion
441
+ of the currency coversion rates:
442
+
443
+ ```
444
+ ➜ ~  rexe -f eur_rates.json -oy
445
+ # or
446
+ ➜ ~  echo $EUR_RATES_JSON | rexe -mb -ij -oy
447
+
448
+ ---
449
+ rates:
450
+ JPY: 126.63
451
+ BRL: 4.3012
452
+ NOK: 9.6915
453
+ ...
454
+ ```
455
+
456
+ This feature is probably only useful in the filter modes, since in the executor mode (`-mn`) self is a new
457
+ instance of `Object` and hardly ever useful as an output value.
458
+
427
459
  ### The $RC Global OpenStruct
428
460
 
429
461
  For your convenience, the information displayed in verbose mode is available to your code at runtime
@@ -450,7 +482,7 @@ OpenStruct {
450
482
  }
451
483
  ```
452
484
 
453
- Probably most useful in that object
485
+ Probably most useful in that object at runtime
454
486
  is the record count, accessible with both `$RC.count` and `$RC.i`.
455
487
  This is only really useful in line mode, because in the others
456
488
  it will always be 0 or 1. Here is an example of how you might use it as a kind of progress indicator:
@@ -472,10 +504,15 @@ and removed by the shell.
472
504
 
473
505
  ### Implementing Domain Specific Languages (DSL's)
474
506
 
475
- 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 I wrote code to work with Ansible and put it in `~/projects/rexe-ansible.rb`, I could define an alias in my startup script:
507
+ Defining methods in your loaded files enables you to effectively define a
508
+ [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) for your command line use.
509
+ You could use different load files for different projects, domains, or contexts,
510
+ and define aliases or one line scripts to give them meaningful names.
511
+ For example, if I wrote code to work with Ansible and put it in `~/projects/ansible-tools/rexe-ansible.rb`,
512
+ I could define an alias in my startup script:
476
513
 
477
514
  ```
478
- ➜ ~  alias rxans="rexe -l ~/projects/rexe-ansible.rb $*"
515
+ ➜ ~  alias rxans="rexe -l ~/projects/ansible-tools/rexe-ansible.rb $*"
479
516
  ```
480
517
  ...and then I would have an Ansible DSL available for me to use by calling `rxans`.
481
518
 
@@ -505,32 +542,81 @@ true
505
542
  This could be really handy if you call `pry` on a custom object that has methods especially suited to your task:
506
543
 
507
544
  ```
508
- ➜ ~  rexe -r wifi-wand,pry WifiWand::MacOsModel.new.pry
545
+ ➜ ~  rexe -r wifi-wand,pry WifiWand::MacOsModel.new.pry
546
+ [1] pry(#<WifiWand::MacOsModel>)> random_mac_address
547
+ "a1:ea:69:d9:ca:05"
548
+ [2] pry(#<WifiWand::MacOsModel>)> connected_network_name
549
+ "My WiFi"
509
550
  ```
510
551
 
511
552
  Ruby is supremely well suited for DSL's since it does not require parentheses for method calls,
512
553
  so calls to your custom methods _look_ like built in language commands and keywords.
513
554
 
514
555
 
515
- ### Quoting Strings in Your Ruby Code
556
+ ### Quotation Marks and Quoting Strings in Your Ruby Code
516
557
 
517
- One complication of using utilities like `rexe` where Ruby code is specified on the shell command line is that
558
+ One complication of using utilities like `rexe` where Ruby code is specified on the command line is that
518
559
  you need to be careful about the shell's special treatment of certain characters. For this reason, it is often
519
560
  necessary to quote the Ruby code. You can use single or double quotes to have the shell treat your source code
520
- as a single argument.
521
- An excellent reference for how they differ is [here](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash).
561
+ as a single argument. An excellent reference for how they differ is on StackOverflow at
562
+ https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash.
563
+
564
+ Personally, I find single quotes more useful since I usually don't want special characters in my Ruby code
565
+ like `$` to be processed by the shell.
566
+
567
+ Sometimes it doesn't matter:
568
+
569
+ ```
570
+ ➜ ~  rexe 'puts "hello"'
571
+ hello
572
+ ➜ ~  rexe "puts 'hello'"
573
+ hello
574
+ ```
575
+
576
+ We can also use `%q` or `%Q`, and sometimes this eliminates the needs for the outer quotes:
577
+
578
+ ```
579
+ ➜ ~  rexe puts %q{hello}
580
+ hello
581
+ ➜ ~  rexe puts %Q{hello}
582
+ hello
583
+ ```
584
+
585
+ Sometimes the quotes to use on the outside (quoting your command in the shell) need to be chosen
586
+ based on which quotes are needed on the inside. For example, in the following command, we need
587
+ double quotes in Ruby in order for interpolation to work, so we use single quotes on the outside:
588
+
589
+ ```
590
+ ➜ ~  rexe puts '"The time is now #{Time.now}"'
591
+ The time is now 2019-03-29 16:41:26 +0800
592
+ ```
593
+
594
+ In this case we also need to use single quotes on the outside,
595
+ because we need literal double quotes in a `%Q{}` expression:
596
+
597
+ ```
598
+ ➜ ~  rexe 'puts %Q{The operating system name is "#{`uname`.chomp}".}'
599
+ The operating system name is "Darwin".
600
+ ```
601
+
602
+ We can eliminate the need for any quotes in the Ruby code using `%Q{}`:
603
+
604
+ ```
605
+ ➜ ~  rexe puts '%Q{The time is now #{Time.now}}'
606
+ The time is now 2019-03-29 17:06:13 +0800
607
+ ```
608
+
609
+ Of course you can always escape the quotes with backslashes instead, but in my experience
610
+ that becomes difficult to read.
522
611
 
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.
524
612
 
525
- When specifying the Ruby code, feel free to fall back on Ruby's super useful `%q{}` and `%Q{}`,
526
- equivalent to single and double quotes, respectively.
527
613
 
528
614
 
529
615
  ### No Op Mode
530
616
 
531
617
  The `-n` no-op mode will result in the specified source code _not_ being executed. This can sometimes be handy
532
- in conjunction with a `-g` (logging) option; if you have a command ready to go but
533
- you want to see the configuration options before running it for real.
618
+ in conjunction with a `-g` (logging) option, if you have are building a rexe command and
619
+ want to inspect the configuration options before executing the Ruby code.
534
620
 
535
621
 
536
622
  ### Mimicking Method Arguments
@@ -542,15 +628,16 @@ One of the previous examples downloaded currency conversion rates.
542
628
  To prepare for an example of how to do this, let's find out the available currency codes:
543
629
 
544
630
  ```
545
- ➜ /  echo $EUR_RATES_JSON | rexe -ij -mb "self['rates'].keys.sort.join(' ')"
631
+ ➜ /  echo $EUR_RATES_JSON | \
632
+ rexe -ij -mb -op "self['rates'].keys.sort.join(' ')"
546
633
  AUD BGN BRL CAD CHF CNY CZK DKK GBP HKD HRK HUF IDR ILS INR ISK JPY KRW MXN MYR NOK NZD PHP PLN RON RUB SEK SGD THB TRY USD ZAR
547
634
  ```
548
635
 
549
- The codes output are the legal arguments that could be sent to `rexe`'s stdin as an argument.
636
+ The codes output are the legal arguments that could be sent to `rexe`'s stdin as an argument in the command below.
550
637
  Let's find out the Euro exchange rate for _PHP_, Philippine Pesos:
551
638
 
552
639
  ```
553
- ➜ ~  echo PHP | rexe -ml -rjson \
640
+ ➜ ~  echo PHP | rexe -ml -op -rjson \
554
641
  "rate = JSON.parse(ENV['EUR_RATES_JSON'])['rates'][self];\
555
642
  %Q{1 EUR = #{rate} #{self}}"
556
643
 
@@ -570,21 +657,32 @@ make the command line too complex to be practical.
570
657
 
571
658
  Sometimes when editing text I need to do some one off text manipulation.
572
659
  Using the system's commands for pasting to and copying from the clipboard,
573
- this can easily be done. On the Mac, the `pbpaste` command outputs to stdout
574
- the clipboard content, and the `pbcopy` command copies its stdin to the clipboard.
575
-
576
- Let's say I have the following currency codes displayed on the screen:
660
+ this can easily be done. On the Mac, we have the following commands:
661
+
662
+ * `pbcopy` - copies the content of stdin _to_ the clipboard
663
+ * `pbpaste` - copies the content _from_ the clipboard to stdout
664
+
665
+ Let's say I have the following currency codes displayed on the screen
666
+ (data abridged for brevity):
577
667
 
578
668
  ```
579
- AUD BGN BRL CAD CHF CNY CZK DKK GBP HKD HRK HUF IDR ILS INR ISK JPY KRW MXN MYR NOK NZD PHP PLN RON RUB SEK SGD THB TRY USD ZAR
669
+ AUD BGN BRL PHP TRY USD ZAR
580
670
  ```
581
671
 
582
672
  ...and I want to turn them into Ruby symbols for inclusion in Ruby source code as keys in a hash
583
673
  whose values will be the display names of the currencies, e.g "Australian Dollar").
674
+
675
+ I could manually select that text and use system menu commands or keys to copy it to the clipboard,
676
+ or I could do this:
677
+
678
+ ```
679
+ ➜ ~  echo AUD BGN BRL PHP TRY USD ZAR | pbcopy
680
+ ```
681
+
584
682
  After copying this line to the clipboard, I could run this:
585
683
 
586
684
  ```
587
- ➜ ~  pbpaste | rexe -ml "split.map(&:downcase).map { |s| %Q{ #{s}: '',} }.join(%Q{\n})"
685
+ ➜ ~  pbpaste | rexe -ml -op "split.map(&:downcase).map { |s| %Q{ #{s}: '',} }.join(%Q{\n})"
588
686
  aud: '',
589
687
  bgn: '',
590
688
  brl: '',
@@ -592,7 +690,7 @@ After copying this line to the clipboard, I could run this:
592
690
  ```
593
691
 
594
692
  If I add `| pbcopy` to the rexe command, then that output text would be copied into the clipboard instead of
595
- displayed in the terminal, and I could then paste it in my editor.
693
+ displayed in the terminal, and I could then paste it into my editor.
596
694
 
597
695
  Using the clipboard in manual operations is handy, but using it in automated scripts is a very bad idea, since
598
696
  there is only one clipboard per user session. If you use the clipboard in an automated script you risk
@@ -604,7 +702,8 @@ when you change the content of the clipboard.
604
702
  Although `rexe` is cleanest with short one liners, you may want to use it to include nontrivial Ruby code
605
703
  in your shell script as well. If you do this, you may need to add trailing backslashes to the lines of Ruby code.
606
704
 
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:
705
+ What might not be so obvious is that you will often need to use semicolons as statement separators.
706
+ For example, here is an example without a semicolon:
608
707
 
609
708
  ```
610
709
  ➜ ~  cowsay hello | rexe -me "print %Q{\u001b[33m} \
@@ -617,7 +716,13 @@ puts to_a"
617
716
  ```
618
717
 
619
718
  The shell combines all backslash terminated lines into a single line of text, so when the Ruby
620
- interpreter sees your code, it's all in a single line. Adding the semicolon fixes the problem:
719
+ interpreter sees your code, it's all in a single line:
720
+
721
+ ```
722
+ ➜ ~  cowsay hello | rexe -me "print %Q{\u001b[33m} puts to_a"
723
+ ```
724
+
725
+ Adding the semicolon fixes the problem:
621
726
 
622
727
  ```
623
728
  ➜ ~  cowsay hello | rexe -me "print %Q{\u001b[33m}; \
@@ -642,15 +747,24 @@ but you want to override it for a single invocation. Here are your options:
642
747
  1) Unspecify _all_ the requires or loads with the `-r!` and `-l!` command line options, respectively.
643
748
 
644
749
  2) Unspecify individual requires or loads by preceding the name with `-`, e.g. `-r -rails`.
645
- Array subtraction is used, so:
750
+ Array subtraction is used, and array subtraction removes _all_
751
+ occurrences of each element of the subtracted (subtrahend) array, so:
646
752
 
647
753
  ```
648
- ➜ ~  rexe -n -r rails,rails,rails,-rails -ga
754
+ ➜ ~  rexe -n -r rails,rails,rails,-rails -gP
755
+ ...
756
+ :requires=>["pp"],
757
+ ...
649
758
  ```
650
759
 
651
760
  ...would show that the final `-rails` cancelled all the previous `rails` specifications.
652
761
 
762
+ We could have also extracted the requires list programmatically using `$RC` (described above) by doing this:
653
763
 
764
+ ```
765
+ ➜ ~  rexe -oP -r rails,rails,rails,-rails '$RC[:options][:requires]'
766
+ ["pp"]
767
+ ```
654
768
 
655
769
 
656
770
  ### Clearing _All_ Options
@@ -676,7 +790,7 @@ Files loaded with the `-l` option are treated the same way.
676
790
 
677
791
  ### Beware of Configured Requires
678
792
 
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):
793
+ 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 `grep`):
680
794
 
681
795
  ```
682
796
  ➜ ~  rexe -gy -r rails 123 2>&1 | grep duration
@@ -700,40 +814,18 @@ Here are some more examples to illustrate the use of `rexe`.
700
814
 
701
815
  ----
702
816
 
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
817
 
726
818
  #### Outputting ENV
727
819
 
728
- Output the contents of `ENV` using AwesomePrint [^3]:
820
+ Output the contents of `ENV` using AwesomePrint [see footnote ^3]:
729
821
 
730
822
  ```
731
823
  ➜ ~  rexe -oa ENV
732
824
  {
733
825
  ...
734
- "LANG" => "en_US.UTF-8",
735
- "PWD" => "/Users/kbennett/work/rexe",
736
- "SHELL" => "/bin/zsh",
826
+ "LANG" => "en_US.UTF-8",
827
+ "PWD" => "/Users/kbennett/work/rexe",
828
+ "SHELL" => "/bin/zsh",
737
829
  ...
738
830
  }
739
831
  ```
@@ -759,7 +851,7 @@ Show disk space used/free on a Mac's main hard drive's main partition:
759
851
  Show the 3 longest file names of the current directory, with their lengths, in descending order:
760
852
 
761
853
  ```
762
- ➜ ~  ls | rexe -ml "%Q{[%4d] %s} % [length, self]" | sort -r | head -3
854
+ ➜ ~  ls | rexe -ml -op "%Q{[%4d] %s} % [length, self]" | sort -r | head -3
763
855
  [ 50] Agoda_Booking_ID_9999999 49_–_RECEIPT_enclosed.pdf
764
856
  [ 40] 679a5c034994544aab4635ecbd50ab73-big.jpg
765
857
  [ 28] 2018-abc-2019-01-16-2340.zip
@@ -789,13 +881,11 @@ alphabetically will result in sorting them numerically as well.
789
881
  ```
790
882
 
791
883
 
792
- ----
793
-
794
884
  ----
795
885
 
796
886
  #### More YouTube: Differentiating Success and Failure
797
887
 
798
- Let's go a little crazy with the YouTube example.
888
+ Let's take the YouTube example from the "Loading Files" section further.
799
889
  Let's have the video that loads be different for the success or failure
800
890
  of the command.
801
891
 
@@ -818,6 +908,8 @@ def play_result(success)
818
908
  end
819
909
 
820
910
 
911
+ # Must pipe the exit code into this Ruby process,
912
+ # e.g. using `echo $? | rexe play_result_by_exit_code
821
913
  def play_result_by_exit_code
822
914
  play_result(STDIN.read.chomp == '0')
823
915
  end
@@ -844,30 +936,33 @@ Then when I issue a command that succeeds, the Hallelujah Chorus is played:
844
936
  Another formatting example...I wanted to reformat this source code...
845
937
 
846
938
  ```
847
- 'i' => Inspect
848
- 'j' => JSON
849
- 'J' => Pretty JSON
850
- 'n' => No Output
851
- 'p' => Puts (default)
852
- 's' => to_s
853
- 'y' => YAML
939
+ 'i' => Inspect
940
+ 'j' => JSON
941
+ 'J' => Pretty JSON
942
+ 'n' => No Output
943
+ 'p' => Puts (default)
944
+ 's' => to_s
945
+ 'y' => YAML
854
946
  ```
855
947
 
856
948
  ...into something more suitable for my help text.
857
949
  Admittedly, the time it took to do this with rexe probably exceeded the time to do it manually,
858
- but it was an interesting exercise and made it easy to try different formats. Here it is:
950
+ but it was an interesting exercise and made it easy to try different formats. Here it is, after
951
+ copying the original text to the clipboard:
859
952
 
860
953
  ```
861
- ➜ ~  pbpaste | rexe -ml "sub(%q{'}, '-o').sub(%q{' =>}, %q{ })"
862
- -oi Inspect
863
- -oj JSON
864
- -oJ Pretty JSON
865
- -on No Output
866
- -op Puts (default)
867
- -os to_s
868
- -oy YAML
869
- ```
870
-
954
+ ➜ ~  pbpaste | rexe -ml -op "sub(%q{'}, '-o').sub(%q{' =>}, %q{ })"
955
+ -oi Inspect
956
+ -oj JSON
957
+ -oJ Pretty JSON
958
+ -on No Output
959
+ -op Puts (default)
960
+ -os to_s
961
+ -oy YAML
962
+ ```
963
+
964
+
965
+ ----
871
966
 
872
967
  #### Reformatting Grep Output
873
968
 
@@ -887,7 +982,7 @@ lib/rock_books/documents/journal_entry.rb:
887
982
  So this is what worked well for me:
888
983
 
889
984
  ```
890
- ➜ ~  grep Struct **/*.rb | grep -v OpenStruct | rexe -ml \
985
+ ➜ ~  grep Struct **/*.rb | grep -v OpenStruct | rexe -ml -op \
891
986
  "a = \
892
987
  gsub('lib/rock_books/', '')\
893
988
  .gsub('< Struct.new', '')\
@@ -913,7 +1008,8 @@ types/acct_amount.rb class AcctAmount (:date, :code, :amount
913
1008
  types/journal_entry_context.rb class JournalEntryContext (:journal, :linenum, :line)
914
1009
  ```
915
1010
 
916
- Although there's a lot going on here, the vertical and horizontal alignments and spacing make the code
1011
+ Although there's a lot going on in this code,
1012
+ the vertical and horizontal alignments and spacing make the code
917
1013
  straightforward to follow. Here's what it does:
918
1014
 
919
1015
  * grep the code base for `"Struct"`
@@ -923,6 +1019,8 @@ straightforward to follow. Here's what it does:
923
1019
  * strip unwanted space because that will mess up the horizontal alignment of the output.
924
1020
  * use C-style printf formatting to align the text into two columns
925
1021
 
1022
+ ----
1023
+
926
1024
 
927
1025
  ### Conclusion
928
1026
 
@@ -933,8 +1031,8 @@ task at hand.
933
1031
 
934
1032
  When we consider a new piece of software, we usually think "what would this be
935
1033
  helpful with now?". However, for me, the power of `rexe` is not so much what I can do
936
- with it in a single use case now, but rather what will I be able to do with it over time
937
- as I accumulate more experience and expertise.
1034
+ with it in a single use case now, but rather what will I be able to do over time
1035
+ as I accumulate more experience and expertise with it.
938
1036
 
939
1037
  I suggest starting to use `rexe` even for modest improvements in workflow, even
940
1038
  if it doesn't seem compelling. There's a good chance that as you use it over
@@ -942,7 +1040,7 @@ time, new ideas will come to you and the workflow improvements will increase
942
1040
  exponentially.
943
1041
 
944
1042
  A word of caution though --
945
- the complexity and difficulty of sharing your `rexe` scripts across systems
1043
+ the complexity and difficulty of _sharing_ your `rexe` scripts across systems
946
1044
  will be proportional to the extent to which you use environment variables
947
1045
  and loaded files for configuration and shared code.
948
1046
  Be responsible and disciplined in making this configuration and code as clean and organized as possible.
@@ -976,4 +1074,7 @@ Here is a _start_ at a method that opens a resource portably across operating sy
976
1074
  end
977
1075
  ```
978
1076
 
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`.
1077
+ [^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, many of the other output formats will also return some form of `"ENV"`. You can handle this by specifying `ENV.to_h`.
1078
+
1079
+ - Keith Bennett (@keithrbennett on Github and Twitter)
1080
+
data/exe/rexe CHANGED
@@ -12,11 +12,20 @@ require 'shellwords'
12
12
 
13
13
  class Rexe
14
14
 
15
- VERSION = '0.14.0'
15
+ VERSION = '0.15.0'
16
16
 
17
17
  PROJECT_URL = 'https://github.com/keithrbennett/rexe'
18
18
 
19
19
 
20
+ module Helpers
21
+ def error_exit(message)
22
+ $stderr.puts(message)
23
+ $stderr.puts("Use the -h option to get help.")
24
+ exit(-1)
25
+ end
26
+ end
27
+
28
+
20
29
  class Options < Struct.new(
21
30
  :input_filespec,
22
31
  :input_format,
@@ -127,6 +136,8 @@ class Rexe
127
136
 
128
137
  class CommandLineParser
129
138
 
139
+ include Helpers
140
+
130
141
  attr_reader :lookups, :options
131
142
 
132
143
  def initialize
@@ -195,6 +206,9 @@ class Rexe
195
206
  -r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
196
207
  ! to clear all, or precede a name with '-' to remove
197
208
 
209
+ If source code is not specified, it will default to 'self', which is most likely useful
210
+ only in a filter mode (-ml, -me, -mb).
211
+
198
212
  If there is an .rexerc file in your home directory, it will be run as Ruby code
199
213
  before processing the input.
200
214
 
@@ -218,7 +232,21 @@ class Rexe
218
232
  end
219
233
 
220
234
 
221
- # Using 'optparse', parses the command line.
235
+ def open_resource(resource_identifier)
236
+ command = case (`uname`.chomp)
237
+ when 'Darwin'
238
+ 'open'
239
+ when 'Linux'
240
+ 'xdg-open'
241
+ else
242
+ 'start'
243
+ end
244
+
245
+ `#{command} #{resource_identifier}`
246
+ end
247
+
248
+
249
+ # Using 'optparse', parses the command line.
222
250
  # Settings go into this instance's properties (see Struct declaration).
223
251
  def parse
224
252
 
@@ -230,7 +258,7 @@ class Rexe
230
258
  parser.on('-f', '--input_file FILESPEC',
231
259
  'Use this file instead of stdin; autodetects YAML and JSON file extensions') do |v|
232
260
  unless File.exist?(v)
233
- raise "File #{v} does not exist."
261
+ error_exit "File #{v} does not exist."
234
262
  end
235
263
  options.input_filespec = v
236
264
  options.input_format = autodetect_file_format(v)
@@ -242,8 +270,7 @@ class Rexe
242
270
  parser.on('-g', '--log_format FORMAT', 'Log format, logs to stderr, defaults to none (see -o for format options)') do |v|
243
271
  options.log_format = lookups.output_formats[v]
244
272
  if options.log_format.nil?
245
- puts help_text
246
- raise "Output mode was '#{v}' but must be one of #{lookups.output_formats.keys}."
273
+ error_exit("Output mode was '#{v}' but must be one of #{lookups.output_formats.keys}.")
247
274
  end
248
275
  end
249
276
 
@@ -257,8 +284,7 @@ class Rexe
257
284
 
258
285
  options.input_format = lookups.input_formats[v]
259
286
  if options.input_format.nil?
260
- puts help_text
261
- raise "Input mode was '#{v}' but must be one of #{lookups.input_formats.keys}."
287
+ error_exit("Input mode was '#{v}' but must be one of #{lookups.input_formats.keys}.")
262
288
  end
263
289
  end
264
290
 
@@ -271,7 +297,7 @@ class Rexe
271
297
 
272
298
  existent, nonexistent = adds.partition { |filespec| File.exists?(filespec) }
273
299
  if nonexistent.any?
274
- raise("\nDid not find the following files to load: #{nonexistent}\n\n")
300
+ error_exit("\nDid not find the following files to load: #{nonexistent}\n\n")
275
301
  else
276
302
  existent.each { |filespec| options.loads << filespec }
277
303
  end
@@ -285,8 +311,7 @@ class Rexe
285
311
 
286
312
  options.input_mode = lookups.input_modes[v]
287
313
  if options.input_mode.nil?
288
- puts help_text
289
- raise "Input mode was '#{v}' but must be one of #{lookups.input_modes.keys}."
314
+ error_exit("Input mode was '#{v}' but must be one of #{lookups.input_modes.keys}.")
290
315
  end
291
316
  end
292
317
 
@@ -295,8 +320,7 @@ class Rexe
295
320
 
296
321
  options.output_format = lookups.output_formats[v]
297
322
  if options.output_format.nil?
298
- puts help_text
299
- raise "Output mode was '#{v}' but must be one of #{lookups.output_formats.keys}."
323
+ error_exit("Output mode was '#{v}' but must be one of #{lookups.output_formats.keys}.")
300
324
  end
301
325
  end
302
326
 
@@ -355,6 +379,8 @@ class Rexe
355
379
 
356
380
  class Main
357
381
 
382
+ include Helpers
383
+
358
384
  attr_reader :callable, :input_parser, :lookups,
359
385
  :options, :output_formatter,
360
386
  :log_formatter, :start_time, :user_source_code
@@ -366,20 +392,6 @@ class Rexe
366
392
  end
367
393
 
368
394
 
369
- def open_resource(resource_identifier)
370
- command = case (`uname`.chomp)
371
- when 'Darwin'
372
- 'open'
373
- when 'Linux'
374
- 'xdg-open'
375
- else
376
- 'start'
377
- end
378
-
379
- `#{command} #{resource_identifier}`
380
- end
381
-
382
-
383
395
  private def load_global_config_if_exists
384
396
  filespec = File.join(Dir.home, '.rexerc')
385
397
  load(filespec) if File.exists?(filespec)
@@ -428,10 +440,6 @@ class Rexe
428
440
 
429
441
 
430
442
  private def create_callable
431
- if user_source_code.empty? && (! options.noop)
432
- raise "No source code provided. Use -h to display help."
433
- end
434
-
435
443
  eval("Proc.new { #{user_source_code} }")
436
444
  end
437
445
 
@@ -483,6 +491,8 @@ class Rexe
483
491
  options.loads.each { |file| load(file) }
484
492
 
485
493
  @user_source_code = ARGV.join(' ')
494
+ @user_source_code = 'self' if @user_source_code == ''
495
+
486
496
  @callable = create_callable
487
497
 
488
498
  init_rexe_context
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rexe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.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: 2019-03-24 00:00:00.000000000 Z
11
+ date: 2019-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print