clamp 1.0.1 → 1.1.0
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/.rubocop.yml +60 -0
- data/.travis.yml +3 -5
- data/CHANGES.md +6 -0
- data/Gemfile +3 -2
- data/Guardfile +1 -1
- data/README.md +14 -1
- data/Rakefile +2 -2
- data/clamp.gemspec +3 -4
- data/examples/defaulted +1 -1
- data/examples/scoop +2 -2
- data/examples/speak +2 -4
- data/examples/subcommand_missing +18 -0
- data/lib/clamp.rb +2 -2
- data/lib/clamp/attribute/declaration.rb +3 -1
- data/lib/clamp/attribute/definition.rb +6 -12
- data/lib/clamp/attribute/instance.rb +1 -1
- data/lib/clamp/command.rb +33 -35
- data/lib/clamp/help.rb +11 -12
- data/lib/clamp/messages.rb +5 -28
- data/lib/clamp/option/declaration.rb +20 -19
- data/lib/clamp/option/definition.rb +11 -18
- data/lib/clamp/option/parsing.rb +27 -18
- data/lib/clamp/parameter/declaration.rb +16 -3
- data/lib/clamp/parameter/definition.rb +7 -2
- data/lib/clamp/parameter/parsing.rb +8 -1
- data/lib/clamp/subcommand/declaration.rb +28 -25
- data/lib/clamp/subcommand/definition.rb +1 -1
- data/lib/clamp/subcommand/execution.rb +7 -7
- data/lib/clamp/subcommand/parsing.rb +2 -2
- data/lib/clamp/truthy.rb +1 -1
- data/lib/clamp/version.rb +1 -1
- data/spec/clamp/command_group_spec.rb +89 -23
- data/spec/clamp/command_spec.rb +20 -21
- data/spec/clamp/messages_spec.rb +1 -1
- data/spec/clamp/option/definition_spec.rb +5 -5
- data/spec/clamp/option_module_spec.rb +1 -1
- data/spec/clamp/parameter/definition_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -3
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bd2b8653f1a6c24e26a9ec5d84f655721cecdee
|
4
|
+
data.tar.gz: 776fa8ff95cf73971de85be5e6f30915bd40df09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51397540a6660a9f10bd1fae184b16d3cac69a64ce17a5f65d4e5bc3d9f3c60140f7a16ae868393372f541c147a1459ef78eaa402a65203e77833ae829d54051
|
7
|
+
data.tar.gz: 27c409d2ebbe33d768b884cff979d33df4099008506c24dbe0080249466610928cd705b88a7f7b76dc10eb4ed7cf2fc2e5be0f2e8919ff74ce8015f2403965d1
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
Eval:
|
2
|
+
Exclude:
|
3
|
+
- "Rakefile"
|
4
|
+
|
5
|
+
Metrics/AbcSize:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
Metrics/LineLength:
|
9
|
+
Max: 120
|
10
|
+
|
11
|
+
Metrics/MethodLength:
|
12
|
+
Max: 30
|
13
|
+
|
14
|
+
Style/AccessorMethodName:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Style/ClassAndModuleChildren:
|
18
|
+
EnforcedStyle: nested
|
19
|
+
Exclude:
|
20
|
+
- "spec/**/*"
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Exclude:
|
24
|
+
- "lib/**/version.rb"
|
25
|
+
- "spec/**/*"
|
26
|
+
|
27
|
+
Style/EmptyLinesAroundBlockBody:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/EmptyLinesAroundClassBody:
|
31
|
+
EnforcedStyle: empty_lines
|
32
|
+
|
33
|
+
Style/EmptyLinesAroundModuleBody:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/Encoding:
|
37
|
+
EnforcedStyle: when_needed
|
38
|
+
Enabled: true
|
39
|
+
|
40
|
+
Style/FileName:
|
41
|
+
Exclude:
|
42
|
+
- "bin/*"
|
43
|
+
|
44
|
+
Style/HashSyntax:
|
45
|
+
EnforcedStyle: hash_rockets
|
46
|
+
|
47
|
+
Style/Lambda:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Style/NumericLiterals:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Style/PredicateName:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
Style/StringLiterals:
|
57
|
+
EnforcedStyle: double_quotes
|
58
|
+
|
59
|
+
Style/WordArray:
|
60
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -6,9 +6,10 @@ group :development do
|
|
6
6
|
gem "guard-rspec", "~> 4.6.5", :require => false
|
7
7
|
gem "listen", "~> 3.0.2"
|
8
8
|
gem "rake", "~> 10.4"
|
9
|
+
gem "rubocop", "~> 0.43.0", :require => false
|
9
10
|
end
|
10
11
|
|
11
12
|
group :test do
|
12
|
-
gem "rspec", "~> 3.
|
13
|
-
gem "rr", "~> 1.
|
13
|
+
gem "rspec", "~> 3.5.0"
|
14
|
+
gem "rr", "~> 1.2.0"
|
14
15
|
end
|
data/Guardfile
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
25
25
|
# * 'just' rspec: 'rspec'
|
26
26
|
|
27
|
-
guard :rspec, cmd
|
27
|
+
guard :rspec, :cmd => "bundle exec rspec" do
|
28
28
|
require "guard/rspec/dsl"
|
29
29
|
dsl = Guard::RSpec::Dsl.new(self)
|
30
30
|
|
data/README.md
CHANGED
@@ -137,7 +137,7 @@ Clamp will handle both "`--force`" and "`--no-force`" options, setting the value
|
|
137
137
|
|
138
138
|
### Required options
|
139
139
|
|
140
|
-
Although
|
140
|
+
Although "required option" is an oxymoron, Clamp lets you mark an option as required, and will verify that a value is provided:
|
141
141
|
|
142
142
|
```ruby
|
143
143
|
option "--password", "PASSWORD", "the secret password", :required => true
|
@@ -365,6 +365,19 @@ Options are inheritable, so any options declared for a command are supported by
|
|
365
365
|
|
366
366
|
Note that, if a subcommand accepts options, they must be specified on the command-line _after_ the subcommand name.
|
367
367
|
|
368
|
+
You can define a `subcommand_missing` method that is called when user tries to run an unknown subcommand:
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
Clamp do
|
372
|
+
def subcommand_missing(name)
|
373
|
+
if name == "foo"
|
374
|
+
return Object.const_get(:FooPlugin) if Object.const_defined?(:FooPlugin)
|
375
|
+
abort "Subcommand 'foo' requires plugin X"
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
```
|
380
|
+
|
368
381
|
Getting help
|
369
382
|
------------
|
370
383
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "bundler"
|
2
2
|
|
3
3
|
Bundler::GemHelper.install_tasks
|
4
4
|
|
@@ -7,6 +7,6 @@ require "rspec/core/rake_task"
|
|
7
7
|
task "default" => "spec"
|
8
8
|
|
9
9
|
RSpec::Core::RakeTask.new do |t|
|
10
|
-
t.pattern =
|
10
|
+
t.pattern = "spec/**/*_spec.rb"
|
11
11
|
t.rspec_opts = ["--colour", "--format", "documentation"]
|
12
12
|
end
|
data/clamp.gemspec
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
1
|
+
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
|
3
2
|
require "clamp/version"
|
4
3
|
|
5
4
|
Gem::Specification.new do |s|
|
@@ -11,9 +10,9 @@ Gem::Specification.new do |s|
|
|
11
10
|
s.email = "mdub@dogbiscuit.org"
|
12
11
|
s.homepage = "http://github.com/mdub/clamp"
|
13
12
|
|
14
|
-
s.license =
|
13
|
+
s.license = "MIT"
|
15
14
|
|
16
|
-
s.summary =
|
15
|
+
s.summary = "a minimal framework for command-line utilities"
|
17
16
|
s.description = <<EOF
|
18
17
|
Clamp provides an object-model for command-line utilities.
|
19
18
|
It handles parsing of command-line options, and generation of usage help.
|
data/examples/defaulted
CHANGED
data/examples/scoop
CHANGED
@@ -7,8 +7,8 @@ require "clamp"
|
|
7
7
|
Clamp do
|
8
8
|
|
9
9
|
option ["-f", "--flavour"], "FLAVOUR", "flavour",
|
10
|
-
|
11
|
-
|
10
|
+
:multivalued => true, :default => ["chocolate"],
|
11
|
+
:attribute_name => :flavours
|
12
12
|
|
13
13
|
def execute
|
14
14
|
puts "one #{flavours.join(' and ')} ice-cream"
|
data/examples/speak
CHANGED
@@ -6,9 +6,9 @@ require "clamp"
|
|
6
6
|
|
7
7
|
Clamp do
|
8
8
|
|
9
|
-
banner %
|
9
|
+
banner %(
|
10
10
|
Say something.
|
11
|
-
|
11
|
+
)
|
12
12
|
|
13
13
|
option "--loud", :flag, "say it loud"
|
14
14
|
option ["-n", "--iterations"], "N", "say it N times", :default => 1 do |s|
|
@@ -18,14 +18,12 @@ Clamp do
|
|
18
18
|
parameter "WORDS ...", "the thing to say", :attribute_name => :words
|
19
19
|
|
20
20
|
def execute
|
21
|
-
|
22
21
|
the_truth = words.join(" ")
|
23
22
|
the_truth.upcase! if loud?
|
24
23
|
|
25
24
|
iterations.times do
|
26
25
|
puts the_truth
|
27
26
|
end
|
28
|
-
|
29
27
|
end
|
30
28
|
|
31
29
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require "clamp"
|
4
|
+
|
5
|
+
Clamp do
|
6
|
+
|
7
|
+
subcommand "hello", "Say hello" do
|
8
|
+
def execute
|
9
|
+
puts "Hello"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def subcommand_missing(name)
|
14
|
+
abort "Install bye plugin first" if name == "bye"
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/clamp.rb
CHANGED
@@ -5,7 +5,7 @@ module Clamp
|
|
5
5
|
|
6
6
|
protected
|
7
7
|
|
8
|
-
def
|
8
|
+
def declare_attribute(attribute, &block)
|
9
9
|
define_reader_for(attribute)
|
10
10
|
define_default_for(attribute)
|
11
11
|
if attribute.multivalued?
|
@@ -16,6 +16,8 @@ module Clamp
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
private
|
20
|
+
|
19
21
|
def define_reader_for(attribute)
|
20
22
|
define_method(attribute.read_method) do
|
21
23
|
attribute.of(self)._read
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "clamp/attribute/instance"
|
2
2
|
|
3
3
|
module Clamp
|
4
4
|
module Attribute
|
@@ -6,18 +6,14 @@ module Clamp
|
|
6
6
|
class Definition
|
7
7
|
|
8
8
|
def initialize(options)
|
9
|
-
if options.
|
9
|
+
if options.key?(:attribute_name)
|
10
10
|
@attribute_name = options[:attribute_name].to_s
|
11
11
|
end
|
12
|
-
if options.
|
13
|
-
|
14
|
-
end
|
15
|
-
if options.has_key?(:environment_variable)
|
12
|
+
@default_value = options[:default] if options.key?(:default)
|
13
|
+
if options.key?(:environment_variable)
|
16
14
|
@environment_variable = options[:environment_variable]
|
17
15
|
end
|
18
|
-
if options.
|
19
|
-
@hidden = options[:hidden]
|
20
|
-
end
|
16
|
+
@hidden = options[:hidden] if options.key?(:hidden)
|
21
17
|
end
|
22
18
|
|
23
19
|
attr_reader :description, :environment_variable
|
@@ -47,9 +43,7 @@ module Clamp
|
|
47
43
|
end
|
48
44
|
|
49
45
|
def append_method
|
50
|
-
if multivalued?
|
51
|
-
"append_to_#{attribute_name}"
|
52
|
-
end
|
46
|
+
"append_to_#{attribute_name}" if multivalued?
|
53
47
|
end
|
54
48
|
|
55
49
|
def multivalued?
|
@@ -63,7 +63,7 @@ module Clamp
|
|
63
63
|
def default_from_environment
|
64
64
|
return if self.defined?
|
65
65
|
return if attribute.environment_variable.nil?
|
66
|
-
return unless ENV.
|
66
|
+
return unless ENV.key?(attribute.environment_variable)
|
67
67
|
# Set the parameter value if it's environment variable is present
|
68
68
|
value = ENV[attribute.environment_variable]
|
69
69
|
begin
|
data/lib/clamp/command.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
1
|
+
require "clamp/messages"
|
2
|
+
require "clamp/errors"
|
3
|
+
require "clamp/help"
|
4
|
+
require "clamp/option/declaration"
|
5
|
+
require "clamp/option/parsing"
|
6
|
+
require "clamp/parameter/declaration"
|
7
|
+
require "clamp/parameter/parsing"
|
8
|
+
require "clamp/subcommand/declaration"
|
9
|
+
require "clamp/subcommand/parsing"
|
10
10
|
|
11
11
|
module Clamp
|
12
12
|
|
@@ -25,12 +25,9 @@ module Clamp
|
|
25
25
|
# @param [String] invocation_path the path used to invoke the command
|
26
26
|
# @param [Hash] context additional data the command may need
|
27
27
|
#
|
28
|
-
def initialize(invocation_path, context = {}
|
28
|
+
def initialize(invocation_path, context = {})
|
29
29
|
@invocation_path = invocation_path
|
30
30
|
@context = context
|
31
|
-
parent_attribute_values.each do |attribute, value|
|
32
|
-
attribute.of(self).set(value)
|
33
|
-
end
|
34
31
|
end
|
35
32
|
|
36
33
|
# @return [String] the path used to invoke this command
|
@@ -39,9 +36,7 @@ module Clamp
|
|
39
36
|
|
40
37
|
# @return [Array<String>] unconsumed command-line arguments
|
41
38
|
#
|
42
|
-
|
43
|
-
@remaining_arguments
|
44
|
-
end
|
39
|
+
attr_reader :remaining_arguments
|
45
40
|
|
46
41
|
# Parse command-line arguments.
|
47
42
|
#
|
@@ -82,6 +77,13 @@ module Clamp
|
|
82
77
|
self.class.help(invocation_path)
|
83
78
|
end
|
84
79
|
|
80
|
+
# Abort with subcommand missing usage error
|
81
|
+
#
|
82
|
+
# @ param [String] name subcommand_name
|
83
|
+
def subcommand_missing(name)
|
84
|
+
signal_usage_error(Clamp.message(:no_such_subcommand, :name => name))
|
85
|
+
end
|
86
|
+
|
85
87
|
include Clamp::Option::Parsing
|
86
88
|
include Clamp::Parameter::Parsing
|
87
89
|
include Clamp::Subcommand::Parsing
|
@@ -91,9 +93,7 @@ module Clamp
|
|
91
93
|
attr_accessor :context
|
92
94
|
|
93
95
|
def handle_remaining_arguments
|
94
|
-
unless remaining_arguments.empty?
|
95
|
-
signal_usage_error Clamp.message(:too_many_arguments)
|
96
|
-
end
|
96
|
+
signal_usage_error Clamp.message(:too_many_arguments) unless remaining_arguments.empty?
|
97
97
|
end
|
98
98
|
|
99
99
|
private
|
@@ -128,22 +128,20 @@ module Clamp
|
|
128
128
|
# @param [Array<String>] arguments command-line arguments
|
129
129
|
# @param [Hash] context additional data the command may need
|
130
130
|
#
|
131
|
-
def run(invocation_path = File.basename($
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
exit(128 + e.signo)
|
146
|
-
end
|
131
|
+
def run(invocation_path = File.basename($PROGRAM_NAME), arguments = ARGV, context = {})
|
132
|
+
new(invocation_path, context).run(arguments)
|
133
|
+
rescue Clamp::UsageError => e
|
134
|
+
$stderr.puts "ERROR: #{e.message}"
|
135
|
+
$stderr.puts ""
|
136
|
+
$stderr.puts "See: '#{e.command.invocation_path} --help'"
|
137
|
+
exit(1)
|
138
|
+
rescue Clamp::HelpWanted => e
|
139
|
+
puts e.command.help
|
140
|
+
rescue Clamp::ExecutionError => e
|
141
|
+
$stderr.puts "ERROR: #{e.message}"
|
142
|
+
exit(e.status)
|
143
|
+
rescue SignalException => e
|
144
|
+
exit(128 + e.signo)
|
147
145
|
end
|
148
146
|
|
149
147
|
end
|