Class: FlexArgs
- Inherits:
-
Object
- Object
- FlexArgs
- Defined in:
- lib/flex_args.rb,
lib/flex_args/parser.rb,
lib/flex_args/version.rb,
lib/flex_args/constraint.rb
Overview
## Abstract
This is FlexArgs, and I am Robert Dober
It will allow for a versatile parsing of command line arguments.
By default the behavior is as follows
### Positional arguments
Are all arguments that do not:
- start with a `-`
- contain any of the following characters: `:,`
- contain the string `".."`
Therefore the following arguments will be parsed as
“‘spec # Only default positional arguments
parse(%w[hello world.glob 13 a-b]).positionals => %w[hello world.glob 13 a-b]
“‘
Now flags start with a ‘-` getting us many single letter flags or a `–` as in Posix
“‘spec # Flags and positionals
args = parse(%w[hello --verbose -world 42])
expect(args.positionals).to eq(%w[hello 42])
expect(args.flags).to eq(Set.new(%i[verbose w o r l d]))
“‘ ### Value arguments
Instead of posix syntax like ‘–key=value` or `–key value` `FlexArgs` uses the `key:value` or `key,alpha,beta` syntax.
“‘spec # Just some values
parse(%w[alpha:42 hello:world]).values => {alpha: 42, hello: "world"}
“‘
N.B. that all digits values are converted to integers, as we can see in the following example signs are also taken into account.
#### Ranges
“‘spec # Ranges and signs
input = %w[range:-2..3 offset:+3 -V a/b.rb]
parsed = parse(input)
expect(parsed.positionals).to eq(["a/b.rb"])
expect(parsed.values).to eq(range: -2..3, offset: 3)
expect(parsed.flags).to eq(Set.new([:V]))
“‘
#### Lists
“‘spec # Just a list
parse(%w[a_list:1,2,a,3..4]).values => {a_list: [1, 2, "a", 3..4]}
“‘
But what if we want ‘,` inside a value? You need to double it
“‘spec # Escaping `,`
parse(%w[escaped:1,a,,b,c]).values => {escaped: [1, "a,b", "c"]}
“‘
#### Multiple Values
This is an alternative way to get a list of values
“‘spec # Multiple Values => Lists
parse(%w[list:1 list:2 hello list:3]).values => {list: [1, 2, 3]}
“‘
### Advanced Features
More advanced features are set with methods on the the instance before invoking ‘parse`.
These features are
- Aliased flags
- Defaults
- Constraints
- allowed
- required
- domain checks
- format checks
- Custom Transformations
- Semantic Checks (v0.2)
and they are documented in the rdocs of the corresponding methods
Defined Under Namespace
Modules: Version Classes: Constraint, Parser
Instance Attribute Summary collapse
-
#alias_definitions ⇒ Object
readonly
Returns the value of attribute alias_definitions.
-
#default_values ⇒ Object
readonly
Returns the value of attribute default_values.
-
#result ⇒ Object
readonly
Returns the value of attribute result.
Instance Method Summary collapse
-
#aliases(alias_definitions) ⇒ Object
## Aliases are defined by passing a hash.
-
#allow(*values) ⇒ Object
## Allowed values and flags.
- #allowed?(value) ⇒ Boolean
-
#constrain(value, *constraints, &block) ⇒ Object
## Constraints.
- #constraints(key) ⇒ Object
- #parse(args) ⇒ Object
-
#values ⇒ Object
Just returns the parsed values, or their default values if a default was provided and the value was not present in the provided arguments.
Instance Attribute Details
#alias_definitions ⇒ Object (readonly)
Returns the value of attribute alias_definitions.
101 102 103 |
# File 'lib/flex_args.rb', line 101 def alias_definitions @alias_definitions end |
#default_values ⇒ Object (readonly)
Returns the value of attribute default_values.
101 102 103 |
# File 'lib/flex_args.rb', line 101 def default_values @default_values end |
#result ⇒ Object (readonly)
Returns the value of attribute result.
101 102 103 |
# File 'lib/flex_args.rb', line 101 def result @result end |
Instance Method Details
#aliases(alias_definitions) ⇒ Object
## Aliases are defined by passing a hash
The key of the hash is the alias and it will be defined as an alias to the value of the hash for each grapheme of the key, here is how that works
“‘spec # Aliases
parser = FlexArgs
.new
.aliases(hu: :help, v: :version)
expect(parser.parse(%w[-uv]).flags).to eq(Set.new(%i[help version]))
expect(parser.parse(%w[-h]).flags).to eq(Set.new(%i[help]))
“‘
131 132 133 134 135 136 137 |
# File 'lib/flex_args.rb', line 131 def aliases(alias_definitions) alias_definitions .each do |key, value| key.to_s.grapheme_clusters.each { define_alias it, value } end self end |
#allow(*values) ⇒ Object
## Allowed values and flags
As soon as this method is called the parser will check that all values in args are allowed
Values are either identified by their name (a ‘Symbol`) or by their name and default value (a pair of `Symbol` and any value
“‘spec
parser = FlexArgs
.new
.allow(:min, [:max, 3])
expect(parser.parse(%w[min:1]).values)
.to eq(min: 1, max: 3)
“‘
Therefore the following args are illegal and an ‘ArgumentError` is raised
“‘spec # Argument Error for unallowed value
expect do
FlexArgs
.new
.allow(:n)
.parse(%w[a:2])
end
.to raise_error(
ArgumentError,
"unallowed value arg a:"
)
“‘
175 176 177 178 |
# File 'lib/flex_args.rb', line 175 def allow(*values) values.each { allow_value it } self end |
#allowed?(value) ⇒ Boolean
180 181 182 183 |
# File 'lib/flex_args.rb', line 180 def allowed?(value) return true unless @allowed_values @allowed_values.member?(value) end |
#constrain(value, *constraints, &block) ⇒ Object
## Constraints
Constraints are defined with the `constraint` method.
**N.B.** defined Constraints **after** allow unless you
want to explicitly add the value arg with `allow`
### Simple forms
#### Regexp constraint
“‘spec # regexp constraints
parser = FlexArgs
.new
.constrain(:n, %r{\A \d+ \z}x)
expect(parser.parse(%w[n:42]).values).to eq(n: 42)
expect { parser.parse(%w[n:42a]) }
.to raise_error(ArgumentError, 'regexp constraint n: (?x-mi:\A \d+ \z) violated by value "42a"')
“‘
#### Range constraints
“‘spec # range constraints
parser = FlexArgs
.new
.constrain(:n, 2..3)
expect(parser.parse(%w[n:2]).values).to eq(n: 2)
expect { parser.parse(%w[n:42a]) }
.to raise_error(ArgumentError, 'range constraint n: 2..3 violated by value "42a"')
expect { parser.parse(%w[n:42]) }
.to raise_error(ArgumentError, 'range constraint n: 2..3 violated by value "42"')
“‘
Please find the documentation about more constraints [here](Constraint.html)
230 231 232 233 234 |
# File 'lib/flex_args.rb', line 230 def constrain(value, *constraints, &block) @allowed_values << value.to_sym if @allowed_values @constraints[value.to_sym] << Constraint.new(value, *constraints, &block) self end |
#constraints(key) ⇒ Object
185 |
# File 'lib/flex_args.rb', line 185 def constraints(key) = @constraints[key] |
#parse(args) ⇒ Object
103 104 105 106 107 108 109 110 111 |
# File 'lib/flex_args.rb', line 103 def parse(args) result = Parser.new(self).parse(args) case result in [:ok, result1] result1 in [:error, errors] raise ArgumentError, errors.join("\n") end end |
#values ⇒ Object
Just returns the parsed values, or their default values if a default was provided and the value was not present in the provided arguments.
241 242 243 |
# File 'lib/flex_args.rb', line 241 def values default_values.merge(values_from_args) end |