Module: Mal
Overview
The module allows you to define simple data structure schemas, and to match your data against those schemas. Primary use is for HTTP parameters, JSON-derived datastructures and the like.
Let’s start with the basics. Any “typespec” returned by the library responds to ‘===`. The most basic (and all-encompassing) typespec there is is called `Anything()`.
Anything() === false #=> true
Anything() === true #=> true
Anything() === Module #=> true
A more specific type is an Only(), which is similar to just using a class, module or Regexp (which all support ===), but it can be composed with other typespecs.
Only(/hello/) === 123 #=> false
Only(/hello/) === "hello world" #=> true
Interesting things come into play when you use combinations of the typespecs. For example, you want to ensure the value referenced by ‘my_var` is either a Fixnum or a String matching a regular expression. For this, you need to create a compound matcher using an `Either()` typespec (disjoint union):
Either(Fixnum, Both(String, /hello/)) === "hello world" #=> true
Either(Fixnum, Both(String, /hello/)) === 123 #=> true
Either(Fixnum, Both(String, /hello/)) === Module #=> false, since it is neither of
You can also use the ‘|` operator on most of the typespecs to create these disjoint unions - but if you have a matchable object on the left side of the expression you mught have to wrap it in an `Only()`:
Only(Fixnum) | Only(String) #=> Either(Fixnum, String)
Even more entertainment becomes possible when you match deeper structures with nesting - hashes for example. There are two methods for those - ‘HashWith()` and `HashOf`. `HashWith` checks for the presence of the given key/value pairs and checks values for matches, but if there are other keys present in the Hash given for verification it won’t complain. ‘HashOf()`, in contrast, will ensure there are only the mentioned keys in the Hash, and will not match if something else is present.
HashWith(age: Fixnum) === {age: 12, name: 'Cisco Kid'} #=> true
HashOf(age: Fixnum) === {age: 12, name: 'Cisco Kid'} #=> false
Note that it is entirely plausible that you would not want to include Mal into your object/class/whatever. For that case, calling methods using their qualified module name (‘Mal.Some()…`) can become a nuisance. If it does, use `Mal.typespec` which is a shortcut to `instance_exec` - but has the convenient property of not alerting your style watchers to your use of `instance_exec` :-P
Defined Under Namespace
Classes: AnythingT, ArrayT, BoolT, CoveringT, EitherT, HashOfOnlyT, HashPermittingT, HashT, IncludingT, LengthT, MaxLengthT, MaybeT, MinLengthT, NilT, ObjectT, OnlyT, SatisfyingT, UnionT, ValueT
Constant Summary collapse
- VERSION =
'0.0.5'
Class Method Summary collapse
-
.typespec(&blk) ⇒ Object
A shortcut for ‘instance_exec`, for defining types using shorthand method names from outside the module:.
Instance Method Summary collapse
-
#Anything ⇒ Object
Just like it says: will match any value given to it.
-
#ArrayOf(typespec_for_array_element) ⇒ Object
Specifies an Array of at least 1 element, where each element matches the typespec for the array element.
-
#Bool ⇒ Object
Specifies a value that is either ‘true` or `false` (truthy or falsy values do not work).
-
#Both(*matchables) ⇒ Object
Specifies a value that matches both the given matchers.
- #CoveredBy(range) ⇒ Object
-
#Either(*matchables) ⇒ Object
Specifies a value that matches either one of the given speciciers.
-
#HashOf(**keys_to_values) ⇒ Object
Specifies a Hash containing only the given keys, with values at those keys matching the given matchers.
-
#HashPermitting(**keys_to_values) ⇒ Object
Specifies a Hash containing the given keys/values or their subset, will also match an empty Hash.
-
#HashWith(**keys_to_values) ⇒ Object
Specifies a Hash containing at least the given keys, with values at those keys matching the given matchers.
- #IncludedIn(*values) ⇒ Object
-
#Maybe(matchable) ⇒ Object
Specifies a value that is either matching the given typespec, or is nil.
-
#Nil ⇒ Object
Specifies a value that may only ever be ‘nil` and nothing else.
-
#ObjectWith(*properties) ⇒ Object
Specifies an object responding to certain methods.
- #OfAtLeastElements(n) ⇒ Object
- #OfAtMostElements(n) ⇒ Object
-
#Only(matchable) ⇒ Object
Specifies a value that matches only the given matcher.
-
#Satisfying(&blk) ⇒ Object
Matches the given value if the passed block/Proc returns true when called with that value Satisfying {|x| x > 10 } === 11 #=> true.
-
#Value(value) ⇒ Object
Matches the contained value exactly using the == operator.
Class Method Details
Instance Method Details
#Anything ⇒ Object
Just like it says: will match any value given to it
391 392 393 |
# File 'lib/mal.rb', line 391 def Anything() AnythingT.new end |
#ArrayOf(typespec_for_array_element) ⇒ Object
Specifies an Array of at least 1 element, where each element matches the typespec for the array element
338 339 340 |
# File 'lib/mal.rb', line 338 def ArrayOf(typespec_for_array_element) ArrayT.new(typespec_for_array_element) end |
#Bool ⇒ Object
Specifies a value that is either ‘true` or `false` (truthy or falsy values do not work)
311 312 313 |
# File 'lib/mal.rb', line 311 def Bool() BoolT.new end |
#Both(*matchables) ⇒ Object
Specifies a value that matches both the given matchers. For instance, can be a matcher for both a String and a Regexp
322 323 324 |
# File 'lib/mal.rb', line 322 def Both(*matchables) UnionT.new(*matchables) end |
#CoveredBy(range) ⇒ Object
408 409 410 |
# File 'lib/mal.rb', line 408 def CoveredBy(range) CoveringT.new(range) end |
#Either(*matchables) ⇒ Object
Specifies a value that matches either one of the given speciciers
327 328 329 |
# File 'lib/mal.rb', line 327 def Either(*matchables) EitherT.new(*matchables) end |
#HashOf(**keys_to_values) ⇒ Object
Specifies a Hash containing only the given keys, with values at those keys matching the given matchers. For example, for a Hash having at the ‘:name` key with a corresponding value that is a String:
HashOfOnly(name: String)
Because the match is-strict, it will not match a Hash having additional keys
HashOf(name: String) === {name: 'John Doe', age: 21} #=> false
379 380 381 |
# File 'lib/mal.rb', line 379 def HashOf(**keys_to_values) HashOfOnlyT.new(**keys_to_values) end |
#HashPermitting(**keys_to_values) ⇒ Object
Specifies a Hash containing the given keys/values or their subset, will also match an empty Hash. Will not match a Hash having extra keys.
386 387 388 |
# File 'lib/mal.rb', line 386 def HashPermitting(**keys_to_values) HashPermittingT.new(**keys_to_values) end |
#HashWith(**keys_to_values) ⇒ Object
Specifies a Hash containing at least the given keys, with values at those keys matching the given matchers. For example, for a Hash having at least the ‘:name` key with a corresponding value that is a String:
HashWith(name: String)
Since the match is non-strict, it will also match a Hash having more keys
HashWith(name: String) === {name: 'John Doe', age: 21} #=> true
351 352 353 |
# File 'lib/mal.rb', line 351 def HashWith(**keys_to_values) HashT.new(**keys_to_values) end |
#IncludedIn(*values) ⇒ Object
412 413 414 |
# File 'lib/mal.rb', line 412 def IncludedIn(*values) IncludingT.new(values) end |
#Maybe(matchable) ⇒ Object
Specifies a value that is either matching the given typespec, or is nil
332 333 334 |
# File 'lib/mal.rb', line 332 def Maybe(matchable) MaybeT.new(matchable) end |
#Nil ⇒ Object
Specifies a value that may only ever be ‘nil` and nothing else
306 307 308 |
# File 'lib/mal.rb', line 306 def Nil() NilT.new(NilClass) end |
#ObjectWith(*properties) ⇒ Object
Specifies an object responding to certain methods
ObjectWith(:downcase) === "foo" #=> true
358 359 360 |
# File 'lib/mal.rb', line 358 def ObjectWith(*properties) ObjectT.new(*properties) end |
#OfAtLeastElements(n) ⇒ Object
362 363 364 |
# File 'lib/mal.rb', line 362 def OfAtLeastElements(n) MinLengthT.new(n) end |
#OfAtMostElements(n) ⇒ Object
366 367 368 |
# File 'lib/mal.rb', line 366 def OfAtMostElements(n) MaxLengthT.new(n) end |
#Only(matchable) ⇒ Object
Specifies a value that matches only the given matcher
316 317 318 |
# File 'lib/mal.rb', line 316 def Only(matchable) OnlyT.new(matchable) end |
#Satisfying(&blk) ⇒ Object
Matches the given value if the passed block/Proc returns true when called with that value
Satisfying {|x| x > 10 } === 11 #=> true
404 405 406 |
# File 'lib/mal.rb', line 404 def Satisfying(&blk) SatisfyingT.new(&blk) end |