bashly 0.7.8 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bashly/cli.rb +2 -1
  3. data/lib/bashly/commands/add.rb +41 -33
  4. data/lib/bashly/commands/base.rb +21 -3
  5. data/lib/bashly/commands/generate.rb +23 -11
  6. data/lib/bashly/commands/preview.rb +5 -4
  7. data/lib/bashly/commands/validate.rb +7 -1
  8. data/lib/bashly/concerns/renderable.rb +8 -1
  9. data/lib/bashly/concerns/validation_helpers.rb +69 -0
  10. data/lib/bashly/config_validator.rb +28 -41
  11. data/lib/bashly/deprecation.rb +25 -0
  12. data/lib/bashly/extensions/array.rb +5 -0
  13. data/lib/bashly/extensions/string.rb +6 -0
  14. data/lib/bashly/extensions/yaml.rb +2 -0
  15. data/lib/bashly/libraries.yml +13 -9
  16. data/lib/bashly/script/argument.rb +13 -1
  17. data/lib/bashly/script/base.rb +7 -29
  18. data/lib/bashly/script/catch_all.rb +4 -0
  19. data/lib/bashly/script/command.rb +35 -7
  20. data/lib/bashly/script/environment_variable.rb +6 -0
  21. data/lib/bashly/script/flag.rb +9 -0
  22. data/lib/bashly/script/wrapper.rb +11 -7
  23. data/lib/bashly/settings.rb +34 -5
  24. data/lib/bashly/templates/bashly.yml +2 -2
  25. data/lib/bashly/templates/settings.yml +24 -0
  26. data/lib/bashly/templates/strings.yml +1 -1
  27. data/lib/bashly/version.rb +1 -1
  28. data/lib/bashly/views/argument/usage.erb +2 -2
  29. data/lib/bashly/views/argument/validations.erb +1 -1
  30. data/lib/bashly/views/command/catch_all_filter.erb +1 -1
  31. data/lib/bashly/views/command/command_fallback.erb +1 -1
  32. data/lib/bashly/views/command/command_filter.erb +1 -1
  33. data/lib/bashly/views/command/command_functions.erb +1 -1
  34. data/lib/bashly/views/command/default_assignments.erb +1 -1
  35. data/lib/bashly/views/command/dependencies_filter.erb +1 -1
  36. data/lib/bashly/views/command/environment_variables_filter.erb +1 -1
  37. data/lib/bashly/views/command/fixed_flags_filter.erb +1 -1
  38. data/lib/bashly/views/command/footer.erb +1 -0
  39. data/lib/bashly/views/command/function.erb +1 -1
  40. data/lib/bashly/views/command/initialize.erb +1 -1
  41. data/lib/bashly/views/command/inspect_args.erb +1 -1
  42. data/lib/bashly/views/command/master_script.erb +1 -0
  43. data/lib/bashly/views/command/normalize_input.erb +1 -1
  44. data/lib/bashly/views/command/parse_requirements.erb +1 -1
  45. data/lib/bashly/views/command/parse_requirements_case.erb +5 -23
  46. data/lib/bashly/views/command/parse_requirements_case_catch_all.erb +18 -0
  47. data/lib/bashly/views/command/parse_requirements_case_repeatable.erb +18 -0
  48. data/lib/bashly/views/command/parse_requirements_case_simple.erb +18 -0
  49. data/lib/bashly/views/command/parse_requirements_while.erb +1 -1
  50. data/lib/bashly/views/command/required_args_filter.erb +1 -1
  51. data/lib/bashly/views/command/required_flags_filter.erb +1 -1
  52. data/lib/bashly/views/command/root_command.erb +1 -1
  53. data/lib/bashly/views/command/run.erb +1 -1
  54. data/lib/bashly/views/command/usage.erb +3 -3
  55. data/lib/bashly/views/command/usage_args.erb +1 -1
  56. data/lib/bashly/views/command/usage_commands.erb +1 -1
  57. data/lib/bashly/views/command/usage_environment_variables.erb +1 -1
  58. data/lib/bashly/views/command/usage_examples.erb +1 -1
  59. data/lib/bashly/views/command/usage_fixed_flags.erb +1 -1
  60. data/lib/bashly/views/command/usage_flags.erb +1 -1
  61. data/lib/bashly/views/command/user_filter.erb +1 -1
  62. data/lib/bashly/views/command/user_lib.erb +2 -2
  63. data/lib/bashly/views/command/version_command.erb +1 -1
  64. data/lib/bashly/views/command/whitelist_filter.erb +11 -1
  65. data/lib/bashly/views/environment_variable/usage.erb +1 -1
  66. data/lib/bashly/views/flag/case.erb +2 -28
  67. data/lib/bashly/views/flag/case_arg.erb +19 -0
  68. data/lib/bashly/views/flag/case_no_arg.erb +8 -0
  69. data/lib/bashly/views/flag/conflicts.erb +1 -1
  70. data/lib/bashly/views/flag/usage.erb +1 -1
  71. data/lib/bashly/views/flag/validations.erb +1 -1
  72. data/lib/bashly/views/wrapper/bash3_bouncer.erb +1 -1
  73. data/lib/bashly/views/wrapper/wrapper.erb +1 -1
  74. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d05f653ff5439edd7108eaff3c6265926dc4e894453fce1c59bc4727c4c98d1f
4
- data.tar.gz: 39afd30e66779103285d9df99f74f4e3cc8af61220d15a6b1cb02b21a4bebe57
3
+ metadata.gz: d3d0126229189987753e653a635054113961b1e9e0244d4cdb956beb1d5aff94
4
+ data.tar.gz: 886987a65edc65d16d2134589cbb4ee9f3fcb9e0b1819c8a87211bcd2d164d0c
5
5
  SHA512:
6
- metadata.gz: 8db8291a3db5a496626676942eddcadb61f7080ab316ed17652af5f58376e40efa85473e7a665a3966dbbfdbc37b6662577a3e13b50d9f49c36a87792854cefc
7
- data.tar.gz: c844bf07c523c6f04a21874a08e3c2c40fafe4562829f419f77fd17f74ebaa70b5006e61c50b430399dcca00158f9d4b4fdb7afe4dfeb2e3a425c8eb544fcc22
6
+ metadata.gz: 880579e8bb650c8835cc7992054f3f4dd3e765ddc1b7072f83ed6fc9049d4b56b38c4a64220c3dd154f8fdbf199462cca1ef955d36d465a0d57ecc00715bd85e
7
+ data.tar.gz: efa2f73f9eed6d5ba1ebb432e37ef639e618bc1556ba83059ccad4804b6568b407d86f91fe11faa3335b69103e368fdb9bf1339f90af1fd15cb742b91163b911
data/lib/bashly/cli.rb CHANGED
@@ -6,7 +6,8 @@ module Bashly
6
6
  class CLI
7
7
  def self.runner
8
8
  runner = MisterBin::Runner.new version: Bashly::VERSION,
9
- header: "Bashly - Bash CLI Generator"
9
+ header: "Bashly - Bash CLI Generator",
10
+ footer: "Help: !txtpur!bashly COMMAND --help!txtrst!\nDocs: !undblu!https://bashly.dannyb.co"
10
11
 
11
12
  runner.route 'init', to: Commands::Init
12
13
  runner.route 'preview', to: Commands::Preview
@@ -3,14 +3,15 @@ module Bashly
3
3
  class Add < Base
4
4
  help "Add extra features and customization to your script"
5
5
 
6
- usage "bashly add strings [--force]"
7
- usage "bashly add lib [--force]"
8
- usage "bashly add config [--force]"
9
6
  usage "bashly add colors [--force]"
10
- usage "bashly add yaml [--force]"
11
- usage "bashly add validations [--force]"
12
- usage "bashly add test [--force]"
13
7
  usage "bashly add comp FORMAT [OUTPUT --force]"
8
+ usage "bashly add config [--force]"
9
+ usage "bashly add lib [--force]"
10
+ usage "bashly add settings [--force]"
11
+ usage "bashly add strings [--force]"
12
+ usage "bashly add test [--force]"
13
+ usage "bashly add validations [--force]"
14
+ usage "bashly add yaml [--force]"
14
15
  usage "bashly add (-h|--help)"
15
16
 
16
17
  option "-f --force", "Overwrite existing files"
@@ -18,14 +19,15 @@ module Bashly
18
19
  param "FORMAT", "Output format, can be one of:\n function : generate a function file to be included in your script.\n script : generate a standalone bash completions script.\n yaml : generate a yaml compatible with completely."
19
20
  param "OUTPUT", "For the 'comp function' command: Name of the generated function.\nFor the 'comp script' or 'comp yaml' commands: path to output file.\nIn all cases, this is optional and will have sensible defaults."
20
21
 
21
- command "strings", "Copy an additional configuration file to your project, allowing you to customize all the tips and error strings."
22
- command "lib", "Create the additional lib directory for additional user scripts. All *.sh scripts in this folder will be included in the final bash script."
23
- command "config", "Add standard functions for handling INI files to the lib directory."
24
22
  command "colors", "Add standard functions for printing colorful and formatted text to the lib directory."
25
- command "yaml", "Add standard functions for reading YAML files to the lib directory."
26
- command "validations", "Add argument validation functions to the lib directory."
27
- command "test", "Add approval testing."
28
23
  command "comp", "Generate a bash completions script or function."
24
+ command "config", "Add standard functions for handling INI files to the lib directory."
25
+ command "lib", "Create the additional lib directory for additional user scripts. All *.sh scripts in this folder will be included in the final bash script."
26
+ command "settings", "Copy a sample settings.yml file to your project, allowing you to customize some bashly options."
27
+ command "strings", "Copy an additional configuration file to your project, allowing you to customize all the tips and error strings."
28
+ command "test", "Add approval testing."
29
+ command "validations", "Add argument validation functions to the lib directory."
30
+ command "yaml", "Add standard functions for reading YAML files to the lib directory."
29
31
 
30
32
  example "bashly add strings --force"
31
33
  example "bashly add comp function"
@@ -34,45 +36,51 @@ module Bashly
34
36
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
35
37
  environment "BASHLY_LIB_DIR", "The path to use for creating the library files, relative to the source dir [default: lib]"
36
38
 
37
- def strings_command
38
- add_lib 'strings'
39
+ attr_reader :skip_src_check
40
+
41
+ def colors_command
42
+ add_lib 'colors'
39
43
  end
40
44
 
41
- def lib_command
42
- add_lib 'lib'
45
+ def comp_command
46
+ format = args['FORMAT']
47
+ output = args['OUTPUT']
48
+
49
+ case format
50
+ when "script" then add_lib 'completions_script', output
51
+ when "function" then add_lib 'completions', output
52
+ when "yaml" then add_lib 'completions_yaml', output
53
+ else raise Error, "Unrecognized format: #{format}"
54
+ end
43
55
  end
44
56
 
45
57
  def config_command
46
58
  add_lib 'config'
47
59
  end
48
60
 
49
- def colors_command
50
- add_lib 'colors'
61
+ def settings_command
62
+ @skip_src_check = true
63
+ add_lib 'settings'
51
64
  end
52
65
 
53
- def yaml_command
54
- add_lib 'yaml'
66
+ def strings_command
67
+ add_lib 'strings'
55
68
  end
56
69
 
57
- def validations_command
58
- add_lib 'validations'
70
+ def lib_command
71
+ add_lib 'lib'
59
72
  end
60
73
 
61
74
  def test_command
62
75
  add_lib 'test'
63
76
  end
64
77
 
65
- def comp_command
66
- format = args['FORMAT']
67
- output = args['OUTPUT']
68
-
69
- case format
70
- when "script" then add_lib 'completions_script', output
71
- when "function" then add_lib 'completions', output
72
- when "yaml" then add_lib 'completions_yaml', output
73
- else raise Error, "Unrecognized format: #{format}"
74
- end
78
+ def yaml_command
79
+ add_lib 'yaml'
80
+ end
75
81
 
82
+ def validations_command
83
+ add_lib 'validations'
76
84
  end
77
85
 
78
86
  private
@@ -89,7 +97,7 @@ module Bashly
89
97
  end
90
98
 
91
99
  def safe_write(path, content)
92
- if !Dir.exist? Settings.source_dir
100
+ if !skip_src_check and !Dir.exist? Settings.source_dir
93
101
  raise InitError, "Directory !txtgrn!#{Settings.source_dir}!txtrst! does not exist\nRun !txtpur!bashly init!txtrst! first"
94
102
  end
95
103
 
@@ -6,10 +6,28 @@ module Bashly
6
6
  class Base < MisterBin::Command
7
7
  include AssetHelper
8
8
 
9
+ def config
10
+ @config ||= Config.new "#{Settings.source_dir}/bashly.yml"
11
+ end
12
+
13
+ def config_validator
14
+ @config_validator ||= ConfigValidator.new config
15
+ end
16
+
9
17
  def validate_config
10
- config = Config.new "#{Settings.source_dir}/bashly.yml"
11
- validator = ConfigValidator.new config
12
- validator.validate
18
+ config_validator.validate
19
+ end
20
+
21
+ def with_valid_config
22
+ validate_config
23
+ yield
24
+ show_deprecations
25
+ end
26
+
27
+ def show_deprecations
28
+ return if config_validator.deprecations.empty? or ENV['BASHLY_HIDE_DEPRECATIONS']
29
+ messages = "\n" + config_validator.deprecations.map(&:message).join("\n\n") + "\n\n"
30
+ say! messages
13
31
  end
14
32
  end
15
33
  end
@@ -3,28 +3,38 @@ module Bashly
3
3
  class Generate < Base
4
4
  help "Generate the bash script and required files"
5
5
 
6
- usage "bashly generate [--force --quiet --upgrade --wrap FUNCTION]"
6
+ usage "bashly generate [options]"
7
7
  usage "bashly generate (-h|--help)"
8
8
 
9
9
  option "-f --force", "Overwrite existing files"
10
10
  option "-q --quiet", "Disable on-screen progress report"
11
11
  option "-u --upgrade", "Upgrade all added library functions"
12
12
  option "-w --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
13
+ option "-e --env ENV", "Force the generation environment (see BASHLY_ENV)"
13
14
 
14
15
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
15
16
  environment "BASHLY_TARGET_DIR", "The path to use for creating the bash script [default: .]"
16
17
  environment "BASHLY_LIB_DIR", "The path to use for upgrading library files, relative to the source dir [default: lib]"
17
18
  environment "BASHLY_STRICT", "When not empty, enable bash strict mode (set -euo pipefail)"
19
+ environment "BASHLY_TAB_INDENT", "When not empty, the generated script will use tab indentation instead of spaces (every 2 leading spaces will be converted to a tab character)"
20
+ environment "BASHLY_ENV", <<~EOF
21
+ Set to 'production' or 'development':
22
+ - production generate a smaller script, without file markers
23
+ - development generate with file markers
24
+
25
+ Can be overridden with --env [default: development]
26
+ EOF
18
27
 
19
28
  example "bashly generate --force"
20
29
  example "bashly generate --wrap my_function"
21
30
 
22
31
  def run
23
- validate_config
24
- create_user_files
25
- upgrade_libs if args['--upgrade']
26
- create_master_script
27
- quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script"
32
+ with_valid_config do
33
+ Settings.env = args['--env'] if args['--env']
34
+ quiet_say "creating !txtgrn!production!txtrst! version" if Settings.production?
35
+ generate_all_files
36
+ quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script"
37
+ end
28
38
  end
29
39
 
30
40
  private
@@ -33,6 +43,12 @@ module Bashly
33
43
  say message unless args['--quiet']
34
44
  end
35
45
 
46
+ def generate_all_files
47
+ create_user_files
48
+ upgrade_libs if args['--upgrade']
49
+ create_master_script
50
+ end
51
+
36
52
  def upgrade_libs
37
53
  generated_files.each do |file|
38
54
  content = File.read file
@@ -104,7 +120,7 @@ module Bashly
104
120
  end
105
121
 
106
122
  def create_master_script
107
- File.write master_script_path, script.code
123
+ File.write master_script_path, script.code(tab_indent: Settings.tab_indent)
108
124
  FileUtils.chmod "+x", master_script_path
109
125
  quiet_say "!txtgrn!created!txtrst! #{master_script_path}"
110
126
  end
@@ -117,10 +133,6 @@ module Bashly
117
133
  "#{Settings.target_dir}/#{command.name}"
118
134
  end
119
135
 
120
- def config
121
- @config ||= Config.new "#{Settings.source_dir}/bashly.yml"
122
- end
123
-
124
136
  def command
125
137
  @command ||= Script::Command.new config
126
138
  end
@@ -9,10 +9,11 @@ module Bashly
9
9
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
10
10
 
11
11
  def run
12
- config = Config.new "#{Settings.source_dir}/bashly.yml"
13
- command = Script::Command.new(config)
14
- script = Script::Wrapper.new command
15
- puts script.code
12
+ with_valid_config do
13
+ command = Script::Command.new config
14
+ script = Script::Wrapper.new command
15
+ puts script.code
16
+ end
16
17
  end
17
18
  end
18
19
  end
@@ -10,7 +10,13 @@ module Bashly
10
10
 
11
11
  def run
12
12
  validate_config
13
- say "!txtgrn!OK"
13
+ show_deprecations
14
+ deprecations = config_validator.deprecations
15
+ if deprecations.empty?
16
+ say "!txtgrn!OK"
17
+ else
18
+ say "!txtred!WARNING!txtrst! Found #{deprecations.count} deprecations"
19
+ end
14
20
  end
15
21
  end
16
22
  end
@@ -4,13 +4,20 @@ module Bashly
4
4
  module Renderable
5
5
  def render(view)
6
6
  template = File.read view_path(view)
7
- ERB.new(template, trim_mode: '%-').result(binding)
7
+ erb = ERB.new(template, trim_mode: '%-')
8
+ erb.filename = "#{views_subfolder}.#{view}"
9
+ erb.result binding
8
10
  end
9
11
 
10
12
  def strings
11
13
  @strings ||= MessageStrings.new
12
14
  end
13
15
 
16
+ def view_marker(id = nil)
17
+ id ||= ":#{caller_locations.first.path}"
18
+ "# #{id}" unless Settings.production?
19
+ end
20
+
14
21
  private
15
22
 
16
23
  def view_path(view)
@@ -0,0 +1,69 @@
1
+ module Bashly
2
+ # This is a `ConfigValidator` concern responsible for providing basic
3
+ # assertion methods.
4
+ module ValidationHelpers
5
+
6
+ def deprecations
7
+ @deprecations ||= []
8
+ end
9
+
10
+ protected
11
+
12
+ def assert(valid, message)
13
+ raise ConfigurationError, message unless valid
14
+ end
15
+
16
+ def refute(invalid, message)
17
+ assert !invalid, message
18
+ end
19
+
20
+ def deprecate(key, **options)
21
+ deprecations.push Deprecation.new(key, **options)
22
+ end
23
+
24
+ def assert_string(key, value)
25
+ assert value.is_a?(String), "#{key} must be a string"
26
+ end
27
+
28
+ def assert_optional_string(key, value)
29
+ assert_string key, value if value
30
+ end
31
+
32
+ def assert_boolean(key, value)
33
+ assert [true, false, nil].include?(value), "#{key} must be a boolean"
34
+ end
35
+
36
+ def assert_array(key, value, of: nil)
37
+ return unless value
38
+ assert value.is_a?(Array), "#{key} must be an array"
39
+ if of
40
+ value.each_with_index do |val, i|
41
+ send "assert_#{of}".to_sym, "#{key}[#{i}]", val
42
+ end
43
+ end
44
+ end
45
+
46
+ def assert_hash(key, value, whitelist = nil)
47
+ assert value.is_a?(Hash), "#{key} must be a hash"
48
+
49
+ if whitelist
50
+ invalid_keys = value.keys.map(&:to_sym) - whitelist
51
+ assert invalid_keys.empty?, "#{key} contains invalid options: #{invalid_keys.join(', ')}"
52
+ end
53
+ end
54
+
55
+ def assert_uniq(key, value, array_key)
56
+ return unless value
57
+ list = value.map { |c| c[array_key] }.compact.flatten
58
+ assert list.uniq?, "#{key} cannot have elements with similar #{array_key} values"
59
+ end
60
+
61
+ def assert_string_or_array(key, value)
62
+ return unless value
63
+ assert [Array, String].include?(value.class),
64
+ "#{key} must be a string or an array"
65
+
66
+ assert_array key, value, of: :string if value.is_a? Array
67
+ end
68
+ end
69
+ end
@@ -1,5 +1,7 @@
1
1
  module Bashly
2
2
  class ConfigValidator
3
+ include ValidationHelpers
4
+
3
5
  attr_reader :data
4
6
 
5
7
  def initialize(data)
@@ -12,40 +14,6 @@ module Bashly
12
14
 
13
15
  private
14
16
 
15
- def assert(valid, message)
16
- raise ConfigurationError, message unless valid
17
- end
18
-
19
- def refute(invalid, message)
20
- assert !invalid, message
21
- end
22
-
23
- def assert_string(key, value)
24
- assert value.is_a?(String), "#{key} must be a string"
25
- end
26
-
27
- def assert_optional_string(key, value)
28
- assert_string key, value if value
29
- end
30
-
31
- def assert_boolean(key, value)
32
- assert [true, false, nil].include?(value), "#{key} must be a boolean"
33
- end
34
-
35
- def assert_array(key, value, of: nil)
36
- return unless value
37
- assert value.is_a?(Array), "#{key} must be an array"
38
- if of
39
- value.each_with_index do |val, i|
40
- send "assert_#{of}".to_sym, "#{key}[#{i}]", val
41
- end
42
- end
43
- end
44
-
45
- def assert_hash(key, value)
46
- assert value.is_a?(Hash), "#{key} must be a hash"
47
- end
48
-
49
17
  def assert_version(key, value)
50
18
  return unless value
51
19
  assert [String, Integer, Float].include?(value.class),
@@ -61,6 +29,7 @@ module Bashly
61
29
  end
62
30
 
63
31
  def assert_catch_all_hash(key, value)
32
+ assert_hash key, value, Script::CatchAll.option_keys
64
33
  assert_string "#{key}.label", value['label']
65
34
  assert_optional_string "#{key}.help", value['help']
66
35
  assert_boolean "#{key}.required", value['required']
@@ -73,7 +42,7 @@ module Bashly
73
42
  end
74
43
 
75
44
  def assert_arg(key, value)
76
- assert_hash key, value
45
+ assert_hash key, value, Script::Argument.option_keys
77
46
  assert_string "#{key}.name", value['name']
78
47
  assert_optional_string "#{key}.help", value['help']
79
48
  assert_optional_string "#{key}.default", value['default']
@@ -89,7 +58,7 @@ module Bashly
89
58
  end
90
59
 
91
60
  def assert_flag(key, value)
92
- assert_hash key, value
61
+ assert_hash key, value, Script::Flag.option_keys
93
62
  assert value['short'] || value['long'], "#{key} must have at least one of long or short name"
94
63
 
95
64
  assert_optional_string "#{key}.long", value['long']
@@ -99,6 +68,7 @@ module Bashly
99
68
  assert_optional_string "#{key}.default", value['default']
100
69
  assert_optional_string "#{key}.validate", value['validate']
101
70
 
71
+ assert_boolean "#{key}.repeatable", value['repeatable']
102
72
  assert_boolean "#{key}.required", value['required']
103
73
  assert_array "#{key}.allowed", value['allowed'], of: :string
104
74
  assert_array "#{key}.conflicts", value['conflicts'], of: :string
@@ -119,7 +89,7 @@ module Bashly
119
89
  end
120
90
 
121
91
  def assert_env_var(key, value)
122
- assert_hash key, value
92
+ assert_hash key, value, Script::EnvironmentVariable.option_keys
123
93
  assert_string "#{key}.name", value['name']
124
94
  assert_optional_string "#{key}.help", value['help']
125
95
  assert_optional_string "#{key}.default", value['default']
@@ -127,21 +97,22 @@ module Bashly
127
97
  end
128
98
 
129
99
  def assert_command(key, value)
130
- assert_hash key, value
100
+ assert_hash key, value, Script::Command.option_keys
131
101
 
132
102
  refute value['commands'] && value['args'], "#{key} cannot have both commands and args"
133
103
  refute value['commands'] && value['flags'], "#{key} cannot have both commands and flags"
134
-
104
+
135
105
  assert_string "#{key}.name", value['name']
136
- assert_optional_string "#{key}.short", value['short']
137
106
  assert_optional_string "#{key}.help", value['help']
138
107
  assert_optional_string "#{key}.footer", value['footer']
139
108
  assert_optional_string "#{key}.group", value['group']
140
109
  assert_optional_string "#{key}.filename", value['filename']
141
110
 
111
+ assert_boolean "#{key}.private", value['private']
142
112
  assert_boolean "#{key}.default", value['default']
143
113
  assert_version "#{key}.version", value['version']
144
114
  assert_catch_all "#{key}.catch_all", value['catch_all']
115
+ assert_string_or_array "#{key}.alias", value['alias']
145
116
  assert_extensible "#{key}.extensible", value['extensible']
146
117
 
147
118
  assert_array "#{key}.args", value['args'], of: :arg
@@ -153,8 +124,19 @@ module Bashly
153
124
  assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var
154
125
  assert_array "#{key}.examples", value['examples'], of: :string
155
126
 
127
+ assert_uniq "#{key}.commands", value['commands'], 'name'
128
+ assert_uniq "#{key}.commands", value['commands'], 'alias'
129
+ assert_uniq "#{key}.flags", value['flags'], 'long'
130
+ assert_uniq "#{key}.flags", value['flags'], 'short'
131
+ assert_uniq "#{key}.args", value['args'], 'name'
132
+
133
+ if value['catch_all'] and value['args']
134
+ repeatable_arg = value['args'].select { |a| a['repeatable'] }.first&.dig 'name'
135
+ refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"
136
+ end
137
+
156
138
  if key == "root"
157
- refute value['short'], "#{key}.short makes no sense"
139
+ refute value['alias'], "#{key}.alias makes no sense"
158
140
  refute value['group'], "#{key}.group makes no sense"
159
141
  refute value['default'], "#{key}.default makes no sense"
160
142
  refute value['private'], "#{key}.private makes no sense"
@@ -162,6 +144,11 @@ module Bashly
162
144
  refute value['version'], "#{key}.version makes no sense"
163
145
  refute value['extensible'], "#{key}.extensible makes no sense"
164
146
  end
147
+
148
+ # DEPRECATION 0.8.0
149
+ if value['short']
150
+ deprecate "#{key}.short", replacement: "alias", reference: "https://github.com/DannyBen/bashly/pull/220"
151
+ end
165
152
  end
166
153
  end
167
154
  end
@@ -0,0 +1,25 @@
1
+ module Bashly
2
+ class Deprecation
3
+ attr_reader :old, :replacement, :reference
4
+
5
+ def initialize(old, replacement: nil, reference: nil)
6
+ @old, @replacement, @reference = old, replacement, reference
7
+ end
8
+
9
+ def message
10
+ result = ["Deprecation Warning:", "!txtred!#{old}!txtrst! is deprecated"]
11
+ result.push "use !txtgrn!#{replacement}!txtrst! instead" if replacement
12
+ result.push "see !undblu!#{reference}!txtrst!" if reference
13
+
14
+ result.map { |line| "!txtred!▐!txtrst! #{line}"}.join("\n")
15
+ end
16
+
17
+ def to_h
18
+ {
19
+ old: old,
20
+ replacement: replacement,
21
+ reference: reference
22
+ }
23
+ end
24
+ end
25
+ end
@@ -4,4 +4,9 @@ class Array
4
4
  indentation = " " * offset
5
5
  map { |line| "#{indentation}#{line}" }
6
6
  end
7
+
8
+ def uniq?
9
+ self == uniq
10
+ end
11
+
7
12
  end
@@ -31,4 +31,10 @@ class String
31
31
  split(/^---\s*/).last
32
32
  end
33
33
 
34
+ def expand_tabs(tabstop = 2)
35
+ gsub(/^( {#{tabstop}}+)/) do
36
+ "\t" * ($1.size / tabstop)
37
+ end
38
+ end
39
+
34
40
  end
@@ -3,6 +3,8 @@ module YAML
3
3
  def self.properly_load_file(path)
4
4
  YAML.load_file path, aliases: true
5
5
  rescue ArgumentError
6
+ # :nocov:
6
7
  YAML.load_file path
8
+ # :nocov:
7
9
  end
8
10
  end
@@ -3,21 +3,25 @@ colors:
3
3
  - source: "templates/lib/colors.sh"
4
4
  target: "%{user_lib_dir}/colors.sh"
5
5
 
6
+ completions: :CompletionsFunction
7
+ completions_script: :CompletionsScript
8
+ completions_yaml: :CompletionsYAML
9
+
6
10
  config:
7
11
  files:
8
12
  - source: "templates/lib/config.sh"
9
13
  target: "%{user_lib_dir}/config.sh"
10
14
 
11
- yaml:
12
- files:
13
- - source: "templates/lib/yaml.sh"
14
- target: "%{user_lib_dir}/yaml.sh"
15
-
16
15
  lib:
17
16
  files:
18
17
  - source: "templates/lib/sample_function.sh"
19
18
  target: "%{user_lib_dir}/sample_function.sh"
20
19
 
20
+ settings:
21
+ files:
22
+ - source: "templates/settings.yml"
23
+ target: "settings.yml"
24
+
21
25
  strings:
22
26
  files:
23
27
  - source: "templates/strings.yml"
@@ -37,7 +41,6 @@ test:
37
41
 
38
42
  Docs: !undblu!https://github.com/DannyBen/approvals.bash
39
43
 
40
-
41
44
  validations:
42
45
  files:
43
46
  - source: "templates/lib/validations/validate_dir_exists.sh"
@@ -49,6 +52,7 @@ validations:
49
52
  - source: "templates/lib/validations/validate_not_empty.sh"
50
53
  target: "%{user_lib_dir}/validations/validate_not_empty.sh"
51
54
 
52
- completions: :CompletionsFunction
53
- completions_script: :CompletionsScript
54
- completions_yaml: :CompletionsYAML
55
+ yaml:
56
+ files:
57
+ - source: "templates/lib/yaml.sh"
58
+ target: "%{user_lib_dir}/yaml.sh"
@@ -1,8 +1,20 @@
1
1
  module Bashly
2
2
  module Script
3
3
  class Argument < Base
4
+ class << self
5
+ def option_keys
6
+ @option_keys ||= %i[
7
+ allowed default help name repeatable required validate
8
+ ]
9
+ end
10
+ end
11
+
4
12
  def usage_string
5
- required ? name.upcase : "[#{name.upcase}]"
13
+ required ? label : "[#{label}]"
14
+ end
15
+
16
+ def label
17
+ repeatable ? "#{name.upcase}..." : name.upcase
6
18
  end
7
19
  end
8
20
  end