Class: Rake::ToolkitProgram::CommandOptionParser

Inherits:
OptionParser
  • Object
show all
Defined in:
lib/rake/toolkit_program/command_option_parser.rb

Constant Summary collapse

IDENTITY =
->(v) {v}
RUBY_GTE_2_4 =
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4')

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arg_dest) ⇒ CommandOptionParser

Returns a new instance of CommandOptionParser.



30
31
32
33
34
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 30

def initialize(arg_dest)
  super()
  @argument_destination = arg_dest
  @positional_mapper = IDENTITY
end

Instance Attribute Details

#argument_destinationObject (readonly)

Returns the value of attribute argument_destination.



36
37
38
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 36

def argument_destination
  @argument_destination
end

Instance Method Details

#capture_positionals(key = nil, precapture_dest_array: false, &blk) ⇒ Object

Explicitly define capture of positional (non-option) arguments

When parsing into a Hash, the default is to store the Array of remaining positional arguments in the nil key. This method overrides that behavior by either specifying a specific key to use or by specifying a block to call with the positional arguments, which is much more useful when accumulating arguments to a non-Hash object. Passing key or a block are mutually exclusive.

precapture_dest_array can be set to true to cause the capture to take place before the positional arguments are accumulated. In this case, the Array object yielded to the block (if this method is called with a block) must be stored, as it will be the recipient of all positional arguments. In any case, when this option is passed to this method, capture behavior for the (empty) Array into which the positional arguments will be stored is carried out before option parsing, and values are (after any transformation dictated by #map_positional_args) stored in the positional arguments Array; there is no option to store positionals for consumption by the command task code in anything other than an Array. Note that the Array into which arguments are captured is not the same array either passed to or returned from the #parse! (or #parse, for that matter) method.

If multiple calls to this method are made, the last one is the one that defines the behavior.

key

Key under which positionals shall be accumulated in a Hash

precapture_dest_array

Capture before argument accumulation



165
166
167
168
169
170
171
172
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 165

def capture_positionals(key=nil, precapture_dest_array: false, &blk)
  if blk && !key.nil?
    raise ArgumentError, "either specify key or block"
  end
  @positionals_key = key
  @positionals_capture = blk
  @precapture_positionals_array = precapture_dest_array
end

#expect_positional_cardinality(cardinality_test, explanation = nil) ⇒ Object

Constrain the number of positional arguments

This is a declarative way of expressing how many positional (i.e. non-option) arguments should be accepted by the command. The #=== (i.e. “case match”) method of cardinality_test is used to test the length of the positional argument Array, raising Rake::ToolkitProgram::WrongArgumentCount if #=== returns false.

A special case exists when cardinality_test is a Symbol: because a Symbol could never match an Integer, Symbol#to_proc is called to create a useful test.

NOTE It is worth attention that Proc#=== is an alias for Proc#call, so the operator argument is passed to the Proc. This enables arbitrary computation for the validity of the positional argument count, syntactically aided by the “stabby-lambda” notation.

While this gem will do its best to explain the argument cardinality, explanation provides an opportunity to explicitly provide a sentence to be included in the help about the allowed cardinality (i.e. count) of positional arguments.



197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 197

def expect_positional_cardinality(cardinality_test, explanation=nil)
  @positional_cardinality_explanation = explanation
  if cardinality_test.kind_of?(Symbol)
    cardinality_test.to_s.tap do |test_name|
      if explanation.nil? && test_name.end_with?('?')
        @positional_cardinality_explanation = (
          "Positional argument count must be #{test_name[0..-2].gsub('_', ' ')}."
        )
      end
    end
    cardinality_test = cardinality_test.to_proc
  end
  @positional_cardinality_test = cardinality_test
end

#invalid_args!(message) ⇒ Object

Convenience method for raising Rake::ToolkitProgram::InvalidCommandLine

The error raised is the standard error for an invalid command line when using Rake::ToolkitProgram.

Raises:



228
229
230
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 228

def invalid_args!(message)
  raise InvalidCommandLine, message
end

#map_positional_args(&blk) ⇒ Object

Define a mapping function for positional arguments during accumulation

The block given to this method will be called with each positional argument in turn; the return value of the block will be acculumated as the positional argument. The block’s computation may be purely functional or it may refer to outside factors in its binding such as accumulated values for options or preceding positional arguments.

Raises:

  • (ArgumentError)


241
242
243
244
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 241

def map_positional_args(&blk)
  raise ArgumentError, "block required" if blk.nil?
  @positional_mapper = blk
end

#no_positional_args!Object

Disallow positional arguments

The command will raise Rake::ToolkitProgram::WrongArgumentCount if any positional arguments are given.



218
219
220
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 218

def no_positional_args!
  expect_positional_cardinality(0)
end

#order!(argv = default_args, into: nil, &nonopt) ⇒ Object

Raises:

  • (ArgumentError)


40
41
42
43
44
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 40

def order!(argv = default_argv, into: nil, &nonopt)
  super(argv, into: into) do |arg|
    nonopt.call(@positional_mapper.call(arg))
  end
end

#parse!(argv = default_argv, into: nil) ⇒ Object

Method override, see OptionParser#parse! – though we don’t do POSIXLY_COMPLIANT



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 55

def parse!(argv = default_argv, into: nil)
  positionals = []
  do_positional_capture(positionals) if @precapture_positionals_array
  order!(argv, into: into, &positionals.method(:<<)).tap do
    argv[0, 0] = positionals
    do_positional_capture(argv) if !@precapture_positionals_array
    
    unless positional_cardinality_ok?(positionals.length)
      raise WrongArgumentCount.new(
        @positional_cardinality_test,
        positionals.length
      )
    end
  end
  return argv
end

#positional_arguments_allowed?Boolean

True unless positional arguments have been prohibited

Technically, this test can only check that the established cardinality test is for 0, given as an Integer. If the test established by #expect_positional_cardinality is a Proc that only returns true for 0 or the Range 0..0, this method will report incorrect results.

Returns:

  • (Boolean)


93
94
95
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 93

def positional_arguments_allowed?
  @positional_cardinality_test != 0
end

#positional_cardinalityObject

Return the established test for positional cardinality (or nil)

If a test has been established by #expect_positional_cardinality, this method returns that test. Otherwise, it returns nil.



103
104
105
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 103

def positional_cardinality
  @positional_cardinality_test
end

#positional_cardinality_explanationObject

String explanation of the positional cardinality, for help



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 110

def positional_cardinality_explanation
  @positional_cardinality_explanation.tap do |explicit|
    return explicit if explicit
  end
  obscure_answer = "A rule exists about the number of positional arguments."
  
  case (pc_test = @positional_cardinality_test)
  when nil, 0 then nil
  when 1 then "Requires 1 positional argument."
  when Integer then "Requires #{pc_test} positional arguments."
  when Range then "Requires #{pc_test.to_inclusive} (inclusive) positional arguments."
  when Proc then begin
    [pc_test.call(:explain)].map do |exp|
      case exp
      when String then exp
      else obscure_answer
      end
    end[0]
  rescue StandardError
    obscure_answer
  end
  else obscure_answer
  end
end

#positional_cardinality_ok?(n) ⇒ Boolean

Query whether a given number of positional arguments is acceptable

The result is based on the test established by #expect_positional_cardinality, and returns true if no such test has been established.

Returns:

  • (Boolean)


79
80
81
82
# File 'lib/rake/toolkit_program/command_option_parser.rb', line 79

def positional_cardinality_ok?(n)
  pc_test = @positional_cardinality_test
  !pc_test || pc_test === n
end