rexe 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSE.txt +201 -21
  4. data/README.md +140 -53
  5. data/exe/rexe +254 -164
  6. data/rexe.gemspec +2 -0
  7. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79b7eb979cbeb0ba6d95c150e58bccecef867212b4783808f06381d9e247aa55
4
- data.tar.gz: e737abbe83eee2bd71d83466a336db48b49ceea1ef88a51615557dcfa623d1d5
3
+ metadata.gz: 38c1bab41a36c75950db8a2a8aa05f46d324f3c221b66181cc8df302b97aabe7
4
+ data.tar.gz: 6a3e33b62857804eb18179233aa3de385ee7b44785dbb1fdd27de4a95e9aa0bc
5
5
  SHA512:
6
- metadata.gz: 729475e954a39717db0f64b1dbfa2e267c41cf23742fb26de919ba2c80347b25adb1951d4c9ae2a3069068a5ac3baa52c9e8761b235bb72491a1fd0b32f82d94
7
- data.tar.gz: 53b3ae64d2f92db487299ce46a2808cb82afea02e8b1ed66dbe4d3dfd5d2eddcc31f2697a1f87194f60c9ac7ffa15cfef8d5d11f5bc0e04b666e9e6d4f7d6f79
6
+ metadata.gz: 52d97220ae00afd76ecb7253f626c135be6f33622130cf43edcabb90bb63f93b8ee3e143734059a6f69a80d57800c29d47adc4c8569c7b08e54676853a6eb36a
7
+ data.tar.gz: ea666de41864df7f84315e69e4481fd1a1b79bf4c32da29b1e76a4483a4a3276a99e494ecf47850e124170ac43ba00cb5c8e10d81421620d3f2b27bbe5c3af21
@@ -1,6 +1,17 @@
1
1
  ## rexe -- Ruby Command Line Executor
2
2
 
3
3
 
4
+ ### v0.13.0
5
+
6
+ * Much refactoring.
7
+ * Allow omitting source code in no-op mode.
8
+ * Add ability to remove load or require files using minus sign preceding name.
9
+ * Requires needed for parsing and formatting will now be included in log output.
10
+ * Change license from MIT to Apache version 2.
11
+ * Add undocumented '--open-project' command line option to launch Github project page in Mac OS and possibly other OS's.
12
+ * Fix and add tests.
13
+
14
+
4
15
  ### v0.12.0
5
16
 
6
17
  * Change verbose -v boolean option to log output format -g option.
@@ -1,21 +1,201 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2019 Keith Bennett
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2019 Bennett Business Solutions, Inc.
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md CHANGED
@@ -42,11 +42,10 @@ make the command long and tedious, discouraging this approach.
42
42
 
43
43
  ### Rexe
44
44
 
45
- Enter the `rexe` script: [^1]
46
-
45
+ The `rexe` script [^1] can simplify such commands.
47
46
  Among other things, `rexe` provides switch-activated input parsing and output formatting so that converting
48
47
  from one format to another is trivial.
49
- This command does the same thing as the previous `ruby` command:
48
+ The previous `ruby` command can be expressed in `rexe` as:
50
49
 
51
50
  ```
52
51
  ➜ ~  echo $EUR_RATES_JSON | rexe -mb -ij -oy self
@@ -61,7 +60,7 @@ line, tipping the scale so that it is practical to do it more often.
61
60
  Here is `rexe`'s help text as of the time of this writing:
62
61
 
63
62
  ```
64
- rexe -- Ruby Command Line Executor/Filter -- v0.12.0 -- https://github.com/keithrbennett/rexe
63
+ rexe -- Ruby Command Line Executor/Filter -- v0.13.0 -- https://github.com/keithrbennett/rexe
65
64
 
66
65
  Executes Ruby code on the command line, optionally taking standard input and writing to standard output.
67
66
 
@@ -77,12 +76,13 @@ Options:
77
76
  -im Marshal
78
77
  -in None
79
78
  -iy YAML
80
- -l, --load RUBY_FILE(S) Ruby file(s) to load, comma separated, or ! to clear
79
+ -l, --load RUBY_FILE(S) Ruby file(s) to load, comma separated;
80
+ ! to clear all, or precede a name with '-' to remove
81
81
  -m, --input_mode MODE Mode with which to handle input (i.e. what `self` will be in your code):
82
82
  -ml line mode; each line is ingested as a separate string
83
83
  -me enumerator mode
84
84
  -mb big string mode; all lines combined into single multiline string
85
- -mn (default) no input mode; no special handling of input; self is an Object.new
85
+ -mn (default) no input mode; no special handling of input; self is an Object.new
86
86
  -n, --[no-]noop Do not execute the code (useful with -g); the following are valid:
87
87
  -n no, -n yes, -n false, -n true, -n n, -n y, -n +, but not -n -
88
88
  -o, --output_format FORMAT Output format (defaults to puts):
@@ -94,9 +94,10 @@ Options:
94
94
  -op Puts (default)
95
95
  -os to_s
96
96
  -oy YAML
97
- -r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated, or ! to clear
97
+ -r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
98
+ ! to clear all, or precede a name with '-' to remove
98
99
 
99
- If there is an .rexerc file in your home directory, it will be run as Ruby code
100
+ If there is an .rexerc file in your home directory, it will be run as Ruby code
100
101
  before processing the input.
101
102
 
102
103
  If there is a REXE_OPTIONS environment variable, its content will be prepended to the command line
@@ -105,7 +106,7 @@ so that you can specify options implicitly (e.g. `export REXE_OPTIONS="-r awesom
105
106
 
106
107
  ### Simplifying the Rexe Invocation
107
108
 
108
- There are two main ways we can simplify the `rexe` command line:
109
+ There are two main ways we can make the `rexe` command line even more concise:
109
110
 
110
111
  * by extracting configuration into the `REXE_OPTIONS` environment variable
111
112
  * by extracting low level and/or shared code into files that are loaded using `-l`,
@@ -137,10 +138,12 @@ def valkyries
137
138
  end
138
139
  ```
139
140
 
140
- 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.) If you like this sort of thing, 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.
141
+ 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]
142
+
143
+ 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.
141
144
 
142
- Here is an example of how you might use this, assuming the above configuration is loaded from your `~/.rexerc` file or
143
- an explicitly loaded file:
145
+ Here is an example of how you might use the `valkyries` method, assuming the above configuration
146
+ is loaded from your `~/.rexerc` file or an explicitly loaded file:
144
147
 
145
148
  ```
146
149
  ➜ ~  tar czf /tmp/my-whole-user-space.tar.gz ~ ; rexe valkyries
@@ -180,7 +183,7 @@ Alternatively you could escape the parentheses with backslashes.)
180
183
 
181
184
  A log entry is optionally output to standard error after completion of the code.
182
185
  The entry is a hash containing the version, date/time of execution, source code
183
- to be evaluated, options (specified by all approaches),
186
+ to be evaluated, options (after parsing both the `REXE_OPTIONS` environment variable and the command line),
184
187
  and the execution time of your Ruby code:
185
188
 
186
189
  ```
@@ -188,8 +191,8 @@ and the execution time of your Ruby code:
188
191
  ...
189
192
  ---
190
193
  :count: 0
191
- :rexe_version: 0.11.0
192
- :start_time: '2019-03-11T20:16:02+07:00'
194
+ :rexe_version: 0.12.0
195
+ :start_time: '2019-03-19T19:39:18+08:00'
193
196
  :source_code: ap JSON.parse(STDIN.read)
194
197
  :options:
195
198
  :input_format: :none
@@ -199,10 +202,14 @@ and the execution time of your Ruby code:
199
202
  :requires:
200
203
  - json
201
204
  - awesome_print
202
- :verbose: true
205
+ - yaml
206
+ :log_format: :yaml
203
207
  :noop: false
204
- :duration_secs: 0.032174
208
+ :duration_secs: 0.116171
205
209
  ```
210
+
211
+ The `yaml` require was not explicitly specified but is automatically added because
212
+ `rexe` will add any requires needed for automatic parsing and formatting.
206
213
 
207
214
  This extra output is sent to standard error (_stderr_) instead of standard output
208
215
  (_stdout_) so that it will not pollute the "real" data when stdout is piped to
@@ -232,17 +239,19 @@ and in different ways. Here is the help text relating to input modes:
232
239
  ```
233
240
 
234
241
  The first three are _filter_ modes; they make standard input available
235
- to your code as `self`, and automatically output to standard output
236
- the last value evaluated by your code.
242
+ to your code as `self`.
237
243
 
238
244
  The last (and default) is the _executor_ mode. It merely assists you in
239
245
  executing the code you provide without any special implicit handling of standard input.
240
246
 
247
+ All input modes automatically output to standard output the last value evaluated by your code.
248
+ You can suppress automatic output with the `-on` option.
249
+
241
250
 
242
251
  #### -ml "Line" Filter Mode
243
252
 
244
253
  In this mode, your code would be called once per line of input,
245
- and in each call, `self` would evaluate to the line of text:
254
+ and in each call, `self` would evaluate to each line of text:
246
255
 
247
256
  ```
248
257
  ➜ ~  echo "hello\ngoodbye" | rexe -ms reverse
@@ -251,13 +260,13 @@ eybdoog
251
260
  ```
252
261
 
253
262
  `reverse` is implicitly called on each line of standard input. `self`
254
- is the input line in each call (we could also have used `self.reverse` but the `self` would have been redundant.).
263
+ is the input line in each call (we could also have used `self.reverse` but the `self.` would have been redundant.).
255
264
 
256
- Be aware that although you can control the _content_ of output records,
265
+ Be aware that, in this mode, although you can control the _content_ of output records,
257
266
  there is no way to selectively _exclude_ records from being output. Even if the result of the code
258
267
  is nil or the empty string, a newline will be output. If this is an issue, you could do one of the following:
259
268
 
260
- * use Enumerator mode and call `select`, `filter`, `reject`, etc.
269
+ * use `-me` Enumerator mode and call `select`, `filter`, `reject`, etc.
261
270
  * use the `-on` _no output_ mode and call `puts` explicitly for the output you _do_ want
262
271
 
263
272
 
@@ -284,7 +293,7 @@ Since `self` is an enumerable, we can call `first` and then `each_with_index`.
284
293
 
285
294
  #### -mb "Big String" Filter Mode
286
295
 
287
- In this mode, all standard input is combined into a single, (possibly
296
+ In this mode, all standard input is combined into a single (possibly
288
297
  large) string, with newline characters joining the lines in the string.
289
298
 
290
299
  A good example of when you would use this is when you parse JSON or YAML text;
@@ -306,8 +315,8 @@ if you defined methods, constants, instance variables, etc., in your code.
306
315
  If you may have more input than would fit in memory, you can do the following:
307
316
 
308
317
  * use `-ml` (line) mode so you are fed only 1 line at a time
309
- * use an Enumerator, either by specifying the `-me` (enumerator) mode option,
310
- or using `-mn` (no input) mode in conjunction with something like `STDIN.each_line`. Then:
318
+ * use an Enumerator, either by a) specifying the `-me` (enumerator) mode option,
319
+ or b) using `-mn` (no input) mode in conjunction with something like `STDIN.each_line`. Then:
311
320
  * Make sure not to call any methods (e.g. `map`, `select`)
312
321
  that will produce an array of all the input because that will pull all the records into memory, or:
313
322
  * use [lazy enumerators](https://www.honeybadger.io/blog/using-lazy-enumerators-to-work-with-large-files-in-ruby/)
@@ -332,7 +341,7 @@ since there is no preprocessing of standard input in that mode.
332
341
 
333
342
  ### Output Formats
334
343
 
335
- Several output formats are provided for your convenience. Here they are:
344
+ Several output formats are provided for your convenience:
336
345
 
337
346
  * `-oa` - Awesome Print - calls `.ai` on the object to get the string that `ap` would print
338
347
  * `-oi` - Inspect - calls `inspect` on the object
@@ -349,7 +358,7 @@ You may wonder why these formats are provided, given that their functionality
349
358
  could be included in the custom code instead. Here's why:
350
359
 
351
360
  * The savings in command line length goes a long way to making these commands more readable and feasible.
352
- * It's much simpler to use multiple formats, as there is no need to change the code itself. This also enables
361
+ * It's much simpler to switch formats, as there is no need to change the code itself. This also enables
353
362
  parameterization of the output format.
354
363
 
355
364
 
@@ -359,7 +368,7 @@ For your convenience, the information displayed in verbose mode is available to
359
368
  by accessing the `$RC` global variable, which contains an OpenStruct. Probably most useful in that object
360
369
  is the record count, accessible with both `$RC.count` and `$RC.i`.
361
370
  This is only really useful in line mode, because in the others
362
- it will always be 0 or 1. Here is an example of how you might use it:
371
+ it will always be 0 or 1. Here is an example of how you might use it as a kind of progress indicator:
363
372
 
364
373
  ```
365
374
  ➜ ~  ➜ ~  find / | rexe -ml -on \
@@ -371,6 +380,11 @@ File entry #108000 is /usr/local/Cellar/go/1.11.5/libexec/src/runtime/os_linux_n
371
380
  ...
372
381
  ```
373
382
 
383
+ Note that a single quote was used for the Ruby code here;
384
+ if a double quote were used, the `$RC` would have been interpreted
385
+ and removed by the shell.
386
+
387
+
374
388
  ### Implementing Domain Specific Languages (DSL's)
375
389
 
376
390
  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:
@@ -393,7 +407,7 @@ trivially easily. Just to illustrate, here's how you would open a REPL on the Fi
393
407
  `self` would evaluate to the `File` class, so you could call class methods implicitly using only their names:
394
408
 
395
409
  ```
396
- rock_books git:(master) ✗  rexe -r pry File.pry
410
+ ~  rexe -r pry File.pry
397
411
 
398
412
  [6] pry(File)> size '/etc/passwd'
399
413
  6804
@@ -403,7 +417,11 @@ true
403
417
  true
404
418
  ```
405
419
 
406
- This could be really handy if you call `pry` on a custom object that has methods especially suited to your task.
420
+ This could be really handy if you call `pry` on a custom object that has methods especially suited to your task:
421
+
422
+ ```
423
+ ➜ ~  rexe -r wifi-wand,pry WifiWand::MacOsModel.new.pry
424
+ ```
407
425
 
408
426
  Ruby is supremely well suited for DSL's since it does not require parentheses for method calls,
409
427
  so calls to your custom methods _look_ like built in language commands and keywords.
@@ -417,7 +435,11 @@ necessary to quote the Ruby code. You can use single or double quotes to have th
417
435
  as a single argument.
418
436
  An excellent reference for how they differ is [here](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash).
419
437
 
420
- Feel free to fall back on Ruby's super useful `%q{}` and `%Q{}`, equivalent to single and double quotes, respectively.
438
+ Personally, I find single quotes more useful since special characters like `$` in my Ruby code will
439
+ not be disturbed.
440
+
441
+ When specifying the Ruby code, feel free to fall back on Ruby's super useful `%q{}` and `%Q{}`,
442
+ equivalent to single and double quotes, respectively.
421
443
 
422
444
 
423
445
  ### No Op Mode
@@ -429,15 +451,19 @@ you want to see the configuration options before running it for real.
429
451
 
430
452
  ### Mimicking Method Arguments
431
453
 
432
- You may want to support arguments in your code. One of the previous examples downloaded currency conversion rates. Let's find out the available currency codes:
454
+ You may want to support arguments in your `rexe` commands.
455
+ You could do this by piping in the arguments as `rexe`'s stdin.
456
+
457
+ One of the previous examples downloaded currency conversion rates.
458
+ To prepare for an example of how to do this, let's find out the available currency codes:
433
459
 
434
460
  ```
435
- ➜ /  echo $EUR_RATES_JSON | rexe -rjson -mb \
436
- "JSON.parse(self)['rates'].keys.sort.join(' ')"
461
+ ➜ /  echo $EUR_RATES_JSON | rexe -ij -mb "self['rates'].keys.sort.join(' ')"
437
462
  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
438
463
  ```
439
-
440
- Here would be a way to output a single rate:
464
+
465
+ The codes output are the legal arguments that could be sent to `rexe`'s stdin as an argument.
466
+ Let's find out the Euro exchange rate for _PHP_, Philippine Pesos:
441
467
 
442
468
  ```
443
469
  ➜ ~  echo PHP | rexe -ml -rjson \
@@ -449,6 +475,12 @@ AUD BGN BRL CAD CHF CNY CZK DKK GBP HKD HRK HUF IDR ILS INR ISK JPY KRW MXN MYR
449
475
 
450
476
  In this code, `self` is the currency code `PHP` (Philippine Peso). We have accessed the JSON text to parse from the environment variable we previously populated.
451
477
 
478
+ Because we "used up" stdin for the argument, we could not make use of automatic parsing
479
+ of the currency exchange data (using the `-ij` option),
480
+ which would have greatly simplified the command. One possible solution to this would be
481
+ to pipe in the JSON or YAML representation of a hash
482
+ with entries for both the argument and the currency exchange data...but this might
483
+ make the command line too complex to be practical.
452
484
 
453
485
  ### Using the Clipboard for Text Processing
454
486
 
@@ -486,11 +518,9 @@ when you change the content of the clipboard.
486
518
  ### Multiline Ruby Commands
487
519
 
488
520
  Although `rexe` is cleanest with short one liners, you may want to use it to include nontrivial Ruby code
489
- in your shell script as well. If you do this, you may need to:
521
+ in your shell script as well. If you do this, you may need to add trailing backslashes to the lines of Ruby code.
490
522
 
491
- * add trailing backslashes to lines of Ruby code
492
- * use %q{} and %Q{} in your Ruby code instead of single and double quotes,
493
- since the quotes have special meaning to the shell
523
+ In addition, don't forget you can use `%q{}` and `%Q{}` in your Ruby code instead of single and double quotes.
494
524
 
495
525
 
496
526
  ### The Use of Semicolons
@@ -536,9 +566,20 @@ puts to_a"
536
566
 
537
567
  There may be times when you have specified a load or require on the command line
538
568
  or in the `REXE_OPTIONS` environment variable,
539
- but you want to override it for a single invocation. Currently you cannot
540
- unspecify a single resource, but you can unspecify _all_ the requires or loads
541
- with the `-r!` and `-l!` command line options, respectively.
569
+ but you want to override it for a single invocation. Here are your options:
570
+
571
+ 1) Unspecify _all_ the requires or loads with the `-r!` and `-l!` command line options, respectively.
572
+
573
+ 2) Unspecify individual requires or loads by preceding the name with `-`, e.g. `-r -rails`.
574
+ Array subtraction is used, so:
575
+
576
+ ```
577
+ ➜ ~  rexe -n -r rails,rails,rails,-rails -ga
578
+ ```
579
+
580
+ ...would show that the final `-rails` cancelled all the previous `rails` specifications.
581
+
582
+
542
583
 
543
584
 
544
585
  ### Clearing _All_ Options
@@ -567,27 +608,49 @@ Files loaded with the `-l` option are treated the same way.
567
608
  Requiring gems and modules for _all_ invocations of `rexe` will make your commands simpler and more concise, but will be a waste of execution time if they are not needed. You can inspect the execution times to see just how much time is being wasted. For example, we can find out that nokogiri takes about 0.15 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):
568
609
 
569
610
  ```
570
- ➜ ~  rexe -gy 2>&1 | grep duration
611
+ ➜ ~  rexe -gy 2>&1 "''" | grep duration
571
612
  :duration_secs: 0.0012
572
613
 
573
- ➜ ~  rexe -gy -r nokogiri 2>&1 | grep duration
614
+ ➜ ~  rexe -gy -r nokogiri "''" 2>&1 | grep duration
574
615
  :duration_secs: 0.148671
575
616
  ```
576
617
 
618
+ (For the above to work, the `nokogiri` gem needs to be installed.)
619
+
620
+
621
+ ### Operating System Support
622
+
623
+ `rexe` has been tested successfully on Mac OS, Linux, and Windows Subsystem for Linux (WSL).
624
+ It is intended as a tool for the Unix shell, and, as such, no attempt is made to support
625
+ Windows non-Unix shells.
577
626
 
578
627
 
579
628
  ### More Examples
580
629
 
581
630
  Here are some more examples to illustrate the use of `rexe`.
582
631
 
632
+ ----
633
+ Output the contents of `ENV` using AwesomePrint:
634
+
635
+ ```
636
+ ➜ ~  rexe -oa ENV
637
+ {
638
+ ...
639
+ "LANG" => "en_US.UTF-8",
640
+ "PWD" => "/Users/kbennett/work/rexe",
641
+ "SHELL" => "/bin/zsh",
642
+ ...
643
+ }
644
+ ```
645
+
583
646
  ----
584
647
 
585
648
  Show disk space used/free on a Mac's main hard drive's main partition:
586
649
 
587
650
  ```
588
651
  ➜ ~  df -h | grep disk1s1 | rexe -ml \
589
- "x = split; puts %Q{#{x[4]} Used: #{x[2]}, Avail #{x[3]}}"
590
- 91% Used: 412Gi, Avail 44Gi
652
+ "x = split; puts %Q{#{x[4]} Used: #{x[2]}, Avail: #{x[3]}}"
653
+ 91% Used: 412Gi, Avail: 44Gi
591
654
  ```
592
655
 
593
656
  (Note that `split` is equivalent to `self.split`, and because the `-ml` option is used, `self` is the line of text.
@@ -729,7 +792,7 @@ Then when I issue a command that succeeds, the Hallelujah Chorus is played:
729
792
 
730
793
  ----
731
794
 
732
- Another formatting example...I wanted to reformat this help text:
795
+ Another formatting example...I wanted to reformat this help text...
733
796
 
734
797
  ```
735
798
  'i' => Inspect
@@ -741,6 +804,7 @@ Another formatting example...I wanted to reformat this help text:
741
804
  'y' => YAML
742
805
  ```
743
806
 
807
+ ...into something more suitable for my help text.
744
808
  Admittedly, the time it took to do this with rexe probably exceeded the time to do it manually,
745
809
  but it was an interesting exercise and made it easy to try different formats. Here it is:
746
810
 
@@ -759,14 +823,15 @@ but it was an interesting exercise and made it easy to try different formats. He
759
823
 
760
824
  ### Conclusion
761
825
 
762
- `rexe` is not revolutionary technology, it's just plumbing that removes low level
826
+ `rexe` is not revolutionary technology, it's just plumbing that removes parsing,
827
+ formatting, and low level
763
828
  configuration from your command line so that you can focus on the high level
764
829
  task at hand.
765
830
 
766
- When we think of a new piece of software, we usually think "what would this be
831
+ When we consider a new piece of software, we usually think "what would this be
767
832
  helpful with now?". However, for me, the power of `rexe` is not so much what I can do
768
833
  with it in a single use case now, but rather what will I be able to do with it over time
769
- as I get used to the concept and my supporting code and its uses evolve.
834
+ as I accumulate more experience and expertise.
770
835
 
771
836
  I suggest starting to use `rexe` even for modest improvements in workflow, even
772
837
  if it doesn't seem compelling. There's a good chance that as you use it over
@@ -779,10 +844,32 @@ will be proportional to the extent to which you use environment variables
779
844
  and loaded files for configuration and shared code.
780
845
  Be responsible and disciplined in making this configuration and code as clean and organized as possible.
781
846
 
847
+ ----
848
+
782
849
  #### Footnotes
783
850
 
784
851
  [^1]: `rexe` is an embellishment of the minimal but excellent `rb` script at
785
852
  https://github.com/thisredone/rb. I started using `rb` and thought of lots of
786
853
  other features I would like to have, so I started working on `rexe`.
787
854
 
788
- [^2]: You might wonder why we don't just refrain from sending output to stdout on null or false. That is certainly easy to implement, but there are other ways to accomplish this (using _enumerable_ or _no input_ modes), and the lack of output might be surprising and disconcerting to the user. What do _you_ think, which approach makes more sense to you?
855
+ [^2]: Making this truly OS-portable is a lot more complex than it looks on the surface.
856
+ On Linux, `xdg-open` may not be installed by default. Also, Windows Subsystem for Linux (WSL)
857
+ out of the box is not able to launch graphical applications.
858
+
859
+ Here is a _start_ at a method that opens a resource portably across operating systems:
860
+
861
+ ```ruby
862
+ def open_resource(resource_identifier)
863
+ command = case (`uname`.chomp)
864
+ when 'Darwin'
865
+ 'open'
866
+ when 'Linux'
867
+ 'xdg-open'
868
+ else
869
+ 'start'
870
+ end
871
+
872
+ `#{command} #{resource_identifier}`
873
+ end
874
+ ```
875
+