clamp 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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