clamp 1.3.2 → 1.3.3
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.
- checksums.yaml +4 -4
- data/.editorconfig +1 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +12 -8
- data/.travis.yml +2 -1
- data/CHANGES.md +4 -0
- data/CODEOWNERS +1 -0
- data/Gemfile +8 -5
- data/Guardfile +2 -2
- data/Rakefile +1 -3
- data/clamp.gemspec +2 -1
- data/lib/clamp/attribute/declaration.rb +1 -0
- data/lib/clamp/attribute/definition.rb +4 -2
- data/lib/clamp/attribute/instance.rb +2 -1
- data/lib/clamp/help.rb +4 -5
- data/lib/clamp/messages.rb +3 -3
- data/lib/clamp/option/declaration.rb +2 -0
- data/lib/clamp/option/definition.rb +10 -5
- data/lib/clamp/option/parsing.rb +8 -3
- data/lib/clamp/parameter/declaration.rb +3 -0
- data/lib/clamp/parameter/definition.rb +8 -5
- data/lib/clamp/parameter/parsing.rb +4 -6
- data/lib/clamp/subcommand/declaration.rb +3 -1
- data/lib/clamp/subcommand/execution.rb +2 -0
- data/lib/clamp/subcommand/parsing.rb +1 -0
- data/lib/clamp/truthy.rb +1 -1
- data/lib/clamp/version.rb +1 -1
- data/spec/clamp/command_group_spec.rb +64 -45
- data/spec/clamp/{option_module_spec.rb → command_option_module_spec.rb} +2 -1
- data/spec/clamp/{option_reordering_spec.rb → command_option_reordering_spec.rb} +3 -3
- data/spec/clamp/command_spec.rb +364 -148
- data/spec/clamp/{help_spec.rb → help/builder_spec.rb} +22 -4
- data/spec/clamp/messages_spec.rb +11 -6
- data/spec/clamp/option/definition_spec.rb +92 -40
- data/spec/clamp/parameter/definition_spec.rb +120 -50
- data/spec/spec_helper.rb +5 -6
- metadata +14 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43f15a863374d1abf2505c8b102de45e94f05146649728354c3d5593ff8f3a01
|
4
|
+
data.tar.gz: 5e9d629fa2e5947ba0060dfb831198ffa4a313a5faa7318b4efb4fd651bbb158
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e68d1317f82da6b7275eb56ad1ef5be9b34fd2390e8819efd488558424c20e550ea4e625d90fa0d5d1303decd0ecd68e11138c4fc505fa66c876a00bd2de107
|
7
|
+
data.tar.gz: f16d43d5234ac429d1839f822177f55d1aee7e1d4eb94c49c6bcd2585c5a9049099a4bd426df01d2c8f409e7957d44c84a34c83adcc6a3710f62efcd11421d7e
|
data/.editorconfig
CHANGED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
plugins:
|
2
|
+
- rubocop-rake
|
3
|
+
- rubocop-rspec
|
4
|
+
|
1
5
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
6
|
+
TargetRubyVersion: 2.5
|
7
|
+
NewCops: enable
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
- "Rakefile"
|
9
|
+
Layout/LineLength:
|
10
|
+
Max: 120
|
7
11
|
|
8
12
|
Layout/EmptyLinesAroundBlockBody:
|
9
13
|
Enabled: false
|
@@ -21,9 +25,6 @@ Metrics/BlockLength:
|
|
21
25
|
Exclude:
|
22
26
|
- "spec/**/*"
|
23
27
|
|
24
|
-
Metrics/LineLength:
|
25
|
-
Max: 120
|
26
|
-
|
27
28
|
Metrics/MethodLength:
|
28
29
|
Max: 30
|
29
30
|
|
@@ -34,7 +35,7 @@ Naming/FileName:
|
|
34
35
|
Exclude:
|
35
36
|
- "bin/*"
|
36
37
|
|
37
|
-
Naming/
|
38
|
+
Naming/PredicatePrefix:
|
38
39
|
Enabled: false
|
39
40
|
|
40
41
|
Style/ClassAndModuleChildren:
|
@@ -65,3 +66,6 @@ Style/StringLiterals:
|
|
65
66
|
|
66
67
|
Style/WordArray:
|
67
68
|
Enabled: false
|
69
|
+
|
70
|
+
RSpec/NestedGroups:
|
71
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @mdub
|
data/Gemfile
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
source "
|
3
|
+
source "https://rubygems.org"
|
4
4
|
|
5
5
|
gemspec
|
6
6
|
|
7
7
|
group :development do
|
8
8
|
gem "guard-rspec", "~> 4.7", require: false
|
9
9
|
gem "highline"
|
10
|
-
gem "listen", "~> 3.
|
11
|
-
gem "
|
12
|
-
gem "
|
10
|
+
gem "listen", "~> 3.9"
|
11
|
+
gem "pry-byebug", "~> 3.11"
|
12
|
+
gem "rake", "~> 13.3"
|
13
|
+
gem "rubocop", "~> 1.79.0", require: false
|
14
|
+
gem "rubocop-rake", "~> 0.7.1", require: false
|
15
|
+
gem "rubocop-rspec", "~> 3.6.0", require: false
|
13
16
|
end
|
14
17
|
|
15
18
|
group :test do
|
16
|
-
gem "rspec", "~> 3.
|
19
|
+
gem "rspec", "~> 3.13"
|
17
20
|
end
|
data/Guardfile
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
# directories %w(app lib config test spec features) \
|
8
8
|
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
9
9
|
|
10
|
-
##
|
10
|
+
## NOTE: if you are using the `directories` clause above and you are not
|
11
11
|
## watching the project directory ('.'), then you will want to move
|
12
12
|
## the Guardfile to a watched dir and symlink it back, e.g.
|
13
13
|
#
|
@@ -17,7 +17,7 @@
|
|
17
17
|
#
|
18
18
|
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
19
19
|
|
20
|
-
#
|
20
|
+
# NOTE: The cmd option is now required due to the increasing number of ways
|
21
21
|
# rspec may be run, below are examples of the most common uses.
|
22
22
|
# * bundler: 'bundle exec rspec'
|
23
23
|
# * bundler binstubs: 'bin/rspec'
|
data/Rakefile
CHANGED
@@ -6,8 +6,6 @@ Bundler::GemHelper.install_tasks
|
|
6
6
|
|
7
7
|
require "rspec/core/rake_task"
|
8
8
|
|
9
|
-
task "default" => "spec"
|
10
|
-
|
11
9
|
RSpec::Core::RakeTask.new do |t|
|
12
10
|
t.pattern = "spec/**/*_spec.rb"
|
13
11
|
t.rspec_opts = ["--colour", "--format", "documentation"]
|
@@ -17,4 +15,4 @@ require "rubocop/rake_task"
|
|
17
15
|
|
18
16
|
RuboCop::RakeTask.new
|
19
17
|
|
20
|
-
task "default" => "rubocop"
|
18
|
+
task "default" => ["spec", "rubocop"]
|
data/clamp.gemspec
CHANGED
@@ -21,7 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
TEXT
|
22
22
|
|
23
23
|
s.files = `git ls-files`.split("\n")
|
24
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
24
|
s.require_paths = ["lib"]
|
26
25
|
|
26
|
+
s.required_ruby_version = ">= 2.5", "< 4"
|
27
|
+
s.metadata["rubygems_mfa_required"] = "true"
|
27
28
|
end
|
@@ -20,8 +20,8 @@ module Clamp
|
|
20
20
|
|
21
21
|
def help_rhs
|
22
22
|
rhs = description
|
23
|
-
comments = required_indicator
|
24
|
-
rhs += " (#{comments})"
|
23
|
+
comments = [required_indicator, default_description].compact
|
24
|
+
rhs += " (#{comments.join(', ')})" unless comments.empty?
|
25
25
|
rhs
|
26
26
|
end
|
27
27
|
|
@@ -95,7 +95,9 @@ module Clamp
|
|
95
95
|
("$#{@environment_variable}" if defined?(@environment_variable)),
|
96
96
|
(@default_value.inspect if defined?(@default_value))
|
97
97
|
].compact
|
98
|
+
|
98
99
|
return nil if default_sources.empty?
|
100
|
+
|
99
101
|
"#{Clamp.message(:default)}: " + default_sources.join(", #{Clamp.message(:or)} ")
|
100
102
|
end
|
101
103
|
|
@@ -70,8 +70,9 @@ module Clamp
|
|
70
70
|
return if self.defined?
|
71
71
|
return if attribute.environment_variable.nil?
|
72
72
|
return unless ENV.key?(attribute.environment_variable)
|
73
|
+
|
73
74
|
# Set the parameter value if it's environment variable is present
|
74
|
-
value = ENV
|
75
|
+
value = ENV.fetch(attribute.environment_variable, nil)
|
75
76
|
begin
|
76
77
|
take(value)
|
77
78
|
rescue ArgumentError => e
|
data/lib/clamp/help.rb
CHANGED
@@ -14,7 +14,7 @@ module Clamp
|
|
14
14
|
@declared_usage_descriptions << usage
|
15
15
|
end
|
16
16
|
|
17
|
-
attr_reader :declared_usage_descriptions
|
17
|
+
attr_reader :declared_usage_descriptions, :description
|
18
18
|
|
19
19
|
def description=(description)
|
20
20
|
@description = description.dup
|
@@ -29,8 +29,6 @@ module Clamp
|
|
29
29
|
self.description = description
|
30
30
|
end
|
31
31
|
|
32
|
-
attr_reader :description
|
33
|
-
|
34
32
|
def derived_usage_description
|
35
33
|
parts = ["[OPTIONS]"]
|
36
34
|
parts += parameters.map(&:name)
|
@@ -84,7 +82,7 @@ module Clamp
|
|
84
82
|
end
|
85
83
|
|
86
84
|
def add_usage(invocation_path, usage_descriptions)
|
87
|
-
line Clamp.message(:usage_heading)
|
85
|
+
line "#{Clamp.message(:usage_heading)}:"
|
88
86
|
usage_descriptions.each do |usage|
|
89
87
|
line " #{invocation_path} #{usage}".rstrip
|
90
88
|
end
|
@@ -92,11 +90,12 @@ module Clamp
|
|
92
90
|
|
93
91
|
def add_description(description)
|
94
92
|
return unless description
|
93
|
+
|
95
94
|
line
|
96
95
|
line description.gsub(/^/, " ")
|
97
96
|
end
|
98
97
|
|
99
|
-
DETAIL_FORMAT = " %-29s %s"
|
98
|
+
DETAIL_FORMAT = " %-29s %s"
|
100
99
|
|
101
100
|
def add_list(heading, items)
|
102
101
|
line
|
data/lib/clamp/messages.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Clamp
|
3
|
+
module Clamp # :nodoc:
|
4
4
|
|
5
5
|
# Message lookup, to allow localization.
|
6
6
|
#
|
@@ -21,8 +21,6 @@ module Clamp #:nodoc:
|
|
21
21
|
init_default_messages
|
22
22
|
end
|
23
23
|
|
24
|
-
private
|
25
|
-
|
26
24
|
DEFAULTS = {
|
27
25
|
too_many_arguments: "too many arguments",
|
28
26
|
option_required: "option '%<option>s' is required",
|
@@ -42,6 +40,8 @@ module Clamp #:nodoc:
|
|
42
40
|
options_heading: "Options"
|
43
41
|
}.freeze
|
44
42
|
|
43
|
+
private
|
44
|
+
|
45
45
|
def messages
|
46
46
|
init_default_messages unless defined?(@messages)
|
47
47
|
@messages
|
@@ -40,6 +40,7 @@ module Clamp
|
|
40
40
|
|
41
41
|
def declare_implicit_help_option
|
42
42
|
return false if effective_options.find { |o| o.handles?("--help") }
|
43
|
+
|
43
44
|
help_switches = ["--help"]
|
44
45
|
help_switches.unshift("-h") unless effective_options.find { |o| o.handles?("-h") }
|
45
46
|
option help_switches, :flag, "print help" do
|
@@ -55,6 +56,7 @@ module Clamp
|
|
55
56
|
|
56
57
|
def options_declared_on(ancestor)
|
57
58
|
return [] unless ancestor.is_a?(Clamp::Option::Declaration)
|
59
|
+
|
58
60
|
ancestor.declared_options
|
59
61
|
end
|
60
62
|
|
@@ -16,7 +16,9 @@ module Clamp
|
|
16
16
|
@description = description
|
17
17
|
super(options)
|
18
18
|
@multivalued = options[:multivalued]
|
19
|
+
|
19
20
|
return unless options.key?(:required)
|
21
|
+
|
20
22
|
@required = options[:required]
|
21
23
|
# Do some light validation for conflicting settings.
|
22
24
|
raise ArgumentError, "Specifying a :default value with :required doesn't make sense" if options.key?(:default)
|
@@ -37,13 +39,13 @@ module Clamp
|
|
37
39
|
@type == :flag
|
38
40
|
end
|
39
41
|
|
40
|
-
def
|
41
|
-
!(switch =~ /^--no-(.*)/ && switches.member?("
|
42
|
+
def flag_set?(switch)
|
43
|
+
!(switch =~ /^--no-(.*)/ && switches.member?("--[no-]#{Regexp.last_match(1)}"))
|
42
44
|
end
|
43
45
|
|
44
46
|
def read_method
|
45
47
|
if flag?
|
46
|
-
super
|
48
|
+
"#{super}?"
|
47
49
|
else
|
48
50
|
super
|
49
51
|
end
|
@@ -51,8 +53,10 @@ module Clamp
|
|
51
53
|
|
52
54
|
def extract_value(switch, arguments)
|
53
55
|
if flag?
|
54
|
-
|
56
|
+
flag_set?(switch)
|
55
57
|
else
|
58
|
+
raise ArgumentError, Clamp.message(:no_value_provided) if arguments.empty?
|
59
|
+
|
56
60
|
arguments.shift
|
57
61
|
end
|
58
62
|
end
|
@@ -63,7 +67,7 @@ module Clamp
|
|
63
67
|
|
64
68
|
def help_lhs
|
65
69
|
lhs = switches.join(", ")
|
66
|
-
lhs += " "
|
70
|
+
lhs += " #{type}" unless flag?
|
67
71
|
lhs
|
68
72
|
end
|
69
73
|
|
@@ -81,6 +85,7 @@ module Clamp
|
|
81
85
|
|
82
86
|
def infer_attribute_name
|
83
87
|
raise Clamp::DeclarationError, "You must specify either a long-switch or an :attribute_value" unless long_switch
|
88
|
+
|
84
89
|
inferred_name = long_switch.sub(/^--(\[no-\])?/, "").tr("-", "_")
|
85
90
|
inferred_name += "_list" if multivalued?
|
86
91
|
inferred_name
|
data/lib/clamp/option/parsing.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Clamp
|
3
|
+
module Clamp # :nodoc:
|
4
4
|
|
5
5
|
class << self
|
6
6
|
|
@@ -29,11 +29,16 @@ module Clamp #:nodoc:
|
|
29
29
|
until remaining_arguments.empty?
|
30
30
|
unless remaining_arguments.first.start_with?("-")
|
31
31
|
break unless argument_buffer.size < argument_buffer_limit
|
32
|
+
|
32
33
|
argument_buffer << remaining_arguments.shift
|
34
|
+
|
33
35
|
next
|
34
36
|
end
|
37
|
+
|
35
38
|
switch = remaining_arguments.shift
|
39
|
+
|
36
40
|
break if switch == "--"
|
41
|
+
|
37
42
|
handle_switch(switch)
|
38
43
|
end
|
39
44
|
remaining_arguments.unshift(*argument_buffer)
|
@@ -42,8 +47,8 @@ module Clamp #:nodoc:
|
|
42
47
|
def handle_switch(switch)
|
43
48
|
switch = split_trailing_switches(switch)
|
44
49
|
option = find_option(switch)
|
45
|
-
value = option.extract_value(switch, remaining_arguments)
|
46
50
|
begin
|
51
|
+
value = option.extract_value(switch, remaining_arguments)
|
47
52
|
option.of(self).take(value)
|
48
53
|
rescue ArgumentError => e
|
49
54
|
signal_usage_error Clamp.message(:option_argument_error, switch: switch, message: e.message)
|
@@ -55,7 +60,7 @@ module Clamp #:nodoc:
|
|
55
60
|
when /\A(-\w)(.+)\z/m # combined short options
|
56
61
|
switch = Regexp.last_match(1)
|
57
62
|
if find_option(switch).flag?
|
58
|
-
remaining_arguments.unshift("
|
63
|
+
remaining_arguments.unshift("-#{Regexp.last_match(2)}")
|
59
64
|
else
|
60
65
|
remaining_arguments.unshift(Regexp.last_match(2))
|
61
66
|
end
|
@@ -33,7 +33,9 @@ module Clamp
|
|
33
33
|
|
34
34
|
def parameter_buffer_limit
|
35
35
|
return 0 unless Clamp.allow_options_after_parameters
|
36
|
+
|
36
37
|
return Float::INFINITY if inheritable_parameters.any?(&:multivalued?)
|
38
|
+
|
37
39
|
inheritable_parameters.size
|
38
40
|
end
|
39
41
|
|
@@ -41,6 +43,7 @@ module Clamp
|
|
41
43
|
|
42
44
|
def superclass_inheritable_parameters
|
43
45
|
return [] unless superclass.respond_to?(:inheritable_parameters, true)
|
46
|
+
|
44
47
|
superclass.inheritable_parameters
|
45
48
|
end
|
46
49
|
|
@@ -32,19 +32,22 @@ module Clamp
|
|
32
32
|
|
33
33
|
def consume(arguments)
|
34
34
|
raise ArgumentError, Clamp.message(:no_value_provided) if required? && arguments.empty?
|
35
|
+
|
35
36
|
arguments.shift(multivalued? ? arguments.length : 1)
|
36
37
|
end
|
37
38
|
|
38
|
-
|
39
|
+
ELLIPSIS_SUFFIX = / \.\.\.$/.freeze
|
40
|
+
OPTIONAL = /^\[(.*)\]/.freeze
|
39
41
|
|
40
|
-
|
41
|
-
OPTIONAL = /^\[(.*)\]/
|
42
|
+
VALID_ATTRIBUTE_NAME = /^[a-z0-9_]+$/.freeze
|
42
43
|
|
43
|
-
|
44
|
+
private
|
44
45
|
|
45
46
|
def infer_attribute_name
|
46
47
|
inferred_name = name.downcase.tr("-", "_").sub(ELLIPSIS_SUFFIX, "").sub(OPTIONAL) { Regexp.last_match(1) }
|
47
|
-
|
48
|
+
|
49
|
+
raise "cannot infer attribute_name from #{name.inspect}" unless inferred_name.match? VALID_ATTRIBUTE_NAME
|
50
|
+
|
48
51
|
inferred_name += "_list" if multivalued?
|
49
52
|
inferred_name
|
50
53
|
end
|
@@ -18,13 +18,11 @@ module Clamp
|
|
18
18
|
|
19
19
|
def set_parameters_from_command_line
|
20
20
|
self.class.parameters.each do |parameter|
|
21
|
-
|
22
|
-
parameter.
|
23
|
-
parameter.of(self).take(value)
|
24
|
-
end
|
25
|
-
rescue ArgumentError => e
|
26
|
-
signal_usage_error Clamp.message(:parameter_argument_error, param: parameter.name, message: e.message)
|
21
|
+
parameter.consume(remaining_arguments).each do |value|
|
22
|
+
parameter.of(self).take(value)
|
27
23
|
end
|
24
|
+
rescue ArgumentError => e
|
25
|
+
signal_usage_error Clamp.message(:parameter_argument_error, param: parameter.name, message: e.message)
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
@@ -31,8 +31,9 @@ module Clamp
|
|
31
31
|
def find_subcommand_class(*names)
|
32
32
|
names.inject(self) do |command_class, name|
|
33
33
|
return nil unless command_class
|
34
|
+
|
34
35
|
subcommand = command_class.find_subcommand(name)
|
35
|
-
subcommand
|
36
|
+
subcommand&.subcommand_class
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
@@ -42,6 +43,7 @@ module Clamp
|
|
42
43
|
|
43
44
|
def default_subcommand=(name)
|
44
45
|
raise Clamp::DeclarationError, "default_subcommand must be defined before subcommands" if has_subcommands?
|
46
|
+
|
45
47
|
@default_subcommand = name
|
46
48
|
end
|
47
49
|
|
@@ -25,6 +25,7 @@ module Clamp
|
|
25
25
|
subcommand = subcommand_class.new(invocation_path_for(name), context)
|
26
26
|
self.class.inheritable_attributes.each do |attribute|
|
27
27
|
next unless attribute.of(self).defined?
|
28
|
+
|
28
29
|
attribute.of(subcommand).set(attribute.of(self).get)
|
29
30
|
end
|
30
31
|
subcommand
|
@@ -38,6 +39,7 @@ module Clamp
|
|
38
39
|
def find_subcommand_class(name)
|
39
40
|
subcommand_def = self.class.find_subcommand(name)
|
40
41
|
return subcommand_def.subcommand_class if subcommand_def
|
42
|
+
|
41
43
|
subcommand_missing(name)
|
42
44
|
end
|
43
45
|
|
data/lib/clamp/truthy.rb
CHANGED
data/lib/clamp/version.rb
CHANGED