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.
data/lib/clamp/help.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'stringio'
2
- require 'clamp/messages'
1
+ require "stringio"
2
+ require "clamp/messages"
3
3
 
4
4
  module Clamp
5
5
 
@@ -15,8 +15,8 @@ module Clamp
15
15
  def description=(description)
16
16
  @description = description.dup
17
17
  if @description =~ /^\A\n*( +)/
18
- indent = $1
19
- @description.gsub!(/^#{indent}/, '')
18
+ indent = Regexp.last_match(1)
19
+ @description.gsub!(/^#{indent}/, "")
20
20
  end
21
21
  @description.strip!
22
22
  end
@@ -29,7 +29,7 @@ module Clamp
29
29
 
30
30
  def derived_usage_description
31
31
  parts = ["[OPTIONS]"]
32
- parts += parameters.map { |a| a.name }
32
+ parts += parameters.map(&:name)
33
33
  parts.join(" ")
34
34
  end
35
35
 
@@ -69,21 +69,20 @@ module Clamp
69
69
  end
70
70
 
71
71
  def add_description(description)
72
- if description
73
- puts ""
74
- puts description.gsub(/^/, " ")
75
- end
72
+ return unless description
73
+ puts ""
74
+ puts description.gsub(/^/, " ")
76
75
  end
77
76
 
78
- DETAIL_FORMAT = " %-29s %s"
77
+ DETAIL_FORMAT = " %-29s %s".freeze
79
78
 
80
79
  def add_list(heading, items)
81
80
  puts "\n#{heading}:"
82
81
  items.reject { |i| i.respond_to?(:hidden?) && i.hidden? }.each do |item|
83
82
  label, description = item.help
84
83
  description.each_line do |line|
85
- puts DETAIL_FORMAT % [label, line]
86
- label = ''
84
+ puts format(DETAIL_FORMAT, label, line)
85
+ label = ""
87
86
  end
88
87
  end
89
88
  end
@@ -6,8 +6,8 @@ module Clamp
6
6
  messages.merge!(new_messages)
7
7
  end
8
8
 
9
- def message(key, options={})
10
- format_string(messages.fetch(key), options)
9
+ def message(key, options = {})
10
+ format(messages.fetch(key), options)
11
11
  end
12
12
 
13
13
  def clear_messages!
@@ -30,38 +30,15 @@ module Clamp
30
30
  :parameters_heading => "Parameters",
31
31
  :subcommands_heading => "Subcommands",
32
32
  :options_heading => "Options"
33
- }
33
+ }.freeze
34
34
 
35
35
  def messages
36
- unless defined?(@messages)
37
- init_default_messages
38
- end
36
+ init_default_messages unless defined?(@messages)
39
37
  @messages
40
38
  end
41
39
 
42
40
  def init_default_messages
43
- @messages = DEFAULTS.clone
44
- end
45
-
46
- begin
47
-
48
- ("%{foo}" % {:foo => "bar"}) # test Ruby 1.9 string interpolation
49
-
50
- def format_string(format, params = {})
51
- format % params
52
- end
53
-
54
- rescue ArgumentError
55
-
56
- # string formatting for ruby 1.8
57
- def format_string(format, params = {})
58
- array_params = format.scan(/%[<{]([^>}]*)[>}]/).collect do |name|
59
- name = name[0]
60
- params[name.to_s] || params[name.to_sym]
61
- end
62
- format.gsub(/%[<]([^>]*)[>]/, '%').gsub(/%[{]([^}]*)[}]/, '%s') % array_params
63
- end
64
-
41
+ @messages = DEFAULTS.dup
65
42
  end
66
43
 
67
44
  end
@@ -1,5 +1,5 @@
1
- require 'clamp/attribute/declaration'
2
- require 'clamp/option/definition'
1
+ require "clamp/attribute/declaration"
2
+ require "clamp/option/definition"
3
3
 
4
4
  module Clamp
5
5
  module Option
@@ -10,9 +10,9 @@ module Clamp
10
10
 
11
11
  def option(switches, type, description, opts = {}, &block)
12
12
  Option::Definition.new(switches, type, description, opts).tap do |option|
13
- declared_options << option
14
13
  block ||= option.default_conversion_block
15
- define_accessors_for(option, &block)
14
+ declare_attribute(option, &block)
15
+ declared_options << option
16
16
  end
17
17
  end
18
18
 
@@ -25,34 +25,35 @@ module Clamp
25
25
  end
26
26
 
27
27
  def recognised_options
28
- declare_implicit_options
28
+ unless @implicit_options_declared
29
+ declare_implicit_help_option
30
+ @implicit_options_declared = true
31
+ end
29
32
  effective_options
30
33
  end
31
34
 
32
35
  private
33
36
 
34
- def declare_implicit_options
35
- return nil if defined?(@implicit_options_declared)
36
- unless effective_options.find { |o| o.handles?("--help") }
37
- help_switches = ["--help"]
38
- help_switches.unshift("-h") unless effective_options.find { |o| o.handles?("-h") }
39
- option help_switches, :flag, "print help" do
40
- request_help
41
- end
37
+ def declare_implicit_help_option
38
+ return false if effective_options.find { |o| o.handles?("--help") }
39
+ help_switches = ["--help"]
40
+ help_switches.unshift("-h") unless effective_options.find { |o| o.handles?("-h") }
41
+ option help_switches, :flag, "print help" do
42
+ request_help
42
43
  end
43
- @implicit_options_declared = true
44
44
  end
45
45
 
46
46
  def effective_options
47
47
  ancestors.inject([]) do |options, ancestor|
48
- if ancestor.kind_of?(Clamp::Option::Declaration)
49
- options + ancestor.declared_options
50
- else
51
- options
52
- end
48
+ options + options_declared_on(ancestor)
53
49
  end
54
50
  end
55
51
 
52
+ def options_declared_on(ancestor)
53
+ return [] unless ancestor.is_a?(Clamp::Option::Declaration)
54
+ ancestor.declared_options
55
+ end
56
+
56
57
  end
57
58
 
58
59
  end
@@ -1,5 +1,5 @@
1
- require 'clamp/attribute/definition'
2
- require 'clamp/truthy'
1
+ require "clamp/attribute/definition"
2
+ require "clamp/truthy"
3
3
 
4
4
  module Clamp
5
5
  module Option
@@ -12,16 +12,11 @@ module Clamp
12
12
  @description = description
13
13
  super(options)
14
14
  @multivalued = options[:multivalued]
15
- if options.has_key?(:required)
16
- @required = options[:required]
17
- # Do some light validation for conflicting settings.
18
- if options.has_key?(:default)
19
- raise ArgumentError, "Specifying a :default value with :required doesn't make sense"
20
- end
21
- if type == :flag
22
- raise ArgumentError, "A required flag (boolean) doesn't make sense."
23
- end
24
- end
15
+ return unless options.key?(:required)
16
+ @required = options[:required]
17
+ # Do some light validation for conflicting settings.
18
+ raise ArgumentError, "Specifying a :default value with :required doesn't make sense" if options.key?(:default)
19
+ raise ArgumentError, "A required flag (boolean) doesn't make sense." if type == :flag
25
20
  end
26
21
 
27
22
  attr_reader :switches, :type
@@ -39,7 +34,7 @@ module Clamp
39
34
  end
40
35
 
41
36
  def flag_value(switch)
42
- !(switch =~ /^--no-(.*)/ && switches.member?("--\[no-\]#{$1}"))
37
+ !(switch =~ /^--no-(.*)/ && switches.member?("--\[no-\]#{Regexp.last_match(1)}"))
43
38
  end
44
39
 
45
40
  def read_method
@@ -59,9 +54,7 @@ module Clamp
59
54
  end
60
55
 
61
56
  def default_conversion_block
62
- if flag?
63
- Clamp.method(:truthy?)
64
- end
57
+ Clamp.method(:truthy?) if flag?
65
58
  end
66
59
 
67
60
  def help_lhs
@@ -75,7 +68,7 @@ module Clamp
75
68
  def recognised_switches
76
69
  switches.map do |switch|
77
70
  if switch =~ /^--\[no-\](.*)/
78
- ["--#{$1}", "--no-#{$1}"]
71
+ ["--#{Regexp.last_match(1)}", "--no-#{Regexp.last_match(1)}"]
79
72
  else
80
73
  switch
81
74
  end
@@ -86,7 +79,7 @@ module Clamp
86
79
  unless long_switch
87
80
  raise Clamp::DeclarationError, "You must specify either a long-switch or an :attribute_value"
88
81
  end
89
- inferred_name = long_switch.sub(/^--(\[no-\])?/, '').tr('-', '_')
82
+ inferred_name = long_switch.sub(/^--(\[no-\])?/, "").tr("-", "_")
90
83
  inferred_name += "_list" if multivalued?
91
84
  inferred_name
92
85
  end
@@ -6,23 +6,30 @@ module Clamp
6
6
  protected
7
7
 
8
8
  def parse_options
9
+ set_options_from_command_line
10
+ default_options_from_environment
11
+ verify_required_options_are_set
12
+ end
13
+
14
+ private
9
15
 
10
- while remaining_arguments.first =~ /\A-/
16
+ def set_options_from_command_line
17
+ while remaining_arguments.first && remaining_arguments.first.start_with?("-")
11
18
 
12
19
  switch = remaining_arguments.shift
13
20
  break if switch == "--"
14
21
 
15
22
  case switch
16
23
  when /\A(-\w)(.+)\z/m # combined short options
17
- switch = $1
24
+ switch = Regexp.last_match(1)
18
25
  if find_option(switch).flag?
19
- remaining_arguments.unshift("-" + $2)
26
+ remaining_arguments.unshift("-" + Regexp.last_match(2))
20
27
  else
21
- remaining_arguments.unshift($2)
28
+ remaining_arguments.unshift(Regexp.last_match(2))
22
29
  end
23
30
  when /\A(--[^=]+)=(.*)\z/m
24
- switch = $1
25
- remaining_arguments.unshift($2)
31
+ switch = Regexp.last_match(1)
32
+ remaining_arguments.unshift(Regexp.last_match(2))
26
33
  end
27
34
 
28
35
  option = find_option(switch)
@@ -35,31 +42,33 @@ module Clamp
35
42
  end
36
43
 
37
44
  end
45
+ end
38
46
 
39
- # Fill in gap from environment
47
+ def default_options_from_environment
40
48
  self.class.recognised_options.each do |option|
41
49
  option.of(self).default_from_environment
42
50
  end
51
+ end
43
52
 
44
- # Verify that all required options are present
53
+ def verify_required_options_are_set
45
54
  self.class.recognised_options.each do |option|
46
55
  # If this option is required and the value is nil, there's an error.
47
- if option.required? and send(option.attribute_name).nil?
48
- if option.environment_variable
49
- message = Clamp.message(:option_or_env_required, :option => option.switches.first, :env => option.environment_variable)
50
- else
51
- message = Clamp.message(:option_required, :option => option.switches.first)
52
- end
53
- signal_usage_error message
56
+ next unless option.required? && send(option.attribute_name).nil?
57
+ if option.environment_variable
58
+ message = Clamp.message(:option_or_env_required,
59
+ :option => option.switches.first,
60
+ :env => option.environment_variable)
61
+ else
62
+ message = Clamp.message(:option_required,
63
+ :option => option.switches.first)
54
64
  end
65
+ signal_usage_error message
55
66
  end
56
67
  end
57
68
 
58
- private
59
-
60
69
  def find_option(switch)
61
70
  self.class.find_option(switch) ||
62
- signal_usage_error(Clamp.message(:unrecognised_option, :switch => switch))
71
+ signal_usage_error(Clamp.message(:unrecognised_option, :switch => switch))
63
72
  end
64
73
 
65
74
  end
@@ -1,5 +1,5 @@
1
- require 'clamp/attribute/declaration'
2
- require 'clamp/parameter/definition'
1
+ require "clamp/attribute/declaration"
2
+ require "clamp/parameter/definition"
3
3
 
4
4
  module Clamp
5
5
  module Parameter
@@ -18,11 +18,24 @@ module Clamp
18
18
 
19
19
  def parameter(name, description, options = {}, &block)
20
20
  Parameter::Definition.new(name, description, options).tap do |parameter|
21
+ declare_attribute(parameter, &block)
21
22
  parameters << parameter
22
- define_accessors_for(parameter, &block)
23
23
  end
24
24
  end
25
25
 
26
+ protected
27
+
28
+ def inheritable_parameters
29
+ superclass_inheritable_parameters + parameters.select(&:inheritable?)
30
+ end
31
+
32
+ private
33
+
34
+ def superclass_inheritable_parameters
35
+ return [] unless superclass.respond_to?(:inheritable_parameters, true)
36
+ superclass.inheritable_parameters
37
+ end
38
+
26
39
  end
27
40
 
28
41
  end
@@ -1,4 +1,4 @@
1
- require 'clamp/attribute/definition'
1
+ require "clamp/attribute/definition"
2
2
 
3
3
  module Clamp
4
4
  module Parameter
@@ -13,10 +13,15 @@ module Clamp
13
13
  @required = options.fetch(:required) do
14
14
  (@name !~ OPTIONAL)
15
15
  end
16
+ @inheritable = options.fetch(:inheritable, true)
16
17
  end
17
18
 
18
19
  attr_reader :name
19
20
 
21
+ def inheritable?
22
+ @inheritable
23
+ end
24
+
20
25
  def help_lhs
21
26
  name
22
27
  end
@@ -34,7 +39,7 @@ module Clamp
34
39
  VALID_ATTRIBUTE_NAME = /^[a-z0-9_]+$/
35
40
 
36
41
  def infer_attribute_name
37
- inferred_name = name.downcase.tr('-', '_').sub(ELLIPSIS_SUFFIX, '').sub(OPTIONAL) { $1 }
42
+ inferred_name = name.downcase.tr("-", "_").sub(ELLIPSIS_SUFFIX, "").sub(OPTIONAL) { Regexp.last_match(1) }
38
43
  unless inferred_name =~ VALID_ATTRIBUTE_NAME
39
44
  raise "cannot infer attribute_name from #{name.inspect}"
40
45
  end
@@ -6,7 +6,13 @@ module Clamp
6
6
  protected
7
7
 
8
8
  def parse_parameters
9
+ set_parameters_from_command_line
10
+ default_parameters_from_environment
11
+ end
12
+
13
+ private
9
14
 
15
+ def set_parameters_from_command_line
10
16
  self.class.parameters.each do |parameter|
11
17
  begin
12
18
  parameter.consume(remaining_arguments).each do |value|
@@ -16,11 +22,12 @@ module Clamp
16
22
  signal_usage_error Clamp.message(:parameter_argument_error, :param => parameter.name, :message => e.message)
17
23
  end
18
24
  end
25
+ end
19
26
 
27
+ def default_parameters_from_environment
20
28
  self.class.parameters.each do |parameter|
21
29
  parameter.of(self).default_from_environment
22
30
  end
23
-
24
31
  end
25
32
 
26
33
  end
@@ -1,5 +1,5 @@
1
- require 'clamp/errors'
2
- require 'clamp/subcommand/definition'
1
+ require "clamp/errors"
2
+ require "clamp/subcommand/definition"
3
3
 
4
4
  module Clamp
5
5
  module Subcommand
@@ -11,19 +11,8 @@ module Clamp
11
11
  end
12
12
 
13
13
  def subcommand(name, description, subcommand_class = self, &block)
14
- unless has_subcommands?
15
- @subcommand_parameter = if @default_subcommand
16
- parameter "[SUBCOMMAND]", "subcommand", :attribute_name => :subcommand_name, :default => @default_subcommand
17
- else
18
- parameter "SUBCOMMAND", "subcommand", :attribute_name => :subcommand_name, :required => false
19
- end
20
- remove_method :default_subcommand_name
21
- parameter "[ARG] ...", "subcommand arguments", :attribute_name => :subcommand_arguments
22
- end
23
- if block
24
- # generate a anonymous sub-class
25
- subcommand_class = Class.new(subcommand_class, &block)
26
- end
14
+ subcommand_class = Class.new(subcommand_class, &block) if block
15
+ declare_subcommand_parameters unless has_subcommands?
27
16
  recognised_subcommands << Subcommand::Definition.new(name, description, subcommand_class)
28
17
  end
29
18
 
@@ -37,20 +26,14 @@ module Clamp
37
26
 
38
27
  def find_subcommand_class(*names)
39
28
  names.inject(self) do |command_class, name|
40
- if command_class
41
- if subcommand = command_class.find_subcommand(name)
42
- subcommand.subcommand_class
43
- end
44
- end
29
+ return nil unless command_class
30
+ subcommand = command_class.find_subcommand(name)
31
+ subcommand.subcommand_class if subcommand
45
32
  end
46
33
  end
47
34
 
48
- def parameters_before_subcommand
49
- parameters.take_while { |p| p != @subcommand_parameter }
50
- end
51
-
52
35
  def inheritable_attributes
53
- recognised_options + parameters_before_subcommand
36
+ recognised_options + inheritable_parameters
54
37
  end
55
38
 
56
39
  def default_subcommand=(name)
@@ -71,6 +54,26 @@ module Clamp
71
54
  end
72
55
  end
73
56
 
57
+ private
58
+
59
+ def declare_subcommand_parameters
60
+ if @default_subcommand
61
+ parameter "[SUBCOMMAND]", "subcommand",
62
+ :attribute_name => :subcommand_name,
63
+ :default => @default_subcommand,
64
+ :inheritable => false
65
+ else
66
+ parameter "SUBCOMMAND", "subcommand",
67
+ :attribute_name => :subcommand_name,
68
+ :required => false,
69
+ :inheritable => false
70
+ end
71
+ remove_method :default_subcommand_name
72
+ parameter "[ARG] ...", "subcommand arguments",
73
+ :attribute_name => :subcommand_arguments,
74
+ :inheritable => false
75
+ end
76
+
74
77
  end
75
78
 
76
79
  end