constrain 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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