Skip to content

Commit 2835211

Browse files
author
Zachary Norman
committed
Init
1 parent affc621 commit 2835211

File tree

3 files changed

+284
-1
lines changed

3 files changed

+284
-1
lines changed

LICENSE.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
The MIT License (MIT)
2+
3+
(c) 2018 Harris Geospatial Solutions, Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.TRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,41 @@
11
# InputValidator
2-
Simple routine that validates parameters or variables.
2+
3+
Routine that can be used to perform input validation for any routine to ensure that parameters are present or a certain type. You can specify each possible type that the data value can represent and optionally require that the value have all of the types. Here are the generic types that can be used:
4+
5+
- required : If set, the value must be present and defined.
6+
7+
- array : If set, value supplied must be an array.
8+
9+
- number : If set, value supplied must be a number.
10+
11+
This routine uses IDL's `isa` function to make the comparison so, in addition to the types above, you can specify anything else that can pass as an argument. Some exampled are: byte, int, long, float, hash, orderedhash, enviraster. They can be any IDL-specific data type and it can also be the type of object such as idlgrwindow or any named, custom object type.
12+
13+
## Examples
14+
15+
See the PRO code on descriptions of the keywords.
16+
17+
### Validate that an argument is present and defined:
18+
19+
```idl
20+
inputValidator, hash('nameOfArg', 'required')
21+
```
22+
23+
Note that this means the variable is not undefined (i.e. defined in the IDL code or passed in as a parameter). A variable defined as `!NULL` will still pass.
24+
25+
### Validate that an argument is a string array and present
26+
27+
```idl
28+
inputValidator, hash('nameOfArg', ['string', 'array', 'required'])
29+
```
30+
31+
### Validate that an argument, if present is a double array
32+
33+
```idl
34+
inputValidator, hash('nameOfArg', ['double', 'array'])
35+
```
36+
37+
## License
38+
39+
(c) 2018 Harris Geospatial Solutions, Inc.
40+
41+
Licensed under MIT, see LICENSE.txt for more details.

inputvalidator.pro

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
;h+
2+
; (c) 2018 Harris Geospatial Solutions, Inc.
3+
;
4+
; Licensed under MIT, see LICENSE.txt for more details.
5+
;h-
6+
7+
;+
8+
; :Examples:
9+
;
10+
; # Validate that an argument is present and defined:
11+
;
12+
; inputValidator, hash('nameOfArg', 'required')
13+
;
14+
; Note that this means the variable is not undefined (i.e. defined in
15+
; the IDL code or passed in as a parameter). A variable
16+
; defined as `!NULL` will still pass.
17+
;
18+
; # Validate that an argument is a string array and present
19+
;
20+
; inputValidator, hash('nameOfArg', ['string', 'array', 'required'])
21+
;
22+
; # Validate that an argument, if present is a double array
23+
;
24+
; inputValidator, hash('nameOfArg', ['double', 'array'])
25+
;
26+
;
27+
;
28+
; :Description:
29+
; Simple routine that can be used to perform input validation
30+
; for any routine to ensure that parameters are present or a
31+
; certain type. You can specify each possible type that the
32+
; data value can represent and optionally require that the value have
33+
; all of the types. Here are the generic types that can be used:
34+
;
35+
; - required : If set, the value must be present and defined.
36+
;
37+
; - array : If set, value supplied must be an array.
38+
;
39+
; - number : If set, value supplied must be a number.
40+
;
41+
; This routine uses IDL's `isa` function to make the comparison so,
42+
; in addition to the types above, you can specify anything else that
43+
; can pass as an argument. Some exampled are: byte, int, long, float,
44+
; hash, orderedhash, enviraster. They can be any IDL-specific data
45+
; type and it can also be the type of object such as idlgrwindow or
46+
; any named, custom object type.
47+
;
48+
; :Params:
49+
; requirements: in, optional/required, type=hash/orderedhash
50+
; Hash type object with key/value pair representing the variable
51+
; name and a string/atring array representing the different types
52+
; that must be present.
53+
;
54+
; This argument is optional only if the `CALLED_FROM` keyword is set.
55+
;
56+
; :Keywords:
57+
; CALLED_FROM: in, optional, type=string
58+
; If present, the validator makes sure that the routine was called from
59+
; the specified function or procedure. The string comparison is case insensitive.
60+
; LEVEL: in, optional, type=uint
61+
; Specify the scope level (with reference to where this was called, and not
62+
; in this scope) for which you want the prefix of the error message to appear.
63+
; For example, if you specify -1, then the prefix will be from the parent of the
64+
; routine that calls this procedure.
65+
; PRINT_NAME: in, optional, type=string
66+
; If specified, then this value will be printed in place of the variable names
67+
; in the requirements hash. This is meant for use with one variable at a time.
68+
; PRINT_PREFIX: in, optional, type=string, default='Variable'
69+
; Set this to a string that you will want printed before any error messages. The
70+
; default value is "Variable". This is provided if you are trying to validate
71+
; an existing variable from something like a hash so you can print the term
72+
; "Key" which is the correct term.
73+
;
74+
; :Author: Zachary Norman - GitHub : znorman-harris
75+
;-
76+
pro inputValidator, requirements,$
77+
CALLED_FROM = called_from,$
78+
LEVEL = level,$
79+
PRINT_NAME = print_name,$
80+
PRINT_PREFIX = print_prefix
81+
82+
compile_opt idl2, hidden
83+
on_error, 2
84+
85+
;check if we have a scope level
86+
if (level ne !NULL) then begin
87+
scopeLevel = -1 + level
88+
endif else begin
89+
scopeLevel = -1
90+
endelse
91+
92+
;check our callback
93+
if keyword_set(called_from) then begin
94+
if ~isa(called_from, /STRING) then begin
95+
message, 'CALLED_FROM specified, but supplied value is not a string, required!'
96+
endif
97+
98+
trace = scope_traceback()
99+
from = strlowcase(trace[-3])
100+
if (strpos(from, strlowcase(called_from)) ne 0) then begin
101+
message, 'Routine not called from expected source!', LEVEL = scopeLevel
102+
endif
103+
104+
;return if nothing else to do
105+
if (n_elements(requriements) eq 0) then begin
106+
return
107+
endif
108+
endif
109+
110+
;make sure we have something to check
111+
if (n_elements(requirements) eq 0) then begin
112+
message, 'requirements argument not provided or has no key/value pairs, required!'
113+
endif
114+
115+
if ~isa(requirements, 'hash') then begin
116+
message, 'requirements argument provided, but it is not a hash or orderedhash, required!'
117+
endif
118+
119+
;get the prefix for printing
120+
if keyword_set(print_prefix) then begin
121+
pName = strtrim(print_prefix,2)
122+
endif else begin
123+
pName = 'Variable'
124+
endelse
125+
126+
;get our scope level
127+
level = scope_level()
128+
129+
;loop over each element
130+
foreach reqs, requirements, varName do begin
131+
;init all of our basic flags
132+
required = 0
133+
array = 0
134+
number = 0
135+
136+
;flag for if we need all data types specified to be present
137+
;otherwise just need one
138+
all = 0
139+
140+
;init array to hold data types
141+
;use array bc overhead will be small
142+
dTypes = []
143+
typeTotal = 0
144+
145+
;get the name that we want to print
146+
if keyword_set(print_name) then begin
147+
varPrint = strtrim(print_name,2)
148+
endif else begin
149+
varPrint = varName
150+
endelse
151+
152+
;loop over our requirements and make the proper flags
153+
foreach req, strlowcase(reqs) do begin
154+
case (req) of
155+
;basic variable information
156+
'required' : required = 1
157+
'array' : array = 1
158+
'number' : number = 1
159+
'all' : all = 1
160+
161+
else:begin
162+
dTypes = [dTypes, req]
163+
end
164+
endcase
165+
endforeach
166+
167+
;check if there are other types to check
168+
types = n_elements(dTypes) gt 0
169+
170+
;check to see if we have a null variable
171+
catch, err
172+
if (err ne 0) then begin
173+
isNull = 1
174+
endif else begin
175+
value = scope_varfetch(varName, LEVEL = level - 1)
176+
isNull = isa(value, /NULL) ; TODO: add info for hash keys
177+
case (1) of
178+
;isa(value, 'hash'): isNull = n_elements(value) eq 0
179+
else:;do nothing
180+
endcase
181+
endelse
182+
catch, /CANCEL
183+
184+
;check if present and required
185+
if (required AND isNull) then begin
186+
message, pName + ' "' + varPrint + '" has not been defined, required!', LEVEL = scopeLevel
187+
endif else begin
188+
if (isNull) then begin
189+
continue
190+
endif
191+
endelse
192+
193+
;check for array
194+
if (array) then begin
195+
if ~isa(value, /ARRAY) then begin
196+
message, pName + ' "' + varPrint + '" is not an array, required!', LEVEL = scopeLevel
197+
endif
198+
endif
199+
200+
;check for number
201+
if (number) then begin
202+
nflag = isa(value, /NUMBER)
203+
if (~nFlag AND ~types) then begin
204+
message, pName + ' "' + varPrint + '" is not a number, required!', LEVEL = scopeLevel
205+
endif
206+
typeTotal += nFlag
207+
endif
208+
209+
;check all of the data types
210+
if (n_elements(dTypes) gt 0) then begin
211+
foreach type, dTypes do begin
212+
flag = isa(value, type)
213+
if (all AND ~flag) then begin
214+
message, pName + ' "' + varPrint + '" is not a "' + type + '", required!', LEVEL = scopeLevel
215+
endif else begin
216+
typeTotal += flag
217+
endelse
218+
endforeach
219+
endif
220+
221+
;validate input
222+
if ((n_elements(dTypes) gt 0) OR number) then begin
223+
case (1) of
224+
(all) : nReq = n_elements(dtypes) + number
225+
else : nReq = 1
226+
endcase
227+
228+
;check if we were none of the potential data types
229+
if ~(typeTotal ge nReq) then begin
230+
message, pName + ' "' + varPrint + '" does not match any optional data types. Optional types are: ' + $
231+
string(10b) + strjoin(dTypes, string(10b)), LEVEL = scopeLevel
232+
endif
233+
endif
234+
endforeach
235+
end

0 commit comments

Comments
 (0)