Class: FlexArgs::Constraint
- Inherits:
-
Object
- Object
- FlexArgs::Constraint
- Defined in:
- lib/flex_args/constraint.rb
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
- #call(value) ⇒ Object
-
#initialize(name, *constraints, &block) ⇒ Constraint
constructor
## Creates a new constraint for the value argument named
name.
Constructor Details
#initialize(name, *constraints, &block) ⇒ Constraint
## Creates a new constraint for the value argument named name
Constraints can be many, which is indicated by the first element in the constraints list, or a constraint can be indicated by a custom made block.
The available constraints are:
### Regexp constraint
These rdoc_specs show the interface that the FlexArgs::Parser uses to validate constraints, the class is therefore part of the public API and can be used in isolation where it serves.
“‘spec # regexp
new(:for_some_value, %r{x}).("x") => [:ok, "x"]
new(:for_some_value, %r{x}).("y") => [:error, "regexp constraint for_some_value: (?-mix:x) violated by value \"y\""]
“‘
### Range constraint
“‘spec # range
new(:for_some_int, 1..9).("1") => [:ok, 1]
new(:for_some_int, 1..9).("0") => [:error, "range constraint for_some_int: 1..9 violated by value \"0\""]
new(:for_some_int, 1..9).("y") => [:error, "range constraint for_some_int: 1..9 violated by value \"y\""]
new(:for_string, "a".."c").("a") => [:ok, "a"]
new(:for_string, "a".."c").("d") => [:error, 'member constraint for_string: "a".."c" violated by value "d"']
“‘
N.B. that ranges not of type integer are treated as Member contraints below.
### Member constraint
While the Range constraint above does int type casting if needed, the Member constraint cannot do that, because it cannot access the type of the container against which membership will be tested.
Member constraints can be triggered by providing a Set, Array or Hash second parameter
“‘spec # Various membership rdoc specs
vowels = %w[a e i o u y]
hashy = Hash[vowels.product([true])]
set = Set.new(vowels)
in_array = new(:in_array, vowels)
in_set = new(:in_set, set)
in_hash = new(:in_hash, hashy)
expect(in_array.("a")).to eq([:ok, "a"])
expect(in_array.("y")).to eq([:ok, "y"])
expect(in_set.("y")).to eq([:ok, "y"])
expect(in_hash.("o")).to eq([:ok, "o"])
expect(in_array.("b"))
.to eq([:error, "member constraint in_array: #{vowels.inspect} violated by value \"b\""])
expect(in_hash.("ec"))
.to eq([:error, "member constraint in_hash: #{hashy.inspect} violated by value \"ec\""])
expect(in_set.("aa"))
.to eq([:error, "member constraint in_set: #{set.inspect} violated by value \"aa\""])
“‘
### Custom constraint
This is easily implemented by passing a block which will return a pair as described above, but also note two more features of the custom constraint
-
exceptions will be caught and transformed into an error, thusly simplyfing the code block:
-
and values can be transformed
“‘spec # custom
constraint = new :even do
value = Integer(it)
value.even? ? [:ok, value / 2] : [:error, "not even"]
end
expect(constraint.("84")).to eq([:ok, 42])
expect(constraint.("21")).to eq([:error, "custom constraint even: violated by value \"21\" with message: \"not even\""])
= '"invalid value for Integer(): \\"abc\\" (ArgumentError)"'
= "custom constraint even: violated by value \"abc\" with message: #{exception_message}"
expect(constraint.("abc")).to eq([:error, ])
“‘
Also note that the correct format of the block’s return value is important
“‘spec # enforce correct format of custom constraint’s block
constraint = new(:bad) { 42 }
expect { constraint.(nil) }
.to raise_error(ArgumentError, "badly formatted custom block for custom constraint bad returned 42, needed [:ok|:error, value_or_message]")
“‘
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/flex_args/constraint.rb', line 103 def initialize(name, *constraints, &block) @name = name case constraints in [Regexp => constraint] _init_regexp(name, constraint) in [Range => range] _init_range(name, range) in [Array | Hash | Set => container] _init_membership(name, container, false) in [Array | Hash | Set => container, :autocast] _init_membership(name, container, true) in [:member, container] _init_membership(name, container) else raise ArgumentError, "illegal constraint spec #{constraints.inspect} for value #{name}" unless block _init_custom(name, &block) end end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
6 7 8 |
# File 'lib/flex_args/constraint.rb', line 6 def name @name end |
Instance Method Details
#call(value) ⇒ Object
123 124 125 |
# File 'lib/flex_args/constraint.rb', line 123 def call(value) @constrainer.(value) end |