Skip to content

Commit aff802c

Browse files
authored
Merge pull request #682 from vim-jp/Validator.Args
Validator.Args: Support blob type, and remove Mod.TYPE constant
2 parents 3132926 + 4935b35 commit aff802c

File tree

3 files changed

+244
-196
lines changed

3 files changed

+244
-196
lines changed

autoload/vital/__vital__/Validator/Args.vim

Lines changed: 82 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,47 @@ set cpo&vim
66
let s:NONE = []
77
lockvar! s:NONE
88

9-
let s:TYPE = {}
10-
let s:TYPE.NUMBER = 0
11-
let s:TYPE.STRING = 1
12-
let s:TYPE.FUNC = 2
13-
let s:TYPE.LIST = 3
14-
let s:TYPE.DICT = 4
15-
let s:TYPE.FLOAT = 5
16-
let s:TYPE.BOOL = 6
17-
let s:TYPE.NONE = 7
18-
let s:TYPE.JOB = 8
19-
let s:TYPE.CHANNEL = 9
20-
let s:TYPE.ANY = range(s:TYPE.NUMBER, s:TYPE.CHANNEL)
21-
let s:TYPE.OPTARG = []
22-
lockvar! s:TYPE
23-
249
function! s:_vital_loaded(V) abort
2510
let s:T = a:V.import('Vim.Type')
26-
endfunction
2711

28-
function! s:_vital_created(module) abort
29-
let a:module.TYPE = s:TYPE
12+
let s:t_end = -1
13+
for t in has('nvim') ? [
14+
\ exists('v:null') ? type(v:null) : -1,
15+
\ exists('v:true') ? type(v:true) : -1,
16+
\ type(0.0),
17+
\ type({}),
18+
\ type([]),
19+
\ type(function('function')),
20+
\ type(''),
21+
\ type(0),
22+
\] : [
23+
\ get(v:, 't_blob', -1),
24+
\ get(v:, 't_channel', -1),
25+
\ get(v:, 't_job', -1),
26+
\ get(v:, 't_none', -1),
27+
\ get(v:, 't_bool', -1),
28+
\ get(v:, 't_float', -1),
29+
\ get(v:, 't_dict', -1),
30+
\ get(v:, 't_list', -1),
31+
\ get(v:, 't_func', -1),
32+
\ get(v:, 't_string', -1),
33+
\ get(v:, 't_number', -1),
34+
\]
35+
if t >= 0
36+
let s:t_end = t
37+
break
38+
endif
39+
endfor
3040
endfunction
3141

3242
function! s:_vital_depends() abort
3343
return ['Vim.Type']
3444
endfunction
3545

36-
3746
function! s:of(prefix, ...) abort
38-
if type(a:prefix) isnot s:TYPE.STRING
39-
throw 'vital: Validator.Args: of(): expected ' . s:T.type_names[s:TYPE.STRING] .
40-
\ ' argument but got ' . s:T.type_names[type(a:prefix)]
47+
if type(a:prefix) isnot# v:t_string
48+
throw 'vital: Validator.Args: of(): expected ' . s:_type_name(v:t_string) .
49+
\ ' argument but got ' . s:_type_name(type(a:prefix))
4150
endif
4251
let validator = {
4352
\ '_prefix': a:prefix,
@@ -58,7 +67,7 @@ function! s:of(prefix, ...) abort
5867
call s:_check_out_of_range(a:no, self._types)
5968
endif
6069
let self._asserts[a:no - 1] = {
61-
\ 'funclist': type(a:funclist) is s:TYPE.LIST ? a:funclist : [a:funclist],
70+
\ 'funclist': type(a:funclist) is# v:t_list ? a:funclist : [a:funclist],
6271
\ 'msg': get(a:000, 0, 'the ' . a:no . 'th argument''s assertion was failed')
6372
\}
6473
return self
@@ -67,9 +76,9 @@ function! s:of(prefix, ...) abort
6776
if !self._enable
6877
return a:args
6978
endif
70-
if type(a:args) isnot s:TYPE.LIST
71-
throw 'vital: Validator.Args: Validator.validate(): expected ' . s:T.type_names[s:TYPE.LIST] .
72-
\ ' argument but got ' . s:T.type_names[type(a:args)]
79+
if type(a:args) isnot# v:t_list
80+
throw 'vital: Validator.Args: Validator.validate(): expected ' . s:_type_name(v:t_list) .
81+
\ ' argument but got ' . s:_type_name(type(a:args))
7382
endif
7483
if has_key(self, '_types')
7584
call s:_validate_arg_types(a:args, self._types, self._prefix)
@@ -85,25 +94,47 @@ endfunction
8594
function! s:_check_type_args(args) abort
8695
let optarg = 0
8796
for i in range(len(a:args))
88-
if a:args[i] is s:TYPE.OPTARG
97+
if a:args[i] is# 'option'
8998
let optarg += 1
9099
if optarg > 1
91-
throw 'vital: Validator.Args: Validator.type(): multiple OPTARG were given'
100+
throw 'vital: Validator.Args: Validator.type(): multiple optional arguments were given'
92101
endif
93102
endif
94-
if !(type(a:args[i]) is s:TYPE.NUMBER &&
95-
\ a:args[i] >= s:TYPE.NUMBER &&
96-
\ a:args[i] <= s:TYPE.CHANNEL) &&
97-
\ !(type(a:args[i]) is s:TYPE.LIST &&
98-
\ empty(filter(copy(a:args[i]),
99-
\ 'type(v:val) isnot s:TYPE.NUMBER || ' .
100-
\ 'v:val < s:TYPE.NUMBER || v:val > s:TYPE.CHANNEL')))
103+
if !s:_is_valid_type_arg(a:args[i])
101104
throw 'vital: Validator.Args: Validator.type(): expected type or union types ' .
102-
\ 'but got ' . s:T.type_names[type(a:args[i])]
105+
\ 'but got ' . s:_type_name(type(a:args[i]))
103106
endif
104107
endfor
105108
endfunction
106109

110+
function! s:_is_valid_type_arg(arg) abort
111+
let n = type(a:arg)
112+
if n is# v:t_number && (v:t_number <=# a:arg && a:arg <=# s:t_end)
113+
return 1
114+
endif
115+
if n is# v:t_string && (a:arg is# 'any' || a:arg is# 'option')
116+
return 1
117+
endif
118+
if n is# v:t_list && empty(filter(copy(a:arg), '!s:_is_valid_type_arg(v:val)'))
119+
return 1
120+
endif
121+
return 0
122+
endfunction
123+
124+
function! s:_type_name(type) abort
125+
if !s:_is_valid_type_arg(a:type)
126+
throw 'vital: Validator.Args: invalid type value: ' . string(a:type)
127+
endif
128+
let n = type(a:type)
129+
if n is# v:t_number
130+
return s:T.type_names[a:type]
131+
elseif n is# v:t_string
132+
return a:type
133+
else
134+
return join(map(copy(a:type), 's:_type_name(v:val)'), ' or ')
135+
endif
136+
endfunction
137+
107138
function! s:_check_assert_args(args) abort
108139
let no = a:args[0]
109140
if no <= 0
@@ -113,7 +144,7 @@ function! s:_check_assert_args(args) abort
113144
endfunction
114145

115146
function! s:_check_out_of_range(no, types) abort
116-
let idx = index(a:types, s:TYPE.OPTARG)
147+
let idx = index(a:types, 'option')
117148
if a:no > len(a:types) - (idx >= 0 && idx !=# len(a:types) - 1 ? 1 : 0)
118149
if idx >= 0
119150
let arity = idx . '-' . (len(a:types) - idx)
@@ -133,13 +164,13 @@ function! s:_validate_arg_types(args, types, prefix) abort
133164
let i = 0
134165
while i < argslen
135166
if i + optarg >= typelen
136-
if optarg && a:types[-1] is s:TYPE.OPTARG
167+
if optarg && a:types[-1] is# 'option'
137168
break
138169
else
139170
throw a:prefix . ': too many arguments'
140171
endif
141172
endif
142-
if a:types[i + optarg] is s:TYPE.OPTARG
173+
if a:types[i + optarg] is# 'option'
143174
let optarg += 1
144175
continue
145176
endif
@@ -148,33 +179,36 @@ function! s:_validate_arg_types(args, types, prefix) abort
148179
\)
149180
let i += 1
150181
endwhile
151-
if !optarg && i < typelen && a:types[i] isnot s:TYPE.OPTARG
182+
if !optarg && i < typelen && a:types[i] isnot# 'option'
152183
throw a:prefix . ': too few arguments'
153184
endif
154185
endfunction
155186

156187
function! s:_validate_type(value, expected_type, prefix, ...) abort
157-
if type(a:expected_type) is s:TYPE.LIST
188+
if a:expected_type is# 'any'
189+
return a:value
190+
endif
191+
if type(a:expected_type) is# v:t_list
158192
let matched = filter(copy(a:expected_type),
159-
\ 's:_validate_type(a:value, v:val, a:prefix, s:NONE) isnot s:NONE')
193+
\ 's:_validate_type(a:value, v:val, a:prefix, s:NONE) isnot# s:NONE')
160194
if empty(matched)
161195
if a:0
162196
return a:1
163197
endif
164-
let expected = join(map(copy(a:expected_type), 's:T.type_names[v:val]'), ' or ')
198+
let expected = s:_type_name(a:expected_type)
165199
throw a:prefix . ': invalid type arguments were given ' .
166200
\ '(expected: ' . expected .
167-
\ ', got: ' . s:T.type_names[type(a:value)] . ')'
201+
\ ', got: ' . s:_type_name(type(a:value)) . ')'
168202
endif
169203
return
170204
endif
171-
if type(a:value) isnot a:expected_type
205+
if type(a:value) isnot# a:expected_type
172206
if a:0
173207
return a:1
174208
endif
175209
throw a:prefix . ': invalid type arguments were given ' .
176-
\ '(expected: ' . s:T.type_names[a:expected_type] .
177-
\ ', got: ' . s:T.type_names[type(a:value)] . ')'
210+
\ '(expected: ' . s:_type_name(a:expected_type) .
211+
\ ', got: ' . s:_type_name(type(a:value)) . ')'
178212
endif
179213
return a:value
180214
endfunction
@@ -196,7 +230,7 @@ function! s:_validate_assert(value, funclist, msg, prefix) abort
196230
endfunction
197231

198232
function! s:_call1(f, arg) abort
199-
if type(a:f) is s:TYPE.FUNC
233+
if type(a:f) is# v:t_func
200234
return call(a:f, [a:arg])
201235
else
202236
return map([a:arg], a:f)[0]

doc/vital/Validator/Args.txt

Lines changed: 22 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ INTRODUCTION |Vital.Validator.Args-introduction|
99
EXAMPLES |Vital.Validator.Args-examples|
1010
INTERFACE |Vital.Validator.Args-interface|
1111
FUNCTIONS |Vital.Validator.Args-functions|
12-
TYPES |Vital.Validator.Args-types|
1312
VALIDATOR OBJECT |Vital.Validator.Args-Validator-object|
1413

1514
==============================================================================
@@ -31,7 +30,7 @@ type() *Vital.Validator.Args-example-type*
3130
" s:func1() receives one number argument
3231
let s:func1_args =
3332
\ s:Validator.of('func1()')
34-
\.type(s:TYPE.NUMBER)
33+
\.type(v:t_number)
3534
function! s:func1(...) abort
3635
" validate() throws an exception when:
3736
" * arity is not 1
@@ -43,39 +42,39 @@ type() *Vital.Validator.Args-example-type*
4342
" s:func2() receives two number and string arguments
4443
let s:func2_args =
4544
\ s:Validator.of('func2()')
46-
\.type(s:TYPE.NUMBER, s:TYPE.STRING)
45+
\.type(v:t_number, v:t_string)
4746
<
4847
type(): Union types *Vital.Validator.Args-example-union-types*
4948
-------------------
5049
>
5150
" s:func3() receives one number or float argument
5251
let s:func3_args =
5352
\ s:Validator.of('func3()')
54-
\.type([s:TYPE.NUMBER, s:TYPE.FLOAT])
53+
\.type([v:t_number, v:t_float])
5554
<
5655
*Vital.Validator.Args-example-optional-arguments*
5756
type(): Optional arguments
5857
--------------------------
5958
>
6059
" s:func4() receives one string argument and zero or more optional arguments
61-
" (NOTE: if the last type is OPTARG, skip the rest arguments validations)
60+
" (NOTE: if the last type is optional argument, skip the rest arguments validations)
6261
let s:func4_args =
6362
\ s:Validator.of('func4()')
64-
\.type(s:TYPE.STRING, s:TYPE.OPTARG)
63+
\.type(v:t_string, 'option')
6564
6665
" if you want to check also the optional arguments, specify the types
67-
" after OPTARG (s:func5() receives exact 1-2 argument(s): Number [, Number])
66+
" after optional argument (s:func5() receives exact 1-2 argument(s): Number [, Number])
6867
let s:func5_args =
6968
\ s:Validator.of('func5()')
70-
\.type(s:TYPE.NUMBER, s:TYPE.OPTARG, s:TYPE.NUMBER)
69+
\.type(v:t_number, 'option', v:t_number)
7170
<
7271
type(): Any type *Vital.Validator.Args-example-any-type*
7372
----------------
7473
>
7574
" s:func6() receives one arbitrary type argument
7675
let s:func6_args =
7776
\ s:Validator.of('func6()')
78-
\.type(s:TYPE.ANY)
77+
\.type('any')
7978
<
8079
assert() *Vital.Validator.Args-example-assert*
8180
--------
@@ -85,7 +84,7 @@ assert() *Vital.Validator.Args-example-assert*
8584
" regardless of invoked order)
8685
let s:func7_args =
8786
\ s:Validator.of('func7()')
88-
\.type(s:TYPE.NUMBER)
87+
\.type(v:t_number)
8988
\.assert(1, 'v:val > 0',
9089
\ 'the first argument should be a positive number')
9190
function! s:func7(...) abort
@@ -99,7 +98,7 @@ assert() *Vital.Validator.Args-example-assert*
9998
10099
" Here is an example of Vim script's built-in function range()
101100
let s:range_args = validator.of('vital: Stream: range()')
102-
\.type(T.NUMBER, T.OPTARG, T.NUMBER, T.NUMBER)
101+
\.type(v:t_number, 'option', v:t_number, v:t_number)
103102
\.assert(3, 'v:val !=# 0', 'stride is zero')
104103
<
105104
==============================================================================
@@ -118,61 +117,30 @@ of({prefix} [, {enable}]) *Vital.Validator.Args.of()*
118117
" Validates arguments if 'g:myplugin#enable_debug' is non-zero.
119118
" Otherwise this does not validate arguments.
120119
let func_args = s:Validator.of('func()', g:myplugin#enable_debug)
121-
\.type(s:TYPE.NUMBER)
120+
\.type(v:t_number)
122121
function! s:func(...) abort
123122
let [n] = s:func_args.validate(a:000)
124123
125124
" ...
126125
endfunction
127126
<
128-
------------------------------------------------------------------------------
129-
TYPES *Vital.Validator.Args-types*
130-
131-
TYPE.NUMBER *Vital.Validator.Args-type-NUMBER*
132-
A |Number| argument.
133-
134-
TYPE.STRING *Vital.Validator.Args-type-STRING*
135-
A |String| argument.
136-
137-
TYPE.FUNC *Vital.Validator.Args-type-FUNC*
138-
A |Funcref| argument.
139-
140-
TYPE.LIST *Vital.Validator.Args-type-LIST*
141-
A |List| argument.
142-
143-
TYPE.DICT *Vital.Validator.Args-type-DICT*
144-
A |Dictionary| argument.
145-
146-
TYPE.FLOAT *Vital.Validator.Args-type-FLOAT*
147-
A |Float| argument.
148-
149-
TYPE.BOOL *Vital.Validator.Args-type-BOOL*
150-
A Boolean argument (|v:true| or |v:false|).
151-
152-
TYPE.NONE *Vital.Validator.Args-type-NONE*
153-
A None argument (|v:null| or |v:none|).
154-
155-
TYPE.JOB *Vital.Validator.Args-type-JOB*
156-
A |Job| argument.
157-
158-
TYPE.CHANNEL *Vital.Validator.Args-type-CHANNEL*
159-
A |Channel| argument.
160-
161-
TYPE.ANY *Vital.Validator.Args-type-ANY*
162-
An arbitrary type argument.
163-
164-
TYPE.OPTARG *Vital.Validator.Args-type-OPTARG*
165-
An optional argument (Vim script's "..." in :function arguments).
166-
If the last type is OPTARG, skip validation of rest arguments.
167-
But if any type(s) were given after OPTARG, check the type(s) and arity.
168-
169127
==============================================================================
170128
VALIDATOR OBJECT *Vital.Validator.Args-Validator-object*
171129

172130
Validator.type([{type} ...]) *Vital.Validator.Args-Validator.type()*
173131
Specify types of arguments.
132+
{type} is |Number| (like `type(42)`, `v:t_string`) or
133+
some special |String| values below.
134+
135+
"any"
136+
An arbitrary type argument.
137+
"option"
138+
An optional argument (Vim script's "..." in :function arguments).
139+
If the last type is optional argument, skip validation of rest arguments.
140+
But if any type(s) were given after optional argument, check the type(s)
141+
and arity.
142+
See examples for |Vital.Validator.Args-example-optional-arguments|.
174143

175-
See |Vital.Validator.Args-types| for all available types.
176144
See |Vital.Validator.Args-example-type| for examples.
177145

178146
*Vital.Validator.Args-Validator.assert()*

0 commit comments

Comments
 (0)