Module: Tins::GO

Defined in:
lib/tins/go.rb

Overview

A command-line option parsing library that provides a flexible way to parse single-character options with optional arguments. It supports multiple values for the same flag and provides a clean API for handling command-line interfaces.

Examples:

Basic usage

# Parse options with pattern 'xy:z'
options = Tins::GO.go('xy:z', ARGV, defaults: { x: true, y: 'default' })
# Handles: -x -y value -z

Multiple values for same option

# Handle: -f foo -f bar -f baz
options = Tins::GO.go('f:', ARGV)
# options['f'] will contain an EnumerableExtension collection with all
values, see `option['f'].to_a`

Defined Under Namespace

Modules: EnumerableExtension

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.go(s, args = ARGV, defaults: {}) ⇒ Hash{String => Object}

Parses the argument array args, according to the pattern s, to retrieve the single character command line options from it. If s is ‘xy:’ an option ‘-x’ without an option argument is searched, and an option ‘-y foo’ with an option argument (‘foo’). To disable the ‘-x’ option, pass ‘~x’.

The defaults argument specifies default values for the options.

An option hash is returned with all found options set to a truthy value representing the number of times they were encountered, or ‘false` if not present. When a default value is specified and the flag is not present, the default value is used instead.

Examples:

Basic usage

# Parse options with pattern 'xy:z'
options = Tins::GO.go('xy:z', ARGV, defaults: { x: true, y: 'default' })
# Handles: -x -y value -z

Multiple values for same option

# Handle: -f foo -f bar -f baz
options = Tins::GO.go('f:', ARGV)
# options['f'] will contain an EnumerableExtension collection with
# all values, see options['f'].to_a

Boolean flag counting

# Handle: -x -x -x
options = Tins::GO.go('x', ARGV)
# options['x'] will be 3 (truthy numeric value)

Boolean flag not present

# Handle: no -x flag
options = Tins::GO.go('x', ARGV)
# options['x'] will be false

Disabling options with default values

# Handle: ~x (disables -x option) when x has a default value
options = Tins::GO.go('x', ARGV, defaults: { x: true })
# options['x'] will be false if no ~x flag is present

Parameters:

  • s (String)

    Option pattern string where each character represents an option, and ‘:’ indicates the option requires an argument

  • args (Array<String>) (defaults to: ARGV)

    Array of arguments to parse (defaults to ARGV)

  • defaults (Hash{String => Object}) (defaults to: {})

    Default values for options

Returns:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/tins/go.rb', line 109

def go(s, args = ARGV, defaults: {})
  d = defaults || {}
  b, v = s.scan(/(.)(:?)/).inject([ {}, {} ]) { |t, (o, a)|
    a = a == ?:
    t[a ? 1 : 0][o] = a ? nil : false
    t
  }
  b.each_key do |k|
    d.key?(k) or next
    if [ 0, false, nil ].include?(d[k])
      b[k] = false
    elsif d[k].respond_to?(:to_int)
      b[k] = d[k].to_int
    else
      b[k] = 1
    end
  end
  v.each_key do |k|
    d.key?(k) or next
    if [ 0, false, nil ].include?(d[k])
      v[k] = nil
    else
      v[k] = d[k].to_s
    end
  end
  r = []
  while a = args.shift
    /\A-(?<p>.+)/ =~ a or (r << a; next)
    until p == ''
      o = p.slice!(0, 1)
      if v.key?(o)
        if p.empty? && args.empty?
          r << a
          break 1
        elsif p == ''
          a = args.shift
        else
          a = p
        end
        if v[o].nil? || !(EnumerableExtension === v[o])
          a = a.dup
          a.extend EnumerableExtension
          a << a
          v[o] = a
        else
          v[o] << a
        end
        break
      elsif b.key?(o)
        if b[o]
          b[o] += 1
        else
          b[o] = 1
        end
      else
        r << a
      end
    end && break
  end
  r.reject! { |a| (b[p] = false) || true if /\A~(?<p>.)/ =~ a  }
  args.replace r
  b.merge(v)
end

Instance Method Details

#go(s, args = ARGV, defaults: {}) ⇒ Hash{String => Object} (private)

Parses the argument array args, according to the pattern s, to retrieve the single character command line options from it. If s is ‘xy:’ an option ‘-x’ without an option argument is searched, and an option ‘-y foo’ with an option argument (‘foo’). To disable the ‘-x’ option, pass ‘~x’.

The defaults argument specifies default values for the options.

An option hash is returned with all found options set to a truthy value representing the number of times they were encountered, or ‘false` if not present. When a default value is specified and the flag is not present, the default value is used instead.

Examples:

Basic usage

# Parse options with pattern 'xy:z'
options = Tins::GO.go('xy:z', ARGV, defaults: { x: true, y: 'default' })
# Handles: -x -y value -z

Multiple values for same option

# Handle: -f foo -f bar -f baz
options = Tins::GO.go('f:', ARGV)
# options['f'] will contain an EnumerableExtension collection with
# all values, see options['f'].to_a

Boolean flag counting

# Handle: -x -x -x
options = Tins::GO.go('x', ARGV)
# options['x'] will be 3 (truthy numeric value)

Boolean flag not present

# Handle: no -x flag
options = Tins::GO.go('x', ARGV)
# options['x'] will be false

Disabling options with default values

# Handle: ~x (disables -x option) when x has a default value
options = Tins::GO.go('x', ARGV, defaults: { x: true })
# options['x'] will be false if no ~x flag is present

Parameters:

  • s (String)

    Option pattern string where each character represents an option, and ‘:’ indicates the option requires an argument

  • args (Array<String>) (defaults to: ARGV)

    Array of arguments to parse (defaults to ARGV)

  • defaults (Hash{String => Object}) (defaults to: {})

    Default values for options

Returns:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/tins/go.rb', line 109

def go(s, args = ARGV, defaults: {})
  d = defaults || {}
  b, v = s.scan(/(.)(:?)/).inject([ {}, {} ]) { |t, (o, a)|
    a = a == ?:
    t[a ? 1 : 0][o] = a ? nil : false
    t
  }
  b.each_key do |k|
    d.key?(k) or next
    if [ 0, false, nil ].include?(d[k])
      b[k] = false
    elsif d[k].respond_to?(:to_int)
      b[k] = d[k].to_int
    else
      b[k] = 1
    end
  end
  v.each_key do |k|
    d.key?(k) or next
    if [ 0, false, nil ].include?(d[k])
      v[k] = nil
    else
      v[k] = d[k].to_s
    end
  end
  r = []
  while a = args.shift
    /\A-(?<p>.+)/ =~ a or (r << a; next)
    until p == ''
      o = p.slice!(0, 1)
      if v.key?(o)
        if p.empty? && args.empty?
          r << a
          break 1
        elsif p == ''
          a = args.shift
        else
          a = p
        end
        if v[o].nil? || !(EnumerableExtension === v[o])
          a = a.dup
          a.extend EnumerableExtension
          a << a
          v[o] = a
        else
          v[o] << a
        end
        break
      elsif b.key?(o)
        if b[o]
          b[o] += 1
        else
          b[o] = 1
        end
      else
        r << a
      end
    end && break
  end
  r.reject! { |a| (b[p] = false) || true if /\A~(?<p>.)/ =~ a  }
  args.replace r
  b.merge(v)
end