lab42_basic_constraints 0.1.1 → 0.2.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 +69 -25
- data/lib/lab42/basic_constraints.rb +20 -18
- data/lib/lab42/basic_constraints/constraint.rb +17 -6
- data/lib/lab42/basic_constraints/constraints/int.rb +19 -0
- data/lib/lab42/basic_constraints/helpers/range_helper.rb +29 -0
- data/lib/lab42/basic_constraints/implementation.rb +85 -7
- data/lib/lab42/basic_constraints/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 672bcf05278d0a451a503939dd0ebf0f69b95914be02d466c0024717747fab76
|
4
|
+
data.tar.gz: d398d43d6dcbb335df544545e4b6c1ea4795c7a4b086725e9fcb4595f87b3c48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98c2067be96925b8724360ed748b91fcb606ecce255867f1da5e11958148cf55006e61a6d1f9397d47c66e552698d9b9131475389dbad69c2c128ab57dabca52
|
7
|
+
data.tar.gz: 7839dd0e966966d27cd560bb9b28d43b1181ca1547f116058a6923176aa04ae0a5bc81fa6a812fa75372fb2fc57951f7a4966e0c45461dbd6af0aee7e93d379d
|
data/README.md
CHANGED
@@ -17,27 +17,46 @@ Given That we alias `Lab42::BasicConstraints` to `BC`
|
|
17
17
|
require "lab42/basic_constraints/alias"
|
18
18
|
```
|
19
19
|
|
20
|
+
Given
|
21
|
+
```ruby
|
22
|
+
let :all_basic_constraints do
|
23
|
+
%i[
|
24
|
+
all_digits_string alphanumeric_string
|
25
|
+
bool
|
26
|
+
date date_time day
|
27
|
+
hour
|
28
|
+
int
|
29
|
+
lowercase_string
|
30
|
+
minute month
|
31
|
+
non_negative_int non_negative_number number
|
32
|
+
positive_int positive_number
|
33
|
+
second string
|
34
|
+
uppercase_string
|
35
|
+
year
|
36
|
+
]
|
37
|
+
end
|
38
|
+
let :all_parametrized_constraints do
|
39
|
+
%i[ int_range limited_string ]
|
40
|
+
end
|
41
|
+
|
42
|
+
```
|
20
43
|
Then All Basic Constraints can be listed by means of `BC.all_constraints`
|
21
44
|
|
22
45
|
```ruby
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
uppercase_string
|
35
|
-
year
|
36
|
-
]
|
37
|
-
|
38
|
-
expect( BC.all_constraints ).to eq(all_basic_constraints)
|
46
|
+
|
47
|
+
expect( Set.new(BC.all_constraints) ).to eq(Set.new(all_basic_constraints + all_parametrized_constraints))
|
48
|
+
```
|
49
|
+
|
50
|
+
And they are implemented of course
|
51
|
+
```ruby
|
52
|
+
all_basic_constraints.each do | constraint_name |
|
53
|
+
expect( BC.from_symbol(constraint_name) ).to be_a(BC::Constraint)
|
54
|
+
end
|
55
|
+
expect( BC.int_range(min: 0) ).to be_a(BC::Constraint)
|
56
|
+
expect( BC.limited_string(max: 10) ).to be_a(BC::Constraint)
|
39
57
|
```
|
40
58
|
|
59
|
+
|
41
60
|
## So we got the ball, now use it!
|
42
61
|
|
43
62
|
The ball, BTW, is a `Lab42::Result` see [lab42_result gem](https://rubygems.org/gems/lab42_result/) for more info
|
@@ -74,17 +93,12 @@ Example: Constraints with and without defaults
|
|
74
93
|
|
75
94
|
```
|
76
95
|
|
77
|
-
|
78
|
-
[here](speculations/constraints.md)
|
79
|
-
|
80
|
-
## Context We are still in Beta and therefor
|
81
|
-
|
82
|
-
Example: Some constraints are not yet implemented
|
83
|
-
|
96
|
+
Example: Avoiding the Exception, à la `Hash#fetch`
|
84
97
|
```ruby
|
85
|
-
expect
|
98
|
+
expect( BC.from_symbol(:positive_number).default{42} ).to eq(42)
|
86
99
|
```
|
87
100
|
|
101
|
+
|
88
102
|
## Context Time's a Sticky Wicket
|
89
103
|
|
90
104
|
... but as defaults are defined for runtime that shall really help us with that
|
@@ -112,9 +126,39 @@ Example: Illegal Dates
|
|
112
126
|
```ruby
|
113
127
|
d.("2020-00-01") in [raised, message ]
|
114
128
|
expect( raised ).to eq(error)
|
115
|
-
expect( message ).to eq("2020-00-01 is not a legal date
|
129
|
+
expect( message ).to eq(%{"2020-00-01" is not a legal date})
|
130
|
+
```
|
131
|
+
|
132
|
+
## Context Equality More Of A Tricky Sticker
|
133
|
+
|
134
|
+
And Most Surprisingly
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
expect(BC.bool).not_to eq(BC.bool)
|
116
138
|
```
|
117
139
|
|
140
|
+
However in many cases the name and the default say a lot about a constraint's behavior
|
141
|
+
|
142
|
+
Given
|
143
|
+
```ruby
|
144
|
+
let(:natural) {BC.non_negative_int}
|
145
|
+
let(:def42) {BC.non_negative_int.set_default(42)}
|
146
|
+
```
|
147
|
+
|
148
|
+
Then we can compare as follows
|
149
|
+
```ruby
|
150
|
+
expect( natural.name ).to eq(BC.non_negative_int.name)
|
151
|
+
expect( natural.default ).to eq(0)
|
152
|
+
expect( def42.name ).to eq(BC.non_negative_int.name)
|
153
|
+
expect( def42.default ).to eq(42)
|
154
|
+
```
|
155
|
+
|
156
|
+
## Detailed Description of all Constraints
|
157
|
+
|
158
|
+
[date_and_time_constraints](date_and_time_constraints.md )
|
159
|
+
[div_constraints](div_constraints.md )
|
160
|
+
[string_constraints](string_constraints.md )
|
161
|
+
|
118
162
|
# LICENSE
|
119
163
|
|
120
164
|
Copyright 2020 Robert Dober robert.dober@gmail.com
|
@@ -2,37 +2,37 @@ require_relative "basic_constraints/implementation.rb"
|
|
2
2
|
module Lab42
|
3
3
|
module BasicConstraints extend self
|
4
4
|
Constraints = {
|
5
|
-
all_digits_string: :
|
6
|
-
alphanumeric_string: :
|
5
|
+
all_digits_string: :all_digits_string,
|
6
|
+
alphanumeric_string: :alphanumeric_string,
|
7
7
|
|
8
8
|
bool: ->(x){[false, true].include? x},
|
9
9
|
|
10
10
|
date: :date,
|
11
|
-
date_time: :
|
12
|
-
day: :
|
11
|
+
date_time: :date_time,
|
12
|
+
day: :day,
|
13
13
|
|
14
|
-
hour: :
|
14
|
+
hour: :hour,
|
15
15
|
|
16
|
-
|
16
|
+
int: Integer,
|
17
|
+
int_range: :int_range,
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
limited_string: :limited_string,
|
20
|
+
lowercase_string: :lowercase_string,
|
21
|
+
|
22
|
+
minute: :minute,
|
23
|
+
month: :month,
|
20
24
|
|
21
|
-
non_empty_string: :not_yet_implemented,
|
22
|
-
non_negative_float: :not_yet_implemented,
|
23
25
|
non_negative_int: :non_negative_int,
|
26
|
+
non_negative_number: :non_negative_number,
|
27
|
+
number: Numeric,
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
positive_float: :not_yet_implemented,
|
28
|
-
positive_int: :not_yet_implemented,
|
29
|
+
positive_int: :positive_int,
|
29
30
|
positive_number: :positive_number,
|
30
31
|
|
31
|
-
second: :
|
32
|
-
|
33
|
-
time: :not_yet_implemented,
|
32
|
+
second: :second,
|
33
|
+
string: String,
|
34
34
|
|
35
|
-
uppercase_string: :
|
35
|
+
uppercase_string: :uppercase_string,
|
36
36
|
|
37
37
|
year: :year
|
38
38
|
}
|
@@ -49,6 +49,8 @@ module Lab42
|
|
49
49
|
Constraint.new(name, &cons)
|
50
50
|
when Symbol
|
51
51
|
Implementation.send(cons, *args, **kwds)
|
52
|
+
when Class
|
53
|
+
Constraint.new(name){ cons === _1 }
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
@@ -5,18 +5,24 @@ module Lab42
|
|
5
5
|
ConstraintError = Class.new RuntimeError
|
6
6
|
MissingDefaultError = Class.new RuntimeError
|
7
7
|
class Constraint
|
8
|
+
attr_reader :default, :name
|
8
9
|
|
9
10
|
def call value
|
10
11
|
return Result.ok if @constraint.(value)
|
11
12
|
Result.error("#{_show value} is not a legal #{@name}", error: Lab42::BasicConstraints::ConstraintError)
|
12
13
|
end
|
13
14
|
|
14
|
-
def default
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def default &blk
|
16
|
+
if @has_default
|
17
|
+
case @default
|
18
|
+
when Proc
|
19
|
+
@default.()
|
20
|
+
else
|
21
|
+
@default
|
22
|
+
end
|
18
23
|
else
|
19
|
-
|
24
|
+
return blk.() if blk
|
25
|
+
raise Lab42::BasicConstraints::MissingDefaultError, "Constraint #{name} has no predefined default"
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
@@ -27,6 +33,7 @@ module Lab42
|
|
27
33
|
else
|
28
34
|
blk
|
29
35
|
end
|
36
|
+
@has_default = true
|
30
37
|
self
|
31
38
|
end
|
32
39
|
|
@@ -35,6 +42,8 @@ module Lab42
|
|
35
42
|
case value
|
36
43
|
when NilClass
|
37
44
|
"nil"
|
45
|
+
when String
|
46
|
+
value.inspect
|
38
47
|
else
|
39
48
|
value
|
40
49
|
end
|
@@ -42,9 +51,11 @@ module Lab42
|
|
42
51
|
|
43
52
|
def initialize name, &blk
|
44
53
|
@constraint = blk
|
45
|
-
@
|
54
|
+
@has_default = false
|
55
|
+
@default = -> {}
|
46
56
|
@name = name
|
47
57
|
end
|
48
58
|
end
|
49
59
|
end
|
50
60
|
end
|
61
|
+
require_relative "constraints/int"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../helpers/range_helper.rb"
|
2
|
+
module Lab42
|
3
|
+
module BasicConstraints
|
4
|
+
class Constraint
|
5
|
+
class IntConstraint < Constraint
|
6
|
+
|
7
|
+
private
|
8
|
+
def initialize name, range: nil, min: nil, max: nil
|
9
|
+
super(name)
|
10
|
+
range = Helpers::RangeHelper.make_range!(range: range, min: min, max: max)
|
11
|
+
@constraint = -> (value) {
|
12
|
+
Integer === value && range === value
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Lab42
|
2
|
+
module BasicConstraints
|
3
|
+
module Helpers
|
4
|
+
module RangeHelper extend self
|
5
|
+
|
6
|
+
def make_range(range: nil, min: nil, max: nil)
|
7
|
+
return unless range || min || max
|
8
|
+
raise ArgumentError, "cannot provide min or max with range" if
|
9
|
+
range && (min || max)
|
10
|
+
range || _make_min_max_range(min, max)
|
11
|
+
end
|
12
|
+
|
13
|
+
def make_range!(range: nil, min: nil, max: nil)
|
14
|
+
make_range(range: range, min: min, max: max)
|
15
|
+
.tap do |range|
|
16
|
+
raise ArgumentError, "Must provide either range or min or max" unless range
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def _make_min_max_range(min, max)
|
22
|
+
min ||= 0
|
23
|
+
max ||= Float::INFINITY
|
24
|
+
min..max
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,9 +1,38 @@
|
|
1
1
|
require_relative "constraint"
|
2
|
+
require_relative "helpers/range_helper"
|
2
3
|
module Lab42
|
3
4
|
module BasicConstraints
|
4
5
|
|
5
6
|
module Implementation extend self
|
6
7
|
|
8
|
+
IntConstraints = {
|
9
|
+
day: 1..31,
|
10
|
+
hour: 0..23,
|
11
|
+
minute: 0..59,
|
12
|
+
month: 1..12,
|
13
|
+
second: 0..59
|
14
|
+
}
|
15
|
+
IntConstraints.each do |constraint_name, constraint_range|
|
16
|
+
define_method constraint_name do
|
17
|
+
Constraint::IntConstraint.new(constraint_name, range: constraint_range)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def int_range(range: nil, min: nil, max: nil)
|
22
|
+
Constraint::IntConstraint.new(:int_range, range: range, min: min, max: max)
|
23
|
+
end
|
24
|
+
|
25
|
+
StringConstraints = {
|
26
|
+
all_digits_string: %r{\A\d*\z},
|
27
|
+
alphanumeric_string: %r{\A[[:alnum:]]*\z}
|
28
|
+
}
|
29
|
+
|
30
|
+
StringConstraints.each do |constraint_name, constraint_rgx|
|
31
|
+
define_method constraint_name do |size: nil, min: nil, max: nil|
|
32
|
+
_regex_constraint(constraint_name, constraint_rgx, size: size, min: min, max: max)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
7
36
|
def date default: nil
|
8
37
|
require "date"
|
9
38
|
Constraint.new(:date) do |value|
|
@@ -14,22 +43,55 @@ module Lab42
|
|
14
43
|
end
|
15
44
|
end
|
16
45
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
46
|
+
def date_time default: nil
|
47
|
+
require "date"
|
48
|
+
Constraint.new(:date_time) do |value|
|
49
|
+
DateTime.parse(value) rescue false
|
20
50
|
end
|
51
|
+
.set_default default do
|
52
|
+
DateTime.now.iso8601
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def limited_string size: nil, min: nil, max: nil
|
57
|
+
size_range = Helpers::RangeHelper.make_range!(range: size, min: min, max: max)
|
58
|
+
Constraint.new(:limited_string) do |value|
|
59
|
+
String === value && size_range === value.size
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def lowercase_string
|
64
|
+
Constraint.new :lowercase_string do |value|
|
65
|
+
String === value && value.downcase == value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def non_negative_int
|
70
|
+
Constraint::IntConstraint.new(:non_negative_int, min: 0)
|
21
71
|
.set_default(0)
|
22
72
|
end
|
23
73
|
|
74
|
+
def non_negative_number
|
75
|
+
Constraint.new :non_negative_number do |value|
|
76
|
+
Numeric === value && !(Complex === value) && value >= 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def positive_int
|
81
|
+
Constraint::IntConstraint.new(:positive_int, min: 1)
|
82
|
+
.set_default(1)
|
83
|
+
end
|
84
|
+
|
24
85
|
def positive_number
|
25
86
|
Constraint.new :positive_number do |value|
|
26
|
-
|
27
|
-
Float === value && value > 0.0
|
87
|
+
Numeric === value && value > 0
|
28
88
|
end
|
29
89
|
end
|
30
90
|
|
31
|
-
def
|
32
|
-
|
91
|
+
def uppercase_string
|
92
|
+
Constraint.new :uppercase_string do |value|
|
93
|
+
String === value && value.upcase == value
|
94
|
+
end
|
33
95
|
end
|
34
96
|
|
35
97
|
def year
|
@@ -40,6 +102,22 @@ module Lab42
|
|
40
102
|
Time.now.utc.year
|
41
103
|
end
|
42
104
|
end
|
105
|
+
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def _regex_constraint(name, rgx, size: nil, min: nil, max: nil)
|
110
|
+
range_size = Helpers::RangeHelper.make_range(range: size, min: min, max: max)
|
111
|
+
if range_size
|
112
|
+
Constraint.new(name) do |value|
|
113
|
+
String === value && range_size === value.size && rgx === value
|
114
|
+
end
|
115
|
+
else
|
116
|
+
Constraint.new(name) do |value|
|
117
|
+
String === value && rgx === value
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
43
121
|
end
|
44
122
|
end
|
45
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab42_basic_constraints
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Dober
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lab42_result
|
@@ -91,6 +91,8 @@ files:
|
|
91
91
|
- lib/lab42/basic_constraints.rb
|
92
92
|
- lib/lab42/basic_constraints/alias.rb
|
93
93
|
- lib/lab42/basic_constraints/constraint.rb
|
94
|
+
- lib/lab42/basic_constraints/constraints/int.rb
|
95
|
+
- lib/lab42/basic_constraints/helpers/range_helper.rb
|
94
96
|
- lib/lab42/basic_constraints/implementation.rb
|
95
97
|
- lib/lab42/basic_constraints/version.rb
|
96
98
|
homepage: https://bitbucket.org/robertdober/lab42_basic_constraints
|