bashly 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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