rexe 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +233 -129
- data/exe/rexe +264 -224
- data/rexe.gemspec +2 -7
- metadata +13 -7
data/exe/rexe
CHANGED
@@ -12,12 +12,13 @@ require 'shellwords'
|
|
12
12
|
|
13
13
|
class Rexe
|
14
14
|
|
15
|
-
VERSION = '0.
|
15
|
+
VERSION = '0.14.0'
|
16
16
|
|
17
17
|
PROJECT_URL = 'https://github.com/keithrbennett/rexe'
|
18
18
|
|
19
19
|
|
20
20
|
class Options < Struct.new(
|
21
|
+
:input_filespec,
|
21
22
|
:input_format,
|
22
23
|
:input_mode,
|
23
24
|
:loads,
|
@@ -34,13 +35,14 @@ class Rexe
|
|
34
35
|
|
35
36
|
|
36
37
|
def clear
|
37
|
-
self.
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
self.
|
41
|
-
self.
|
42
|
-
self.
|
43
|
-
self.
|
38
|
+
self.input_filespec = nil
|
39
|
+
self.input_format = :none
|
40
|
+
self.input_mode = :none
|
41
|
+
self.output_format = :none
|
42
|
+
self.loads = []
|
43
|
+
self.requires = []
|
44
|
+
self.log_format = :none
|
45
|
+
self.noop = false
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
@@ -54,7 +56,7 @@ class Rexe
|
|
54
56
|
'l' => :line,
|
55
57
|
'e' => :enumerator,
|
56
58
|
'b' => :one_big_string,
|
57
|
-
'n' => :
|
59
|
+
'n' => :none
|
58
60
|
}
|
59
61
|
end
|
60
62
|
|
@@ -86,7 +88,7 @@ class Rexe
|
|
86
88
|
'j' => :json,
|
87
89
|
'J' => :pretty_json,
|
88
90
|
'm' => :marshal,
|
89
|
-
'n' => :
|
91
|
+
'n' => :none,
|
90
92
|
'p' => :puts, # default
|
91
93
|
'P' => :pretty_print,
|
92
94
|
's' => :to_s,
|
@@ -101,7 +103,7 @@ class Rexe
|
|
101
103
|
inspect: ->(obj) { obj.inspect + "\n" },
|
102
104
|
json: ->(obj) { obj.to_json },
|
103
105
|
marshal: ->(obj) { Marshal.dump(obj) },
|
104
|
-
|
106
|
+
none: ->(_obj) { nil },
|
105
107
|
pretty_json: ->(obj) { JSON.pretty_generate(obj) },
|
106
108
|
pretty_print: ->(obj) { obj.pretty_inspect },
|
107
109
|
puts: ->(obj) { sio = StringIO.new; sio.puts(obj); sio.string }, # default
|
@@ -123,42 +125,54 @@ class Rexe
|
|
123
125
|
|
124
126
|
|
125
127
|
|
126
|
-
|
127
|
-
:log_formatter, :start_time, :user_source_code
|
128
|
+
class CommandLineParser
|
128
129
|
|
130
|
+
attr_reader :lookups, :options
|
129
131
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
132
|
+
def initialize
|
133
|
+
@lookups = Lookups.new
|
134
|
+
@options = Options.new
|
135
|
+
end
|
135
136
|
|
136
137
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
138
|
+
# Inserts contents of REXE_OPTIONS environment variable at the beginning of ARGV.
|
139
|
+
private def prepend_environment_options
|
140
|
+
env_opt_string = ENV['REXE_OPTIONS']
|
141
|
+
if env_opt_string
|
142
|
+
args_to_prepend = Shellwords.shellsplit(env_opt_string)
|
143
|
+
ARGV.unshift(args_to_prepend).flatten!
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
def add_format_requires_to_requires_list
|
149
|
+
formats = [options.input_format, options.output_format, options.log_format]
|
150
|
+
requires = formats.map { |format| lookups.format_requires[format] }.uniq.compact
|
151
|
+
requires.each { |r| options.requires << r }
|
152
|
+
end
|
142
153
|
|
143
154
|
|
144
|
-
|
145
|
-
|
155
|
+
def help_text
|
156
|
+
<<~HEREDOC
|
146
157
|
|
147
158
|
rexe -- Ruby Command Line Executor/Filter -- v#{VERSION} -- #{PROJECT_URL}
|
148
159
|
|
149
|
-
Executes Ruby code on the command line, optionally
|
160
|
+
Executes Ruby code on the command line, optionally automating management of standard input
|
161
|
+
and standard output, and optionally parsing input and formatting output with YAML, JSON, etc.
|
150
162
|
|
151
163
|
rexe [options] 'Ruby source code'
|
152
164
|
|
153
165
|
Options:
|
154
166
|
|
155
167
|
-c --clear_options Clear all previous command line options specified up to now
|
168
|
+
-f --input_file Use this file instead of stdin; autodetects YAML and JSON file extensions
|
169
|
+
If YAML or JSON: parses file in that mode, sets input mode to -mb
|
156
170
|
-g --log_format FORMAT Log format, logs to stderr, defaults to none (see -o for format options)
|
157
171
|
-h, --help Print help and exit
|
158
|
-
-i, --input_format FORMAT Input format
|
172
|
+
-i, --input_format FORMAT Input format
|
159
173
|
-ij JSON
|
160
174
|
-im Marshal
|
161
|
-
-in None
|
175
|
+
-in None (default)
|
162
176
|
-iy YAML
|
163
177
|
-l, --load RUBY_FILE(S) Ruby file(s) to load, comma separated;
|
164
178
|
! to clear all, or precede a name with '-' to remove
|
@@ -174,8 +188,8 @@ class Rexe
|
|
174
188
|
-oj JSON
|
175
189
|
-oJ Pretty JSON
|
176
190
|
-om Marshal
|
177
|
-
-on No Output
|
178
|
-
-op Puts
|
191
|
+
-on No Output (default)
|
192
|
+
-op Puts
|
179
193
|
-os to_s
|
180
194
|
-oy YAML
|
181
195
|
-r, --require REQUIRE(S) Gems and built-in libraries to require, comma separated;
|
@@ -187,273 +201,299 @@ class Rexe
|
|
187
201
|
If there is a REXE_OPTIONS environment variable, its content will be prepended to the command line
|
188
202
|
so that you can specify options implicitly (e.g. `export REXE_OPTIONS="-r awesome_print,yaml"`)
|
189
203
|
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
# Inserts contents of REXE_OPTIONS environment variable at the beginning of ARGV.
|
195
|
-
private def prepend_environment_options
|
196
|
-
env_opt_string = ENV['REXE_OPTIONS']
|
197
|
-
if env_opt_string
|
198
|
-
args_to_prepend = Shellwords.shellsplit(env_opt_string)
|
199
|
-
ARGV.unshift(args_to_prepend).flatten!
|
204
|
+
HEREDOC
|
200
205
|
end
|
201
|
-
end
|
202
206
|
|
203
207
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
'
|
208
|
-
|
209
|
-
'
|
210
|
-
|
211
|
-
|
208
|
+
# File file input mode; detects the input mode (JSON, YAML, or None) from the extension.
|
209
|
+
def autodetect_file_format(filespec)
|
210
|
+
extension = File.extname(filespec).downcase
|
211
|
+
if extension == '.json'
|
212
|
+
:json
|
213
|
+
elsif extension == '.yml' || extension == '.yaml'
|
214
|
+
:yaml
|
215
|
+
else
|
216
|
+
:none
|
217
|
+
end
|
212
218
|
end
|
213
219
|
|
214
|
-
`#{command} #{resource_identifier}`
|
215
|
-
end
|
216
|
-
|
217
220
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
requires.each { |r| options.requires << r }
|
222
|
-
end
|
221
|
+
# Using 'optparse', parses the command line.
|
222
|
+
# Settings go into this instance's properties (see Struct declaration).
|
223
|
+
def parse
|
223
224
|
|
225
|
+
prepend_environment_options
|
224
226
|
|
225
|
-
|
226
|
-
# Settings go into this instance's properties (see Struct declaration).
|
227
|
-
private def parse_command_line
|
227
|
+
OptionParser.new do |parser|
|
228
228
|
|
229
|
-
OptionParser.new do |parser|
|
230
229
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
230
|
+
parser.on('-f', '--input_file FILESPEC',
|
231
|
+
'Use this file instead of stdin; autodetects YAML and JSON file extensions') do |v|
|
232
|
+
unless File.exist?(v)
|
233
|
+
raise "File #{v} does not exist."
|
234
|
+
end
|
235
|
+
options.input_filespec = v
|
236
|
+
options.input_format = autodetect_file_format(v)
|
237
|
+
if [:json, :yaml].include?(options.input_format)
|
238
|
+
options.input_mode = :one_big_string
|
239
|
+
end
|
236
240
|
end
|
237
|
-
end
|
238
241
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
242
|
+
parser.on('-g', '--log_format FORMAT', 'Log format, logs to stderr, defaults to none (see -o for format options)') do |v|
|
243
|
+
options.log_format = lookups.output_formats[v]
|
244
|
+
if options.log_format.nil?
|
245
|
+
puts help_text
|
246
|
+
raise "Output mode was '#{v}' but must be one of #{lookups.output_formats.keys}."
|
247
|
+
end
|
248
|
+
end
|
246
249
|
|
247
|
-
|
248
|
-
if options.input_format.nil?
|
250
|
+
parser.on("-h", "--help", "Show help") do |_help_requested|
|
249
251
|
puts help_text
|
250
|
-
|
252
|
+
exit
|
251
253
|
end
|
252
|
-
end
|
253
254
|
|
254
|
-
|
255
|
-
|
256
|
-
options.loads.clear
|
257
|
-
else
|
258
|
-
loadfiles = v.split(',').map(&:strip)
|
259
|
-
removes, adds = loadfiles.partition { |filespec| filespec[0] == '-' }
|
255
|
+
parser.on('-i', '--input_format FORMAT',
|
256
|
+
'Mode with which to parse input values (n = none (default), j = JSON, m = Marshal, y = YAML') do |v|
|
260
257
|
|
261
|
-
|
262
|
-
if
|
263
|
-
|
264
|
-
|
265
|
-
existent.each { |filespec| options.loads << filespec }
|
258
|
+
options.input_format = lookups.input_formats[v]
|
259
|
+
if options.input_format.nil?
|
260
|
+
puts help_text
|
261
|
+
raise "Input mode was '#{v}' but must be one of #{lookups.input_formats.keys}."
|
266
262
|
end
|
263
|
+
end
|
264
|
+
|
265
|
+
parser.on('-l', '--load RUBY_FILE(S)', 'Ruby file(s) to load, comma separated, or ! to clear') do |v|
|
266
|
+
if v == '!'
|
267
|
+
options.loads.clear
|
268
|
+
else
|
269
|
+
loadfiles = v.split(',').map(&:strip).map { |s| File.expand_path(s) }
|
270
|
+
removes, adds = loadfiles.partition { |filespec| filespec[0] == '-' }
|
267
271
|
|
268
|
-
|
272
|
+
existent, nonexistent = adds.partition { |filespec| File.exists?(filespec) }
|
273
|
+
if nonexistent.any?
|
274
|
+
raise("\nDid not find the following files to load: #{nonexistent}\n\n")
|
275
|
+
else
|
276
|
+
existent.each { |filespec| options.loads << filespec }
|
277
|
+
end
|
278
|
+
|
279
|
+
removes.each { |filespec| options.loads -= [filespec[1..-1]] }
|
280
|
+
end
|
269
281
|
end
|
270
|
-
end
|
271
282
|
|
272
|
-
|
273
|
-
|
283
|
+
parser.on('-m', '--input_mode MODE',
|
284
|
+
'Mode with which to handle input (-ml, -me, -mb, -mn (default)') do |v|
|
274
285
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
286
|
+
options.input_mode = lookups.input_modes[v]
|
287
|
+
if options.input_mode.nil?
|
288
|
+
puts help_text
|
289
|
+
raise "Input mode was '#{v}' but must be one of #{lookups.input_modes.keys}."
|
290
|
+
end
|
279
291
|
end
|
280
|
-
end
|
281
292
|
|
282
|
-
|
283
|
-
|
293
|
+
parser.on('-o', '--output_format FORMAT',
|
294
|
+
'Mode with which to format values for output (`-o` + [aijJmnpsy])') do |v|
|
284
295
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
296
|
+
options.output_format = lookups.output_formats[v]
|
297
|
+
if options.output_format.nil?
|
298
|
+
puts help_text
|
299
|
+
raise "Output mode was '#{v}' but must be one of #{lookups.output_formats.keys}."
|
300
|
+
end
|
289
301
|
end
|
290
|
-
end
|
291
302
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
303
|
+
parser.on('-r', '--require REQUIRE(S)',
|
304
|
+
'Gems and built-in libraries (e.g. shellwords, yaml) to require, comma separated, or ! to clear') do |v|
|
305
|
+
if v == '!'
|
306
|
+
options.requires.clear
|
307
|
+
else
|
308
|
+
v.split(',').map(&:strip).each do |r|
|
309
|
+
if r[0] == '-'
|
310
|
+
options.requires -= [r[1..-1]]
|
311
|
+
else
|
312
|
+
options.requires << r
|
313
|
+
end
|
302
314
|
end
|
303
315
|
end
|
304
316
|
end
|
305
|
-
end
|
306
317
|
|
307
|
-
|
308
|
-
|
309
|
-
|
318
|
+
parser.on('-c', '--clear_options', "Clear all previous command line options") do |v|
|
319
|
+
options.clear
|
320
|
+
end
|
310
321
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
322
|
+
# See https://stackoverflow.com/questions/54576873/ruby-optionparser-short-code-for-boolean-option
|
323
|
+
# for an excellent explanation of this optparse incantation.
|
324
|
+
# According to the answer, valid options are:
|
325
|
+
# -n no, -n yes, -n false, -n true, -n n, -n y, -n +, but not -n -.
|
326
|
+
parser.on('-n', '--[no-]noop [FLAG]', TrueClass, "Do not execute the code (useful with -g)") do |v|
|
327
|
+
options.noop = (v.nil? ? true : v)
|
328
|
+
end
|
318
329
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
330
|
+
parser.on('-v', '--version', 'Print version') do
|
331
|
+
puts VERSION
|
332
|
+
exit
|
333
|
+
end
|
323
334
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
335
|
+
# Undocumented feature
|
336
|
+
parser.on('', '--open-project') do
|
337
|
+
open_resource(PROJECT_URL)
|
338
|
+
exit(0)
|
339
|
+
end
|
340
|
+
|
341
|
+
end.parse!
|
329
342
|
|
330
|
-
|
343
|
+
# We want to do this after all options have been processed because we don't want any clearing of the
|
344
|
+
# options (by '-c', etc.) to result in exclusion of these needed requires.
|
345
|
+
add_format_requires_to_requires_list
|
331
346
|
|
332
|
-
|
333
|
-
|
334
|
-
add_format_requires_to_requires_list
|
347
|
+
options.requires = options.requires.sort.uniq
|
348
|
+
options.loads.uniq!
|
335
349
|
|
336
|
-
|
337
|
-
options.loads.uniq!
|
350
|
+
options
|
338
351
|
|
352
|
+
end
|
339
353
|
end
|
340
354
|
|
341
355
|
|
342
|
-
|
343
|
-
filespec = File.join(Dir.home, '.rexerc')
|
344
|
-
load(filespec) if File.exists?(filespec)
|
345
|
-
end
|
356
|
+
class Main
|
346
357
|
|
358
|
+
attr_reader :callable, :input_parser, :lookups,
|
359
|
+
:options, :output_formatter,
|
360
|
+
:log_formatter, :start_time, :user_source_code
|
347
361
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
362
|
+
|
363
|
+
def initialize
|
364
|
+
@lookups = Lookups.new
|
365
|
+
@start_time = DateTime.now
|
366
|
+
end
|
353
367
|
|
354
368
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
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}`
|
360
380
|
end
|
361
381
|
|
362
|
-
value = eval_context_object.instance_eval(&code)
|
363
382
|
|
364
|
-
|
365
|
-
|
383
|
+
private def load_global_config_if_exists
|
384
|
+
filespec = File.join(Dir.home, '.rexerc')
|
385
|
+
load(filespec) if File.exists?(filespec)
|
366
386
|
end
|
367
|
-
rescue Errno::EPIPE
|
368
|
-
exit(-13)
|
369
|
-
end
|
370
387
|
|
371
388
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
def $RC.i; count end # `i` aliases `count` so you can more concisely get the count in your user code
|
386
|
-
end
|
389
|
+
private def init_parser_and_formatters
|
390
|
+
@input_parser = lookups.input_parsers[options.input_format]
|
391
|
+
@output_formatter = lookups.formatters[options.output_format]
|
392
|
+
@log_formatter = lookups.formatters[options.log_format]
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
# Executes the user specified code in the manner appropriate to the input mode.
|
397
|
+
# Performs any optionally specified parsing on input and formatting on output.
|
398
|
+
private def execute(eval_context_object, code)
|
399
|
+
if options.input_format != :none && options.input_mode != :none
|
400
|
+
eval_context_object = input_parser.(eval_context_object)
|
401
|
+
end
|
387
402
|
|
403
|
+
value = eval_context_object.instance_eval(&code)
|
388
404
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
405
|
+
unless options.output_format == :none
|
406
|
+
print output_formatter.(value)
|
407
|
+
end
|
408
|
+
rescue Errno::EPIPE
|
409
|
+
exit(-13)
|
393
410
|
end
|
394
411
|
|
395
|
-
eval("Proc.new { #{user_source_code} }")
|
396
|
-
end
|
397
412
|
|
413
|
+
# The global $RC (Rexe Context) OpenStruct is available in your user code.
|
414
|
+
# In order to make it possible to access this object in your loaded files, we are not creating
|
415
|
+
# it here; instead we add properties to it. This way, you can initialize an OpenStruct yourself
|
416
|
+
# in your loaded code and it will still work. If you do that, beware, any properties you add will be
|
417
|
+
# included in the log output. If the to_s of your added objects is large, that might be a pain.
|
418
|
+
private def init_rexe_context
|
419
|
+
$RC ||= OpenStruct.new
|
420
|
+
$RC.count = 0
|
421
|
+
$RC.rexe_version = VERSION
|
422
|
+
$RC.start_time = start_time.iso8601
|
423
|
+
$RC.source_code = user_source_code
|
424
|
+
$RC.options = options.to_h
|
425
|
+
|
426
|
+
def $RC.i; count end # `i` aliases `count` so you can more concisely get the count in your user code
|
427
|
+
end
|
398
428
|
|
399
|
-
private def lookup_action(mode)
|
400
|
-
{
|
401
|
-
line: -> { STDIN.each { |l| execute(l.chomp, callable); $RC.count += 1 } },
|
402
|
-
enumerator: -> { execute(STDIN.each_line, callable); $RC.count += 1 },
|
403
|
-
one_big_string: -> { big_string = STDIN.read; execute(big_string, callable); $RC.count += 1 },
|
404
|
-
no_input: -> { execute(Object.new, callable) }
|
405
|
-
}[mode]
|
406
|
-
end
|
407
429
|
|
430
|
+
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
|
408
434
|
|
409
|
-
|
410
|
-
if options.log_format != :none
|
411
|
-
$RC.duration_secs = Time.now - start_time.to_time
|
412
|
-
STDERR.puts(log_formatter.($RC.to_h))
|
435
|
+
eval("Proc.new { #{user_source_code} }")
|
413
436
|
end
|
414
|
-
end
|
415
437
|
|
416
438
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
439
|
+
private def lookup_action(mode)
|
440
|
+
input = options.input_filespec ? File.open(options.input_filespec) : STDIN
|
441
|
+
{
|
442
|
+
line: -> { input.each { |l| execute(l.chomp, callable); $RC.count += 1 } },
|
443
|
+
enumerator: -> { execute(input.each_line, callable); $RC.count += 1 },
|
444
|
+
one_big_string: -> { big_string = input.read; execute(big_string, callable); $RC.count += 1 },
|
445
|
+
none: -> { execute(Object.new, callable) }
|
446
|
+
}.fetch(mode)
|
447
|
+
end
|
448
|
+
|
449
|
+
|
450
|
+
private def output_log_entry
|
451
|
+
if options.log_format != :none
|
452
|
+
$RC.duration_secs = Time.now - start_time.to_time
|
453
|
+
STDERR.puts(log_formatter.($RC.to_h))
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
|
458
|
+
# Bypasses Bundler's restriction on loading gems
|
459
|
+
# (see https://stackoverflow.com/questions/55144094/bundler-doesnt-permit-using-gems-in-project-home-directory)
|
460
|
+
private def require!(the_require)
|
461
|
+
begin
|
429
462
|
require the_require
|
463
|
+
rescue LoadError => error
|
464
|
+
gem_path = `gem which #{the_require}`
|
465
|
+
if gem_path.chomp.strip.empty?
|
466
|
+
raise error # re-raise the error, can't fix it
|
467
|
+
else
|
468
|
+
load_dir = File.dirname(gem_path)
|
469
|
+
$LOAD_PATH << load_dir
|
470
|
+
require the_require
|
471
|
+
end
|
430
472
|
end
|
431
473
|
end
|
432
|
-
end
|
433
474
|
|
434
475
|
|
435
|
-
|
436
|
-
|
476
|
+
# This class' entry point.
|
477
|
+
def call
|
437
478
|
|
438
|
-
|
439
|
-
parse_command_line
|
479
|
+
@options = CommandLineParser.new.parse
|
440
480
|
|
441
|
-
|
442
|
-
|
443
|
-
|
481
|
+
options.requires.each { |r| require!(r) }
|
482
|
+
load_global_config_if_exists
|
483
|
+
options.loads.each { |file| load(file) }
|
444
484
|
|
445
|
-
|
446
|
-
|
485
|
+
@user_source_code = ARGV.join(' ')
|
486
|
+
@callable = create_callable
|
447
487
|
|
448
|
-
|
449
|
-
|
488
|
+
init_rexe_context
|
489
|
+
init_parser_and_formatters
|
450
490
|
|
451
|
-
|
452
|
-
|
491
|
+
# This is where the user's source code will be executed; the action will in turn call `execute`.
|
492
|
+
lookup_action(options.input_mode).call unless options.noop
|
453
493
|
|
454
|
-
|
494
|
+
output_log_entry
|
495
|
+
end
|
455
496
|
end
|
456
497
|
end
|
457
498
|
|
458
|
-
|
459
|
-
Bundler.with_clean_env { Rexe.new.call }
|
499
|
+
Bundler.with_clean_env { Rexe::Main.new.call }
|