clamp 1.2.1 → 1.3.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -4
  3. data/.travis.yml +4 -6
  4. data/CHANGES.md +7 -0
  5. data/Gemfile +8 -6
  6. data/Guardfile +3 -1
  7. data/Rakefile +8 -0
  8. data/clamp.gemspec +8 -6
  9. data/examples/admin +3 -2
  10. data/examples/defaulted +4 -3
  11. data/examples/flipflop +1 -0
  12. data/examples/fubar +1 -0
  13. data/examples/gitdown +2 -1
  14. data/examples/scoop +3 -2
  15. data/examples/speak +3 -2
  16. data/examples/subcommand_missing +1 -0
  17. data/examples/word +1 -0
  18. data/lib/clamp.rb +3 -1
  19. data/lib/clamp/attribute/declaration.rb +5 -0
  20. data/lib/clamp/attribute/definition.rb +15 -12
  21. data/lib/clamp/attribute/instance.rb +5 -3
  22. data/lib/clamp/command.rb +9 -1
  23. data/lib/clamp/errors.rb +7 -3
  24. data/lib/clamp/help.rb +8 -6
  25. data/lib/clamp/messages.rb +21 -14
  26. data/lib/clamp/option/declaration.rb +4 -0
  27. data/lib/clamp/option/definition.rb +9 -3
  28. data/lib/clamp/option/parsing.rb +37 -32
  29. data/lib/clamp/parameter/declaration.rb +4 -0
  30. data/lib/clamp/parameter/definition.rb +9 -3
  31. data/lib/clamp/parameter/parsing.rb +5 -1
  32. data/lib/clamp/subcommand/declaration.rb +15 -13
  33. data/lib/clamp/subcommand/definition.rb +2 -0
  34. data/lib/clamp/subcommand/execution.rb +11 -0
  35. data/lib/clamp/subcommand/parsing.rb +4 -0
  36. data/lib/clamp/truthy.rb +4 -2
  37. data/lib/clamp/version.rb +3 -1
  38. data/spec/clamp/command_group_spec.rb +27 -9
  39. data/spec/clamp/command_spec.rb +84 -49
  40. data/spec/clamp/messages_spec.rb +5 -4
  41. data/spec/clamp/option/definition_spec.rb +13 -11
  42. data/spec/clamp/option_module_spec.rb +3 -1
  43. data/spec/clamp/option_reordering_spec.rb +6 -4
  44. data/spec/clamp/parameter/definition_spec.rb +14 -12
  45. data/spec/spec_helper.rb +3 -3
  46. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e919d5a5f983e9de93adeccf16090c2ccf673d6
4
- data.tar.gz: fcc637ed598db752ac2411970391ff9440e96fcc
3
+ metadata.gz: a8365dad9e1c1555dfddea4d47c063438af94be5
4
+ data.tar.gz: b618f175a72f08180fb77315cc1a4ceafbbb134e
5
5
  SHA512:
6
- metadata.gz: bc3d0c1e9a7172ab3a0f8d09cc0583aec4f03ee8a85db033d2e0c413a03a7455ddc1c1cca622781620a28ab47148ebe9b3245d54ac533278bc0398e767dc558b
7
- data.tar.gz: 9551a0bbae48288c19b9ac5a2f1918753620d4deefd8efc1e47fa5206c9911e9ee80aa60223f017133e7ff545d8d61624ff1308fb17a9412d2c1724ee6623c9b
6
+ metadata.gz: 2bec2151d2344efc7fbcd37709646904d20e7456fa83365484aacfa318bb23207a8e3ae9e813457d26d791f56b8c890eb863ccb59a85724a53b542193af26384
7
+ data.tar.gz: 0be7bb668484292023495887a581e8e887e0d3f10f2fac89353f6e6a6d091a2f3e9a308902a3f8548c169dd138c0aec7a90e28fac950e36999f9524b1ffab886
@@ -1,3 +1,6 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.1
3
+
1
4
  Eval:
2
5
  Exclude:
3
6
  - "Rakefile"
@@ -14,6 +17,10 @@ Layout/EmptyLinesAroundModuleBody:
14
17
  Metrics/AbcSize:
15
18
  Enabled: false
16
19
 
20
+ Metrics/BlockLength:
21
+ Exclude:
22
+ - "spec/**/*"
23
+
17
24
  Metrics/LineLength:
18
25
  Max: 120
19
26
 
@@ -27,6 +34,9 @@ Naming/FileName:
27
34
  Exclude:
28
35
  - "bin/*"
29
36
 
37
+ Naming/PredicateName:
38
+ Enabled: false
39
+
30
40
  Style/ClassAndModuleChildren:
31
41
  EnforcedStyle: nested
32
42
  Exclude:
@@ -35,21 +45,19 @@ Style/ClassAndModuleChildren:
35
45
  Style/Documentation:
36
46
  Exclude:
37
47
  - "lib/**/version.rb"
48
+ - "examples/*"
38
49
  - "spec/**/*"
39
50
 
40
51
  Style/Encoding:
41
52
  Enabled: true
42
53
 
43
- Style/HashSyntax:
44
- EnforcedStyle: hash_rockets
45
-
46
54
  Style/Lambda:
47
55
  Enabled: false
48
56
 
49
57
  Style/NumericLiterals:
50
58
  Enabled: false
51
59
 
52
- Naming/PredicateName:
60
+ Style/StderrPuts:
53
61
  Enabled: false
54
62
 
55
63
  Style/StringLiterals:
@@ -1,8 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.8
4
- - 2.2.4
5
- - 2.3.1
6
- before_install:
7
- - gem update --system
8
- - gem install bundler
3
+ - 2.1.9
4
+ - 2.2.10
5
+ - 2.3.7
6
+ - 2.5.1
data/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.0 (2018-06-17)
4
+
5
+ * Add `.execute` DSL method.
6
+ * Append '(required)' to the description of required options.
7
+ * Fix issue#75: don't generate `default_XXX` method unless a default is specified.
8
+ * Fix issue#90: allow required options to be provided after subcommands.
9
+
3
10
  ## 1.2.0 (2018-02-12)
4
11
 
5
12
  * Add option to `Clamp.allow_options_after_parameters`.
data/Gemfile CHANGED
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "http://rubygems.org"
2
4
 
3
5
  gemspec
4
6
 
5
7
  group :development do
6
- gem "guard-rspec", "~> 4.6.5", :require => false
7
- gem "listen", "~> 3.0.2"
8
- gem "rake", "~> 10.4"
9
- gem "rubocop", :require => false
8
+ gem "guard-rspec", "~> 4.7", require: false
9
+ gem "highline"
10
+ gem "listen", "~> 3.0"
11
+ gem "rake", "~> 12.3"
12
+ gem "rubocop", require: false
10
13
  end
11
14
 
12
15
  group :test do
13
- gem "rspec", "~> 3.5.0"
14
- gem "rr", "~> 1.2.0"
16
+ gem "rspec", "~> 3.7"
15
17
  end
data/Guardfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A sample Guardfile
2
4
  # More info at https://github.com/guard/guard#readme
3
5
 
@@ -24,7 +26,7 @@
24
26
  # * zeus: 'zeus rspec' (requires the server to be started separately)
25
27
  # * 'just' rspec: 'rspec'
26
28
 
27
- guard :rspec, :cmd => "bundle exec rspec" do
29
+ guard :rspec, cmd: "bundle exec rspec" do
28
30
  require "guard/rspec/dsl"
29
31
  dsl = Guard::RSpec::Dsl.new(self)
30
32
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler"
2
4
 
3
5
  Bundler::GemHelper.install_tasks
@@ -10,3 +12,9 @@ RSpec::Core::RakeTask.new do |t|
10
12
  t.pattern = "spec/**/*_spec.rb"
11
13
  t.rspec_opts = ["--colour", "--format", "documentation"]
12
14
  end
15
+
16
+ require "rubocop/rake_task"
17
+
18
+ RuboCop::RakeTask.new
19
+
20
+ task "default" => "rubocop"
@@ -1,4 +1,6 @@
1
- $LOAD_PATH.push File.expand_path("../lib", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path("lib", __dir__)
2
4
  require "clamp/version"
3
5
 
4
6
  Gem::Specification.new do |s|
@@ -8,15 +10,15 @@ Gem::Specification.new do |s|
8
10
  s.platform = Gem::Platform::RUBY
9
11
  s.authors = ["Mike Williams"]
10
12
  s.email = "mdub@dogbiscuit.org"
11
- s.homepage = "http://github.com/mdub/clamp"
13
+ s.homepage = "https://github.com/mdub/clamp"
12
14
 
13
15
  s.license = "MIT"
14
16
 
15
17
  s.summary = "a minimal framework for command-line utilities"
16
- s.description = <<EOF
17
- Clamp provides an object-model for command-line utilities.
18
- It handles parsing of command-line options, and generation of usage help.
19
- EOF
18
+ s.description = <<-TEXT.gsub(/^\s+/, "")
19
+ Clamp provides an object-model for command-line utilities.
20
+ It handles parsing of command-line options, and generation of usage help.
21
+ TEXT
20
22
 
21
23
  s.files = `git ls-files`.split("\n")
22
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # An example of options and parameters
4
5
 
@@ -6,12 +7,12 @@ require "clamp"
6
7
 
7
8
  Clamp do
8
9
 
9
- option "--timeout", "SECONDS", "connection timeout", :default => 5, :environment_variable => "MYAPP_TIMEOUT" do |x|
10
+ option "--timeout", "SECONDS", "connection timeout", default: 5, environment_variable: "MYAPP_TIMEOUT" do |x|
10
11
  Integer(x)
11
12
  end
12
13
 
13
14
  parameter "HOST", "server address"
14
- parameter "[PORT]", "server port", :default => 80, :environment_variable => "MYAPP_PORT"
15
+ parameter "[PORT]", "server port", default: 80, environment_variable: "MYAPP_PORT"
15
16
 
16
17
  def execute
17
18
  puts "trying to connect to #{host} on port #{port} (waiting up to #{timeout} seconds)"
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # An example of default values and methods
4
5
 
@@ -8,10 +9,10 @@ require "highline"
8
9
  Clamp do
9
10
 
10
11
  option ["-U", "--user"], "USER", "user name",
11
- :environment_variable => "THE_USER",
12
- :default => "bob"
12
+ environment_variable: "THE_USER",
13
+ default: "bob"
13
14
  option ["-P", "--password"], "PASSWORD", "password",
14
- :environment_variable => "THE_PASSWORD"
15
+ environment_variable: "THE_PASSWORD"
15
16
 
16
17
  def execute
17
18
  puts "User: #{user}, Password: #{password}"
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # An example of subcommands (including a default subcommand)
4
5
 
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # An example of nested subcommands
4
5
 
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # Demonstrate how subcommands can be declared as classes
4
5
 
@@ -25,7 +26,7 @@ module GitDown
25
26
  class CloneCommand < AbstractCommand
26
27
 
27
28
  parameter "REPOSITORY", "repository to clone"
28
- parameter "[DIR]", "working directory", :default => "."
29
+ parameter "[DIR]", "working directory", default: "."
29
30
 
30
31
  def execute
31
32
  say "cloning to #{dir}"
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # An example of multi-valued options
4
5
 
@@ -7,8 +8,8 @@ require "clamp"
7
8
  Clamp do
8
9
 
9
10
  option ["-f", "--flavour"], "FLAVOUR", "flavour",
10
- :multivalued => true, :default => ["chocolate"],
11
- :attribute_name => :flavours
11
+ multivalued: true, default: ["chocolate"],
12
+ attribute_name: :flavours
12
13
 
13
14
  def execute
14
15
  puts "one #{flavours.join(' and ')} ice-cream"
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # A simple Clamp command, with options and parameters
4
5
 
@@ -11,11 +12,11 @@ Clamp do
11
12
  )
12
13
 
13
14
  option "--loud", :flag, "say it loud"
14
- option ["-n", "--iterations"], "N", "say it N times", :default => 1 do |s|
15
+ option ["-n", "--iterations"], "N", "say it N times", default: 1 do |s|
15
16
  Integer(s)
16
17
  end
17
18
 
18
- parameter "WORDS ...", "the thing to say", :attribute_name => :words
19
+ parameter "WORDS ...", "the thing to say", attribute_name: :words
19
20
 
20
21
  def execute
21
22
  the_truth = words.join(" ")
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # Demonstrate subcommand_missing
4
5
 
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # Demonstrate "restful" style; parameters precede subcommands
4
5
 
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "clamp/version"
2
4
 
3
5
  require "clamp/command"
4
6
 
5
- def Clamp(&block)
7
+ def Clamp(&block) # rubocop:disable Naming/MethodName
6
8
  Class.new(Clamp::Command, &block).run
7
9
  end
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Clamp
2
4
  module Attribute
3
5
 
6
+ # Methods to generate attribute accessors.
7
+ #
4
8
  module Declaration
5
9
 
6
10
  protected
@@ -25,6 +29,7 @@ module Clamp
25
29
  end
26
30
 
27
31
  def define_default_for(attribute)
32
+ return false if attribute.default_value.nil?
28
33
  define_method(attribute.default_method) do
29
34
  attribute.default_value
30
35
  end
@@ -1,25 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "clamp/attribute/instance"
2
4
 
3
5
  module Clamp
4
6
  module Attribute
5
7
 
8
+ # Represents an attribute of a Clamp::Command class.
9
+ #
6
10
  class Definition
7
11
 
8
12
  def initialize(options)
9
- if options.key?(:attribute_name)
10
- @attribute_name = options[:attribute_name].to_s
11
- end
13
+ @attribute_name = options[:attribute_name].to_s if options.key?(:attribute_name)
12
14
  @default_value = options[:default] if options.key?(:default)
13
- if options.key?(:environment_variable)
14
- @environment_variable = options[:environment_variable]
15
- end
15
+ @environment_variable = options[:environment_variable] if options.key?(:environment_variable)
16
16
  @hidden = options[:hidden] if options.key?(:hidden)
17
17
  end
18
18
 
19
19
  attr_reader :description, :environment_variable
20
20
 
21
21
  def help_rhs
22
- description + default_description
22
+ rhs = description
23
+ comments = required_indicator || default_description
24
+ rhs += " (#{comments})" if comments
25
+ rhs
23
26
  end
24
27
 
25
28
  def help
@@ -77,11 +80,11 @@ module Clamp
77
80
  def option_missing_message
78
81
  if environment_variable
79
82
  Clamp.message(:option_or_env_required,
80
- :option => switches.first,
81
- :env => environment_variable)
83
+ option: switches.first,
84
+ env: environment_variable)
82
85
  else
83
86
  Clamp.message(:option_required,
84
- :option => switches.first)
87
+ option: switches.first)
85
88
  end
86
89
  end
87
90
 
@@ -92,8 +95,8 @@ module Clamp
92
95
  ("$#{@environment_variable}" if defined?(@environment_variable)),
93
96
  (@default_value.inspect if defined?(@default_value))
94
97
  ].compact
95
- return "" if default_sources.empty?
96
- " (default: " + default_sources.join(", or ") + ")"
98
+ return nil if default_sources.empty?
99
+ "#{Clamp.message(:default)}: " + default_sources.join(", #{Clamp.message(:or)} ")
97
100
  end
98
101
 
99
102
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Clamp
2
4
  module Attribute
3
5
 
4
- # Represents an option/parameter of a Clamp::Command instance.
6
+ # Represents an attribute of a Clamp::Command instance.
5
7
  #
6
8
  class Instance
7
9
 
@@ -27,7 +29,7 @@ module Clamp
27
29
  end
28
30
 
29
31
  def default
30
- command.send(attribute.default_method)
32
+ command.send(attribute.default_method) if command.respond_to?(attribute.default_method, true)
31
33
  end
32
34
 
33
35
  # default implementation of read_method
@@ -73,7 +75,7 @@ module Clamp
73
75
  begin
74
76
  take(value)
75
77
  rescue ArgumentError => e
76
- signal_usage_error Clamp.message(:env_argument_error, :env => attribute.environment_variable, :message => e.message)
78
+ signal_usage_error Clamp.message(:env_argument_error, env: attribute.environment_variable, message: e.message)
77
79
  end
78
80
  end
79
81
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "clamp/messages"
2
4
  require "clamp/errors"
3
5
  require "clamp/help"
@@ -48,6 +50,7 @@ module Clamp
48
50
  parse_options
49
51
  parse_parameters
50
52
  parse_subcommand
53
+ verify_required_options_are_set
51
54
  handle_remaining_arguments
52
55
  end
53
56
 
@@ -81,7 +84,7 @@ module Clamp
81
84
  #
82
85
  # @ param [String] name subcommand_name
83
86
  def subcommand_missing(name)
84
- signal_usage_error(Clamp.message(:no_such_subcommand, :name => name))
87
+ signal_usage_error(Clamp.message(:no_such_subcommand, name: name))
85
88
  end
86
89
 
87
90
  include Clamp::Option::Parsing
@@ -122,6 +125,11 @@ module Clamp
122
125
  include Clamp::Subcommand::Declaration
123
126
  include Help
124
127
 
128
+ # An alternative to "def execute"
129
+ def execute(&block)
130
+ define_method(:execute, &block)
131
+ end
132
+
125
133
  # Create an instance of this command class, and run it.
126
134
  #
127
135
  # @param [String] invocation_path the path used to invoke the command