bashly 0.7.0 → 0.7.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bashly/cli.rb +1 -0
  3. data/lib/bashly/commands/add.rb +14 -25
  4. data/lib/bashly/commands/generate.rb +18 -17
  5. data/lib/bashly/commands/validate.rb +19 -0
  6. data/lib/bashly/config_validator.rb +135 -0
  7. data/lib/bashly/extensions/string.rb +4 -0
  8. data/lib/bashly/libraries/base.rb +19 -0
  9. data/lib/bashly/libraries/completions.rb +14 -0
  10. data/lib/bashly/{library → libraries}/completions_function.rb +18 -6
  11. data/lib/bashly/libraries/completions_script.rb +29 -0
  12. data/lib/bashly/libraries/completions_yaml.rb +27 -0
  13. data/lib/bashly/libraries.yml +39 -0
  14. data/lib/bashly/library.rb +63 -0
  15. data/lib/bashly/refinements/compose_refinements.rb +45 -0
  16. data/lib/bashly/script/base.rb +2 -1
  17. data/lib/bashly/script/command.rb +10 -21
  18. data/lib/bashly/version.rb +1 -1
  19. data/lib/bashly/views/command/command_filter.erb +1 -1
  20. data/lib/bashly/views/command/default_assignments.erb +2 -2
  21. data/lib/bashly/views/command/default_initialize_script.erb +6 -6
  22. data/lib/bashly/views/command/environment_variables_filter.erb +1 -1
  23. data/lib/bashly/views/command/fixed_flags_filter.erb +1 -1
  24. data/lib/bashly/views/command/initialize.erb +1 -1
  25. data/lib/bashly/views/command/run.erb +4 -4
  26. data/lib/bashly/views/command/usage_commands.erb +1 -1
  27. data/lib/bashly.rb +2 -1
  28. metadata +12 -13
  29. data/lib/bashly/library/base.rb +0 -57
  30. data/lib/bashly/library/colors.rb +0 -9
  31. data/lib/bashly/library/completions.rb +0 -28
  32. data/lib/bashly/library/completions_script.rb +0 -17
  33. data/lib/bashly/library/completions_yaml.rb +0 -15
  34. data/lib/bashly/library/config.rb +0 -9
  35. data/lib/bashly/library/sample.rb +0 -9
  36. data/lib/bashly/library/strings.rb +0 -12
  37. data/lib/bashly/library/validations.rb +0 -9
  38. data/lib/bashly/library/yaml.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13bbac52a39c2f6afb768d043911861a31f8e6abc8ff1472340a13c2834d5944
4
- data.tar.gz: 54c4fea2c664dcd0c6aace3360004d715d87b5d4ed98ffd7d3ccdc6c0a120406
3
+ metadata.gz: 53a5744ae1746cdd47de191ea91539ab7336aca894f583384ef0b170c03a746e
4
+ data.tar.gz: 0e1e9bc417d3947bcce84c3c6f44df87521dfeeae2329cc736a53816cb66cba3
5
5
  SHA512:
6
- metadata.gz: f1c273771d9048c074fb9551ba4521e9cb38c98a819f53647186822155898f767b7dd95093642e01464788378833d4dd9e408efecf304a9feb1ba09ebf2edef3
7
- data.tar.gz: efbdad6c22cfe1b7fbb46533db42f4c14b828259efeb5ede1099e20980ad505773af36897e27f8c6c7b25538a523427e63c1a5dac7ff958d753ae3810caf5eb9
6
+ metadata.gz: 72154aafdc3c3787b4d23a2935192a92c21b94b830d7fb01c22057ed839d30120d8a31a8962b7b075110551d034b2c971b92010e55c88a17d4e9041ecb309ad7
7
+ data.tar.gz: a02638101b685d5e9de575fe4537991c558c462dc030355b5e8ab6ffe4f32b8018c510afb516f51c02d4412a20c21a3703b5dc5872a0f377baa343345f045605
data/lib/bashly/cli.rb CHANGED
@@ -10,6 +10,7 @@ module Bashly
10
10
 
11
11
  runner.route 'init', to: Commands::Init
12
12
  runner.route 'preview', to: Commands::Preview
13
+ runner.route 'validate', to: Commands::Validate
13
14
  runner.route 'generate', to: Commands::Generate
14
15
  runner.route 'add', to: Commands::Add
15
16
 
@@ -32,27 +32,27 @@ module Bashly
32
32
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
33
33
 
34
34
  def strings_command
35
- add_lib Library::Strings.new
35
+ add_lib 'strings'
36
36
  end
37
37
 
38
38
  def lib_command
39
- add_lib Library::Sample.new
39
+ add_lib 'lib'
40
40
  end
41
41
 
42
42
  def config_command
43
- add_lib Library::Config.new
43
+ add_lib 'config'
44
44
  end
45
45
 
46
46
  def colors_command
47
- add_lib Library::Colors.new
47
+ add_lib 'colors'
48
48
  end
49
49
 
50
50
  def yaml_command
51
- add_lib Library::YAML.new
51
+ add_lib 'yaml'
52
52
  end
53
53
 
54
54
  def validations_command
55
- add_lib Library::Validations.new
55
+ add_lib 'validations'
56
56
  end
57
57
 
58
58
  def comp_command
@@ -60,35 +60,24 @@ module Bashly
60
60
  output = args['OUTPUT']
61
61
 
62
62
  case format
63
- when "script"
64
- path = output || "#{Settings.target_dir}/completions.bash"
65
- add_lib Library::CompletionsScript.new(path)
66
-
67
- when "function"
68
- function = output || "send_completions"
69
- path = "#{Settings.source_dir}/lib/#{function}.sh"
70
- add_lib Library::CompletionsFunction.new(path, function: function)
71
-
72
- when "yaml"
73
- path = output || "#{Settings.target_dir}/completions.yml"
74
- add_lib Library::CompletionsYAML.new(path)
75
-
76
- else
77
- raise Error, "Unrecognized format: #{format}"
78
-
63
+ when "script" then add_lib 'completions_script', output
64
+ when "function" then add_lib 'completions', output
65
+ when "yaml" then add_lib 'completions_yaml', output
66
+ else raise Error, "Unrecognized format: #{format}"
79
67
  end
80
68
 
81
69
  end
82
70
 
83
71
  private
84
72
 
85
- def add_lib(handler)
73
+ def add_lib(name, *args)
74
+ library = Bashly::Library.new name, *args
86
75
  files_created = 0
87
- handler.files.each do |file|
76
+ library.files.each do |file|
88
77
  created = safe_write file[:path], file[:content]
89
78
  files_created += 1 if created
90
79
  end
91
- message = handler.post_install_message
80
+ message = library.post_install_message
92
81
  say "\n#{message}" if message and files_created > 0
93
82
  end
94
83
 
@@ -1,6 +1,8 @@
1
1
  module Bashly
2
2
  module Commands
3
3
  class Generate < Base
4
+ using ComposeRefinements
5
+
4
6
  help "Generate the bash script and required files"
5
7
 
6
8
  usage "bashly generate [--force --quiet --upgrade --wrap FUNCTION]"
@@ -13,6 +15,7 @@ module Bashly
13
15
 
14
16
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
15
17
  environment "BASHLY_TARGET_DIR", "The path to use for creating the bash script [default: .]"
18
+ environment "BASHLY_STRICT", "When not empty, enable bash strict mode (set -euo pipefail)"
16
19
 
17
20
  example "bashly generate --force"
18
21
  example "bashly generate --wrap my_function"
@@ -35,20 +38,9 @@ module Bashly
35
38
  content = File.read file
36
39
 
37
40
  if content =~ /\[@bashly-upgrade (.+)\]/
38
- lib = $1
39
-
40
- case lib
41
- when "colors"
42
- upgrade file, Library::Colors.new
43
- when "config"
44
- upgrade file, Library::Config.new
45
- when "yaml"
46
- upgrade file, Library::YAML.new
47
- when "validations"
48
- upgrade file, Library::Validations.new
49
- when /completions (.+)/
50
- upgrade file, Library::CompletionsFunction.new(file, function: $1)
51
- end
41
+ args = $1.split ' '
42
+ library_name = args.shift
43
+ upgrade file, library_name, *args
52
44
  end
53
45
  end
54
46
  end
@@ -57,8 +49,17 @@ module Bashly
57
49
  Dir["#{Settings.source_dir}/**/*.*"].sort
58
50
  end
59
51
 
60
- def upgrade(existing_file, handler)
61
- file = handler.files.select { |f| f[:path] == existing_file }.first
52
+ def upgrade(existing_file, library_name, *args)
53
+ if Library.exist? library_name
54
+ upgrade! existing_file, library_name, *args
55
+ else
56
+ quiet_say "!txtred!warning!txtrst! not upgrading !txtcyn!#{existing_file}!txtrst!, unknown library '#{library_name}'"
57
+ end
58
+ end
59
+
60
+ def upgrade!(existing_file, library_name, *args)
61
+ library = Bashly::Library.new library_name, *args
62
+ file = library.find_file existing_file
62
63
 
63
64
  if file
64
65
  File.deep_write file[:path], file[:content]
@@ -117,7 +118,7 @@ module Bashly
117
118
  end
118
119
 
119
120
  def config
120
- @config ||= Config.new "#{Settings.source_dir}/bashly.yml"
121
+ @config ||= Config.new("#{Settings.source_dir}/bashly.yml").compose
121
122
  end
122
123
 
123
124
  def command
@@ -0,0 +1,19 @@
1
+ module Bashly
2
+ module Commands
3
+ class Validate < Base
4
+ help "Scan the configuration file for errors"
5
+
6
+ usage "bashly validate"
7
+ usage "bashly validate (-h|--help)"
8
+
9
+ environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
10
+
11
+ def run
12
+ config = Config.new "#{Settings.source_dir}/bashly.yml"
13
+ validator = ConfigValidator.new config
14
+ validator.validate
15
+ say "!txtgrn!OK"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,135 @@
1
+ module Bashly
2
+ class ConfigValidator
3
+ attr_reader :data
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ end
8
+
9
+ def validate
10
+ assert_command "root", data
11
+ end
12
+
13
+ private
14
+
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
+ def assert_version(key, value)
50
+ return unless value
51
+ assert [String, Integer, Float].include?(value.class),
52
+ "#{key} must be a string or a number"
53
+ end
54
+
55
+ def assert_catch_all(key, value)
56
+ return unless value
57
+ assert [TrueClass, String, Hash].include?(value.class),
58
+ "#{key} must be a boolean, a string or a hash"
59
+
60
+ assert_catch_all_hash key, value if value.is_a? Hash
61
+ end
62
+
63
+ def assert_catch_all_hash(key, value)
64
+ assert_string "#{key}.label", value['label']
65
+ assert_optional_string "#{key}.help", value['help']
66
+ assert_boolean "#{key}.required", value['required']
67
+ end
68
+
69
+ def assert_extensible(key, value)
70
+ return unless value
71
+ assert [TrueClass, String].include?(value.class),
72
+ "#{key} must be a boolean or a string"
73
+ end
74
+
75
+ def assert_arg(key, value)
76
+ assert_hash key, value
77
+ assert_string "#{key}.name", value['name']
78
+ assert_optional_string "#{key}.help", value['help']
79
+ assert_optional_string "#{key}.default", value['default']
80
+ assert_optional_string "#{key}.validate", value['validate']
81
+ assert_boolean "#{key}.required", value['required']
82
+
83
+ assert_array "#{key}.allowed", value['allowed'], of: :string
84
+ end
85
+
86
+ def assert_flag(key, value)
87
+ assert_hash key, value
88
+ assert value['short'] || value['long'], "#{key} must have at least one of long or short name"
89
+
90
+ assert_optional_string "#{key}.long", value['long']
91
+ assert_optional_string "#{key}.short", value['short']
92
+ assert_optional_string "#{key}.help", value['help']
93
+ assert_optional_string "#{key}.arg", value['arg']
94
+ assert_optional_string "#{key}.default", value['default']
95
+ assert_optional_string "#{key}.validate", value['validate']
96
+
97
+ assert_boolean "#{key}.required", value['required']
98
+ assert_array "#{key}.allowed", value['allowed'], of: :string
99
+ end
100
+
101
+ def assert_env_var(key, value)
102
+ assert_hash key, value
103
+ assert_string "#{key}.name", value['name']
104
+ assert_optional_string "#{key}.help", value['help']
105
+ assert_optional_string "#{key}.default", value['default']
106
+ assert_boolean "#{key}.required", value['required']
107
+ end
108
+
109
+ def assert_command(key, value)
110
+ assert_hash key, value
111
+
112
+ refute value['commands'] && value['args'], "#{key} cannot have both commands and args"
113
+ refute value['commands'] && value['flags'], "#{key} cannot have both commands and flags"
114
+
115
+ assert_string "#{key}.name", value['name']
116
+ assert_optional_string "#{key}.short", value['short']
117
+ assert_optional_string "#{key}.help", value['help']
118
+ assert_optional_string "#{key}.footer", value['footer']
119
+ assert_optional_string "#{key}.group", value['group']
120
+
121
+ assert_boolean "#{key}.default", value['default']
122
+ assert_version "#{key}.version", value['version']
123
+ assert_catch_all "#{key}.catch_all", value['catch_all']
124
+ assert_extensible "#{key}.extensible", value['extensible']
125
+
126
+ assert_array "#{key}.args", value['args'], of: :arg
127
+ assert_array "#{key}.flags", value['flags'] , of: :flag
128
+ assert_array "#{key}.commands", value['commands'], of: :command
129
+ assert_array "#{key}.completions", value['completions'], of: :string
130
+ assert_array "#{key}.dependencies", value['dependencies'], of: :string
131
+ assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var
132
+ assert_array "#{key}.examples", value['examples'], of: :string
133
+ end
134
+ end
135
+ end
@@ -27,4 +27,8 @@ class String
27
27
  gsub(/\s+\n/m, "\n\n").lines.reject { |l| l =~ /^\s*##/ }.join ""
28
28
  end
29
29
 
30
+ def remove_front_matter
31
+ split(/^---\s*/).last
32
+ end
33
+
30
34
  end
@@ -0,0 +1,19 @@
1
+ module Bashly
2
+ module Libraries
3
+ class Base
4
+ attr_reader :args
5
+
6
+ def initialize(*args)
7
+ @args = args
8
+ end
9
+
10
+ def files
11
+ raise NotImplementedError, "Please implement #files"
12
+ end
13
+
14
+ def post_install_message
15
+ nil
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module Bashly
2
+ module Libraries
3
+ class Completions < Base
4
+ protected
5
+ def command
6
+ @command ||= Script::Command.new config
7
+ end
8
+
9
+ def config
10
+ @config ||= Bashly::Config.new "#{Settings.source_dir}/bashly.yml"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,11 +1,13 @@
1
1
  module Bashly
2
- module Library
2
+ module Libraries
3
3
  class CompletionsFunction < Completions
4
- def file_content
4
+ def files
5
5
  [
6
- "# [@bashly-upgrade completions #{function_name}]",
7
- command.completion_function(function_name)
8
- ].join "\n"
6
+ {
7
+ path: "#{Settings.source_dir}/lib/#{function_name}.sh",
8
+ content: completions_function_code(function_name)
9
+ }
10
+ ]
9
11
  end
10
12
 
11
13
  def post_install_message
@@ -18,9 +20,19 @@ module Bashly
18
20
  EOF
19
21
  end
20
22
 
23
+ private
24
+
21
25
  def function_name
22
- options[:function]
26
+ @function_name ||= args[0] || 'send_completions'
23
27
  end
28
+
29
+ def completions_function_code(function_name)
30
+ [
31
+ "## [@bashly-upgrade completions #{function_name}]",
32
+ command.completion_function(function_name)
33
+ ].join "\n"
34
+ end
35
+
24
36
  end
25
37
  end
26
38
  end
@@ -0,0 +1,29 @@
1
+ module Bashly
2
+ module Libraries
3
+ class CompletionsScript < Completions
4
+ def files
5
+ [
6
+ {
7
+ path: target_path,
8
+ content: command.completion_script
9
+ }
10
+ ]
11
+ end
12
+
13
+ def post_install_message
14
+ <<~EOF
15
+ In order to enable completions, run:
16
+
17
+ !txtpur!$ source #{target_path}
18
+ EOF
19
+ end
20
+
21
+ private
22
+
23
+ def target_path
24
+ @target_path ||= args[0] || "#{Settings.target_dir}/completions.bash"
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ module Bashly
2
+ module Libraries
3
+ class CompletionsYAML < Completions
4
+ def files
5
+ [
6
+ {
7
+ path: target_path,
8
+ content: command.completion_data.to_yaml
9
+ }
10
+ ]
11
+ end
12
+
13
+ def post_install_message
14
+ <<~EOF
15
+ This file can be converted to a completions script using the !txtgrn!completely!txtrst! gem.
16
+ EOF
17
+ end
18
+
19
+ private
20
+
21
+ def target_path
22
+ @target_path ||= args[0] || "#{Settings.target_dir}/completions.yml"
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ colors:
2
+ files:
3
+ - source: "templates/lib/colors.sh"
4
+ target: "%{user_source_dir}/lib/colors.sh"
5
+
6
+ config:
7
+ files:
8
+ - source: "templates/lib/config.sh"
9
+ target: "%{user_source_dir}/lib/config.sh"
10
+
11
+ yaml:
12
+ files:
13
+ - source: "templates/lib/yaml.sh"
14
+ target: "%{user_source_dir}/lib/yaml.sh"
15
+
16
+ lib:
17
+ files:
18
+ - source: "templates/lib/sample_function.sh"
19
+ target: "%{user_source_dir}/lib/sample_function.sh"
20
+
21
+ strings:
22
+ files:
23
+ - source: "templates/strings.yml"
24
+ target: "%{user_source_dir}/bashly-strings.yml"
25
+
26
+ validations:
27
+ files:
28
+ - source: "templates/lib/validations/validate_dir_exists.sh"
29
+ target: "%{user_source_dir}/lib/validations/validate_dir_exists.sh"
30
+ - source: "templates/lib/validations/validate_file_exists.sh"
31
+ target: "%{user_source_dir}/lib/validations/validate_file_exists.sh"
32
+ - source: "templates/lib/validations/validate_integer.sh"
33
+ target: "%{user_source_dir}/lib/validations/validate_integer.sh"
34
+ - source: "templates/lib/validations/validate_not_empty.sh"
35
+ target: "%{user_source_dir}/lib/validations/validate_not_empty.sh"
36
+
37
+ completions: :CompletionsFunction
38
+ completions_script: :CompletionsScript
39
+ completions_yaml: :CompletionsYAML
@@ -0,0 +1,63 @@
1
+ module Bashly
2
+ class Library
3
+ class << self
4
+ def exist?(name)
5
+ config.has_key? name.to_s
6
+ end
7
+
8
+ def config
9
+ @config ||= YAML.load_file(config_path)
10
+ end
11
+
12
+ def config_path
13
+ @config_path ||= File.expand_path 'libraries.yml', __dir__
14
+ end
15
+ end
16
+
17
+ include AssetHelper
18
+ attr_reader :name, :args
19
+
20
+ def initialize(name, *args)
21
+ @name, @args = name.to_s, args
22
+ end
23
+
24
+ def files
25
+ if custom_handler
26
+ custom_handler.files
27
+
28
+ else
29
+ config['files'].map do |file|
30
+ { path: file['target'] % target_file_args,
31
+ content: asset_content(file['source']) }
32
+ end
33
+ end
34
+ end
35
+
36
+ def post_install_message
37
+ if custom_handler
38
+ custom_handler.post_install_message
39
+ else
40
+ config['post_install_message']
41
+ end
42
+ end
43
+
44
+ def find_file(path)
45
+ files.select { |f| f[:path] == path }.first
46
+ end
47
+
48
+ private
49
+
50
+ def custom_handler
51
+ return nil unless config.is_a? Symbol
52
+ @custom_handler ||= Bashly::Libraries.const_get(config).new(*args)
53
+ end
54
+
55
+ def config
56
+ @config ||= self.class.config[name]
57
+ end
58
+
59
+ def target_file_args
60
+ { user_source_dir: Settings.source_dir }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,45 @@
1
+ require 'yaml'
2
+
3
+ module ComposeRefinements
4
+ refine Hash do
5
+ def compose(keyword = 'import')
6
+ result = {}
7
+ each do |k, v|
8
+ if k.to_s == keyword
9
+ sub = safe_load_yaml(v).compose keyword
10
+ if sub.is_a? Array
11
+ result = sub
12
+ else
13
+ result.merge! sub
14
+ end
15
+ elsif v.respond_to? :compose
16
+ result[k] = v.compose keyword
17
+ else
18
+ result[k] = v
19
+ end
20
+ end
21
+ result
22
+ end
23
+
24
+ def safe_load_yaml(path)
25
+ loaded = YAML.load_file path
26
+ return loaded if loaded.is_a? Array or loaded.is_a? Hash
27
+ raise Bashly::ConfigurationError, "Cannot find a valid YAML in !txtgrn!#{path}"
28
+
29
+ rescue Errno::ENOENT
30
+ raise Bashly::ConfigurationError, "Cannot find import file !txtgrn!#{path}"
31
+ end
32
+ end
33
+
34
+ refine Array do
35
+ def compose(keyword = 'import')
36
+ map do |x|
37
+ if x.respond_to? :compose
38
+ x.compose keyword
39
+ else
40
+ x
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -23,6 +23,7 @@ module Bashly
23
23
  long
24
24
  name
25
25
  parent_name
26
+ private
26
27
  required
27
28
  short
28
29
  validate
@@ -32,7 +33,7 @@ module Bashly
32
33
  def initialize(options)
33
34
  raise Error, "Invalid options provided" unless options.respond_to? :keys
34
35
  @options = options
35
- verify if respond_to? :verify
36
+ validate_options if respond_to? :validate_options
36
37
  end
37
38
 
38
39
  def optional
@@ -32,18 +32,15 @@ module Bashly
32
32
 
33
33
  # Returns a label for the catch_all directive
34
34
  def catch_all_label
35
- return nil unless catch_all
36
-
37
- if catch_all.is_a? String
38
- "#{catch_all.upcase}..."
39
- elsif catch_all.is_a?(Hash) and catch_all['label'].is_a?(String)
40
- "#{catch_all['label'].upcase}..."
41
- else
42
- "..."
35
+ case catch_all
36
+ when nil then nil
37
+ when String then "#{catch_all.upcase}..."
38
+ when Hash then "#{catch_all['label'].upcase}..."
39
+ else "..."
43
40
  end
44
41
  end
45
42
 
46
- # Returns a used defined help string for the catch_all directive
43
+ # Returns a user defined help string for the catch_all directive
47
44
  def catch_all_help
48
45
  return nil unless catch_all
49
46
 
@@ -154,7 +151,7 @@ module Bashly
154
151
  default_content = placeholder ? "echo \"error: cannot load file\"" : ''
155
152
 
156
153
  content = if File.exist? path
157
- File.read path
154
+ File.read(path).remove_front_matter
158
155
  else
159
156
  default_content
160
157
  end
@@ -213,9 +210,9 @@ module Bashly
213
210
  end
214
211
 
215
212
  # Raise an exception if there are some serious issues with the command
216
- # definition.
217
- def verify
218
- verify_commands if commands.any?
213
+ # definition. This is called by Base#initialize.
214
+ def validate_options
215
+ Bashly::ConfigValidator.new(options).validate
219
216
  end
220
217
 
221
218
  # Returns an array of all the args with a whitelist
@@ -228,14 +225,6 @@ module Bashly
228
225
  flags.select &:allowed
229
226
  end
230
227
 
231
- private
232
-
233
- def verify_commands
234
- if args.any? or flags.any?
235
- raise ConfigurationError, "Error in the !txtgrn!#{full_name}!txtrst! command.\nThe !txtgrn!commands!txtrst! key cannot be at the same level as the !txtgrn!args!txtrst! or !txtgrn!flags!txtrst! keys."
236
- end
237
- end
238
-
239
228
  end
240
229
  end
241
230
  end
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.1"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  # :command.command_filter
2
2
  % if commands.any?
3
- action=$1
3
+ action=${1:-}
4
4
 
5
5
  case $action in
6
6
  -* )
@@ -1,7 +1,7 @@
1
1
  # :command.default_assignments
2
2
  % default_args.each do |arg|
3
- [[ -n ${args[<%= arg.name %>]} ]] || args[<%= arg.name %>]="<%= arg.default %>"
3
+ [[ -n ${args[<%= arg.name %>]:-} ]] || args[<%= arg.name %>]="<%= arg.default %>"
4
4
  % end
5
5
  % default_flags.each do |flag|
6
- [[ -n ${args[<%= flag.long %>]} ]] || args[<%= flag.long %>]="<%= flag.default %>"
6
+ [[ -n ${args[<%= flag.long %>]:-} ]] || args[<%= flag.long %>]="<%= flag.default %>"
7
7
  % end
@@ -1,6 +1,6 @@
1
- # Code here runs inside the initialize() function
2
- # Use it for anything that you need to run before any other function, like
3
- # setting environment vairables:
4
- # CONFIG_FILE=settings.ini
5
- #
6
- # Feel free to empty (but not delete) this file.
1
+ ## Code here runs inside the initialize() function
2
+ ## Use it for anything that you need to run before any other function, like
3
+ ## setting environment vairables:
4
+ ## CONFIG_FILE=settings.ini
5
+ ##
6
+ ## Feel free to empty (but not delete) this file.
@@ -6,7 +6,7 @@ export <%= env_var.name.upcase %>="${<%= env_var.name.upcase %>:-<%= env_var.def
6
6
  % end
7
7
  % if required_environment_variables.any?
8
8
  % required_environment_variables.each do |env_var|
9
- if [[ -z "$<%= env_var.name.upcase %>" ]]; then
9
+ if [[ -z "${<%= env_var.name.upcase %>:-}" ]]; then
10
10
  printf "<%= strings[:missing_required_environment_variable] % { var: env_var.name.upcase } %>\n"
11
11
  exit 1
12
12
  fi
@@ -1,5 +1,5 @@
1
1
  # :command.fixed_flag_filter
2
- case "$1" in
2
+ case "${1:-}" in
3
3
  % if short_flag_exist? "-v"
4
4
  --version )
5
5
  % else
@@ -2,7 +2,7 @@
2
2
  initialize() {
3
3
  version="<%= version %>"
4
4
  long_usage=''
5
- set -e
5
+ <%= ENV['BASHLY_STRICT'] ? "set -euo pipefail" : "set -e" %>
6
6
 
7
7
  <%= load_user_file("initialize.sh", placeholder: false).indent 2 %>
8
8
  }
@@ -1,15 +1,15 @@
1
1
  # :command.run
2
2
  run() {
3
- declare -A args
4
- declare -a other_args
5
- declare -a input
3
+ declare -A args=()
4
+ declare -a other_args=()
5
+ declare -a input=()
6
6
  normalize_input "$@"
7
7
  parse_requirements "${input[@]}"
8
8
 
9
9
  <%- condition = "if" -%>
10
10
  <%- deep_commands.each do |command| -%>
11
11
  <%= condition %> [[ $action == "<%= command.action_name %>" ]]; then
12
- if [[ ${args[--help]} ]]; then
12
+ if [[ ${args[--help]:-} ]]; then
13
13
  long_usage=yes
14
14
  <%= command.function_name %>_usage
15
15
  else
@@ -3,7 +3,7 @@
3
3
  printf "<%= strings[:commands] %>\n"
4
4
  % end
5
5
  % maxlen = command_names.map(&:size).max
6
- % commands.each do |command|
6
+ % commands.reject(&:private).each do |command|
7
7
  % summary = command.summary
8
8
  % summary = strings[:default_command_summary] % { summary: summary } if command.default
9
9
  % if command.group
data/lib/bashly.rb CHANGED
@@ -9,7 +9,8 @@ requires 'bashly/concerns'
9
9
 
10
10
  requires 'bashly/settings'
11
11
  requires 'bashly/exceptions'
12
+ requires 'bashly/refinements'
12
13
  requires 'bashly/script/base'
13
14
  requires 'bashly/commands/base'
14
- requires 'bashly/library/base'
15
+ requires 'bashly/libraries/base'
15
16
  requires 'bashly'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-29 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -82,26 +82,25 @@ files:
82
82
  - lib/bashly/commands/generate.rb
83
83
  - lib/bashly/commands/init.rb
84
84
  - lib/bashly/commands/preview.rb
85
+ - lib/bashly/commands/validate.rb
85
86
  - lib/bashly/concerns/asset_helper.rb
86
87
  - lib/bashly/concerns/completions.rb
87
88
  - lib/bashly/concerns/renderable.rb
88
89
  - lib/bashly/config.rb
90
+ - lib/bashly/config_validator.rb
89
91
  - lib/bashly/exceptions.rb
90
92
  - lib/bashly/extensions/array.rb
91
93
  - lib/bashly/extensions/file.rb
92
94
  - lib/bashly/extensions/string.rb
93
- - lib/bashly/library/base.rb
94
- - lib/bashly/library/colors.rb
95
- - lib/bashly/library/completions.rb
96
- - lib/bashly/library/completions_function.rb
97
- - lib/bashly/library/completions_script.rb
98
- - lib/bashly/library/completions_yaml.rb
99
- - lib/bashly/library/config.rb
100
- - lib/bashly/library/sample.rb
101
- - lib/bashly/library/strings.rb
102
- - lib/bashly/library/validations.rb
103
- - lib/bashly/library/yaml.rb
95
+ - lib/bashly/libraries.yml
96
+ - lib/bashly/libraries/base.rb
97
+ - lib/bashly/libraries/completions.rb
98
+ - lib/bashly/libraries/completions_function.rb
99
+ - lib/bashly/libraries/completions_script.rb
100
+ - lib/bashly/libraries/completions_yaml.rb
101
+ - lib/bashly/library.rb
104
102
  - lib/bashly/message_strings.rb
103
+ - lib/bashly/refinements/compose_refinements.rb
105
104
  - lib/bashly/script/argument.rb
106
105
  - lib/bashly/script/base.rb
107
106
  - lib/bashly/script/command.rb
@@ -1,57 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Base
4
- include AssetHelper
5
-
6
- attr_reader :target_path, :options
7
-
8
- def initialize(target_path = nil, options = nil)
9
- @target_path = target_path || Settings.source_dir
10
- @options = options || {}
11
- end
12
-
13
- def files
14
- case content
15
- when String then content_from_string content
16
- when Hash then [content]
17
- else content
18
- end
19
- end
20
-
21
- def post_install_message
22
- nil
23
- end
24
-
25
- def content
26
- raise NotImplementedError, "Please implement either #content"
27
- end
28
-
29
- private
30
-
31
- def content_from_string(string)
32
- if File.directory? asset("templates/lib/#{string}")
33
- content_for_dir string
34
- else
35
- [content_for_file(string)]
36
- end
37
- end
38
-
39
- def content_for_file(file)
40
- {
41
- path: "#{target_path}/lib/#{file}",
42
- content: asset_content("templates/lib/#{file}")
43
- }
44
- end
45
-
46
- def content_for_dir(dir)
47
- Dir[asset("templates/lib/#{dir}/*.sh")].sort.map do |file|
48
- {
49
- path: "#{target_path}/lib/#{dir}/#{File.basename file}",
50
- content: File.read(file)
51
- }
52
- end
53
- end
54
-
55
- end
56
- end
57
- end
@@ -1,9 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Colors < Base
4
- def content
5
- "colors.sh"
6
- end
7
- end
8
- end
9
- end
@@ -1,28 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Completions < Base
4
- def content
5
- { path: target_path, content: file_content }
6
- end
7
-
8
- def file_content
9
- raise NotImplementedError, "Please implement #file_content"
10
- end
11
-
12
- protected
13
-
14
- def completions
15
- @completions ||= command.completion_data
16
- end
17
-
18
- def config
19
- @config ||= Bashly::Config.new "#{Settings.source_dir}/bashly.yml"
20
- end
21
-
22
- def command
23
- @command ||= Script::Command.new config
24
- end
25
-
26
- end
27
- end
28
- end
@@ -1,17 +0,0 @@
1
- module Bashly
2
- module Library
3
- class CompletionsScript < Completions
4
- def file_content
5
- command.completion_script
6
- end
7
-
8
- def post_install_message
9
- <<~EOF
10
- In order to enable completions, run:
11
-
12
- !txtpur!$ source #{target_path}
13
- EOF
14
- end
15
- end
16
- end
17
- end
@@ -1,15 +0,0 @@
1
- module Bashly
2
- module Library
3
- class CompletionsYAML < Completions
4
- def file_content
5
- completions.to_yaml
6
- end
7
-
8
- def post_install_message
9
- <<~EOF
10
- This file can be converted to a completions script using the !txtgrn!completely!txtrst! gem.
11
- EOF
12
- end
13
- end
14
- end
15
- end
@@ -1,9 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Config < Base
4
- def content
5
- "config.sh"
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Sample < Base
4
- def content
5
- "sample_function.sh"
6
- end
7
- end
8
- end
9
- end
@@ -1,12 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Strings < Base
4
- def content
5
- {
6
- path: "#{target_path}/bashly-strings.yml",
7
- content: asset_content("templates/strings.yml")
8
- }
9
- end
10
- end
11
- end
12
- end
@@ -1,9 +0,0 @@
1
- module Bashly
2
- module Library
3
- class Validations < Base
4
- def content
5
- "validations"
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Bashly
2
- module Library
3
- class YAML < Base
4
- def content
5
- "yaml.sh"
6
- end
7
- end
8
- end
9
- end