sigt 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +264 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +91 -0
- data/Makefile +16 -0
- data/README.md +70 -0
- data/flake.lock +61 -0
- data/flake.nix +19 -0
- data/lib/sigt.rb +75 -0
- data/sigt.gemspec +22 -0
- data/spec/sigt_spec.rb +60 -0
- data/spec/spec_helper.rb +11 -0
- metadata +153 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bcecf066ed19e5b18159d39077989d93bd0536388a57c33699c9dae801d4fd16
|
4
|
+
data.tar.gz: 78380ed65941b6407de7cb247704b2b053b6e499a36dc5bfaba5dfcd03acbd68
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43722030a8c3f2bc44b811365ea964674af519a6507f87deb757dcdf92f27c0a41828533aa6866e6f9c0c9df12182a2402389d8ccb1f1e652e1cca651185feef
|
7
|
+
data.tar.gz: 0c75f526477414bd6a8b439b02ef592272fbb02975007b8cc91c1d646ba021f7354b2a7a8c4f71dde11ef1c87eb88f9d531981da5c585bbebc9f7c12301944b6
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-minitest
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 3.0
|
6
|
+
NewCops: disable
|
7
|
+
|
8
|
+
Layout/SpaceAroundMethodCallOperator:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Layout/SpaceInLambdaLiteral:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Layout/MultilineMethodCallIndentation:
|
15
|
+
Enabled: true
|
16
|
+
EnforcedStyle: indented
|
17
|
+
|
18
|
+
Layout/FirstArrayElementIndentation:
|
19
|
+
EnforcedStyle: consistent
|
20
|
+
|
21
|
+
Layout/SpaceInsideHashLiteralBraces:
|
22
|
+
Enabled: true
|
23
|
+
|
24
|
+
Layout/LineLength:
|
25
|
+
Max: 100
|
26
|
+
Exclude:
|
27
|
+
- "spec/**/*.rb"
|
28
|
+
|
29
|
+
Layout/HashAlignment:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Lint/AmbiguousBlockAssociation:
|
33
|
+
Enabled: true
|
34
|
+
# because 'expect { foo }.to change { bar }' is fine
|
35
|
+
Exclude:
|
36
|
+
- "spec/**/*.rb"
|
37
|
+
|
38
|
+
Lint/BooleanSymbol:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Lint/ConstantDefinitionInBlock:
|
42
|
+
Exclude:
|
43
|
+
- "spec/**/*.rb"
|
44
|
+
|
45
|
+
Lint/RaiseException:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Lint/StructNewOverride:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Lint/SuppressedException:
|
52
|
+
Exclude:
|
53
|
+
- "spec/spec_helper.rb"
|
54
|
+
|
55
|
+
Lint/LiteralAsCondition:
|
56
|
+
Exclude:
|
57
|
+
- "spec/**/*.rb"
|
58
|
+
|
59
|
+
Naming/PredicateName:
|
60
|
+
Enabled: false
|
61
|
+
|
62
|
+
Naming/FileName:
|
63
|
+
Exclude:
|
64
|
+
- "lib/*-*.rb"
|
65
|
+
|
66
|
+
Naming/MethodName:
|
67
|
+
Enabled: false
|
68
|
+
|
69
|
+
Naming/MethodParameterName:
|
70
|
+
Enabled: false
|
71
|
+
|
72
|
+
Naming/MemoizedInstanceVariableName:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
Metrics/MethodLength:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
Metrics/ClassLength:
|
79
|
+
Enabled: false
|
80
|
+
|
81
|
+
Metrics/BlockLength:
|
82
|
+
Enabled: false
|
83
|
+
|
84
|
+
Metrics/AbcSize:
|
85
|
+
Max: 25
|
86
|
+
|
87
|
+
Metrics/CyclomaticComplexity:
|
88
|
+
Enabled: true
|
89
|
+
Max: 12
|
90
|
+
|
91
|
+
Style/ExponentialNotation:
|
92
|
+
Enabled: false
|
93
|
+
|
94
|
+
Style/HashEachMethods:
|
95
|
+
Enabled: false
|
96
|
+
|
97
|
+
Style/HashTransformKeys:
|
98
|
+
Enabled: false
|
99
|
+
|
100
|
+
Style/HashTransformValues:
|
101
|
+
Enabled: false
|
102
|
+
|
103
|
+
Style/AccessModifierDeclarations:
|
104
|
+
Enabled: false
|
105
|
+
|
106
|
+
Style/Alias:
|
107
|
+
Enabled: true
|
108
|
+
EnforcedStyle: prefer_alias_method
|
109
|
+
|
110
|
+
Style/AsciiComments:
|
111
|
+
Enabled: false
|
112
|
+
|
113
|
+
Style/BlockDelimiters:
|
114
|
+
Enabled: false
|
115
|
+
|
116
|
+
Style/ClassAndModuleChildren:
|
117
|
+
Exclude:
|
118
|
+
- "spec/**/*.rb"
|
119
|
+
|
120
|
+
Style/ConditionalAssignment:
|
121
|
+
Enabled: false
|
122
|
+
|
123
|
+
Style/DateTime:
|
124
|
+
Enabled: false
|
125
|
+
|
126
|
+
Style/Documentation:
|
127
|
+
Enabled: false
|
128
|
+
|
129
|
+
Style/EachWithObject:
|
130
|
+
Enabled: false
|
131
|
+
|
132
|
+
Style/FormatString:
|
133
|
+
Enabled: false
|
134
|
+
|
135
|
+
Style/FormatStringToken:
|
136
|
+
Enabled: false
|
137
|
+
|
138
|
+
Style/GuardClause:
|
139
|
+
Enabled: false
|
140
|
+
|
141
|
+
Style/IfUnlessModifier:
|
142
|
+
Enabled: false
|
143
|
+
|
144
|
+
Style/Lambda:
|
145
|
+
Enabled: false
|
146
|
+
|
147
|
+
Style/LambdaCall:
|
148
|
+
Enabled: false
|
149
|
+
|
150
|
+
Style/ParallelAssignment:
|
151
|
+
Enabled: false
|
152
|
+
|
153
|
+
Style/RaiseArgs:
|
154
|
+
Enabled: false
|
155
|
+
|
156
|
+
Style/StabbyLambdaParentheses:
|
157
|
+
Enabled: false
|
158
|
+
|
159
|
+
Style/StringLiterals:
|
160
|
+
Enabled: true
|
161
|
+
EnforcedStyle: double_quotes
|
162
|
+
ConsistentQuotesInMultiline: false
|
163
|
+
|
164
|
+
Style/StringLiteralsInInterpolation:
|
165
|
+
Enabled: true
|
166
|
+
EnforcedStyle: double_quotes
|
167
|
+
|
168
|
+
Style/SymbolArray:
|
169
|
+
Exclude:
|
170
|
+
- "spec/**/*.rb"
|
171
|
+
|
172
|
+
Style/TrailingUnderscoreVariable:
|
173
|
+
Enabled: false
|
174
|
+
|
175
|
+
Style/MultipleComparison:
|
176
|
+
Enabled: false
|
177
|
+
|
178
|
+
Style/Next:
|
179
|
+
Enabled: false
|
180
|
+
|
181
|
+
Style/AccessorGrouping:
|
182
|
+
Enabled: false
|
183
|
+
|
184
|
+
Style/EmptyLiteral:
|
185
|
+
Enabled: false
|
186
|
+
|
187
|
+
Style/Semicolon:
|
188
|
+
Exclude:
|
189
|
+
- "spec/**/*.rb"
|
190
|
+
|
191
|
+
Style/HashAsLastArrayItem:
|
192
|
+
Exclude:
|
193
|
+
- "spec/**/*.rb"
|
194
|
+
|
195
|
+
Style/CaseEquality:
|
196
|
+
Exclude:
|
197
|
+
- "lib/dry/monads/**/*.rb"
|
198
|
+
- "lib/dry/struct/**/*.rb"
|
199
|
+
- "lib/dry/types/**/*.rb"
|
200
|
+
- "spec/**/*.rb"
|
201
|
+
|
202
|
+
Style/ExplicitBlockArgument:
|
203
|
+
Exclude:
|
204
|
+
- "lib/dry/types/**/*.rb"
|
205
|
+
|
206
|
+
Style/CombinableLoops:
|
207
|
+
Enabled: false
|
208
|
+
|
209
|
+
Style/EmptyElse:
|
210
|
+
Enabled: false
|
211
|
+
|
212
|
+
Style/DoubleNegation:
|
213
|
+
Enabled: false
|
214
|
+
|
215
|
+
Style/MultilineBlockChain:
|
216
|
+
Enabled: false
|
217
|
+
|
218
|
+
Style/NumberedParametersLimit:
|
219
|
+
Max: 2
|
220
|
+
|
221
|
+
Lint/UnusedBlockArgument:
|
222
|
+
Exclude:
|
223
|
+
- "spec/**/*.rb"
|
224
|
+
|
225
|
+
Lint/Debugger:
|
226
|
+
Exclude:
|
227
|
+
- "bin/console"
|
228
|
+
|
229
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
230
|
+
Exclude:
|
231
|
+
- "spec/**/*.rb"
|
232
|
+
|
233
|
+
Metrics/ParameterLists:
|
234
|
+
Exclude:
|
235
|
+
- "spec/**/*.rb"
|
236
|
+
|
237
|
+
Lint/EmptyBlock:
|
238
|
+
Exclude:
|
239
|
+
- "spec/**/*.rb"
|
240
|
+
|
241
|
+
Lint/EmptyFile:
|
242
|
+
Exclude:
|
243
|
+
- "spec/**/*.rb"
|
244
|
+
|
245
|
+
Lint/UselessMethodDefinition:
|
246
|
+
Exclude:
|
247
|
+
- "spec/**/*.rb"
|
248
|
+
|
249
|
+
Lint/SelfAssignment:
|
250
|
+
Enabled: false
|
251
|
+
|
252
|
+
Lint/EmptyClass:
|
253
|
+
Enabled: false
|
254
|
+
|
255
|
+
Naming/ConstantName:
|
256
|
+
Exclude:
|
257
|
+
- "spec/**/*.rb"
|
258
|
+
|
259
|
+
Naming/VariableNumber:
|
260
|
+
Exclude:
|
261
|
+
- "spec/**/*.rb"
|
262
|
+
|
263
|
+
Naming/BinaryOperatorParameterName:
|
264
|
+
Enabled: false
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sigt (0.0.1)
|
5
|
+
dry-types (~> 1.7.2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.2)
|
11
|
+
bigdecimal (3.1.7)
|
12
|
+
coderay (1.1.3)
|
13
|
+
concurrent-ruby (1.2.3)
|
14
|
+
docile (1.4.0)
|
15
|
+
dry-core (1.0.1)
|
16
|
+
concurrent-ruby (~> 1.0)
|
17
|
+
zeitwerk (~> 2.6)
|
18
|
+
dry-inflector (1.0.0)
|
19
|
+
dry-logic (1.5.0)
|
20
|
+
concurrent-ruby (~> 1.0)
|
21
|
+
dry-core (~> 1.0, < 2)
|
22
|
+
zeitwerk (~> 2.6)
|
23
|
+
dry-struct (1.6.0)
|
24
|
+
dry-core (~> 1.0, < 2)
|
25
|
+
dry-types (>= 1.7, < 2)
|
26
|
+
ice_nine (~> 0.11)
|
27
|
+
zeitwerk (~> 2.6)
|
28
|
+
dry-types (1.7.2)
|
29
|
+
bigdecimal (~> 3.0)
|
30
|
+
concurrent-ruby (~> 1.0)
|
31
|
+
dry-core (~> 1.0)
|
32
|
+
dry-inflector (~> 1.0)
|
33
|
+
dry-logic (~> 1.4)
|
34
|
+
zeitwerk (~> 2.6)
|
35
|
+
ice_nine (0.11.2)
|
36
|
+
json (2.7.1)
|
37
|
+
language_server-protocol (3.17.0.3)
|
38
|
+
method_source (1.0.0)
|
39
|
+
minitest (5.22.3)
|
40
|
+
parallel (1.24.0)
|
41
|
+
parser (3.3.0.5)
|
42
|
+
ast (~> 2.4.1)
|
43
|
+
racc
|
44
|
+
pry (0.14.2)
|
45
|
+
coderay (~> 1.1)
|
46
|
+
method_source (~> 1.0)
|
47
|
+
racc (1.7.3)
|
48
|
+
rainbow (3.1.1)
|
49
|
+
regexp_parser (2.9.0)
|
50
|
+
rexml (3.2.6)
|
51
|
+
rubocop (1.62.1)
|
52
|
+
json (~> 2.3)
|
53
|
+
language_server-protocol (>= 3.17.0)
|
54
|
+
parallel (~> 1.10)
|
55
|
+
parser (>= 3.3.0.2)
|
56
|
+
rainbow (>= 2.2.2, < 4.0)
|
57
|
+
regexp_parser (>= 1.8, < 3.0)
|
58
|
+
rexml (>= 3.2.5, < 4.0)
|
59
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
60
|
+
ruby-progressbar (~> 1.7)
|
61
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
62
|
+
rubocop-ast (1.31.2)
|
63
|
+
parser (>= 3.3.0.4)
|
64
|
+
rubocop-minitest (0.35.0)
|
65
|
+
rubocop (>= 1.61, < 2.0)
|
66
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
67
|
+
ruby-progressbar (1.13.0)
|
68
|
+
simplecov (0.22.0)
|
69
|
+
docile (~> 1.1)
|
70
|
+
simplecov-html (~> 0.11)
|
71
|
+
simplecov_json_formatter (~> 0.1)
|
72
|
+
simplecov-html (0.12.3)
|
73
|
+
simplecov_json_formatter (0.1.4)
|
74
|
+
unicode-display_width (2.5.0)
|
75
|
+
zeitwerk (2.6.13)
|
76
|
+
|
77
|
+
PLATFORMS
|
78
|
+
arm64-darwin-22
|
79
|
+
ruby
|
80
|
+
|
81
|
+
DEPENDENCIES
|
82
|
+
dry-struct (~> 1.6.0)
|
83
|
+
minitest (~> 5.22.3)
|
84
|
+
pry (~> 0.14.2)
|
85
|
+
rubocop (~> 1.62.1)
|
86
|
+
rubocop-minitest (~> 0.35.0)
|
87
|
+
sigt!
|
88
|
+
simplecov (~> 0.22.0)
|
89
|
+
|
90
|
+
BUNDLED WITH
|
91
|
+
2.5.3
|
data/Makefile
ADDED
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# SigT
|
2
|
+
|
3
|
+
![](https://images.unsplash.com/photo-1622966591413-81d31b41c8a3?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NTV8fHNpZ25hdHVyZXxlbnwwfHwwfHx8MA%3D%3D)
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
```bash
|
8
|
+
gem install sigt
|
9
|
+
```
|
10
|
+
|
11
|
+
## Example
|
12
|
+
|
13
|
+
### Function composition
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
module Types
|
17
|
+
include Dry.Types()
|
18
|
+
end
|
19
|
+
|
20
|
+
AgeHash = Types::Hash.schema(age: Types::Integer, name: Types::String)
|
21
|
+
FinalHash = AgeHash & Types::Hash.schema(created_at: Types.Instance(Time))
|
22
|
+
|
23
|
+
TO_INTEGER = -> (x) { x.to_i }
|
24
|
+
TO_JSON = -> (x) { x.to_json }
|
25
|
+
|
26
|
+
hash = SigT[Types::Integer => AgeHash] { |age| Hash[age: age, name: "poe"] }
|
27
|
+
|
28
|
+
with_date = SigT[AgeHash => FinalHash] do |hash|
|
29
|
+
hash.update(created_at: Time.now.utc)
|
30
|
+
end
|
31
|
+
|
32
|
+
fn = TO_INTEGER >> hash >> with_date >> TO_JSON
|
33
|
+
fn["42"]
|
34
|
+
#=> "{\"age\":42,\"name\":\"poe\",\"created_at\":\"2024-03-22 22:28:26 UTC\"}"
|
35
|
+
```
|
36
|
+
|
37
|
+
### Dry::Types
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
sig = SigT[Types::String => Types::Hash.schema(name: Types::String)]
|
41
|
+
|
42
|
+
fn = sig[] { |input| Hash[name: input] }
|
43
|
+
|
44
|
+
fn[1]
|
45
|
+
#=> SigT::InputError: 1 violates constraints (type?(String, 1) failed)
|
46
|
+
|
47
|
+
fn["elcuervo"]
|
48
|
+
#=> {:name=>"elcuervo"}
|
49
|
+
```
|
50
|
+
|
51
|
+
### Dry::Struct
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class TestInput < Dry::Struct
|
55
|
+
attribute :url, SigT::Types::String
|
56
|
+
attribute? :potato_count, SigT::Types::Integer
|
57
|
+
end
|
58
|
+
|
59
|
+
class TestOutput < Dry::Struct
|
60
|
+
attribute :complexity, SigT::Types::Float
|
61
|
+
attribute? :url, SigT::Types::String
|
62
|
+
end
|
63
|
+
|
64
|
+
fn = SigT[TestInput => TestOutput] do |input|
|
65
|
+
TestOutput.new(complexity: 0.4, url: input.url)
|
66
|
+
end
|
67
|
+
|
68
|
+
fn.call(TestInput.new(url: "test"))
|
69
|
+
# => #<TestOutput complexity=0.4 url="test">
|
70
|
+
```
|
data/flake.lock
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
{
|
2
|
+
"nodes": {
|
3
|
+
"flake-utils": {
|
4
|
+
"inputs": {
|
5
|
+
"systems": "systems"
|
6
|
+
},
|
7
|
+
"locked": {
|
8
|
+
"lastModified": 1710146030,
|
9
|
+
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
10
|
+
"owner": "numtide",
|
11
|
+
"repo": "flake-utils",
|
12
|
+
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
13
|
+
"type": "github"
|
14
|
+
},
|
15
|
+
"original": {
|
16
|
+
"owner": "numtide",
|
17
|
+
"repo": "flake-utils",
|
18
|
+
"type": "github"
|
19
|
+
}
|
20
|
+
},
|
21
|
+
"nixpkgs": {
|
22
|
+
"locked": {
|
23
|
+
"lastModified": 1710889954,
|
24
|
+
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
|
25
|
+
"owner": "nixos",
|
26
|
+
"repo": "nixpkgs",
|
27
|
+
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
|
28
|
+
"type": "github"
|
29
|
+
},
|
30
|
+
"original": {
|
31
|
+
"owner": "nixos",
|
32
|
+
"ref": "nixpkgs-unstable",
|
33
|
+
"repo": "nixpkgs",
|
34
|
+
"type": "github"
|
35
|
+
}
|
36
|
+
},
|
37
|
+
"root": {
|
38
|
+
"inputs": {
|
39
|
+
"flake-utils": "flake-utils",
|
40
|
+
"nixpkgs": "nixpkgs"
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"systems": {
|
44
|
+
"locked": {
|
45
|
+
"lastModified": 1681028828,
|
46
|
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
47
|
+
"owner": "nix-systems",
|
48
|
+
"repo": "default",
|
49
|
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
50
|
+
"type": "github"
|
51
|
+
},
|
52
|
+
"original": {
|
53
|
+
"owner": "nix-systems",
|
54
|
+
"repo": "default",
|
55
|
+
"type": "github"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
},
|
59
|
+
"root": "root",
|
60
|
+
"version": 7
|
61
|
+
}
|
data/flake.nix
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
inputs = {
|
3
|
+
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
4
|
+
flake-utils.url = "github:numtide/flake-utils";
|
5
|
+
};
|
6
|
+
|
7
|
+
outputs = { self, nixpkgs, flake-utils }:
|
8
|
+
flake-utils.lib.eachDefaultSystem (system:
|
9
|
+
let
|
10
|
+
pkgs = import nixpkgs { inherit system; };
|
11
|
+
in
|
12
|
+
{
|
13
|
+
devShells.default = pkgs.mkShell {
|
14
|
+
buildInputs = with pkgs; [
|
15
|
+
ruby_3_3
|
16
|
+
];
|
17
|
+
};
|
18
|
+
});
|
19
|
+
}
|
data/lib/sigt.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The SigT class provides functionality for defining and enforcing type signatures
|
4
|
+
# on method inputs and outputs using the dry-types gem. It allows for the dynamic
|
5
|
+
# validation of method arguments and return values against specified type constraints.
|
6
|
+
#
|
7
|
+
class SigT
|
8
|
+
module Types
|
9
|
+
include Dry.Types()
|
10
|
+
|
11
|
+
Type = Types.Instance(Dry::Types::Type)
|
12
|
+
Signature = Types::Hash
|
13
|
+
.map(Type, Type)
|
14
|
+
.constrained(max_size: 1)
|
15
|
+
end
|
16
|
+
|
17
|
+
Error = Class.new(StandardError)
|
18
|
+
SignatureError = Class.new(Error)
|
19
|
+
InputError = Class.new(Error)
|
20
|
+
OutputError = Class.new(Error)
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# Defines a signature for input and output types and wraps the provided block with type
|
24
|
+
# validation checks.
|
25
|
+
# @param signature [Hash] A hash representing the input and output types.
|
26
|
+
# @yield [input] The block to be executed.
|
27
|
+
# @yieldparam input [Object] The input object to be processed.
|
28
|
+
# @yieldreturn [Object] The result of the block execution, which will be validated against the
|
29
|
+
# output type.
|
30
|
+
# @raise [SignatureError] If the signature does not conform to the expected structure or
|
31
|
+
# constraints.
|
32
|
+
# @raise [InputError] If the input object does not match the expected type.
|
33
|
+
# @raise [OutputError] If the output object does not match the expected type.
|
34
|
+
# @return [Proc] A proc that represents the wrapped block, which validates input and output
|
35
|
+
# types.
|
36
|
+
#
|
37
|
+
def [](signature, &block)
|
38
|
+
Types::Signature[signature]
|
39
|
+
.flatten
|
40
|
+
.then do |input, output|
|
41
|
+
return sandwich(input, block, output) if block
|
42
|
+
-> (&fn) { sandwich(input, fn, output) }
|
43
|
+
end
|
44
|
+
rescue Dry::Types::ConstraintError => e
|
45
|
+
raise SignatureError, "Signature can only have 1 Dry::Type => Dry::Type compatible objects"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Creates a sandwiched function that validates the input, executes the function, and then
|
51
|
+
# validates the output.
|
52
|
+
# @param input [Dry::Types::Type] The expected type of the input.
|
53
|
+
# @param fn [Proc] The function to execute between type checks.
|
54
|
+
# @param output [Dry::Types::Type] The expected type of the output.
|
55
|
+
# @return [Proc] A proc that takes an input, validates it, executes the function, and validates
|
56
|
+
# the output.
|
57
|
+
#
|
58
|
+
def sandwich(input, fn, output)
|
59
|
+
wrap_or_raise(input, InputError) >> fn >> wrap_or_raise(output, OutputError)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Wraps a block with type validation, raising an error if the validation fails.
|
63
|
+
# @param type [Dry::Types::Type] The type to validate against.
|
64
|
+
# @param error [Class] The error class to be raised if validation fails.
|
65
|
+
# @return [Proc] A proc that represents the wrapped block, which performs type validation.
|
66
|
+
#
|
67
|
+
def wrap_or_raise(type, error)
|
68
|
+
-> (input) do
|
69
|
+
type[input]
|
70
|
+
rescue StandardError => e
|
71
|
+
raise error, e.message
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/sigt.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "sigt"
|
5
|
+
s.version = "0.0.1"
|
6
|
+
s.summary = "Signature Types"
|
7
|
+
s.authors = ["elcuervo"]
|
8
|
+
s.licenses = %w[MIT]
|
9
|
+
s.email = ["elcuervo@elcuervo.net"]
|
10
|
+
s.homepage = "http://github.com/elcuervo/sigt"
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.test_files = `git ls-files test`.split("\n")
|
13
|
+
|
14
|
+
s.add_dependency("dry-types", "~> 1.7.2")
|
15
|
+
|
16
|
+
s.add_development_dependency("dry-struct", "~> 1.6.0")
|
17
|
+
s.add_development_dependency("minitest", "~> 5.22.3")
|
18
|
+
s.add_development_dependency("pry", "~> 0.14.2")
|
19
|
+
s.add_development_dependency("simplecov", "~> 0.22.0")
|
20
|
+
s.add_development_dependency("rubocop", "~> 1.62.1")
|
21
|
+
s.add_development_dependency("rubocop-minitest", "~> 0.35.0")
|
22
|
+
end
|
data/spec/sigt_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe SigT do
|
6
|
+
describe "simple definition" do
|
7
|
+
let(:fn) do
|
8
|
+
SigT[SigT::Types::String => SigT::Types::Integer] do |params|
|
9
|
+
params.to_i + 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "defines an input/output signature" do
|
14
|
+
assert_equal fn["1"], 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "checks the input" do
|
18
|
+
assert_raises(SigT::InputError) { fn[1] }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "checks output input" do
|
22
|
+
bad = SigT[SigT::Types::String => SigT::Types::Hash] do |input|
|
23
|
+
input
|
24
|
+
end
|
25
|
+
|
26
|
+
assert_raises(SigT::OutputError) { bad["1"] }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "multiline" do
|
30
|
+
sig = SigT[SigT::Types::String => SigT::Types::Hash.schema(name: SigT::Types::String)]
|
31
|
+
fn = sig[] { |input| Hash[name: input] }
|
32
|
+
|
33
|
+
assert_equal fn["raven"], { name: "raven" }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "complex definition" do
|
38
|
+
class TestInput < Dry::Struct
|
39
|
+
attribute :url, SigT::Types::String
|
40
|
+
attribute? :potato_count, SigT::Types::Integer
|
41
|
+
end
|
42
|
+
|
43
|
+
class TestOutput < Dry::Struct
|
44
|
+
attribute :complexity, SigT::Types::Float
|
45
|
+
attribute? :url, SigT::Types::String
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:fn) do
|
49
|
+
SigT[TestInput => TestOutput] do |input|
|
50
|
+
TestOutput.new(complexity: 0.4, url: input.url)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "defines an input/output signature" do
|
55
|
+
input = TestInput.new(url: "test")
|
56
|
+
|
57
|
+
assert_equal fn[input].class, TestOutput
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sigt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- elcuervo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry-types
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-struct
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.6.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 5.22.3
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 5.22.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.14.2
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.14.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.22.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.22.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.62.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.62.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.35.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.35.0
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- elcuervo@elcuervo.net
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rubocop.yml"
|
120
|
+
- Gemfile
|
121
|
+
- Gemfile.lock
|
122
|
+
- Makefile
|
123
|
+
- README.md
|
124
|
+
- flake.lock
|
125
|
+
- flake.nix
|
126
|
+
- lib/sigt.rb
|
127
|
+
- sigt.gemspec
|
128
|
+
- spec/sigt_spec.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
homepage: http://github.com/elcuervo/sigt
|
131
|
+
licenses:
|
132
|
+
- MIT
|
133
|
+
metadata: {}
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubygems_version: 3.5.6
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: Signature Types
|
153
|
+
test_files: []
|