markdown_exec 1.3.1 → 1.3.3.1

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.
data/Rakefile CHANGED
@@ -30,10 +30,10 @@ require_relative 'lib/tap'
30
30
  include CLI
31
31
 
32
32
  include Tap
33
- tap_config envvar: MarkdownExec::TAP_DEBUG
34
33
 
35
34
  RuboCop::RakeTask.new do |task|
36
35
  task.requires << 'rubocop-minitest'
36
+ task.requires << 'rubocop-rspec'
37
37
  end
38
38
 
39
39
  desc 'named task because minitest not included in rubocop tests'
@@ -42,7 +42,7 @@ task :rubocopminitest do
42
42
  end
43
43
 
44
44
  task default: %i[test reek rubocop rubocopminitest]
45
- # task default: %i[spec test reek rubocop rubocopminitest]
45
+ # task default: %i[rspec test reek rubocop rubocopminitest]
46
46
 
47
47
  # task :default => :build
48
48
 
@@ -73,6 +73,12 @@ task :clean do
73
73
  system 'rm *.gem'
74
74
  end
75
75
 
76
+ desc 'minitest'
77
+ task :minitest do
78
+ puts `bundle exec ruby ./lib/object_present.rb`
79
+ puts `bundle exec ruby ./lib/cached_nested_file_reader.rb`
80
+ end
81
+
76
82
  desc 'reek'
77
83
  task :reek do
78
84
  `reek --config .reek .`
@@ -237,15 +243,58 @@ task :update_menu_yml do
237
243
 
238
244
  ## secondary options
239
245
  #
246
+ {
247
+ arg_name: 'BOOL',
248
+ default: false,
249
+ description: 'Display only blocks of type "bash"',
250
+ env_var: 'MDE_BASH_ONLY',
251
+ opt_name: 'bash_only',
252
+ procname: 'val_as_bool'
253
+ },
240
254
  {
241
255
  arg_name: "INT.#{DISPLAY_LEVEL_BASE}-#{DISPLAY_LEVEL_MAX}",
242
256
  default: DISPLAY_LEVEL_DEFAULT,
243
- description: "Output display level (#{DISPLAY_LEVEL_BASE} to #{DISPLAY_LEVEL_MAX} [data, +context, +info])",
257
+ description: 'Output display level ' \
258
+ "(#{DISPLAY_LEVEL_BASE} to #{DISPLAY_LEVEL_MAX} " \
259
+ '[data, +context, +info])',
244
260
  env_var: 'MDE_DISPLAY_LEVEL',
245
261
  long_name: 'display-level',
246
262
  opt_name: 'display_level',
247
263
  procname: 'val_as_int'
248
264
  },
265
+ {
266
+ arg_name: 'REGEX',
267
+ default: nil,
268
+ description: 'Exclude blocks with name matching',
269
+ env_var: 'MDE_EXCLUDE_BY_NAME_REGEX',
270
+ opt_name: 'exclude_by_name_regex',
271
+ procname: 'val_as_str'
272
+ },
273
+ {
274
+ arg_name: 'REGEX',
275
+ default: nil,
276
+ description: 'Exclude blocks with shell matching',
277
+ env_var: 'MDE_EXCLUDE_BY_SHELL_REGEX',
278
+ opt_name: 'exclude_by_shell_regex',
279
+ procname: 'val_as_str'
280
+ },
281
+ {
282
+ arg_name: 'BOOL',
283
+ default: true,
284
+ description: 'Hide all blocks of type "expect"',
285
+ env_var: 'MDE_EXCLUDE_EXPECT_BLOCKS',
286
+ opt_name: 'exclude_expect_blocks',
287
+ procname: 'val_as_bool'
288
+ },
289
+ {
290
+ arg_name: 'BOOL',
291
+ default: true,
292
+ description: 'Exclude blocks with name matching expression " \
293
+ "`block_name_hidden_match`',
294
+ env_var: 'MDE_HIDE_BLOCKS_BY_NAME',
295
+ opt_name: 'hide_blocks_by_name',
296
+ procname: 'val_as_bool'
297
+ },
249
298
  {
250
299
  arg_name: 'INT.1-',
251
300
  default: 32,
@@ -260,7 +309,6 @@ task :update_menu_yml do
260
309
  default: MarkdownExec::BIN_NAME,
261
310
  description: 'Name prefix for stdout files',
262
311
  env_var: 'MDE_LOGGED_STDOUT_FILENAME_PREFIX',
263
- # long_name: 'logged-stdout-filename-prefix',
264
312
  opt_name: 'logged_stdout_filename_prefix',
265
313
  procname: 'val_as_str'
266
314
  },
@@ -269,7 +317,6 @@ task :update_menu_yml do
269
317
  default: false,
270
318
  description: 'Display document name in block selection menu',
271
319
  env_var: 'MDE_MENU_BLOCKS_WITH_DOCNAME',
272
- # long_name: 'menu-blocks-with-docname',
273
320
  opt_name: 'menu_blocks_with_docname',
274
321
  procname: 'val_as_bool'
275
322
  },
@@ -278,10 +325,25 @@ task :update_menu_yml do
278
325
  default: false,
279
326
  description: 'Display headings (levels 1,2,3) in block selection menu',
280
327
  env_var: 'MDE_MENU_BLOCKS_WITH_HEADINGS',
281
- # long_name: 'menu-blocks-with-headings',
282
328
  opt_name: 'menu_blocks_with_headings',
283
329
  procname: 'val_as_bool'
284
330
  },
331
+ {
332
+ arg_name: 'BOOL',
333
+ default: true,
334
+ description: 'Display Exit option at top of menu',
335
+ env_var: 'MDE_MENU_EXIT_AT_TOP',
336
+ opt_name: 'menu_exit_at_top',
337
+ procname: 'val_as_bool'
338
+ },
339
+ {
340
+ arg_name: 'BOOL',
341
+ default: true,
342
+ description: 'Display Exit option in menu',
343
+ env_var: 'MDE_MENU_WITH_EXIT',
344
+ opt_name: 'menu_with_exit',
345
+ procname: 'val_as_bool'
346
+ },
285
347
  {
286
348
  arg_name: 'BOOL',
287
349
  default: false,
@@ -291,6 +353,14 @@ task :update_menu_yml do
291
353
  opt_name: 'output_execution_summary',
292
354
  procname: 'val_as_bool'
293
355
  },
356
+ {
357
+ arg_name: 'BOOL',
358
+ default: false,
359
+ description: 'Output saved script filename at end of execution',
360
+ env_var: 'MDE_OUTPUT_SAVED_SCRIPT_FILENAME',
361
+ opt_name: 'output_saved_script_filename',
362
+ procname: 'val_as_bool'
363
+ },
294
364
  {
295
365
  arg_name: 'BOOL',
296
366
  default: false,
@@ -332,7 +402,6 @@ task :update_menu_yml do
332
402
  default: 0o755,
333
403
  description: 'chmod for saved scripts',
334
404
  env_var: 'MDE_SAVED_SCRIPT_CHMOD',
335
- # long_name: 'saved-script-chmod',
336
405
  opt_name: 'saved_script_chmod',
337
406
  procname: 'val_as_int'
338
407
  },
@@ -341,7 +410,6 @@ task :update_menu_yml do
341
410
  default: MarkdownExec::BIN_NAME,
342
411
  description: 'Name prefix for saved scripts',
343
412
  env_var: 'MDE_SAVED_SCRIPT_FILENAME_PREFIX',
344
- # long_name: 'saved-script-filename-prefix',
345
413
  opt_name: 'saved_script_filename_prefix',
346
414
  procname: 'val_as_str'
347
415
  },
@@ -359,7 +427,6 @@ task :update_menu_yml do
359
427
  default: 'mde_*.sh',
360
428
  description: 'Glob matching saved scripts',
361
429
  env_var: 'MDE_SAVED_SCRIPT_GLOB',
362
- # long_name: 'saved-script-glob',
363
430
  opt_name: 'saved_script_glob',
364
431
  procname: 'val_as_str'
365
432
  },
@@ -377,11 +444,25 @@ task :update_menu_yml do
377
444
  default: 'mde_*.out.txt',
378
445
  description: 'Glob matching saved outputs',
379
446
  env_var: 'MDE_SAVED_STDOUT_GLOB',
380
- # long_name: 'saved-stdout-glob',
381
447
  opt_name: 'saved_stdout_glob',
382
448
  procname: 'val_as_str'
383
449
  },
384
-
450
+ {
451
+ arg_name: 'REGEX',
452
+ default: nil,
453
+ description: 'Select blocks with name matching',
454
+ env_var: 'MDE_SELECT_BY_NAME_REGEX',
455
+ opt_name: 'select_by_name_regex',
456
+ procname: 'val_as_str'
457
+ },
458
+ {
459
+ arg_name: 'REGEX',
460
+ default: nil,
461
+ description: 'Select blocks with shell matching',
462
+ env_var: 'MDE_SELECT_BY_SHELL_REGEX',
463
+ opt_name: 'select_by_shell_regex',
464
+ procname: 'val_as_str'
465
+ },
385
466
  {
386
467
  default: '^[\(\[].*[\)\]]$',
387
468
  description: 'Pattern for blocks to hide from user-selection',
@@ -408,13 +489,13 @@ task :update_menu_yml do
408
489
  procname: 'val_as_str'
409
490
  },
410
491
  {
411
- default: '<(?<full>(?<type>\$)?(?<name>[A-Za-z]\S*))',
492
+ default: '<(?<full>(?<type>\$)?(?<name>[A-Za-z_\-\.\w]+))',
412
493
  env_var: 'MDE_BLOCK_STDIN_SCAN',
413
494
  opt_name: 'block_stdin_scan',
414
495
  procname: 'val_as_str'
415
496
  },
416
497
  {
417
- default: '>(?<full>(?<type>\$)?(?<name>[A-Za-z]\S*))',
498
+ default: '>(?<full>(?<type>\$)?(?<name>[A-Za-z_\-\.\w]+))',
418
499
  env_var: 'MDE_BLOCK_STDOUT_SCAN',
419
500
  opt_name: 'block_stdout_scan',
420
501
  procname: 'val_as_str'
@@ -432,7 +513,7 @@ task :update_menu_yml do
432
513
  procname: 'val_as_str'
433
514
  },
434
515
  {
435
- default: '^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$',
516
+ default: '^`{3,}(?<shell>[^`\s]*) *:?(?<name>[^\s]*) *(?<rest>.*) *$',
436
517
  env_var: 'MDE_FENCED_START_EX_MATCH',
437
518
  opt_name: 'fenced_start_ex_match',
438
519
  procname: 'val_as_str'
@@ -455,6 +536,12 @@ task :update_menu_yml do
455
536
  opt_name: 'heading3_match',
456
537
  procname: 'val_as_str'
457
538
  },
539
+ {
540
+ default: '^ *@import (.+)$',
541
+ env_var: 'MDE_IMPORT_PATTERN',
542
+ opt_name: 'import_pattern',
543
+ procname: 'val_as_str'
544
+ },
458
545
  {
459
546
  default: '*.[Mm][Dd]',
460
547
  env_var: 'MDE_MD_FILENAME_GLOB',
@@ -605,18 +692,12 @@ task :update_menu_yml do
605
692
  env_var: 'MDE_OUTPUT_DIVIDER_COLOR',
606
693
  opt_name: 'output_divider_color',
607
694
  procname: 'val_as_str'
608
- # },
609
- # {
610
- # default: '',
611
- # description: '',
612
- # env_var: 'MDE_PROMPT_',
613
- # opt_name: 'prompt_',
614
- # procname: 'val_as_str'
615
695
  }
616
696
  ]
617
697
 
618
698
  File.write(MENU_YML,
619
- "# #{MarkdownExec::APP_NAME} - #{MarkdownExec::APP_DESC} (#{MarkdownExec::VERSION})\n" +
699
+ "# #{MarkdownExec::APP_NAME} - #{MarkdownExec::APP_DESC} " \
700
+ "(#{MarkdownExec::VERSION})\n" +
620
701
  menu_options.to_yaml)
621
702
  puts `stat #{MENU_YML}`
622
703
  end
@@ -630,10 +711,13 @@ def update_tab_completion(target)
630
711
 
631
712
  svhs = YAML.load File.open(MENU_YML)
632
713
  svhs.each do |svh|
633
- svh[:compreply] = CLI::value_for_cli(svh[:default]) if svh[:compreply].nil?
714
+ svh[:compreply] = CLI.value_for_cli(svh[:default]) if svh[:compreply].nil?
634
715
  end.tap_inspect name: :svhs, type: :yaml
635
716
 
636
- File.write target, ERB.new(File.read(filespec = File.join(BF, 'tab_completion.sh.erb'))).result(binding)
717
+ File.write target,
718
+ ERB.new(File.read(filespec = File.join(BF,
719
+ 'tab_completion.sh.erb')))
720
+ .result(binding)
637
721
  puts `stat #{filespec}`
638
722
  end
639
723
 
@@ -13,7 +13,7 @@ __filedirs_all()
13
13
  }
14
14
 
15
15
  _mde_echo_version() {
16
- echo "1.3.1"
16
+ echo "1.3.3.1"
17
17
  }
18
18
 
19
19
  _mde() {
@@ -138,4 +138,4 @@ _mde() {
138
138
 
139
139
  complete -o filenames -o nospace -F _mde mde
140
140
  # _mde_echo_version
141
- # echo "Updated: 2022-10-29 23:24:15 UTC"
141
+ # echo "Updated: 2023-10-04 01:23:26 UTC"
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # encoding=utf-8
5
+
6
+ # version 2023-10-03
7
+
8
+ require 'bundler/setup'
9
+ Bundler.require(:default)
10
+
11
+ ##
12
+ # The CachedNestedFileReader class provides functionality to read file lines with the ability
13
+ # to process '#import filename' directives. When such a directive is encountered in a file,
14
+ # the corresponding 'filename' is read and its contents are inserted at that location.
15
+ # This class caches read files to avoid re-reading the same file multiple times.
16
+ # It allows clients to read lines with or without providing a block.
17
+ #
18
+ class CachedNestedFileReader
19
+ def initialize(import_pattern: /^ *#import (.+)$/)
20
+ @file_cache = {}
21
+ @import_pattern = import_pattern
22
+ end
23
+
24
+ def readlines(filename, &block)
25
+ if @file_cache.key?(filename)
26
+ @file_cache[filename].each(&block) if block_given?
27
+ return @file_cache[filename]
28
+ end
29
+
30
+ directory_path = File.dirname(filename)
31
+ lines = File.readlines(filename, chomp: true)
32
+ processed_lines = []
33
+
34
+ lines.each do |line|
35
+ if (match = line.match(@import_pattern))
36
+ included_file_path = if match[1].strip.match %r{^/}
37
+ match[1].strip
38
+ else
39
+ File.join(directory_path, match[1].strip)
40
+ end
41
+ processed_lines += readlines(included_file_path, &block)
42
+ else
43
+ processed_lines.push(line)
44
+ yield line if block_given?
45
+ end
46
+ end
47
+
48
+ @file_cache[filename] = processed_lines
49
+ end
50
+
51
+ private
52
+
53
+ def fetch_lines(filename)
54
+ @fetch_lines_cache[filename] ||= File.readlines(filename, chomp: true)
55
+ end
56
+ end
57
+
58
+ if $PROGRAM_NAME == __FILE__
59
+ require 'minitest/autorun'
60
+ require 'tempfile'
61
+
62
+ ##
63
+ # The CachedNestedFileReaderTest class provides testing for
64
+ # the CachedNestedFileReader class.
65
+ #
66
+ class CachedNestedFileReaderTest < Minitest::Test
67
+ def setup
68
+ @file2 = Tempfile.new('test2.txt')
69
+ @file2.write("ImportedLine1\nImportedLine2")
70
+ @file2.rewind
71
+
72
+ @file1 = Tempfile.new('test1.txt')
73
+ @file1.write("Line1\nLine2\n #insert #{@file2.path}\nLine3")
74
+ @file1.rewind
75
+ # binding.pry
76
+ @reader = CachedNestedFileReader.new(import_pattern: /^ *#insert (.+)$/)
77
+ end
78
+
79
+ def teardown
80
+ @file1.close
81
+ @file1.unlink
82
+
83
+ @file2.close
84
+ @file2.unlink
85
+ end
86
+
87
+ def test_readlines_without_imports
88
+ result = []
89
+ @reader.readlines(@file2.path) { |line| result << line }
90
+ assert_equal %w[ImportedLine1 ImportedLine2], result
91
+ end
92
+
93
+ def test_readlines_with_imports
94
+ result = []
95
+ @reader.readlines(@file1.path) { |line| result << line }
96
+ assert_equal %w[Line1 Line2 ImportedLine1 ImportedLine2 Line3], result
97
+ end
98
+
99
+ def test_caching_functionality
100
+ # First read
101
+ result1 = []
102
+ @reader.readlines(@file2.path) { |line| result1 << line }
103
+
104
+ # Simulate file content change
105
+ @file2.reopen(@file2.path, 'w') { |f| f.write('ChangedLine') }
106
+
107
+ # Second read (should read from cache, not the changed file)
108
+ result2 = []
109
+ @reader.readlines(@file2.path) { |line| result2 << line }
110
+
111
+ assert_equal result1, result2
112
+ assert_equal %w[ImportedLine1 ImportedLine2], result2
113
+ end
114
+ end
115
+ end
data/lib/colorize.rb CHANGED
@@ -14,6 +14,10 @@
14
14
  # │ │ │
15
15
  # │5 │ for flashing text
16
16
  class String
17
+ def plain
18
+ self
19
+ end
20
+
17
21
  def black
18
22
  "\033[30m#{self}\033[0m"
19
23
  end
data/lib/env.rb CHANGED
@@ -10,17 +10,22 @@ module Env
10
10
  # :reek:NilCheck
11
11
  # :reek:UtilityFunction
12
12
  def env_bool(name, default: false)
13
- return default if name.nil? || (val = ENV[name]).nil?
13
+ return default if name.nil? || (val = ENV.fetch(name, nil)).nil?
14
14
  return false if val.empty? || val == '0'
15
15
 
16
16
  true
17
17
  end
18
18
 
19
+ # :reek:UtilityFunction
20
+ def env_bool_false(name)
21
+ !(val = (name && ENV.fetch(name, nil))).nil? && !(val.empty? || val == '0')
22
+ end
23
+
19
24
  # skip :reek:DataClump
20
25
  # skip :reek:NilCheck
21
26
  # skip :reek:UtilityFunction
22
27
  def env_int(name, default: 0)
23
- return default if name.nil? || (val = ENV[name]).nil?
28
+ return default if name.nil? || (val = ENV.fetch(name, nil)).nil?
24
29
  return default if val.empty?
25
30
 
26
31
  val.to_i
@@ -30,7 +35,7 @@ module Env
30
35
  # skip :reek:NilCheck
31
36
  # skip :reek:UtilityFunction
32
37
  def env_str(name, default: '')
33
- return default if name.nil? || (val = ENV[name]).nil?
38
+ return default if name.nil? || (val = ENV.fetch(name, nil)).nil?
34
39
 
35
40
  val || default
36
41
  end
data/lib/env_opts.rb ADDED
@@ -0,0 +1,242 @@
1
+ # frozen_string_literal: true
2
+
3
+ # encoding=utf-8
4
+
5
+ require_relative 'tap'
6
+
7
+ include Tap #; tap_config
8
+
9
+ # define options with initial values
10
+ # option to read value from environmnt variables
11
+ # option to cast input values
12
+ # value priority: default < environment < argument
13
+ #
14
+ # :reek:TooManyMethods
15
+ class EnvOpts
16
+ attr_reader :opts, :values
17
+
18
+ def initialize(opts_raw = {}, argv = ARGV)
19
+ @opts = {}
20
+ @values = {}
21
+ add_options(opts_raw)
22
+ # parse(argv, &block) if block_given?
23
+ block_given? ? parse(argv, &block) : parse(argv)
24
+
25
+ self # rubocop:disable Lint/Void
26
+ end
27
+
28
+ # add options to menu
29
+ # calculate help text
30
+ #
31
+ # :reek:NestedIterators
32
+ def add_options(opts_raw)
33
+ return self if opts_raw.nil?
34
+
35
+ help_rows = opts_raw.map do |key, opt_raw|
36
+ opt_name = key_name_to_option_name(key)
37
+
38
+ # set_per_options(opt_name, opt_raw)
39
+ @opts[opt_name] = (opt_raw ||= {})
40
+ set_key_value_as_cast(opt_name, EnvOpts.optdefault(opt_raw))
41
+ set_key_value_per_environment_as_cast(opt_name, opt_raw)
42
+
43
+ [
44
+ [20, '-', "--#{opt_name}"],
45
+ [16, '-',
46
+ if @opts[opt_name][:env].present?
47
+ option_name_to_environment_name(opt_name, @opts[opt_name])
48
+ else
49
+ ''
50
+ end],
51
+ # [24, '-', get_environment_value_from_option(opt_name, @opts[opt_name])],
52
+ [24, '-', @opts[opt_name][:default]],
53
+ [6, '-', if (fixed = opt_raw.fetch(:fixed, nil)).nil?
54
+ ":#{option_cast(@opts[opt_name])}"
55
+ else
56
+ fixed.to_s
57
+ end]
58
+ ]
59
+ end
60
+
61
+ max_widths = help_rows.reduce([0, 0, 0, 0]) do |memo, vals|
62
+ vals.map.with_index do |val, ind|
63
+ [memo[ind], val[2].to_s.length].max
64
+ end
65
+ end
66
+
67
+ @values['help'] = help_rows.map do |row|
68
+ row.map.with_index do |cell, ind|
69
+ format("%#{cell[1]}#{max_widths[ind]}s", cell[2])
70
+ end.join(' ')
71
+ end.join("\n")
72
+
73
+ self
74
+ end
75
+
76
+ # accept :d or :default option
77
+ #
78
+ def self.optdefault(opt_raw)
79
+ return opt_raw[:d] unless opt_raw[:d].nil?
80
+
81
+ opt_raw[:default]
82
+ end
83
+
84
+ def output_help
85
+ puts @values['help']
86
+ end
87
+
88
+ # process arguments as mostly pairs of option name and value
89
+ #
90
+ def parse(argv = ARGV)
91
+ return self if argv.nil? || !(argv&.count || 0).positive?
92
+
93
+ args_ind = 0
94
+ while args_ind < argv.count
95
+ args_consumed = 0
96
+ arg = argv.fetch(args_ind, '') #.tap_inspect 'argument', source: 'EnvOpts'
97
+ if arg.start_with? '--'
98
+ opt_name = arg[2..-1] #.tap_inspect 'opt_name', source: 'EnvOpts'
99
+ args_consumed = consume_arguments(opt_name,
100
+ argv.fetch(args_ind + 1, nil))
101
+ end
102
+
103
+ if args_consumed.zero?
104
+ if arg == '--help'
105
+ output_help
106
+ exit
107
+ elsif block_given?
108
+ yield 'NAO', [arg]
109
+ args_consumed = 1
110
+ else
111
+ warn "Invalid argument: #{arg.inspect} in #{argv.inspect}"
112
+ exit 1
113
+ end
114
+ end
115
+
116
+ args_ind += args_consumed
117
+ end
118
+
119
+ self
120
+ end
121
+
122
+ # set option current values per environment values
123
+ #
124
+ def options_per_environment_as_cast(opts_raw)
125
+ return self if opts_raw.nil?
126
+
127
+ opts_raw.each do |key, opt_raw|
128
+ set_key_value_per_environment_as_cast(key_name_to_option_name(key),
129
+ opt_raw)
130
+ end
131
+
132
+ self
133
+ end
134
+
135
+ # symbol name to option name
136
+ # option names use hyphens
137
+ #
138
+ def self.symbol_name_to_option_name(name)
139
+ name.to_s.gsub('_', '-') #.tap_inspect
140
+ end
141
+
142
+ private
143
+
144
+ # convert key name or symbol to an option name
145
+ #
146
+ def key_name_to_option_name(key)
147
+ (key.is_a?(Symbol) ? EnvOpts.symbol_name_to_option_name(key) : key) #.tap_inspect
148
+ end
149
+
150
+ # get cast of environment variable
151
+ #
152
+ def option_cast(opt_raw)
153
+ (opt_raw[:cast].present? ? opt_raw[:cast].to_s : 'to_s')
154
+ end
155
+
156
+ # update value for named option
157
+ # return number of arguments used
158
+ #
159
+ def consume_arguments(opt_name, value)
160
+ return 0 if (opt_raw = @opts.fetch(opt_name, nil)).nil?
161
+
162
+ return 0 unless opt_raw.fetch(:option, true)
163
+
164
+ if !(fixed = opt_raw.fetch(:fixed, nil)).nil?
165
+ set_key_value_as_cast(opt_name, fixed)
166
+ 1
167
+ elsif value.nil?
168
+ 0
169
+ else
170
+ set_key_value_as_cast(opt_name, value)
171
+ 2
172
+ end
173
+ end
174
+
175
+ # option names use hyphens
176
+ #
177
+ def method_name_to_option_name(name)
178
+ name.to_s.gsub('_', '-') #.tap_inspect
179
+ end
180
+
181
+ # read and write options using the option name as a method
182
+ #
183
+ def method_missing(method_name, *args)
184
+ if method_name.to_s.end_with?('=')
185
+ value = args.first
186
+ name = method_name_to_option_name(method_name.to_s[0..-2])
187
+ set_key_value_as_cast(name, value)
188
+ else
189
+ @values[method_name_to_option_name(method_name)]
190
+ end #.tap_inspect "ref #{method_name}", source: 'EnvOpts'
191
+ end
192
+
193
+ # option name to environment name
194
+ # if true or empty, compute from option name
195
+ #
196
+ def option_name_to_environment_name(opt_name, opt_raw)
197
+ case env_name = opt_raw.fetch(:env, '')
198
+ when true, ''
199
+ "#{@values['env-prefix']}#{opt_name.upcase.gsub('-', '_')}"
200
+ else
201
+ env_name
202
+ end
203
+ end
204
+
205
+ # get environment value from option
206
+ #
207
+ def get_environment_value_from_option(opt_name, opt_raw)
208
+ ENV.fetch(option_name_to_environment_name(opt_name, opt_raw),
209
+ nil)
210
+ end
211
+
212
+ # option names are available as methods
213
+ #
214
+ # :reek:BooleanParameter
215
+ def respond_to_missing?(method_name, include_private = false)
216
+ (@opts.keys.include?(method_name_to_option_name(method_name)) || super)
217
+ end
218
+
219
+ def set_key_value_as_cast(key, value)
220
+ opt = @opts[key]
221
+ set_key_value_raw(key, (opt[:cast] ? value.send(opt[:cast]) : value))
222
+ end
223
+
224
+ # set key value_per environment as cast
225
+ #
226
+ def set_key_value_per_environment_as_cast(key, opt_raw)
227
+ return if opt_raw[:env].nil?
228
+
229
+ value = get_environment_value_from_option(key, opt_raw)
230
+
231
+ return unless value
232
+
233
+ set_key_value_as_cast(key,
234
+ opt_raw[:cast] ? value.send(opt_raw[:cast]) : value)
235
+ end
236
+
237
+ # set key value (raw)
238
+ #
239
+ def set_key_value_raw(key, value)
240
+ @values[key] = value
241
+ end
242
+ end