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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff3fb59b6d713b01843aa67e4e90855e58f99b1fcffa8ff27ae66b53987d9672
4
- data.tar.gz: 98237076729ee99035e1af426308f12ef36963879950287f107486ae0485e061
3
+ metadata.gz: ceffc61373ff30143743c0cca412f43abe64bbb6e012722c1ba2ab5035fe939b
4
+ data.tar.gz: ed70c819e47438f269c1d58d1291d4cde4eef22fc73049fd67c4b4d1b9c3da7a
5
5
  SHA512:
6
- metadata.gz: 533a2c7486903550fa42c3f349417130a8dd69642adf6d2e27599bd9f5e4b6be3fca0dcfcc58370cf4d64169952e06df5a0ad76603d424741f0c7846301f66ac
7
- data.tar.gz: 95ee72d76e6ccfdd7faffd971214ecc6b171ab1a58debfd5a6a043a0764e8f154a910a7086399363a4bc88e94406a7a048f5efa32cadf5c1d8ded2e1725fcc37
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-2 (and maybe ruby-3)
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 # An integer
39
- constrain b, [Symbol, String] => Integer # Hash with String or Symbol keys
40
- constrain c, [String], NilClass # Array of strings or nil
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
- The alternative is to include the constrain Module in a common root class to
46
- have it available in all child classes
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
- EMAIL_RE = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9.-]+$/
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 email(address)
110
- constrain address, EMAIL_RE
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 Old: Class | Class syntax
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 Old: A tuple method: "Symbol => constrain.tuple(String, Integer)"
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 maybe more): "Expected [#<PgGraph::Data::Record:public.pings[1] {id: 1, name: 'Ping A'}>, #<PgGraph::Data::Record:public.pings[2] {id: 2, name: 'Ping B'}>, nil] to match [PgGraph::Data::Record]
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'
@@ -1,3 +1,3 @@
1
1
  module Constrain
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0"
3
3
  end
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, **opts)
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.9.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-01-21 00:00:00.000000000 Z
11
+ date: 2023-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov