constrain 0.7.0 → 0.9.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: e58649bbac9af8f3464dedd63c6c76e72c6f37440da629a10b5aba3319972214
4
- data.tar.gz: c82c606c419af6c2af55aaca6a57bf03d2229917241bf800d32dba8d8a6a512c
3
+ metadata.gz: ff3fb59b6d713b01843aa67e4e90855e58f99b1fcffa8ff27ae66b53987d9672
4
+ data.tar.gz: 98237076729ee99035e1af426308f12ef36963879950287f107486ae0485e061
5
5
  SHA512:
6
- metadata.gz: 6e0b90a537bea77af54c907ccb7fb1ea0a501623ba42c793c94ac446cfcbee615cac3d2937ec86741af883698ef3558ba4a3bc34030e3d1be68c36730e159097
7
- data.tar.gz: 3d0212bdafd1a03d9058b8ad94bc423f346ec6b36752c1dbbc11b2f3b319d77493754cb68be712ce7dc7ab02986eab1329b7fa42ec116b770a0e31517c9c7124
6
+ metadata.gz: 533a2c7486903550fa42c3f349417130a8dd69642adf6d2e27599bd9f5e4b6be3fca0dcfcc58370cf4d64169952e06df5a0ad76603d424741f0c7846301f66ac
7
+ data.tar.gz: 95ee72d76e6ccfdd7faffd971214ecc6b171ab1a58debfd5a6a043a0764e8f154a910a7086399363a4bc88e94406a7a048f5efa32cadf5c1d8ded2e1725fcc37
data/TODO CHANGED
@@ -1,11 +1,15 @@
1
1
 
2
- o Allow 'constrain SomeClass < SomeOtherClass'
2
+ o Use | to create class-or expressions
3
+ o Old: Class | Class syntax
4
+ o Use & to construct tuple expressions
5
+ o Old: A tuple method: "Symbol => constrain.tuple(String, Integer)"
6
+ o Better error message for 'constrain EXPR'
7
+ o Explain that 'constrain EXPR' can be used for 'constrain SomeClass < AnotherClass'
3
8
  o Match ranges and regular expressions
4
- o A tuple method: "Symbol => constrain.tuple(String, Integer)"
5
9
  o An array and hash method: "Symbol => constrain.array(Integer), String => constrain.hash(Symbol, Integer)"
6
- o Class | Class syntax
7
10
  o Constrained attributes: constrain_reader, constrain_writer, constrain_accessor:
8
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]
9
12
 
10
13
  + constrain value, class-expr, "Error message"
11
14
  + Check against values: 'constrain arg, :one_value, :another_value, 1, 2, 3'
15
+ + Allow 'constrain EXRP'
@@ -1,3 +1,3 @@
1
1
  module Constrain
2
- VERSION = "0.7.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/constrain.rb CHANGED
@@ -3,8 +3,12 @@ require "constrain/version"
3
3
  module Constrain
4
4
  # Raised if types doesn't match a class expression
5
5
  class MatchError < StandardError
6
- def initialize(value, exprs, message: nil, unwind: 0)
7
- super message || "Expected #{value.inspect} to match #{Constrain.fmt_exprs(exprs)}"
6
+ def initialize(value, exprs, message: nil, unwind: 0, not_argument: false, not_value: nil)
7
+ if not_argument
8
+ super message || "Expected #{value.inspect} to not equal #{not_value.inspect}"
9
+ else
10
+ super message || "Expected #{value.inspect} to match #{Constrain.fmt_exprs(exprs)}"
11
+ end
8
12
  end
9
13
  end
10
14
 
@@ -12,17 +16,6 @@ module Constrain
12
16
  base.extend ClassMethods
13
17
  end
14
18
 
15
- # See Constrain.constrain
16
- def constrain(value, *exprs)
17
- Constrain.do_constrain(value, *exprs)
18
- end
19
-
20
- # Like #constrain but returns true/false to indicate the result instead of
21
- # raising an exception
22
- def constrain?(value, *exprs)
23
- Constrain.do_constrain?(value, *exprs)
24
- end
25
-
26
19
  # :call-seq:
27
20
  # constrain(value, *class-expressions, unwind: 0)
28
21
  # constrain(value, *values, unwind: 0)
@@ -31,38 +24,41 @@ module Constrain
31
24
  # ArgumentError if the expression is invalid and a Constrain::MatchError if
32
25
  # the value doesn't match. The exception's backtrace skips :unwind number of
33
26
  # entries
34
- def self.constrain(value, *exprs)
35
- do_constrain(value, *exprs)
27
+ def self.constrain(value, *exprs, **opts)
28
+ do_constrain(value, *exprs, **opts)
36
29
  end
37
30
 
38
- # Return true if the value matches the class expression. Raises a
39
- # ArgumentError if the expression is invalid
40
- def self.constrain?(value, *exprs)
41
- do_constrain?(value, *exprs)
31
+ # See Constrain.constrain
32
+ def constrain(...) = Constrain.do_constrain(...)
33
+
34
+ # Like #constrain but returns true/false to indicate the result instead of
35
+ # raising an exception
36
+ def self.constrain?(value, *exprs, **opts)
37
+ do_constrain?(value, *exprs, **opts)
42
38
  end
43
39
 
40
+ # See Constrain.constrain?
41
+ def constrain?(...) = Constrain.do_constrain?(...)
42
+
44
43
  module ClassMethods
45
44
  # See Constrain.constrain
46
- def constrain(*args)
47
-
48
- Constrain.do_constrain(*args) end
45
+ def constrain(...) Constrain.do_constrain(...) end
49
46
 
50
47
  # See Constrain.constrain?
51
- def constrain?(*args) Constrain.do_constrain?(*args) end
48
+ def constrain?(...) Constrain.do_constrain?(...) end
52
49
  end
53
50
 
51
+ # :call-seq:
52
+ # do_constrain(value, *exprs, unwind: 0, message: nil, not: nil)
53
+ #
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)
58
- if exprs.last.is_a?(Hash)
59
- unwind = (exprs.last.delete(:unwind) || 0) + 1
60
- message = exprs.last.delete(:message)
61
- !exprs.last.empty? or exprs.pop # Remove option hash if empty
62
- else
63
- unwind = 1
64
- message = nil
65
- end
57
+ def self.do_constrain(value, *exprs, unwind: 0, message: nil, **opts)
58
+ opts.keys.empty? || opts.keys == [:not] or raise ArgumentError
59
+ unwind += 1
60
+ not_argument = opts.key?(:not)
61
+ not_value = opts[:not]
66
62
 
67
63
  begin
68
64
  if exprs.empty?
@@ -71,6 +67,10 @@ module Constrain
71
67
  exprs.any? { |expr| Constrain.do_constrain_value?(value, expr) } or
72
68
  raise MatchError.new(value, exprs, message: message, unwind: unwind)
73
69
  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
74
  rescue ArgumentError, Constrain::MatchError => ex
75
75
  ex.set_backtrace(caller[1 + unwind..-1])
76
76
  raise
@@ -78,17 +78,19 @@ module Constrain
78
78
  value
79
79
  end
80
80
 
81
- def self.do_constrain?(value, *exprs)
81
+ def self.do_constrain?(...)
82
82
  begin
83
- !exprs.empty? or raise ArgumentError, "Empty constraint"
84
- exprs.any? { |expr| Constrain.do_constrain_value?(value, expr) }
83
+ do_constrain(...)
84
+ rescue MatchError
85
+ return false
85
86
  end
87
+ true
86
88
  end
87
89
 
88
90
  def self.do_constrain_value?(value, expr)
89
91
  case expr
90
92
  when Class, Module
91
- value.is_a?(expr)
93
+ expr === value
92
94
  when Array
93
95
  !expr.empty? or raise ArgumentError, "Empty array in constraint"
94
96
  value.is_a?(Array) && value.all? { |elem| expr.any? { |e| Constrain.constrain?(elem, e) } }
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.7.0
4
+ version: 0.9.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: 2022-09-03 00:00:00.000000000 Z
11
+ date: 2023-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov