Skip to content

Commit 1614006

Browse files
authored
Merge pull request #222 from DannyBen/add/uniq-validations
Validate uniqueness of command args, flags and subcommands
2 parents e436f15 + 174cc94 commit 1614006

File tree

9 files changed

+126
-55
lines changed

9 files changed

+126
-55
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
module Bashly
2+
# This is a `ConfigValidator` concern responsible for providing basic
3+
# assertion methods.
4+
module ValidationHelpers
5+
6+
def deprecations
7+
@deprecations ||= []
8+
end
9+
10+
protected
11+
12+
def assert(valid, message)
13+
raise ConfigurationError, message unless valid
14+
end
15+
16+
def refute(invalid, message)
17+
assert !invalid, message
18+
end
19+
20+
def deprecate(key, **options)
21+
deprecations.push Deprecation.new(key, **options)
22+
end
23+
24+
def assert_string(key, value)
25+
assert value.is_a?(String), "#{key} must be a string"
26+
end
27+
28+
def assert_optional_string(key, value)
29+
assert_string key, value if value
30+
end
31+
32+
def assert_boolean(key, value)
33+
assert [true, false, nil].include?(value), "#{key} must be a boolean"
34+
end
35+
36+
def assert_array(key, value, of: nil)
37+
return unless value
38+
assert value.is_a?(Array), "#{key} must be an array"
39+
if of
40+
value.each_with_index do |val, i|
41+
send "assert_#{of}".to_sym, "#{key}[#{i}]", val
42+
end
43+
end
44+
end
45+
46+
def assert_hash(key, value, whitelist = nil)
47+
assert value.is_a?(Hash), "#{key} must be a hash"
48+
49+
if whitelist
50+
invalid_keys = value.keys.map(&:to_sym) - whitelist
51+
assert invalid_keys.empty?, "#{key} contains invalid options: #{invalid_keys.join(', ')}"
52+
end
53+
end
54+
55+
def assert_uniq(key, value, array_key)
56+
return unless value
57+
list = value.map { |c| c[array_key] }.compact.flatten
58+
assert list.uniq?, "#{key} cannot have elements with similar #{array_key} values"
59+
end
60+
61+
def assert_string_or_array(key, value)
62+
return unless value
63+
assert [Array, String].include?(value.class),
64+
"#{key} must be a string or an array"
65+
66+
assert_array key, value, of: :string if value.is_a? Array
67+
end
68+
end
69+
end

lib/bashly/config_validator.rb

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Bashly
22
class ConfigValidator
3+
include ValidationHelpers
4+
35
attr_reader :data
46

57
def initialize(data)
@@ -10,63 +12,8 @@ def validate
1012
assert_command "root", data
1113
end
1214

13-
def deprecations
14-
@deprecations ||= []
15-
end
16-
1715
private
1816

19-
def assert(valid, message)
20-
raise ConfigurationError, message unless valid
21-
end
22-
23-
def refute(invalid, message)
24-
assert !invalid, message
25-
end
26-
27-
def deprecate(key, **options)
28-
deprecations.push Deprecation.new(key, **options)
29-
end
30-
31-
def assert_string(key, value)
32-
assert value.is_a?(String), "#{key} must be a string"
33-
end
34-
35-
def assert_optional_string(key, value)
36-
assert_string key, value if value
37-
end
38-
39-
def assert_boolean(key, value)
40-
assert [true, false, nil].include?(value), "#{key} must be a boolean"
41-
end
42-
43-
def assert_array(key, value, of: nil)
44-
return unless value
45-
assert value.is_a?(Array), "#{key} must be an array"
46-
if of
47-
value.each_with_index do |val, i|
48-
send "assert_#{of}".to_sym, "#{key}[#{i}]", val
49-
end
50-
end
51-
end
52-
53-
def assert_hash(key, value, whitelist = nil)
54-
assert value.is_a?(Hash), "#{key} must be a hash"
55-
56-
if whitelist
57-
invalid_keys = value.keys.map(&:to_sym) - whitelist
58-
assert invalid_keys.empty?, "#{key} contains invalid options: #{invalid_keys.join(', ')}"
59-
end
60-
end
61-
62-
def assert_string_or_array(key, value)
63-
return unless value
64-
assert [Array, String].include?(value.class),
65-
"#{key} must be a string or an array"
66-
67-
assert_array key, value, of: :string if value.is_a? Array
68-
end
69-
7017
def assert_version(key, value)
7118
return unless value
7219
assert [String, Integer, Float].include?(value.class),
@@ -177,6 +124,12 @@ def assert_command(key, value)
177124
assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var
178125
assert_array "#{key}.examples", value['examples'], of: :string
179126

127+
assert_uniq "#{key}.commands", value['commands'], 'name'
128+
assert_uniq "#{key}.commands", value['commands'], 'alias'
129+
assert_uniq "#{key}.flags", value['flags'], 'long'
130+
assert_uniq "#{key}.flags", value['flags'], 'short'
131+
assert_uniq "#{key}.args", value['args'], 'name'
132+
180133
if value['catch_all'] and value['args']
181134
repeatable_arg = value['args'].select { |a| a['repeatable'] }.first&.dig 'name'
182135
refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"

lib/bashly/extensions/array.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@ def indent(offset)
44
indentation = " " * offset
55
map { |line| "#{indentation}#{line}" }
66
end
7+
8+
def uniq?
9+
self == uniq
10+
end
11+
712
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#<Bashly::ConfigurationError: root.args cannot have elements with similar name values>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#<Bashly::ConfigurationError: root.commands cannot have elements with similar alias values>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#<Bashly::ConfigurationError: root.commands cannot have elements with similar name values>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#<Bashly::ConfigurationError: root.flags cannot have elements with similar long values>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#<Bashly::ConfigurationError: root.flags cannot have elements with similar short values>

spec/fixtures/script/validations.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,42 @@
209209
help: Path to one or more files
210210
repeatable: true
211211
required: true
212+
213+
:non_uniq_command_names:
214+
name: invalid
215+
help: commands with the same name
216+
commands:
217+
- name: upload
218+
- name: download
219+
- name: download
220+
221+
:non_uniq_command_aliases:
222+
name: invalid
223+
help: commands with the same alias
224+
commands:
225+
- name: connect
226+
alias: c
227+
- name: config
228+
alias: [c, conf]
229+
230+
:non_uniq_flags_longs:
231+
name: invalid
232+
help: flags with the same long name
233+
flags:
234+
- long: --force
235+
- long: --force
236+
237+
:non_uniq_flags_shorts:
238+
name: invalid
239+
help: flags with the same short name
240+
flags:
241+
- short: -f
242+
- short: -f
243+
244+
:non_uniq_arg_names:
245+
name: invalid
246+
help: args with the same name
247+
args:
248+
- name: file
249+
- name: file
250+

0 commit comments

Comments
 (0)