tchae 0.0.1
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 +7 -0
- data/lib/tchae.rb +2 -0
- data/lib/tchae/core.rb +407 -0
- data/lib/tchae/version.rb +3 -0
- metadata +77 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3223e8b9f142d6df07e3140a7469647fb6b285d4324d8720957ebee438dfdab7
|
4
|
+
data.tar.gz: f0602b5cb2d128f42d097744299e226c504835d231f099f8cace33566033778c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6354b81ae20b79d584d6c6b34e0cdb293f11f6cfebf8e39c2a7dd90f72401af33c8355acba4945ee33c190322c9e4769c7284145a0103eaec57ad070306b4c21
|
7
|
+
data.tar.gz: 5fa9f4da97ca1063e73814dd5c54d4848d1ee08eeea055ea2fe0ca16c6752107c92cf913f3f5ef05ffefca4158c901e84e00387b3fa4aedb556cb8b1a6cc945e
|
data/lib/tchae.rb
ADDED
data/lib/tchae/core.rb
ADDED
@@ -0,0 +1,407 @@
|
|
1
|
+
class Object
|
2
|
+
def class_respond_to?(*args)
|
3
|
+
self.class.respond_to?(*args)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module Tchae
|
8
|
+
EMPTY_ARRAY = [].freeze
|
9
|
+
|
10
|
+
def self.Wrapper(handling = ::Tchae::Handling::RAISE)
|
11
|
+
MethodValidator.new(handling)
|
12
|
+
end
|
13
|
+
|
14
|
+
# wrap method with validation, and on invalid,
|
15
|
+
# exit with control flow and retun a wrapped error object
|
16
|
+
# on success return a wrapped return object
|
17
|
+
def self.do_method_wrapping_return(obj, wrapper, tea_methodsymb,
|
18
|
+
proclmbda, params, kwparms)
|
19
|
+
unless params.empty?
|
20
|
+
if (err = wrapper.args.positional.valid_or_return_error(params))
|
21
|
+
return Return(nil, err)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
unless kwparms.empty?
|
25
|
+
if (err = wrapper.args.keyword.valid_or_return_error(kwparms))
|
26
|
+
return Return(nil, err)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
unchecked_result = if proclmbda.arity.zero?
|
31
|
+
obj.__send__(tea_methodsymb)
|
32
|
+
elsif kwparms.empty?
|
33
|
+
obj.__send__(tea_methodsymb, *params)
|
34
|
+
elsif params.empty?
|
35
|
+
obj.__send__(tea_methodsymb, **kwparms)
|
36
|
+
else
|
37
|
+
obj.__send__(tea_methodsymb, *params, **kwparms)
|
38
|
+
end
|
39
|
+
|
40
|
+
wrapper.result.valid_or_return_error unchecked_result
|
41
|
+
end
|
42
|
+
|
43
|
+
# wrap method with validation, and on invalid,
|
44
|
+
# exit by raising exception
|
45
|
+
|
46
|
+
def self.do_method_wrapping_raise(obj, wrapper, tea_methodsymb,
|
47
|
+
proclmbda, params, kwparms)
|
48
|
+
|
49
|
+
wrapper.args.positional.valid_or_raise_exception(params)
|
50
|
+
wrapper.args.keyword.valid_or_raise_exception(kwparms)
|
51
|
+
unchecked_result = if proclmbda.arity.zero?
|
52
|
+
obj.__send__(tea_methodsymb)
|
53
|
+
elsif kwparms.empty?
|
54
|
+
obj.__send__(tea_methodsymb, *params)
|
55
|
+
elsif params.empty?
|
56
|
+
obj.__send__(tea_methodsymb, **kwparms)
|
57
|
+
else
|
58
|
+
obj.__send__(tea_methodsymb, *params, **kwparms)
|
59
|
+
end
|
60
|
+
wrapper.result.valid_or_raise_exception unchecked_result
|
61
|
+
end
|
62
|
+
|
63
|
+
class Error
|
64
|
+
attr_reader :msg
|
65
|
+
def initialize(input); end
|
66
|
+
end
|
67
|
+
|
68
|
+
class ReturnTypeError < Error
|
69
|
+
end
|
70
|
+
|
71
|
+
class ArgumentValueError < Error
|
72
|
+
end
|
73
|
+
|
74
|
+
class ArgumentTypeError < Error
|
75
|
+
end
|
76
|
+
|
77
|
+
class ReturnTypeException < TypeError
|
78
|
+
end
|
79
|
+
|
80
|
+
class ArgumentValueException < ArgumentError
|
81
|
+
end
|
82
|
+
|
83
|
+
class ArgumentTypeException < TypeError
|
84
|
+
end
|
85
|
+
|
86
|
+
class Validator
|
87
|
+
attr_reader :message
|
88
|
+
|
89
|
+
def initialize(proc, msg: nil)
|
90
|
+
@proc = proc
|
91
|
+
@message = msg.nil? ? "does not fulfill #{proc}.to_s" : msg
|
92
|
+
end
|
93
|
+
|
94
|
+
def execute(input)
|
95
|
+
input.instance_exec(&@proc)
|
96
|
+
end
|
97
|
+
|
98
|
+
def valid_or_raise_exception(input, eklass)
|
99
|
+
raise eklass unless execute(input)
|
100
|
+
|
101
|
+
input
|
102
|
+
end
|
103
|
+
|
104
|
+
def valid_or_return_error(input, eklass)
|
105
|
+
execute(input) ? input : return_error(input, eklass)
|
106
|
+
end
|
107
|
+
|
108
|
+
def return_error(input, eklass)
|
109
|
+
eklass.new(input)
|
110
|
+
end
|
111
|
+
|
112
|
+
def wrapped_result_or_error(result, eklass)
|
113
|
+
execute(result) ? Return(result) : Return(nil, return_error(result, eklass))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# same as Validator but with Arity 1 execution semantics
|
118
|
+
class Validator1 < Validator
|
119
|
+
def execute(input)
|
120
|
+
@proc.call(input)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class ResultWrapper
|
125
|
+
attr_reader :result
|
126
|
+
attr_reader :error
|
127
|
+
def initialize(res, err = nil)
|
128
|
+
@result = res
|
129
|
+
@error = err
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Result
|
134
|
+
def initialize(wrapper)
|
135
|
+
@wrapper = wrapper
|
136
|
+
@valtor = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
def expect(constraint = nil, &proc)
|
140
|
+
@valtor = if block_given?
|
141
|
+
raise(ArgumentError, 'The Result.expect method accepts either a block or an argument but not both') if constraint
|
142
|
+
|
143
|
+
Tchae(proc)
|
144
|
+
else
|
145
|
+
Tchae(constraint)
|
146
|
+
end
|
147
|
+
@wrapper
|
148
|
+
end
|
149
|
+
|
150
|
+
def valid_or_raise_exception(result)
|
151
|
+
return result unless @valtor
|
152
|
+
|
153
|
+
@valtor.valid_or_raise_exception(result, ::Tchae::ReturnTypeException)
|
154
|
+
end
|
155
|
+
|
156
|
+
def valid_or_return_error(result)
|
157
|
+
return Return(result) unless @valtor
|
158
|
+
|
159
|
+
@valtor.wrapped_result_or_error(result, ::Tchae::ReturnTypeError)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class PositionalArgs < Array
|
164
|
+
def initialize(wrapper)
|
165
|
+
super()
|
166
|
+
@wrapper = wrapper
|
167
|
+
end
|
168
|
+
|
169
|
+
def arg(&proc)
|
170
|
+
push Tchae(proc)
|
171
|
+
@wrapper
|
172
|
+
end
|
173
|
+
|
174
|
+
def expect(constraints = EMPTY_ARRAY, &proc)
|
175
|
+
constraints.each { |inp| push Tchae(inp) }
|
176
|
+
instance_exec(&proc) if block_given?
|
177
|
+
@wrapper
|
178
|
+
end
|
179
|
+
|
180
|
+
def valid_or_raise_exception(params)
|
181
|
+
params.zip(self).each do |parm, valtor|
|
182
|
+
next unless valtor
|
183
|
+
|
184
|
+
valtor.valid_or_raise_exception(parm, ::Tchae::ArgumentTypeException)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def valid_or_return_error(params)
|
189
|
+
# returns nil if everything valid or an Error object otherwise
|
190
|
+
valid = true
|
191
|
+
failed = params.zip(self).each do |parm, valtor|
|
192
|
+
next unless valtor
|
193
|
+
|
194
|
+
unless valtor.execute(parm)
|
195
|
+
valid = false
|
196
|
+
break valtor.return_error(parm, ::Tchae::ArgumentTypeError)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
valid ? nil : failed
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class KeywordArgs < Hash
|
204
|
+
def initialize(wrapper)
|
205
|
+
super()
|
206
|
+
@wrapper = wrapper
|
207
|
+
end
|
208
|
+
|
209
|
+
def expect(**keywprocs)
|
210
|
+
keywprocs.each { |argsymb, proc| self[argsymb] = Tchae(proc) }
|
211
|
+
@wrapper
|
212
|
+
end
|
213
|
+
|
214
|
+
def valid_or_raise_exception(keywps)
|
215
|
+
each do |key, valtor|
|
216
|
+
next unless valtor
|
217
|
+
next unless ((parm = keywps[key]) if keywps.key?(key))
|
218
|
+
|
219
|
+
valtor.valid_or_raise_exception(parm, ::Tchae::ArgumentTypeException)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def valid_or_return_error(keywps)
|
224
|
+
# returns nil if everything valid or an Error object otherwise
|
225
|
+
valid = true
|
226
|
+
failed = each do |key, valtor|
|
227
|
+
next unless valtor
|
228
|
+
next unless ((parm = keywps[key]) if keywps.key?(key))
|
229
|
+
|
230
|
+
unless valtor.execute(parm)
|
231
|
+
valid = false
|
232
|
+
break valtor.return_error(parm, ::Tchae::ArgumentTypeError)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
valid ? nil : failed
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
class Arguments
|
240
|
+
attr_reader :positional
|
241
|
+
attr_reader :keyword
|
242
|
+
def initialize(wrapper)
|
243
|
+
@wrapper = wrapper
|
244
|
+
@positional = PositionalArgs.new(wrapper)
|
245
|
+
@keyword = KeywordArgs.new(wrapper)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
module Handling
|
249
|
+
RAISE = :raise_exception
|
250
|
+
RETURN = :return_wrapper
|
251
|
+
ALL = [RAISE, RETURN].freeze
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Central validator factory
|
256
|
+
def Tchae(inp)
|
257
|
+
case inp
|
258
|
+
when Class
|
259
|
+
Tchae::Validator.new -> { is_a?(inp) }, msg: "is not a #{inp}"
|
260
|
+
when Symbol
|
261
|
+
Tchae::Validator.new -> { respond_to?(inp) }, msg: "does not respond to #{inp}"
|
262
|
+
when Proc
|
263
|
+
Tchae::Validator.new inp
|
264
|
+
when Array
|
265
|
+
Tchae::Validator1.new ->(value) { inp.find(value) }
|
266
|
+
else
|
267
|
+
Tchae::Validator.new inp.to_proc
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
module Tchae
|
272
|
+
class MethodValidator
|
273
|
+
HANDLING_VTOR = Tchae(Handling::ALL).freeze
|
274
|
+
attr_reader :result
|
275
|
+
attr_reader :args
|
276
|
+
attr_accessor :handling
|
277
|
+
def initialize(handling = ::Tchae::Handling::RAISE)
|
278
|
+
HANDLING_VTOR.valid_or_raise_exception(handling, ArgumentValueError)
|
279
|
+
@result = Result.new(self)
|
280
|
+
@args = Arguments.new(self)
|
281
|
+
@handling = handling
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
NilWrapper = MethodValidator.new.freeze
|
286
|
+
|
287
|
+
module PI
|
288
|
+
def create_validated_method(methodname,
|
289
|
+
wrapper = Tchae::NilWrapper,
|
290
|
+
lambda: nil,
|
291
|
+
&proc)
|
292
|
+
proclmbda = if lambda.nil?
|
293
|
+
proc
|
294
|
+
else
|
295
|
+
raise ArgumentError, 'Please provide a block or the :lambda parameter but not both' if block_given?
|
296
|
+
|
297
|
+
lambda
|
298
|
+
end
|
299
|
+
|
300
|
+
if wrapper.handling == ::Tchae::Handling::RETURN
|
301
|
+
create_valid_or_return_method(methodname, wrapper, &proclmbda)
|
302
|
+
else # RAISE
|
303
|
+
create_valid_or_raise_method(methodname, wrapper, &proclmbda)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def create_valid_or_raise_method(methodname,
|
308
|
+
wrapper = Tchae::NilWrapper, &proc)
|
309
|
+
if block_given?
|
310
|
+
tea_methodsymb = "__tea_#{methodname}".to_sym
|
311
|
+
define_method "__tea_#{methodname}", proc
|
312
|
+
define_method(methodname) do |*params, **kwparms|
|
313
|
+
Tchae.do_method_wrapping_raise(self, wrapper,
|
314
|
+
tea_methodsymb, proc,
|
315
|
+
params, kwparms)
|
316
|
+
end
|
317
|
+
else
|
318
|
+
define_method(methodname) {}
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def create_valid_or_return_method(methodname,
|
323
|
+
wrapper = Tchae::NilWrapper,
|
324
|
+
&proc)
|
325
|
+
if block_given?
|
326
|
+
tea_methodsymb = "__tea_#{methodname}".to_sym
|
327
|
+
define_method "__tea_#{methodname}", proc
|
328
|
+
define_method(methodname) do |*params, **kwparms|
|
329
|
+
Tchae.do_method_wrapping_return(self,
|
330
|
+
wrapper,
|
331
|
+
tea_methodsymb,
|
332
|
+
proc,
|
333
|
+
params,
|
334
|
+
kwparms)
|
335
|
+
end
|
336
|
+
else
|
337
|
+
define_method(methodname) {}
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
module PISingleton
|
343
|
+
def create_validated_singleton_method(methodname,
|
344
|
+
wrapper = Tchae::NilWrapper,
|
345
|
+
lambda: nil,
|
346
|
+
&proc)
|
347
|
+
|
348
|
+
proclmbda = if lambda.nil?
|
349
|
+
proc
|
350
|
+
else
|
351
|
+
raise ArgumentError, 'Please provide a block or the :lambda parameter but not both' if block_given?
|
352
|
+
|
353
|
+
lambda
|
354
|
+
end
|
355
|
+
|
356
|
+
if wrapper.handling == ::Tchae::Handling::RETURN
|
357
|
+
create_valid_or_return_singleton_method(methodname, wrapper, &proclmbda)
|
358
|
+
else # RAISE
|
359
|
+
create_valid_or_raise_singleton_method(methodname, wrapper, &proclmbda)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def create_valid_or_raise_singleton_method(methodname,
|
364
|
+
wrapper = Tchae::NilWrapper, &proc)
|
365
|
+
if block_given?
|
366
|
+
tea_methodsymb = "__tea_#{methodname}".to_sym
|
367
|
+
define_singleton_method "__tea_#{methodname}", proc
|
368
|
+
define_singleton_method(methodname) do |*params, **kwparms|
|
369
|
+
Tchae.do_method_wrapping_raise(self, wrapper,
|
370
|
+
tea_methodsymb, proc,
|
371
|
+
params, kwparms)
|
372
|
+
end
|
373
|
+
else
|
374
|
+
define_singleton_method(methodname) {}
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def create_valid_or_return_singleton_method(methodname,
|
379
|
+
wrapper = Tchae::NilWrapper, &proc)
|
380
|
+
if block_given?
|
381
|
+
tea_methodsymb = "__tea_#{methodname}".to_sym
|
382
|
+
define_singleton_method "__tea_#{methodname}", proc
|
383
|
+
define_singleton_method(methodname) do |*params, **kwparms|
|
384
|
+
Tchae.do_method_wrapping_return(self, wrapper,
|
385
|
+
tea_methodsymb, proc,
|
386
|
+
params, kwparms)
|
387
|
+
end
|
388
|
+
else
|
389
|
+
define_singleton_method(methodname) {}
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
# central return wrapper
|
396
|
+
def Return(result, error = nil)
|
397
|
+
Tchae::ResultWrapper.new(result, error)
|
398
|
+
end
|
399
|
+
class Object
|
400
|
+
extend Tchae::PI
|
401
|
+
include Tchae::PISingleton
|
402
|
+
end
|
403
|
+
|
404
|
+
class Module
|
405
|
+
include Tchae::PI
|
406
|
+
include Tchae::PISingleton
|
407
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tchae
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- D.M.
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '12.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '12.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.51'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.51'
|
41
|
+
description: Tchae is a lightweight ruby validation library
|
42
|
+
email: dev@aithscel.eu
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- lib/tchae.rb
|
48
|
+
- lib/tchae/core.rb
|
49
|
+
- lib/tchae/version.rb
|
50
|
+
homepage: https://gitlab.com/dm0da/tchae
|
51
|
+
licenses:
|
52
|
+
- MIT
|
53
|
+
metadata:
|
54
|
+
bug_tracker_uri: https://gitlab.com/dm0da/tchae/issues
|
55
|
+
changelog_uri: https://gitlab.com/dm0da/tchae/blob/master/CHANGELOG
|
56
|
+
source_code_uri: https://gitlab.com/dm0da/tchae/tree/master
|
57
|
+
wiki_uri: https://gitlab.com/dm0da/tchae/wikis/home
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.4.0
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubygems_version: 3.1.2
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Tchae is a lightweight ruby validation library
|
77
|
+
test_files: []
|