constrain 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +56 -15
- data/TODO +14 -3
- data/lib/constrain/version.rb +1 -1
- data/lib/constrain.rb +1 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ceffc61373ff30143743c0cca412f43abe64bbb6e012722c1ba2ab5035fe939b
|
4
|
+
data.tar.gz: ed70c819e47438f269c1d58d1291d4cde4eef22fc73049fd67c4b4d1b9c3da7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94aeb7517bb00357f29bedf15a0b509fcefb28664e9c31e59f3a592e64c69da601a1e379cfeb473e7af590f69d1879c0dded102e55f159ecb8ef5dd8d8a84f58
|
7
|
+
data.tar.gz: e1eb0ec5ad04063965262a6be821027859a61c5fa42ec3b97da18d2e95e5193b95a8f96e4bf3a222bf866bd8e0c38579f7d50dd5380b305b3cc3badb66eceebf
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ f("Hello", "world") # Boom
|
|
22
22
|
It is intended to be an aid in development only and to be deactivated in
|
23
23
|
production (TODO: Make it possible to deactivate)
|
24
24
|
|
25
|
-
Constrain works with ruby-
|
25
|
+
Constrain works with ruby-3
|
26
26
|
|
27
27
|
## Usage
|
28
28
|
|
@@ -35,15 +35,24 @@ require 'constrain'
|
|
35
35
|
include Constrain
|
36
36
|
|
37
37
|
def f(a, b, c)
|
38
|
-
constrain a, Integer
|
39
|
-
constrain b, [Symbol, String] => Integer
|
40
|
-
constrain c, [String], NilClass
|
38
|
+
constrain a, Integer # An integer
|
39
|
+
constrain b, { [Symbol, String] => Integer } # Hash with String or Symbol keys
|
40
|
+
constrain c, [String], NilClass # Array of strings or nil
|
41
41
|
...
|
42
42
|
end
|
43
43
|
```
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
Constrain only defines the methods \#constrain and \#constrain? so it is
|
46
|
+
acceptible in most cases. An alternative is to include the constrain module
|
47
|
+
in a common root class to have it available in all child classes:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class BaseClass
|
51
|
+
include Constrain
|
52
|
+
...
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
47
56
|
|
48
57
|
## Methods
|
49
58
|
|
@@ -103,11 +112,11 @@ Simple values are compared to the expected result using the #=== operator. This
|
|
103
112
|
means you can use regular expressions too:
|
104
113
|
|
105
114
|
```ruby
|
106
|
-
# Simple email regular expression (https://stackoverflow.com/a/719543)
|
107
|
-
|
115
|
+
# Simple (!) email address regular expression (https://stackoverflow.com/a/719543)
|
116
|
+
EMAIL_ADDRESS_RE = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9.-]+$/
|
108
117
|
|
109
|
-
def
|
110
|
-
constrain address,
|
118
|
+
def send_email(address)
|
119
|
+
constrain address, EMAIL_ADDRESS_RE
|
111
120
|
...
|
112
121
|
end
|
113
122
|
```
|
@@ -164,8 +173,8 @@ Hashes match if value is a hash and every key/value pair match one of the given
|
|
164
173
|
key-class/value-class expressions:
|
165
174
|
|
166
175
|
```ruby
|
167
|
-
constrain({"str" => 42}, String => Integer) # Success
|
168
|
-
constrain({"str" => 42}, String => String) # Failure
|
176
|
+
constrain({"str" => 42}, { String => Integer }) # Success
|
177
|
+
constrain({"str" => 42}, { String => String }) # Failure
|
169
178
|
```
|
170
179
|
|
171
180
|
Note that the parenthesis are needed because otherwise the Ruby parser would
|
@@ -177,15 +186,15 @@ element so that `[String, Symbol]` matches either a String or a Symbol value
|
|
177
186
|
while `[String]` matches an array of String objects:
|
178
187
|
|
179
188
|
```ruby
|
180
|
-
constrain({ sym: 42 }, [Symbol, String] => Integer) # Success
|
181
|
-
constrain({ [sym] => 42 }, [Symbol, String] => Integer) # Failure
|
189
|
+
constrain({ sym: 42 }, { [Symbol, String] => Integer }) # Success
|
190
|
+
constrain({ [sym] => 42 }, { [Symbol, String] => Integer }) # Failure
|
182
191
|
```
|
183
192
|
|
184
193
|
To specify an array of Symbol or String objects in hash keys or values, make
|
185
194
|
sure the list expression is enclosed in an array:
|
186
195
|
|
187
196
|
```ruby
|
188
|
-
constrain({ [sym] => 42 }, [[Symbol, String]] => Integer) # Success
|
197
|
+
constrain({ [sym] => 42 }, { [[Symbol, String]] => Integer }) # Success
|
189
198
|
```
|
190
199
|
|
191
200
|
#### nil, true and false
|
@@ -245,6 +254,38 @@ include business logic that should be kept in the production code. Constrain is
|
|
245
254
|
only thouhgt of as a tool to catch developer errors - not errors that stem from
|
246
255
|
corrupted data
|
247
256
|
|
257
|
+
## Other uses
|
258
|
+
|
259
|
+
Constrain can be used to type-check complex structures like YAML documents:
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
# A YAML value
|
263
|
+
value = {
|
264
|
+
"str" => "a",
|
265
|
+
"int" => 42,
|
266
|
+
"arr" => [1, 2],
|
267
|
+
"hash" => {
|
268
|
+
"key1" => "b",
|
269
|
+
"key2" => 42
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
# Type description
|
274
|
+
type = {
|
275
|
+
"str" => String,
|
276
|
+
"int" => Integer,
|
277
|
+
"arr" => [Integer],
|
278
|
+
"hash" => {
|
279
|
+
"key1" => [String, Integer],
|
280
|
+
"key2" => [String, Integer]
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
puts constrain?(value, type) ? "yes" : "no" # Outputs 'yes'
|
285
|
+
value["str"] = 42
|
286
|
+
puts constrain?(value, type) ? "yes" : "no" # Outputs 'no'
|
287
|
+
```
|
288
|
+
|
248
289
|
## Installation
|
249
290
|
|
250
291
|
Add this line to your application's Gemfile:
|
data/TODO
CHANGED
@@ -1,14 +1,25 @@
|
|
1
1
|
|
2
|
+
o A constrain_class method that allows for inherited-from tests
|
3
|
+
o Allow single-argument boolean expressions: 'constrain !a.empty?'
|
4
|
+
o This seems to cause a stack error: 'constrain some-hash, Symbol'
|
5
|
+
o Allow range as value expressions. And REs!
|
2
6
|
o Use | to create class-or expressions
|
3
|
-
o
|
7
|
+
o Class | Class syntax
|
8
|
+
o Will solve problem with [String, Integer] as a String/Integer vs. An array
|
9
|
+
of strings and integers
|
4
10
|
o Use & to construct tuple expressions
|
5
|
-
o
|
11
|
+
o Class & Class (doesn't look good - maybe Class + Class ?)
|
12
|
+
o Alt: A tuple method: "Symbol => constrain.tuple(String, Integer)"
|
6
13
|
o Better error message for 'constrain EXPR'
|
7
14
|
o Explain that 'constrain EXPR' can be used for 'constrain SomeClass < AnotherClass'
|
8
15
|
o Match ranges and regular expressions
|
9
16
|
o An array and hash method: "Symbol => constrain.array(Integer), String => constrain.hash(Symbol, Integer)"
|
17
|
+
Nope. Solved by | syntax
|
10
18
|
o Constrained attributes: constrain_reader, constrain_writer, constrain_accessor:
|
11
|
-
o Messages should include info about the unexpected element type in arrays (and
|
19
|
+
o Messages should include info about the unexpected element type in arrays (and
|
20
|
+
maybe more): "Expected [#<PgGraph::Data::Record:public.pings[1] {id: 1, name:
|
21
|
+
'Ping A'}>, #<PgGraph::Data::Record:public.pings[2] {id: 2, name: 'Ping B'}>,
|
22
|
+
nil] to match [PgGraph::Data::Record]
|
12
23
|
|
13
24
|
+ constrain value, class-expr, "Error message"
|
14
25
|
+ Check against values: 'constrain arg, :one_value, :another_value, 1, 2, 3'
|
data/lib/constrain/version.rb
CHANGED
data/lib/constrain.rb
CHANGED
@@ -54,12 +54,8 @@ module Constrain
|
|
54
54
|
# unwind is automatically incremented by one because ::do_constrain is always
|
55
55
|
# called from one of the other constrain methods
|
56
56
|
#
|
57
|
-
def self.do_constrain(value, *exprs, unwind: 0, message: nil
|
58
|
-
opts.keys.empty? || opts.keys == [:not] or raise ArgumentError
|
57
|
+
def self.do_constrain(value, *exprs, unwind: 0, message: nil)
|
59
58
|
unwind += 1
|
60
|
-
not_argument = opts.key?(:not)
|
61
|
-
not_value = opts[:not]
|
62
|
-
|
63
59
|
begin
|
64
60
|
if exprs.empty?
|
65
61
|
value or raise MatchError.new(value, [], message: message, unwind: unwind)
|
@@ -67,10 +63,6 @@ module Constrain
|
|
67
63
|
exprs.any? { |expr| Constrain.do_constrain_value?(value, expr) } or
|
68
64
|
raise MatchError.new(value, exprs, message: message, unwind: unwind)
|
69
65
|
end
|
70
|
-
!not_argument || value != not_value or
|
71
|
-
raise MatchError.new(
|
72
|
-
value, exprs, message: message, unwind: unwind, not_argument: true, not_value: not_value)
|
73
|
-
|
74
66
|
rescue ArgumentError, Constrain::MatchError => ex
|
75
67
|
ex.set_backtrace(caller[1 + unwind..-1])
|
76
68
|
raise
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: constrain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simplecov
|