bashly 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bashly/commands/shell.rb +1 -1
  3. data/lib/bashly/concerns/completions.rb +3 -3
  4. data/lib/bashly/docs/env.yml +10 -0
  5. data/lib/bashly/docs/flag.yml +23 -0
  6. data/lib/bashly/libraries/render/mandoc/mandoc.gtx +7 -4
  7. data/lib/bashly/libraries/render/markdown/markdown.gtx +7 -3
  8. data/lib/bashly/libraries/settings/settings.yml +5 -0
  9. data/lib/bashly/libraries/strings/strings.yml +4 -0
  10. data/lib/bashly/script/command.rb +9 -208
  11. data/lib/bashly/script/environment_variable.rb +5 -1
  12. data/lib/bashly/script/flag.rb +5 -2
  13. data/lib/bashly/script/introspection/arguments.rb +41 -0
  14. data/lib/bashly/script/introspection/commands.rb +111 -0
  15. data/lib/bashly/script/introspection/dependencies.rb +16 -0
  16. data/lib/bashly/script/introspection/environment_variables.rb +47 -0
  17. data/lib/bashly/script/introspection/examples.rb +14 -0
  18. data/lib/bashly/script/introspection/flags.rb +58 -0
  19. data/lib/bashly/script/introspection/visibility.rb +19 -0
  20. data/lib/bashly/settings.rb +5 -0
  21. data/lib/bashly/version.rb +1 -1
  22. data/lib/bashly/views/argument/usage.gtx +3 -3
  23. data/lib/bashly/views/command/environment_variables_filter.gtx +6 -0
  24. data/lib/bashly/views/command/long_usage.gtx +8 -4
  25. data/lib/bashly/views/command/needy_flags_filter.gtx +9 -0
  26. data/lib/bashly/views/command/parse_requirements.gtx +1 -0
  27. data/lib/bashly/views/command/usage_commands.gtx +10 -3
  28. data/lib/bashly/views/command/usage_environment_variables.gtx +20 -4
  29. data/lib/bashly/views/command/usage_flags.gtx +10 -2
  30. data/lib/bashly/views/environment_variable/usage.gtx +2 -2
  31. data/lib/bashly/views/environment_variable/validations.gtx +9 -0
  32. data/lib/bashly/views/flag/needs.gtx +22 -0
  33. data/lib/bashly/views/flag/usage.gtx +11 -3
  34. data/lib/bashly.rb +27 -40
  35. metadata +27 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36c0868dbf2a0e4d5d2fecdc5854aac4e1bea8f7953a07712ccc985289c89b57
4
- data.tar.gz: 63df3d720e1b36ce7ab658224fde796fb9460c92c7946bd867204c0e0caea304
3
+ metadata.gz: cde8d4a8294ffd7dee63567440b351ffbd67b69f1295306b20931b8f4328a77c
4
+ data.tar.gz: e99ca77abffd677b1469e145383ef74a90a28da29af88625d7bf378563909031
5
5
  SHA512:
6
- metadata.gz: 39e367d86e8bf21ae076c35887157234e7d39d003f17a596aa4711a02a87c6b3856ac27b0f1c73c30837b2589358e479c069dba4cff657431fdca98f44116718
7
- data.tar.gz: eceaabeafea2e93a9cf7c9d7c2f999a2303c0d9172ddd7799bb0d1f9eafe62166ee9512d8688ad9cc6547dd28e20b7c8925ca489cb2639fd3cd2456517461e7a
6
+ metadata.gz: 3f33a67b5da7958d3dccc0e8ada2f5fb097d786fd35045e8a8148ac543ec1326e0d1da51c2b264b674ba1f8ffb1c5dc868dc2244afccc5b8d93c7429b68797c1
7
+ data.tar.gz: 9972faa37b1f14b4dd38be6c0d15a743640f065357b7a347299f3255a8f50377a580e64b284631ae99cf8eb1207045ce08eb4c9e65860d67827a55be435219e3
@@ -19,7 +19,7 @@ module Bashly
19
19
  terminal = MisterBin::Terminal.new runner, {
20
20
  autocomplete: autocomplete,
21
21
  show_usage: true,
22
- prompt: "$ bashly ",
22
+ prompt: '$ bashly ',
23
23
  }
24
24
 
25
25
  terminal.on('help') { runner.run %w[--help] }
@@ -29,7 +29,7 @@ module Bashly
29
29
  end
30
30
  end
31
31
 
32
- public_commands.each do |command|
32
+ visible_commands.each do |command|
33
33
  result.merge! command.completion_data(with_version: false)
34
34
  end
35
35
 
@@ -62,7 +62,7 @@ module Bashly
62
62
  end
63
63
 
64
64
  def completion_flag_names
65
- public_flags.map(&:name) + public_flags.map(&:short)
65
+ visible_flags.map(&:name) + visible_flags.map(&:short)
66
66
  end
67
67
 
68
68
  def completion_allowed_args
@@ -73,7 +73,7 @@ module Bashly
73
73
  trivial_flags = %w[--help -h]
74
74
  trivial_flags += %w[--version -v] if with_version
75
75
  all = (
76
- public_command_aliases + trivial_flags +
76
+ visible_command_aliases + trivial_flags +
77
77
  completion_flag_names + completion_allowed_args
78
78
  )
79
79
 
@@ -49,6 +49,16 @@ environment_variable.required:
49
49
  help: Specify that this variable is required.
50
50
  url: https://bashly.dannyb.co/configuration/environment-variable/#required
51
51
  example: |-
52
+ environment_variables:
52
53
  - name: api_key
53
54
  help: Your API key
54
55
  required: true
56
+
57
+ environment_variable.validate:
58
+ help: Apply custom validation functions.
59
+
60
+ url: https://bashly.dannyb.co/configuration/environment-variable/#validate
61
+ example: |-
62
+ environment_variables:
63
+ - name: build_dir
64
+ validate: dir_exists
@@ -113,6 +113,29 @@ flag.long:
113
113
  short: -s
114
114
  help: Clone using SSH
115
115
 
116
+ flag.needs:
117
+ help: Specify that this flag needs one or more additional flags. Use the long name of these needed flags.
118
+ url: https://bashly.dannyb.co/configuration/flag/#needs
119
+ example: |-
120
+ flags:
121
+ - long: --add
122
+ arg: alias
123
+
124
+ # When using --add, --command and --target must also be provided
125
+ needs: [--command, --target]
126
+
127
+ - long: --command
128
+ arg: command
129
+ help: Command for the alias
130
+
131
+ # Note that this relationship is marked on both sides
132
+ needs: [--add]
133
+
134
+ - long: --target
135
+ arg: target
136
+ help: Where to add the alias
137
+ needs: [--add]
138
+
116
139
  flag.private:
117
140
  help: Specify that this flag should not be displayed in the help text.
118
141
  url: https://bashly.dannyb.co/configuration/flag/#private
@@ -43,7 +43,7 @@ if extensible
43
43
  end
44
44
  >
45
45
 
46
- if public_commands.any?
46
+ if visible_commands.any?
47
47
  grouped_commands.each do |group, commands|
48
48
  > {{ group.gsub(/:$/, '').upcase }}
49
49
  > ==================================================
@@ -127,6 +127,9 @@ if flags.any?
127
127
  if flag.conflicts
128
128
  > - Conflicts With: **{{ flag.conflicts.join(', ') }}**
129
129
  end
130
+ if flag.needs
131
+ > - Needs: **{{ flag.needs.join(', ') }}**
132
+ end
130
133
  >
131
134
  end
132
135
  end
@@ -147,11 +150,11 @@ if dependencies.any?
147
150
  end
148
151
  end
149
152
 
150
- if public_environment_variables.any?
153
+ if visible_environment_variables.any?
151
154
  > ENVIRONMENT VARIABLES
152
155
  > ==================================================
153
156
  >
154
- public_environment_variables.each do |environment_variable|
157
+ visible_environment_variables.each do |environment_variable|
155
158
  > {{ environment_variable.name.upcase }}
156
159
  > --------------------------------------------------
157
160
  >
@@ -183,7 +186,7 @@ end
183
186
 
184
187
  see_also = []
185
188
  see_also << parents.first if parents.any?
186
- see_also += public_commands.map { |x| x.full_name.to_hyphen } if public_commands.any?
189
+ see_also += visible_commands.map { |x| x.full_name.to_hyphen } if visible_commands.any?
187
190
  see_also += x_mandoc_see_also if x_mandoc_see_also && x_mandoc_see_also.is_a?(Array)
188
191
  see_also.map! do |item|
189
192
  item.match(/(.+)(\(\d\))/) ? "**#{$1}**#{$2}" : "**#{item}**(1)"
@@ -62,10 +62,10 @@ end
62
62
 
63
63
  # === Environment Variables
64
64
 
65
- if public_environment_variables.any?
65
+ if visible_environment_variables.any?
66
66
  > ## Environment Variables
67
67
  >
68
- public_environment_variables.each do |environment_variable|
68
+ visible_environment_variables.each do |environment_variable|
69
69
  attributes = environment_variable.required || environment_variable.default
70
70
 
71
71
  > #### *{{ environment_variable.name.upcase }}*
@@ -152,7 +152,8 @@ if flags.any?
152
152
  > ## Options
153
153
  >
154
154
  flags.each do |flag|
155
- attributes = flag.required || flag.repeatable || flag.default || flag.allowed || flag.conflicts
155
+ attributes = flag.required || flag.repeatable || flag.default ||
156
+ flag.allowed || flag.conflicts || flag.needs
156
157
 
157
158
  > #### *{{ flag.usage_string }}*
158
159
  >
@@ -177,6 +178,9 @@ if flags.any?
177
178
  if flag.conflicts
178
179
  > | Conflicts With: | *{{ flag.conflicts.join(', ') }}*
179
180
  end
181
+ if flag.needs
182
+ > | Needs: | *{{ flag.needs.join(', ') }}*
183
+ end
180
184
  >
181
185
  end
182
186
  end
@@ -59,6 +59,11 @@ partials_extension: sh
59
59
  # required arguments
60
60
  show_examples_on_error: false
61
61
 
62
+ # When using private commands, flags, or environment variables, you may set
63
+ # this option to a name of an environment variable that, if set, will reveal
64
+ # all the private elements in the usage texts, as if they were public.
65
+ private_reveal_key: ~
66
+
62
67
  # Display various usage elements in color by providing the name of the color
63
68
  # function. The value for each property is a name of a function that is
64
69
  # available in your script, for example: `green` or `bold`.
@@ -18,6 +18,8 @@ required: "(required)"
18
18
  repeatable: "(repeatable)"
19
19
  default: "Default: %{value}"
20
20
  allowed: "Allowed: %{values}"
21
+ needs: "Needs: %{values}"
22
+ conflicts: "Conflicts: %{values}"
21
23
 
22
24
  # Fixed flags help text
23
25
  help_flag_text: Show this help
@@ -25,6 +27,7 @@ version_flag_text: Show version number
25
27
 
26
28
  # Error messages
27
29
  flag_requires_an_argument: "%{name} requires an argument: %{usage}"
30
+ flag_needs_another: "%{name} needs %{need}"
28
31
  invalid_argument: "invalid argument: %s"
29
32
  invalid_flag: "invalid option: %s"
30
33
  invalid_command: "invalid command: %s"
@@ -39,3 +42,4 @@ disallowed_argument: "%{name} must be one of: %{allowed}"
39
42
  disallowed_environment_variable: "%{name} environment variable must be one of: %{allowed}"
40
43
  unsupported_bash_version: "bash version 4 or higher is required"
41
44
  validation_error: "validation error in %s:\\n%s"
45
+ environment_variable_validation_error: "validation error in environment variable %s:\\n%s"
@@ -2,6 +2,13 @@ module Bashly
2
2
  module Script
3
3
  class Command < Base
4
4
  include Completions::Command
5
+ include Introspection::Arguments
6
+ include Introspection::Commands
7
+ include Introspection::Dependencies
8
+ include Introspection::EnvironmentVariables
9
+ include Introspection::Examples
10
+ include Introspection::Flags
11
+ include Introspection::Visibility
5
12
 
6
13
  class << self
7
14
  def option_keys
@@ -39,15 +46,6 @@ module Bashly
39
46
  options['alias'].is_a?(String) ? [options['alias']] : options['alias']
40
47
  end
41
48
 
42
- # Returns an array of Arguments
43
- def args
44
- return [] unless options['args']
45
-
46
- options['args'].map do |options|
47
- Argument.new options
48
- end
49
- end
50
-
51
49
  # Returns a string suitable to be a headline
52
50
  def caption_string
53
51
  help.empty? ? full_name : "#{full_name} - #{summary}"
@@ -58,123 +56,12 @@ module Bashly
58
56
  @catch_all ||= CatchAll.from_config options['catch_all']
59
57
  end
60
58
 
61
- # Returns a full list of the Command names and aliases combined
62
- def command_aliases
63
- commands.map(&:aliases).flatten
64
- end
65
-
66
- # Returns a data structure for displaying subcommands help
67
- def command_help_data
68
- result = {}
69
-
70
- public_commands.each do |command|
71
- result[command.group_string] ||= {}
72
- result[command.group_string][command.name] = { summary: command.summary_string }
73
- next unless command.expose
74
-
75
- command.public_commands.each do |subcommand|
76
- result[command.group_string]["#{command.name} #{subcommand.name}"] = {
77
- summary: subcommand.summary_string,
78
- help_only: command.expose != 'always',
79
- }
80
- end
81
- end
82
-
83
- result
84
- end
85
-
86
- # Returns only the names of the Commands
87
- def command_names
88
- commands.map(&:name)
89
- end
90
-
91
- # Returns an array of the Commands
92
- def commands
93
- return [] unless options['commands']
94
-
95
- options['commands'].map do |options|
96
- result = Command.new options
97
- result.parents = parents + [name]
98
- result.parent_command = self
99
- result
100
- end
101
- end
102
-
103
- # Returns a flat array containing all the commands in this tree.
104
- # This includes children + grandchildren (recursive), and may include self
105
- def deep_commands(include_self: false)
106
- result = []
107
- result << self if include_self
108
- commands.each do |command|
109
- result << command
110
- if command.commands.any?
111
- result += command.deep_commands
112
- end
113
- end
114
- result
115
- end
116
-
117
- # If any of this command's subcommands has the default option set to
118
- # true, this default command will be returned, nil otherwise.
119
- def default_command
120
- commands.find(&:default)
121
- end
122
-
123
- # Returns an array of all the default Args
124
- def default_args
125
- args.select(&:default)
126
- end
127
-
128
- # Returns an array of all the default Environment Variables
129
- def default_environment_variables
130
- environment_variables.select(&:default)
131
- end
132
-
133
- # Returns an array of all the default Flags
134
- def default_flags
135
- flags.select(&:default)
136
- end
137
-
138
- # Returns an array of Dependency objects
139
- def dependencies
140
- return [] unless options['dependencies']
141
-
142
- @dependencies ||= options['dependencies'].map do |key, value|
143
- Dependency.from_config key, value
144
- end
145
- end
146
-
147
- # Returns an array of EnvironmentVariable objects
148
- def environment_variables
149
- return [] unless options['environment_variables']
150
-
151
- options['environment_variables'].map do |options|
152
- EnvironmentVariable.new options
153
- end
154
- end
155
-
156
- # Returns an array of examples
157
- def examples
158
- return nil unless options['examples']
159
-
160
- options['examples'].is_a?(Array) ? options['examples'] : [options['examples']]
161
- end
162
-
163
59
  # Returns the filename that is expected to hold the user code for this
164
60
  # command
165
61
  def filename
166
62
  options['filename'] || implicit_filename
167
63
  end
168
64
 
169
- # Returns an array of Flags
170
- def flags
171
- return [] unless options['flags']
172
-
173
- options['flags'].map do |options|
174
- Flag.new options
175
- end
176
- end
177
-
178
65
  # Returns a unique name, suitable to be used in a bash function
179
66
  def function_name
180
67
  options['function'] || full_name.to_underscore
@@ -186,12 +73,6 @@ module Bashly
186
73
  parents.any? ? (parents + [name]).join(' ') : name
187
74
  end
188
75
 
189
- # Returns true if this command's flags should be considered as gloal
190
- # flags, and cascade to subcommands
191
- def global_flags?
192
- flags.any? and commands.any?
193
- end
194
-
195
76
  # Returns the string for the group caption
196
77
  def group_string
197
78
  if group
@@ -201,23 +82,6 @@ module Bashly
201
82
  end
202
83
  end
203
84
 
204
- # Returns subcommands by group
205
- def grouped_commands
206
- result = {}
207
-
208
- public_commands.each do |command|
209
- result[command.group_string] ||= []
210
- result[command.group_string] << command
211
- next unless command.expose
212
-
213
- command.public_commands.each do |subcommand|
214
- result[command.group_string] << subcommand
215
- end
216
- end
217
-
218
- result
219
- end
220
-
221
85
  # Returns true if this command, or any subcommand (deep) as any arg or
222
86
  # flag with arg that is defined as unique
223
87
  def has_unique_args_or_flags?
@@ -246,56 +110,11 @@ module Bashly
246
110
  @parents ||= []
247
111
  end
248
112
 
249
- # Returns only commands that are not private
250
- def public_commands
251
- commands.reject(&:private)
252
- end
253
-
254
- # Returns a full list of the public Command names and aliases combined
255
- def public_command_aliases
256
- public_commands.map(&:aliases).flatten
257
- end
258
-
259
- # Returns only environment variables that are not private
260
- def public_environment_variables
261
- environment_variables.reject(&:private)
262
- end
263
-
264
- # Returns only flags that are not private
265
- def public_flags
266
- flags.reject(&:private)
267
- end
268
-
269
- # Returns true if one of the args is repeatable
270
- def repeatable_arg_exist?
271
- args.any?(&:repeatable)
272
- end
273
-
274
- # Returns an array of all the required Arguments
275
- def required_args
276
- args.select(&:required)
277
- end
278
-
279
- # Returns an array of all the required EnvironmentVariables
280
- def required_environment_variables
281
- environment_variables.select(&:required)
282
- end
283
-
284
- # Returns an array of all the required Flags
285
- def required_flags
286
- flags.select(&:required)
287
- end
288
-
289
113
  # Returns true if this is the root command (no parents)
290
114
  def root_command?
291
115
  parents.empty?
292
116
  end
293
117
 
294
- # Returns true if one of the flags matches the provided short code
295
- def short_flag_exist?(flag)
296
- flags.any? { |f| f.short == flag }
297
- end
298
-
299
118
  # Returns the summary string
300
119
  def summary_string
301
120
  if default
@@ -322,11 +141,8 @@ module Bashly
322
141
  result.compact.join ' '
323
142
  end
324
143
 
325
- # Returns an array of args usage_string for the command's usage_string
326
- def usage_string_args
327
- args.map(&:usage_string)
328
- end
329
-
144
+ # Returns a base usage string that considers whether this command is the
145
+ # default, and if it has any parents. Used internally by `usage_string`.
330
146
  def base_usage_pattern
331
147
  usage_pattern = default ? "[#{name}]" : name
332
148
  parents.any? ? (parents + [usage_pattern]).join(' ') : usage_pattern
@@ -344,21 +160,6 @@ module Bashly
344
160
  @validatables ||= args.select(&:validate) + flags.select(&:validate)
345
161
  end
346
162
 
347
- # Returns an array of all the args with a whitelist
348
- def whitelisted_args
349
- args.select(&:allowed)
350
- end
351
-
352
- # Returns an array of all the environment_variables with a whitelist arg
353
- def whitelisted_environment_variables
354
- environment_variables.select(&:allowed)
355
- end
356
-
357
- # Returns an array of all the flags with a whitelist arg
358
- def whitelisted_flags
359
- flags.select(&:allowed)
360
- end
361
-
362
163
  private
363
164
 
364
165
  # Returns either a flat filename (docker_status_command.sh) or a nested
@@ -1,9 +1,13 @@
1
1
  module Bashly
2
2
  module Script
3
3
  class EnvironmentVariable < Base
4
+ include Introspection::Visibility
5
+
4
6
  class << self
5
7
  def option_keys
6
- @option_keys ||= %i[allowed default help name required private]
8
+ @option_keys ||= %i[
9
+ allowed default help name required private validate
10
+ ]
7
11
  end
8
12
  end
9
13
 
@@ -1,13 +1,16 @@
1
+ require 'shellwords'
2
+
1
3
  module Bashly
2
4
  module Script
3
5
  class Flag < Base
4
6
  include Completions::Flag
7
+ include Introspection::Visibility
5
8
 
6
9
  class << self
7
10
  def option_keys
8
11
  @option_keys ||= %i[
9
- allowed arg completions conflicts default help long repeatable
10
- required short unique validate private
12
+ allowed arg completions conflicts default help long needs
13
+ repeatable required short unique validate private
11
14
  ]
12
15
  end
13
16
  end
@@ -0,0 +1,41 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module Arguments
5
+ # Returns an array of Arguments
6
+ def args
7
+ return [] unless options['args']
8
+
9
+ options['args'].map do |options|
10
+ Argument.new options
11
+ end
12
+ end
13
+
14
+ # Returns an array of all the default Args
15
+ def default_args
16
+ args.select(&:default)
17
+ end
18
+
19
+ # Returns true if one of the args is repeatable
20
+ def repeatable_arg_exist?
21
+ args.any?(&:repeatable)
22
+ end
23
+
24
+ # Returns an array of all the required Arguments
25
+ def required_args
26
+ args.select(&:required)
27
+ end
28
+
29
+ # Returns an array of args usage_string for the command's usage_string
30
+ def usage_string_args
31
+ args.map(&:usage_string)
32
+ end
33
+
34
+ # Returns an array of all the args with a whitelist
35
+ def whitelisted_args
36
+ args.select(&:allowed)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,111 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module Commands
5
+ # Returns a full list of the Command names and aliases combined
6
+ def command_aliases
7
+ commands.map(&:aliases).flatten
8
+ end
9
+
10
+ # Returns a data structure for displaying subcommands help
11
+ def command_help_data
12
+ result = {}
13
+
14
+ commands.each do |command|
15
+ result[command.group_string] ||= {}
16
+ result[command.group_string][command.name] = {
17
+ summary: command.summary_string,
18
+ visibility: command.visibility,
19
+ }
20
+ next unless command.expose
21
+
22
+ command.commands.each do |subcommand|
23
+ result[command.group_string]["#{command.name} #{subcommand.name}"] = {
24
+ summary: subcommand.summary_string,
25
+ visibility: subcommand.visibility,
26
+ help_only: command.expose != 'always',
27
+ }
28
+ end
29
+ end
30
+
31
+ result
32
+ end
33
+
34
+ # Returns only the names of the Commands
35
+ def command_names
36
+ commands.map(&:name)
37
+ end
38
+
39
+ # Returns an array of the Commands
40
+ def commands
41
+ return [] unless options['commands']
42
+
43
+ options['commands'].map do |options|
44
+ result = Command.new options
45
+ result.parents = parents + [name]
46
+ result.parent_command = self
47
+ result
48
+ end
49
+ end
50
+
51
+ # Returns a flat array containing all the commands in this tree.
52
+ # This includes children + grandchildren (recursive), and may include self
53
+ def deep_commands(include_self: false)
54
+ result = []
55
+ result << self if include_self
56
+ commands.each do |command|
57
+ result << command
58
+ if command.commands.any?
59
+ result += command.deep_commands
60
+ end
61
+ end
62
+ result
63
+ end
64
+
65
+ # If any of this command's subcommands has the default option set to
66
+ # true, this default command will be returned, nil otherwise.
67
+ def default_command
68
+ commands.find(&:default)
69
+ end
70
+
71
+ # Returns subcommands by group
72
+ def grouped_commands
73
+ result = {}
74
+
75
+ visible_commands.each do |command|
76
+ result[command.group_string] ||= []
77
+ result[command.group_string] << command
78
+ next unless command.expose
79
+
80
+ command.visible_commands.each do |subcommand|
81
+ result[command.group_string] << subcommand
82
+ end
83
+ end
84
+
85
+ result
86
+ end
87
+
88
+ # Returns only commands that are not private
89
+ def public_commands
90
+ commands.reject(&:private)
91
+ end
92
+
93
+ # Returns a full list of the public Command names and aliases combined
94
+ def public_command_aliases
95
+ public_commands.map(&:aliases).flatten
96
+ end
97
+
98
+ # Returns only public commands, or both public and private commands
99
+ # if Settings.private_reveal_key is set
100
+ def visible_commands
101
+ Settings.private_reveal_key ? commands : public_commands
102
+ end
103
+
104
+ # Returns a full list of the visible Command names and aliases combined
105
+ def visible_command_aliases
106
+ visible_commands.map(&:aliases).flatten
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,16 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module Dependencies
5
+ # Returns an array of Dependency objects
6
+ def dependencies
7
+ return [] unless options['dependencies']
8
+
9
+ @dependencies ||= options['dependencies'].map do |key, value|
10
+ Dependency.from_config key, value
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module EnvironmentVariables
5
+ # Returns an array of all the Environment Variables with default values
6
+ def default_environment_variables
7
+ environment_variables.select(&:default)
8
+ end
9
+
10
+ # Returns an array of EnvironmentVariable objects
11
+ def environment_variables
12
+ return [] unless options['environment_variables']
13
+
14
+ options['environment_variables'].map do |options|
15
+ EnvironmentVariable.new options
16
+ end
17
+ end
18
+
19
+ # Returns only environment variables that are not private
20
+ def public_environment_variables
21
+ environment_variables.reject(&:private)
22
+ end
23
+
24
+ # Returns an array of all the required EnvironmentVariables
25
+ def required_environment_variables
26
+ environment_variables.select(&:required)
27
+ end
28
+
29
+ # Returns an array of all the environment_variables with a validation
30
+ def validated_environment_variables
31
+ environment_variables.select(&:validate)
32
+ end
33
+
34
+ # Returns only public environment variables, or both public and private
35
+ # environment variables if Settings.private_reveal_key is set
36
+ def visible_environment_variables
37
+ Settings.private_reveal_key ? environment_variables : public_environment_variables
38
+ end
39
+
40
+ # Returns an array of all the environment_variables with a whitelist arg
41
+ def whitelisted_environment_variables
42
+ environment_variables.select(&:allowed)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,14 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module Examples
5
+ # Returns an array of examples
6
+ def examples
7
+ return nil unless options['examples']
8
+
9
+ options['examples'].is_a?(Array) ? options['examples'] : [options['examples']]
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,58 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module Flags
5
+ # Returns an array of all the default Flags
6
+ def default_flags
7
+ flags.select(&:default)
8
+ end
9
+
10
+ # Returns an array of Flags
11
+ def flags
12
+ return [] unless options['flags']
13
+
14
+ options['flags'].map do |options|
15
+ Flag.new options
16
+ end
17
+ end
18
+
19
+ # Returns true if this command's flags should be considered as gloal
20
+ # flags, and cascade to subcommands
21
+ def global_flags?
22
+ flags.any? and commands.any?
23
+ end
24
+
25
+ # Returns an array of all fpags that need other flags
26
+ def needy_flags
27
+ flags.select(&:needs)
28
+ end
29
+
30
+ # Returns only flags that are not private
31
+ def public_flags
32
+ flags.reject(&:private)
33
+ end
34
+
35
+ # Returns an array of all the required Flags
36
+ def required_flags
37
+ flags.select(&:required)
38
+ end
39
+
40
+ # Returns true if one of the flags matches the provided short code
41
+ def short_flag_exist?(flag)
42
+ flags.any? { |f| f.short == flag }
43
+ end
44
+
45
+ # Returns only public flags, or both public and private flags if
46
+ # Settings.private_reveal_key is set
47
+ def visible_flags
48
+ Settings.private_reveal_key ? flags : public_flags
49
+ end
50
+
51
+ # Returns an array of all the flags with a whitelist arg
52
+ def whitelisted_flags
53
+ flags.select(&:allowed)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ module Bashly
2
+ module Script
3
+ module Introspection
4
+ module Visibility
5
+ # Returns :public, :private, or :semi_private based on the `private`
6
+ # option of the host, in conjunction with `Settings.private_reveal_key`.
7
+ def visibility
8
+ if !options['private']
9
+ :public
10
+ elsif Settings.private_reveal_key
11
+ :semi_private
12
+ else
13
+ :private
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -10,6 +10,7 @@ module Bashly
10
10
  :config_path,
11
11
  :lib_dir,
12
12
  :partials_extension,
13
+ :private_reveal_key,
13
14
  :show_examples_on_error,
14
15
  :source_dir,
15
16
  :strict,
@@ -54,6 +55,10 @@ module Bashly
54
55
  @partials_extension ||= get :partials_extension
55
56
  end
56
57
 
58
+ def private_reveal_key
59
+ @private_reveal_key ||= get :private_reveal_key
60
+ end
61
+
57
62
  def production?
58
63
  env == :production
59
64
  end
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = '1.2.1'
2
+ VERSION = '1.2.2'
3
3
  end
@@ -4,14 +4,14 @@
4
4
  > printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
5
5
 
6
6
  if allowed
7
- > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
7
+ > printf " %s\n" "{{ strings[:allowed] % { values: allowed.join(', ') } }}"
8
8
  end
9
9
 
10
10
  if default
11
11
  if default.is_a? Array
12
- > printf " {{ strings[:default] % { value: default.join(', ') } }}\n"
12
+ > printf " %s\n" "{{ strings[:default] % { value: default.join(', ') } }}"
13
13
  else
14
- > printf " {{ strings[:default] % { value: default } }}\n"
14
+ > printf " %s\n" "{{ strings[:default] % { value: default } }}"
15
15
  end
16
16
  end
17
17
 
@@ -24,3 +24,9 @@ if whitelisted_environment_variables.any?
24
24
  > fi
25
25
  end
26
26
  end
27
+
28
+ if validated_environment_variables.any?
29
+ validated_environment_variables.each do |env_var|
30
+ = env_var.render(:validations)
31
+ end
32
+ end
@@ -1,13 +1,17 @@
1
1
  = view_marker
2
2
 
3
- > if [[ -n $long_usage ]]; then
4
- options_caption = public_commands.any? && public_flags.any? ? strings[:global_options] : strings[:options]
3
+ > if [[ -n "$long_usage" ]]; then
4
+ options_caption = strings[:options]
5
+ if commands.any? && (public_flags.any? || (flags.any? && Settings.private_reveal_key))
6
+ options_caption = strings[:global_options]
7
+ end
8
+
5
9
  > printf "%s\n" "{{ options_caption.color(:caption) }}"
6
10
  >
7
- = render(:usage_flags).indent 2 if public_flags.any?
11
+ = render(:usage_flags).indent 2 if flags.any?
8
12
  = render(:usage_fixed_flags).indent 2
9
13
  = render(:usage_args).indent 2 if args.any? or catch_all.help
10
- = render(:usage_environment_variables).indent 2 if public_environment_variables.any?
14
+ = render(:usage_environment_variables).indent 2 if environment_variables.any?
11
15
  = render(:usage_examples).indent 2 if examples
12
16
  = render(:footer).indent 2 if footer
13
17
  >
@@ -0,0 +1,9 @@
1
+ if needy_flags.any?
2
+ = view_marker
3
+
4
+ needy_flags.each do |flag|
5
+ = flag.render(:needs)
6
+ end
7
+
8
+ >
9
+ end
@@ -13,6 +13,7 @@ end
13
13
  = render(:parse_requirements_while).indent 2
14
14
  = render(:required_args_filter).indent 2
15
15
  = render(:required_flags_filter).indent 2
16
+ = render(:needy_flags_filter).indent 2
16
17
  = render(:catch_all_filter).indent 2
17
18
  = render(:default_assignments).indent 2
18
19
  = render(:validations).indent 2
@@ -6,11 +6,18 @@ command_help_data.each do |group, commands|
6
6
  > printf "%s\n" "{{ group.color(:caption) }}"
7
7
 
8
8
  commands.each do |command, info|
9
+ next if info[:visibility] == :private
10
+
11
+ line = %Q[printf " %s #{info[:summary].sanitize_for_print}\\n" "#{command.ljust(maxlen).color(:command)}"]
9
12
  if info[:help_only]
10
- > [[ -n $long_usage ]] && printf " %s {{ info[:summary].sanitize_for_print }}\n" "{{ command.ljust(maxlen).color(:command) }}"
11
- else
12
- > printf " %s {{ info[:summary].sanitize_for_print }}\n" "{{ command.ljust(maxlen).color(:command) }}"
13
+ line = %Q[[[ -n "$long_usage" ]] && #{line}]
14
+ end
15
+
16
+ if info[:visibility] == :semi_private
17
+ line = %Q[[[ -n "${#{Settings.private_reveal_key}:-}" ]] && #{line}]
13
18
  end
19
+
20
+ = line
14
21
  end
15
22
 
16
23
  > echo
@@ -1,10 +1,26 @@
1
1
  = view_marker
2
2
 
3
- > printf "%s\n" "{{ strings[:environment_variables].color(:caption) }}"
4
- >
3
+ caption = %Q[printf "%s\\n" "#{strings[:environment_variables].color(:caption)}"]
4
+ if public_environment_variables.any?
5
+ = caption
6
+ >
7
+ elsif environment_variables.any? && Settings.private_reveal_key
8
+ > if [[ -n "${{{ Settings.private_reveal_key }}:-}" ]]; then
9
+ = caption.indent(2)
10
+ > fi
11
+ >
12
+ end
13
+
14
+ environment_variables.each do |env_var|
15
+ next if env_var.visibility == :private
5
16
 
6
- public_environment_variables.each do |env_var|
7
- = env_var.render :usage
17
+ if env_var.visibility == :semi_private
18
+ > if [[ -n "${{{ Settings.private_reveal_key }}:-}" ]]; then
19
+ = env_var.render(:usage).indent(2)
20
+ > fi
21
+ else
22
+ = env_var.render :usage
23
+ end
8
24
  end
9
25
 
10
26
  >
@@ -1,7 +1,15 @@
1
1
  = view_marker
2
2
 
3
- public_flags.each do |flag|
4
- = flag.render :usage
3
+ flags.each do |flag|
4
+ next if flag.visibility == :private
5
+
6
+ if flag.visibility == :semi_private
7
+ > if [[ -n "${{{ Settings.private_reveal_key }}:-}" ]]; then
8
+ = flag.render(:usage).indent(2)
9
+ > fi
10
+ else
11
+ = flag.render :usage
12
+ end
5
13
  end
6
14
 
7
15
  >
@@ -4,11 +4,11 @@
4
4
  > printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
5
5
 
6
6
  if allowed
7
- > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
7
+ > printf " %s\n" "{{ strings[:allowed] % { values: allowed.join(', ') } }}"
8
8
  end
9
9
 
10
10
  if default
11
- > printf " {{ strings[:default] % { value: default } }}\n"
11
+ > printf " %s\n" "{{ strings[:default] % { value: default } }}"
12
12
  end
13
13
 
14
14
  > echo
@@ -0,0 +1,9 @@
1
+ if validate
2
+ = view_marker
3
+
4
+ > if [[ -v {{ name.upcase }} && -n $(validate_{{ validate }} "${{ name.upcase }}") ]]; then
5
+ > printf "{{ strings[:environment_variable_validation_error] }}\n" "{{ usage_string }}" "$(validate_{{ validate }} "${{ name.upcase }}")" >&2
6
+ > exit 1
7
+ > fi
8
+ >
9
+ end
@@ -0,0 +1,22 @@
1
+ if needs
2
+
3
+ = view_marker
4
+
5
+ if needs.count == 1
6
+ > if [[ -n ${args['{{ name }}']+x} ]] && [[ -z "${args[{{ needs.first }}]:-}" ]]; then
7
+ > printf "%s\n" "{{ strings[:flag_needs_another] % { name: name, need: needs.first } }}" >&2
8
+ > exit 1
9
+ > fi
10
+ >
11
+ else
12
+ > if [[ -n ${args['{{ name }}']+x} ]]; then
13
+ > for need in {{ needs.join ' ' }}; do
14
+ > if [[ -z "${args[$need]:-}" ]]; then
15
+ > printf "%s\n" "{{ strings[:flag_needs_another] % { name: name, need: "$need" } }}" >&2
16
+ > exit 1
17
+ > fi
18
+ > done
19
+ > fi
20
+ >
21
+ end
22
+ end
@@ -4,16 +4,24 @@
4
4
  > printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
5
5
 
6
6
  if allowed
7
- > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
7
+ > printf " %s\n" "{{ strings[:allowed] % { values: allowed.join(', ') } }}"
8
8
  end
9
9
 
10
10
  if default
11
11
  if default.is_a? Array
12
- > printf " {{ strings[:default] % { value: default.join(', ') } }}\n"
12
+ > printf " %s\n" "{{ strings[:default] % { value: default.join(', ') } }}"
13
13
  else
14
- > printf " {{ strings[:default] % { value: default } }}\n"
14
+ > printf " %s\n" "{{ strings[:default] % { value: default } }}"
15
15
  end
16
16
  end
17
17
 
18
+ if needs
19
+ > printf " %s\n" "{{ strings[:needs] % { values: needs.join(', ') } }}"
20
+ end
21
+
22
+ if conflicts
23
+ > printf " %s\n" "{{ strings[:conflicts] % { values: conflicts.join(', ') } }}"
24
+ end
25
+
18
26
  > echo
19
27
  >
data/lib/bashly.rb CHANGED
@@ -3,53 +3,40 @@ if ENV['DEBUGGER']
3
3
  require 'lp'
4
4
  end
5
5
 
6
- require 'bashly/extensions/array'
7
- require 'bashly/extensions/file'
8
- require 'bashly/extensions/string'
9
- require 'bashly/extensions/yaml'
10
- require 'bashly/exceptions'
6
+ require 'requires'
7
+ requires 'bashly/extensions'
8
+ requires 'bashly/exceptions'
11
9
 
12
10
  module Bashly
13
- autoload :CLI, 'bashly/cli'
14
- autoload :Config, 'bashly/config'
15
- autoload :ConfigValidator, 'bashly/config_validator'
16
- autoload :Library, 'bashly/library'
17
- autoload :LibrarySource, 'bashly/library_source'
18
- autoload :LibrarySourceConfig, 'bashly/library_source_config'
19
- autoload :MessageStrings, 'bashly/message_strings'
20
- autoload :RenderContext, 'bashly/render_context'
21
- autoload :RenderSource, 'bashly/render_source'
22
- autoload :VERSION, 'bashly/version'
23
-
24
- autoload :AssetHelper, 'bashly/concerns/asset_helper'
25
- autoload :Completions, 'bashly/concerns/completions'
26
- autoload :ComposeRefinements, 'bashly/refinements/compose_refinements'
27
- autoload :Renderable, 'bashly/concerns/renderable'
28
- autoload :Settings, 'bashly/settings'
29
- autoload :ValidationHelpers, 'bashly/concerns/validation_helpers'
11
+ autoloads 'bashly/refinements', %i[ComposeRefinements]
12
+
13
+ autoloads 'bashly', %i[
14
+ CLI Config ConfigValidator Library LibrarySource LibrarySourceConfig
15
+ MessageStrings RenderContext RenderSource Settings VERSION
16
+ ]
17
+
18
+ autoloads 'bashly/concerns', %i[
19
+ AssetHelper Completions Renderable ValidationHelpers
20
+ ]
30
21
 
31
22
  module Script
32
- autoload :Argument, 'bashly/script/argument'
33
- autoload :Base, 'bashly/script/base'
34
- autoload :CatchAll, 'bashly/script/catch_all'
35
- autoload :Command, 'bashly/script/command'
36
- autoload :Dependency, 'bashly/script/dependency'
37
- autoload :EnvironmentVariable, 'bashly/script/environment_variable'
38
- autoload :Flag, 'bashly/script/flag'
39
- autoload :Wrapper, 'bashly/script/wrapper'
23
+ autoloads 'bashly/script', %i[
24
+ Argument Base CatchAll Command Dependency EnvironmentVariable Flag
25
+ Wrapper
26
+ ]
27
+
28
+ module Introspection
29
+ autoloads 'bashly/script/introspection', %i[
30
+ Arguments Commands Dependencies EnvironmentVariables Examples Flags
31
+ Visibility
32
+ ]
33
+ end
40
34
  end
41
35
 
42
36
  module Commands
43
- autoload :Add, 'bashly/commands/add'
44
- autoload :Base, 'bashly/commands/base'
45
- autoload :Completions, 'bashly/commands/completions'
46
- autoload :Doc, 'bashly/commands/doc'
47
- autoload :Generate, 'bashly/commands/generate'
48
- autoload :Init, 'bashly/commands/init'
49
- autoload :Preview, 'bashly/commands/preview'
50
- autoload :Render, 'bashly/commands/render'
51
- autoload :Shell, 'bashly/commands/shell'
52
- autoload :Validate, 'bashly/commands/validate'
37
+ autoloads 'bashly/commands', %i[
38
+ Add Base Completions Doc Generate Init Preview Render Shell Validate
39
+ ]
53
40
  end
54
41
 
55
42
  module Libraries
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: 1.2.1
4
+ version: 1.2.2
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: 2024-07-25 00:00:00.000000000 Z
11
+ date: 2024-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -100,6 +100,20 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0.7'
103
+ - !ruby/object:Gem::Dependency
104
+ name: requires
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 1.1.0
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 1.1.0
103
117
  - !ruby/object:Gem::Dependency
104
118
  name: tty-markdown
105
119
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +234,13 @@ files:
220
234
  - lib/bashly/script/dependency.rb
221
235
  - lib/bashly/script/environment_variable.rb
222
236
  - lib/bashly/script/flag.rb
237
+ - lib/bashly/script/introspection/arguments.rb
238
+ - lib/bashly/script/introspection/commands.rb
239
+ - lib/bashly/script/introspection/dependencies.rb
240
+ - lib/bashly/script/introspection/environment_variables.rb
241
+ - lib/bashly/script/introspection/examples.rb
242
+ - lib/bashly/script/introspection/flags.rb
243
+ - lib/bashly/script/introspection/visibility.rb
223
244
  - lib/bashly/script/wrapper.rb
224
245
  - lib/bashly/settings.rb
225
246
  - lib/bashly/templates/bashly.yml
@@ -248,6 +269,7 @@ files:
248
269
  - lib/bashly/views/command/inspect_args.gtx
249
270
  - lib/bashly/views/command/long_usage.gtx
250
271
  - lib/bashly/views/command/master_script.gtx
272
+ - lib/bashly/views/command/needy_flags_filter.gtx
251
273
  - lib/bashly/views/command/normalize_input.gtx
252
274
  - lib/bashly/views/command/normalize_input_function.gtx
253
275
  - lib/bashly/views/command/normalize_input_simple.gtx
@@ -275,10 +297,12 @@ files:
275
297
  - lib/bashly/views/command/version_command.gtx
276
298
  - lib/bashly/views/command/whitelist_filter.gtx
277
299
  - lib/bashly/views/environment_variable/usage.gtx
300
+ - lib/bashly/views/environment_variable/validations.gtx
278
301
  - lib/bashly/views/flag/case.gtx
279
302
  - lib/bashly/views/flag/case_arg.gtx
280
303
  - lib/bashly/views/flag/case_no_arg.gtx
281
304
  - lib/bashly/views/flag/conflicts.gtx
305
+ - lib/bashly/views/flag/needs.gtx
282
306
  - lib/bashly/views/flag/usage.gtx
283
307
  - lib/bashly/views/flag/validations.gtx
284
308
  - lib/bashly/views/wrapper/bash3_bouncer.gtx
@@ -308,7 +332,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
308
332
  - !ruby/object:Gem::Version
309
333
  version: '0'
310
334
  requirements: []
311
- rubygems_version: 3.5.14
335
+ rubygems_version: 3.5.17
312
336
  signing_key:
313
337
  specification_version: 4
314
338
  summary: Bash Command Line Tool Generator