Class: OptionsByExample::UsageSpecification

Inherits:
Object
  • Object
show all
Defined in:
lib/options_by_example/usage_specification.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text) ⇒ UsageSpecification

Returns a new instance of UsageSpecification.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/options_by_example/usage_specification.rb', line 11

def initialize(text)
  @message = text.gsub('$0', File.basename($0)).gsub(/\n+\Z/, "\n\n")

  # --- 1) Parse argument names -------------------------------------
  #
  # Parse the usage string and extract both optional argument names
  # and required argument names, for example:
  #
  # Usage: connect [options] [mode] host port

  @argument_names = {}
  inline_options = []

  usage_line = text.lines.grep(/Usage:/).first
  raise "Expected usage string, got none" unless usage_line
  tokens = usage_line.split(/(\[.*?\]?\]|\w+ \.\.\.)|\s+/).reject(&:empty?)
  raise "Expected usage line to start with 'Usage:'" unless tokens.shift == 'Usage:'
  raise "Expected command name on same line as 'Usage:'" unless tokens.shift
  tokens.shift if tokens.first == '[options]'

  while /^\[(--?\w.*)\]$/ === tokens.first
    inline_options << $1
    tokens.shift
  end

  while /^(\w+)( ?\.\.\.)?$/ === tokens.first
    vararg_if_dotted = $2 ? :vararg : :required
    @argument_names[sanitize $1] = vararg_if_dotted
    tokens.shift
  end

  while /^\[(\w+)\]$/ === tokens.first
    @argument_names[sanitize $1] = :optional
    tokens.shift
  end

  if /^\[(\w+) ?\.\.\.\]$/ === tokens.first
    @argument_names[sanitize $1] = :optional_vararg
    tokens.shift
  end

  raise "Found invalid usage token '#{tokens.first}'" unless tokens.empty?

  if count_arguments(:vararg) > 0 && count_arguments(/optional/) > 0
    raise "Cannot combine vararg and optional arguments"
  end

  if count_arguments(/vararg/) > 1
    raise "Found more than one vararg arguments"
  end

  # --- 2) Parse option names ---------------------------------------
  #
  # Parse the usage message and extract option names, their short and
  # long forms, and the associated argument name (if any), eg:
  #
  # Options:
  #   -s, --secure        Use secure connection
  #   -v, --verbose       Enable verbose output
  #   -r, --retries NUM   Number of connection retries (default 3)
  #   -t, --timeout NUM   Set connection timeout in seconds

  @option_names = {}

  options = inline_options + text.lines.grep(/^\s*--?\w/)
  options.each do |string|
    tokens = string.strip.split(/(\s+)|(,)\s*/)

    short_form = nil
    long_form = nil
    option_name = nil
    argument_arity = nil
    argument_type = nil
    default_value = nil

    if /^-(\w)$/ === tokens.first
      short_form = tokens.shift
      option_name = sanitize $1
      tokens.shift if tokens.first == ','
    end

    if /^--([\w-]+)$/ === tokens.first
      long_form = tokens.shift
      option_name = sanitize $1
    end

    if tokens.shift == ' '
      if /^(\[(.+)\]|(.+)\?)$/ === tokens.first
        argument_type = $2 || $3
        argument_arity = :optional
        tokens.shift
      else
        argument_type = tokens.shift
        argument_arity = :required
      end
    end

    if /\(default\s+(\S+)\)$/ === tokens.join
      default_value = $1
    end

    ary = [option_name, argument_arity, argument_type, default_value]
    [short_form, long_form].each do |each|
      @option_names[each] = ary if each
    end
  end
end

Instance Attribute Details

#argument_namesObject (readonly)

Returns the value of attribute argument_names.



8
9
10
# File 'lib/options_by_example/usage_specification.rb', line 8

def argument_names
  @argument_names
end

#messageObject (readonly)

Returns the value of attribute message.



7
8
9
# File 'lib/options_by_example/usage_specification.rb', line 7

def message
  @message
end

#option_namesObject (readonly)

Returns the value of attribute option_names.



9
10
11
# File 'lib/options_by_example/usage_specification.rb', line 9

def option_names
  @option_names
end