the base
This commit is contained in:
8
lib/data/paramsparser/get_params.v
Normal file
8
lib/data/paramsparser/get_params.v
Normal file
@@ -0,0 +1,8 @@
|
||||
module paramsparser
|
||||
|
||||
// Looks for a string of params in the parameters. If it doesn't exist this function will return an error.
|
||||
// Furthermore an error will be returned if the params is not properly formatted
|
||||
pub fn (params &Params) get_params(key string) !Params {
|
||||
mut valuestr := params.get(key)!
|
||||
return parse(valuestr)!
|
||||
}
|
||||
25
lib/data/paramsparser/jsonschema.v
Normal file
25
lib/data/paramsparser/jsonschema.v
Normal file
@@ -0,0 +1,25 @@
|
||||
module paramsparser
|
||||
|
||||
// import freeflowuniverse.herolib.data.jsonschema
|
||||
|
||||
// pub struct ParamsPub {
|
||||
// pub mut:
|
||||
// params []Param
|
||||
// args []string //are commands without key/val, best not to use
|
||||
// }
|
||||
|
||||
// pub struct ParamPub {
|
||||
// pub:
|
||||
// key string
|
||||
// value string
|
||||
// }
|
||||
|
||||
// pub fn (mut params Params) json_schema() jsonschema.Schema {
|
||||
// return jsonschema.Schema {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn json_import(data string) !Params {
|
||||
// return json.decode(Params, data)
|
||||
// }
|
||||
144
lib/data/paramsparser/params.v
Normal file
144
lib/data/paramsparser/params.v
Normal file
@@ -0,0 +1,144 @@
|
||||
module paramsparser
|
||||
|
||||
@[heap]
|
||||
pub struct Params {
|
||||
pub mut:
|
||||
params []Param
|
||||
args []string
|
||||
comments []string
|
||||
}
|
||||
|
||||
pub struct Param {
|
||||
pub mut:
|
||||
key string
|
||||
value string
|
||||
comment string
|
||||
}
|
||||
|
||||
// get params from txt, same as parse()
|
||||
pub fn new(txt string) !Params {
|
||||
return parse(txt)!
|
||||
}
|
||||
|
||||
pub fn new_from_dict(kwargs map[string]string) !Params {
|
||||
mut p := Params{}
|
||||
for key, val in kwargs {
|
||||
p.set(key, val)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
pub fn new_params() Params {
|
||||
return Params{}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) delete(key string) {
|
||||
key2 := key.to_lower().trim_space()
|
||||
if params.exists(key) {
|
||||
mut params_out := []Param{}
|
||||
for p in params.params {
|
||||
if p.key != key2 {
|
||||
params_out << p
|
||||
}
|
||||
}
|
||||
params.params = params_out
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) set(key string, value string) {
|
||||
key2 := key.to_lower().trim_space().trim_left('/')
|
||||
params.delete(key2)
|
||||
params.params << Param{
|
||||
key: key2
|
||||
value: str_normalize(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) set_with_comment(key string, value string, comment string) {
|
||||
key2 := key.to_lower().trim_space().trim_left('/')
|
||||
params.delete(key2)
|
||||
params.params << Param{
|
||||
key: key2
|
||||
value: str_normalize(value)
|
||||
comment: comment_normalize(comment)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) delete_arg(key string) {
|
||||
key2 := key.to_lower().trim_space()
|
||||
if params.exists_arg(key2) {
|
||||
params.args.delete(params.args.index(key2))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) set_arg(value string) {
|
||||
mut value2 := value.trim(" '").trim_left('/')
|
||||
value2 = value2.replace('<<BR>>', '\n')
|
||||
value2 = value2.replace('<BR>', '\n')
|
||||
if !params.exists_arg(value2) {
|
||||
params.args << value2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) set_arg_with_comment(value string, comment string) {
|
||||
value2 := value.trim(" '").trim_left('/')
|
||||
if !params.exists_arg(str_normalize(value2)) {
|
||||
params.args << value2
|
||||
if comment.len > 0 {
|
||||
params.comments << comment_normalize(comment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn str_normalize(txt_ string) string {
|
||||
mut txt := txt_
|
||||
txt = txt.replace('\\\\n', '\n')
|
||||
txt = txt.replace("\\'", "'")
|
||||
txt = txt.replace('<<BR>>', '\n')
|
||||
txt = txt.replace('<BR>', '\n') // console.print_debug(txt)
|
||||
return txt.trim_space()
|
||||
}
|
||||
|
||||
fn comment_normalize(txt_ string) string {
|
||||
mut txt := str_normalize(txt_)
|
||||
return txt.trim_space().trim_right('-').trim_space()
|
||||
}
|
||||
|
||||
// parse new txt as params and merge into params
|
||||
pub fn (mut params Params) add(txt string) ! {
|
||||
paramsnew := parse(txt)!
|
||||
for p in paramsnew.params {
|
||||
params.set(p.key, p.value)
|
||||
}
|
||||
for a in paramsnew.args {
|
||||
params.set_arg(a)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) merge(params_to_merge Params) ! {
|
||||
for p in params_to_merge.params {
|
||||
params.set(p.key, p.value)
|
||||
}
|
||||
for a in params_to_merge.args {
|
||||
params.set_arg(a)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (p Params) empty() bool {
|
||||
if p.params.len == 0 && p.args.len == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (p Params) heroscript() string {
|
||||
mut out := ''
|
||||
out = p.export(
|
||||
presort: ['id', 'cid', 'oid', 'name']
|
||||
postsort: ['mtime', 'ctime', 'time']
|
||||
indent: ' '
|
||||
maxcolsize: 30
|
||||
multiline: true
|
||||
)
|
||||
return out
|
||||
}
|
||||
41
lib/data/paramsparser/params_currency.v
Normal file
41
lib/data/paramsparser/params_currency.v
Normal file
@@ -0,0 +1,41 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.data.currency
|
||||
|
||||
// TODO: fix if necessary
|
||||
// see currency object, gets it from params
|
||||
pub fn (params &Params) get_currencyamount(key string) !currency.Amount {
|
||||
valuestr := params.get(key)!
|
||||
return currency.amount_get(valuestr)!
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_currencyamount_default(key string, defval string) !currency.Amount {
|
||||
if params.exists(key) {
|
||||
return params.get_currencyamount(key)!
|
||||
}
|
||||
return currency.amount_get(defval)!
|
||||
}
|
||||
|
||||
// get currency expressed in float in line to currency passed
|
||||
pub fn (params &Params) get_currencyfloat(key string) !f64 {
|
||||
valuestr := params.get(key)!
|
||||
a := currency.amount_get(valuestr)!
|
||||
return a.val
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_currencyfloat_default(key string, defval f64) !f64 {
|
||||
if params.exists(key) {
|
||||
return params.get_currencyfloat(key)!
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
// TODO: this probably does not belong here
|
||||
// fn (mut cs Currency) default_set(cur string, usdval f64) {
|
||||
// cur2 := cur.trim_space().to_upper()
|
||||
// mut c1 := Currency{
|
||||
// name: cur2
|
||||
// usdval: usdval
|
||||
// }
|
||||
// cs.currency[cur2] = &c1
|
||||
// }
|
||||
50
lib/data/paramsparser/params_currency_test.v
Normal file
50
lib/data/paramsparser/params_currency_test.v
Normal file
@@ -0,0 +1,50 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.data.currency
|
||||
import os
|
||||
|
||||
const testparams = Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'dollars'
|
||||
value: '100USD'
|
||||
},
|
||||
Param{
|
||||
key: 'euros'
|
||||
value: '100EUR'
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn test_get_currencyamount() ! {
|
||||
// testusd
|
||||
os.setenv('OFFLINE', 'true', true)
|
||||
mut amount := testparams.get_currencyamount('dollars')!
|
||||
assert amount.currency.name == 'USD'
|
||||
assert amount.currency.usdval == 1.0
|
||||
assert amount.val == 100.0
|
||||
|
||||
// testeuro
|
||||
amount = testparams.get_currencyamount('euros')!
|
||||
assert amount.currency.name == 'EUR'
|
||||
assert amount.currency.usdval >= 0.9 // may need revision in future
|
||||
assert amount.val == 100.0
|
||||
}
|
||||
|
||||
fn test_get_currencyamount_default() ! {
|
||||
// testeuro
|
||||
os.setenv('OFFLINE', 'true', true)
|
||||
mut amount := testparams.get_currencyamount_default('na', '20EUR')!
|
||||
assert amount.currency.name == 'EUR'
|
||||
assert amount.currency.usdval >= 0.9 // may need revision in future
|
||||
assert amount.val == 20
|
||||
}
|
||||
|
||||
fn test_get_currency_float() ! {
|
||||
// todo
|
||||
// testeuro
|
||||
// mut amount := testparams.get_currencyamount_default('na', '20EUR')!
|
||||
// assert amount.currency.name == 'EUR'
|
||||
// assert amount.currency.usdval > 1 // may need revision in future
|
||||
// assert amount.val == 20
|
||||
}
|
||||
31
lib/data/paramsparser/params_exists.v
Normal file
31
lib/data/paramsparser/params_exists.v
Normal file
@@ -0,0 +1,31 @@
|
||||
module paramsparser
|
||||
|
||||
// check if kwarg exist
|
||||
// line:
|
||||
// arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok
|
||||
// arg1 is an arg
|
||||
// description is a kwarg
|
||||
pub fn (params &Params) exists(key_ string) bool {
|
||||
key := key_.to_lower().trim_space()
|
||||
for p in params.params {
|
||||
if p.key == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// check if arg exist (arg is just a value in the string e.g. red, not value:something)
|
||||
// line:
|
||||
// arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok
|
||||
// arg1 is an arg
|
||||
// description is a kwarg
|
||||
pub fn (params &Params) exists_arg(key_ string) bool {
|
||||
key := key_.to_lower().trim_space()
|
||||
for p in params.args {
|
||||
if p == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
21
lib/data/paramsparser/params_exists_test.v
Normal file
21
lib/data/paramsparser/params_exists_test.v
Normal file
@@ -0,0 +1,21 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_params_exists() {
|
||||
test := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
key3: val3
|
||||
arg1
|
||||
'
|
||||
params := new(test)!
|
||||
assert params.exists('key1') == true
|
||||
assert params.exists('KeY1') == true
|
||||
assert params.exists('key2') == true
|
||||
assert params.exists('key3') == true
|
||||
assert params.exists('key4') == false
|
||||
assert params.exists('arg1') == false
|
||||
|
||||
assert params.exists_arg('arg1') == true
|
||||
assert params.exists_arg('ArG1') == true
|
||||
assert params.exists_arg('key1') == false
|
||||
}
|
||||
297
lib/data/paramsparser/params_export_import.v
Normal file
297
lib/data/paramsparser/params_export_import.v
Normal file
@@ -0,0 +1,297 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import crypto.sha256
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
struct ParamExportItem {
|
||||
mut:
|
||||
key string
|
||||
value string
|
||||
comment string
|
||||
firstline bool // done by us to know if it still fits on the first line
|
||||
isarg bool
|
||||
}
|
||||
|
||||
fn (mut item ParamExportItem) check() {
|
||||
// should not be needed in theory
|
||||
item.value = item.value.replace('\\n', '\n').trim_space()
|
||||
item.comment = item.comment.replace('\\n', '\n').trim_space()
|
||||
}
|
||||
|
||||
// is to put on first line typically
|
||||
fn (item ParamExportItem) oneline() string {
|
||||
if item.isarg {
|
||||
return '${item.key}'
|
||||
} else if item.comment.len > 0 && item.value.len == 0 {
|
||||
comment := item.comment.replace('\n', '\\n')
|
||||
return '//${comment}-/'
|
||||
} else {
|
||||
txt := '${item.key}:${item.getval()}'
|
||||
if item.comment.len > 0 {
|
||||
comment := item.comment.replace('\n', '\\n')
|
||||
return '//${comment}-/ ${txt}'
|
||||
} else {
|
||||
return txt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (item ParamExportItem) getval() string {
|
||||
mut val := item.value
|
||||
val = val.replace('\n', '\\n')
|
||||
if val.contains(' ') || val.contains(':') || val.contains('\\n')
|
||||
|| item.key in ['cid', 'oid', 'gid'] {
|
||||
val = val.replace('"', "'")
|
||||
if val.contains("'") {
|
||||
val = val.replace("'", "\\'")
|
||||
}
|
||||
val = "'${val}'"
|
||||
}
|
||||
if val == '' {
|
||||
// so empty strings are written as empty quotes
|
||||
val = "''"
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// to put after the first line
|
||||
fn (item ParamExportItem) afterline() string {
|
||||
mut out := ''
|
||||
if item.value.contains('\n') {
|
||||
if item.comment.len > 0 {
|
||||
out += texttools.indent(item.comment, ' // ')
|
||||
}
|
||||
out += '${item.key}:\'\n'
|
||||
out += texttools.indent(item.value, ' ')
|
||||
out += " '"
|
||||
} else {
|
||||
if item.comment.contains('\n') {
|
||||
out += texttools.indent(item.comment, '// ')
|
||||
}
|
||||
out += '${item.key}:${item.getval()}'
|
||||
if item.comment.len > 0 && !item.comment.contains('\n') {
|
||||
out += ' //${item.comment}'
|
||||
}
|
||||
}
|
||||
return out.trim_right(' \n')
|
||||
}
|
||||
|
||||
// will first do the args, then the kwargs
|
||||
// presort means will always come first
|
||||
fn (p Params) export_helper(args_ ExportArgs) ![]ParamExportItem {
|
||||
mut args := args_
|
||||
if args.sortdefault && args.presort.len == 0 {
|
||||
args.presort = ['id', 'cid', 'gid', 'oid', 'name', 'alias']
|
||||
}
|
||||
if p.args.len > 0 && args.args_allowed == false {
|
||||
return error('args are not allowed')
|
||||
}
|
||||
mut args_done := []string{}
|
||||
mut order := []string{}
|
||||
mut order_delayed := []string{}
|
||||
mut keys_to_be_sorted := []string{}
|
||||
mut keys_existing := []string{}
|
||||
mut dict_param := map[string]ParamExportItem{}
|
||||
mut result_params := []ParamExportItem{} // the ones who always need to come first
|
||||
mut firstlinesize := 0
|
||||
|
||||
// comments are always 1st
|
||||
if args.comments_remove == false {
|
||||
for comment in p.comments {
|
||||
result_params << ParamExportItem{
|
||||
key: ''
|
||||
isarg: false
|
||||
comment: comment
|
||||
firstline: args.oneline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// args are always 2nd
|
||||
if args.args_remove == false {
|
||||
mut args2 := p.args.clone()
|
||||
args2.sort()
|
||||
for mut arg in args2 {
|
||||
arg = texttools.name_fix(arg)
|
||||
if arg in args_done {
|
||||
return error('Double arg: ${arg}')
|
||||
}
|
||||
args_done << arg
|
||||
result_params << ParamExportItem{
|
||||
key: arg
|
||||
isarg: true
|
||||
comment: ''
|
||||
firstline: true
|
||||
}
|
||||
firstlinesize += arg.len + 1
|
||||
}
|
||||
}
|
||||
|
||||
// now we will process the params (comments and args done)
|
||||
for param in p.params {
|
||||
// skip empty parameter when exporting
|
||||
if args.skip_empty && val_is_empty(param.value) {
|
||||
continue
|
||||
}
|
||||
mut key := texttools.name_fix(param.key)
|
||||
keys_existing << key
|
||||
if key !in args.presort && key !in args.postsort {
|
||||
keys_to_be_sorted << key
|
||||
}
|
||||
dict_param[key] = ParamExportItem{
|
||||
key: key
|
||||
value: param.value
|
||||
comment: param.comment
|
||||
firstline: false
|
||||
}
|
||||
}
|
||||
|
||||
keys_to_be_sorted.sort()
|
||||
for key in args.presort.reverse() {
|
||||
if key in keys_existing {
|
||||
keys_to_be_sorted.prepend(key) // make sure we have the presorted once first
|
||||
}
|
||||
}
|
||||
for key in args.postsort {
|
||||
if key in keys_existing {
|
||||
keys_to_be_sorted << key // now add the ones at the end
|
||||
}
|
||||
}
|
||||
|
||||
// now we have all keys sorted
|
||||
for keyname in keys_to_be_sorted {
|
||||
param_export_item := dict_param[keyname] // or { panic("bug: can't find $keyname in dict in export/import for params.") }}
|
||||
val := param_export_item.value
|
||||
// if val.len == 0 {
|
||||
// continue
|
||||
// }
|
||||
if val.len > 25 || param_export_item.comment.len > 0 || firstlinesize > args.maxcolsize
|
||||
|| val.contains('\\n') {
|
||||
order_delayed << keyname
|
||||
continue
|
||||
}
|
||||
order << keyname
|
||||
firstlinesize += keyname.len + val.len + 2
|
||||
}
|
||||
|
||||
for key in order {
|
||||
mut param_export_item := dict_param[key] // or { panic("bug: can't find $keyname in dict in export/import for params.") }
|
||||
param_export_item.check()
|
||||
param_export_item.firstline = true
|
||||
result_params << param_export_item
|
||||
}
|
||||
|
||||
for key in order_delayed {
|
||||
mut param_export_item := dict_param[key] // or { panic("bug: can't find $keyname in dict in export/import for params.") }
|
||||
param_export_item.check()
|
||||
result_params << param_export_item
|
||||
}
|
||||
|
||||
return result_params
|
||||
}
|
||||
|
||||
fn val_is_empty(val string) bool {
|
||||
return val == '' || val == '[]'
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct ExportArgs {
|
||||
pub mut:
|
||||
presort []string
|
||||
postsort []string
|
||||
sortdefault bool = true // if set will do the default sorting
|
||||
args_allowed bool = true
|
||||
args_remove bool
|
||||
comments_remove bool
|
||||
maxcolsize int = 120
|
||||
oneline bool // if set then will put all on oneline
|
||||
multiline bool = true // if we will put the multiline strings as multiline in output
|
||||
indent string
|
||||
pre string // e.g. can be used to insert action e.g. !!remark.define (pre=prefix on the first line)
|
||||
skip_empty bool
|
||||
}
|
||||
|
||||
// standardised export format .
|
||||
// .
|
||||
// it outputs a default way sorted and readable .
|
||||
//```js
|
||||
// presort []string
|
||||
// postsort []string
|
||||
// sortdefault bool = true //if set will do the default sorting
|
||||
// args_allowed bool = true
|
||||
// args_remove bool
|
||||
// comments_remove bool
|
||||
// maxcolsize int = 120
|
||||
// oneline bool // if set then will put all on oneline
|
||||
// multiline bool = true // if we will put the multiline strings as multiline in output
|
||||
// indent string
|
||||
// pre string // e.g. can be used to insert action e.g. !!remark.define (pre=prefix on the first line)
|
||||
//```
|
||||
pub fn (p Params) export(args ExportArgs) string {
|
||||
items := p.export_helper(args) or { panic(err) }
|
||||
mut out_pre := []string{}
|
||||
mut out := []string{}
|
||||
mut out_post := []string{}
|
||||
for item in items {
|
||||
if args.oneline {
|
||||
out << item.oneline()
|
||||
} else {
|
||||
if item.key == '' && item.comment.len > 0 {
|
||||
out_pre << texttools.indent(item.comment, '// ')
|
||||
continue
|
||||
}
|
||||
if item.isarg {
|
||||
assert item.comment.len == 0
|
||||
out << item.key
|
||||
continue
|
||||
}
|
||||
if item.firstline {
|
||||
out << item.oneline()
|
||||
} else {
|
||||
out_post << '${args.indent}${item.afterline()}'
|
||||
}
|
||||
}
|
||||
}
|
||||
mut outstr := ''
|
||||
if args.oneline {
|
||||
if args.pre.len > 0 {
|
||||
outstr += args.pre + ' '
|
||||
}
|
||||
outstr += out.join(' ')
|
||||
} else {
|
||||
comments := out_pre.join('\n')
|
||||
oneliner := out.join(' ') + '\n'
|
||||
poststr := out_post.join('\n')
|
||||
if args.pre.len > 0 {
|
||||
outstr += comments
|
||||
outstr += args.pre + ' ' + oneliner
|
||||
outstr += poststr
|
||||
} else {
|
||||
outstr += comments
|
||||
outstr += oneliner
|
||||
outstr += poststr
|
||||
}
|
||||
}
|
||||
return outstr
|
||||
}
|
||||
|
||||
pub fn importparams(txt string) !Params {
|
||||
return parse(txt)
|
||||
}
|
||||
|
||||
pub fn (p Params) equal(p2 Params) bool {
|
||||
a := p.export()
|
||||
b := p2.export()
|
||||
// console.print_debug("----------------\n$a")
|
||||
// console.print_debug("================\n$b")
|
||||
// console.print_debug("----------------")
|
||||
return a == b
|
||||
}
|
||||
|
||||
// returns a unique sha256 in hex, will allways return the same independent of order of params
|
||||
pub fn (p Params) hexhash() string {
|
||||
a := p.export(oneline: true, multiline: false)
|
||||
console.print_debug(a)
|
||||
return sha256.hexhash(a)
|
||||
}
|
||||
293
lib/data/paramsparser/params_export_test.v
Normal file
293
lib/data/paramsparser/params_export_test.v
Normal file
@@ -0,0 +1,293 @@
|
||||
module paramsparser
|
||||
|
||||
import crypto.sha256
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
const textin5 = "
|
||||
//this is first comment (line1)
|
||||
//this is 2nd comment (line2)
|
||||
red green blue
|
||||
id:a5 name6:aaaaa //comment_line2
|
||||
name:'need to do something 1'
|
||||
//comment
|
||||
description:'
|
||||
## markdown works in it
|
||||
|
||||
description can be multiline
|
||||
lets see what happens
|
||||
|
||||
- a
|
||||
- something else
|
||||
|
||||
### subtitle
|
||||
|
||||
```python
|
||||
#even code block in the other block, crazy parsing for sure
|
||||
def test():
|
||||
print()
|
||||
```
|
||||
'
|
||||
name2: test
|
||||
name3: hi name10:'this is with space' name11:aaa11
|
||||
|
||||
name4: 'aaa'
|
||||
|
||||
//somecomment
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
fn test_export_helper1() {
|
||||
params := parse(textin5) or { panic(err) }
|
||||
|
||||
// presort []string
|
||||
// args_allowed bool=true
|
||||
// maxcolsize int = 80
|
||||
// oneline bool //if set then will put all on oneline
|
||||
// multiline bool = true //if we will put the multiline strings as multiline in output
|
||||
// indent string
|
||||
o := params.export_helper(maxcolsize: 600) or { panic(err) }
|
||||
// console.print_debug('${o}')
|
||||
assert o.len == 14
|
||||
// console.print_debug(o.len)
|
||||
assert o[o.len - 1].firstline == false
|
||||
// console.print_debug(o[o.len - 2])
|
||||
assert o[o.len - 2].firstline == false
|
||||
assert o[o.len - 1].key == 'name5'
|
||||
// assert o[o.len - 2].key == 'name6'
|
||||
assert o[0].comment.len > 0
|
||||
assert o[0].key == ''
|
||||
assert o[0].value == ''
|
||||
assert sha256.hexhash(o.str()) == '3b3f7830145d5d1dfb01aea879ad052350f2ec4e921c2ee6cbfacbb0f1029ebd'
|
||||
}
|
||||
|
||||
fn test_export_helper2() {
|
||||
params := parse(textin5) or { panic(err) }
|
||||
o := params.export_helper(maxcolsize: 60) or { panic(err) }
|
||||
|
||||
assert sha256.hexhash(o.str()) == '0bb7fb65107a69b1a0296dbdd1b0505b178e8bebdb33d2cec307f411b05c6033'
|
||||
}
|
||||
|
||||
const textin6 = "
|
||||
//mycomment
|
||||
red blue
|
||||
id:a6 name6:aaaaa
|
||||
|
||||
name4: 'a aa' //comment_line2
|
||||
|
||||
//somecomment
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
fn test_export_6() {
|
||||
params := parse(textin6) or { panic(err) }
|
||||
o := params.export_helper(maxcolsize: 60) or { panic(err) }
|
||||
|
||||
paramsout := params.export()
|
||||
|
||||
console.print_debug(paramsout)
|
||||
|
||||
console.print_debug("EXPECT:
|
||||
// mycomment
|
||||
blue red id:a6 name6:aaaaa
|
||||
name4:'a aa' //comment_line2
|
||||
name5:aab //somecomment
|
||||
")
|
||||
|
||||
assert sha256.hexhash(paramsout) == '7b45308e1b5e729e78c8b9b12cda6cd6da4919005a7d54ecc45f07a2d26c304b'
|
||||
}
|
||||
|
||||
const textin7 = "
|
||||
//mycomment
|
||||
red blue
|
||||
id:a7 name6:aaaaa
|
||||
|
||||
name4: '
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
|
||||
//somecomment
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
fn test_export_7() {
|
||||
params := parse(textin7) or { panic(err) }
|
||||
o := params.export_helper(maxcolsize: 60) or { panic(err) }
|
||||
console.print_debug('${o}')
|
||||
|
||||
paramsout := params.export()
|
||||
|
||||
console.print_debug("EXPECT:
|
||||
// mycomment
|
||||
blue red id:a7 name6:aaaaa
|
||||
name4:'
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
name5:aab //somecomment
|
||||
")
|
||||
|
||||
console.print_debug(paramsout)
|
||||
|
||||
assert sha256.hexhash(paramsout) == '0407be8ca3abb9214e3579c40ae1b02297cf05bf50ae687ea6b2b57bb8c5a54e'
|
||||
}
|
||||
|
||||
const textin8 = "
|
||||
//mycomment
|
||||
red blue
|
||||
id:a8 name6:aaaaa
|
||||
|
||||
name4: '
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
|
||||
//somecomment
|
||||
//
|
||||
//multiline
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
fn test_export_8() {
|
||||
params := parse(textin8) or { panic(err) }
|
||||
o := params.export_helper(maxcolsize: 60) or { panic(err) }
|
||||
console.print_debug('${o}')
|
||||
|
||||
paramsout := params.export()
|
||||
|
||||
console.print_debug(paramsout)
|
||||
|
||||
console.print_debug("EXPECT:
|
||||
// mycomment
|
||||
blue red id:a8 name6:aaaaa
|
||||
name4:'
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
// somecomment
|
||||
//
|
||||
// multiline
|
||||
name5:aab
|
||||
")
|
||||
|
||||
assert sha256.hexhash(paramsout) == 'ed1188df660ab6c69ea5cb967df86e7f356b513045c66e8ebb109763f3110ea2'
|
||||
}
|
||||
|
||||
const textin9 = "
|
||||
//mycomment
|
||||
red blue
|
||||
id:a9 name6:aaaaa
|
||||
|
||||
name4: '
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
|
||||
//somecomment
|
||||
//
|
||||
//multiline
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
fn test_export_9() {
|
||||
params := parse(textin9) or { panic(err) }
|
||||
o := params.export_helper(oneline: true) or { panic(err) }
|
||||
console.print_debug('${o}')
|
||||
|
||||
console.print_debug("EXPECT:
|
||||
// mycomment
|
||||
!!remark.define blue red id:a9 name6:aaaaa
|
||||
name4:'
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
// somecomment
|
||||
//
|
||||
// multiline
|
||||
name5:aab
|
||||
")
|
||||
|
||||
paramsout := params.export(oneline: true)
|
||||
|
||||
console.print_debug(paramsout)
|
||||
|
||||
assert sha256.hexhash(paramsout) == '811bef1e55b3b4b1b725e1a7514b092526c8fdef8dddf6ad15f9d1ca49c3eb51'
|
||||
}
|
||||
|
||||
const textin10 = "
|
||||
//mycomment
|
||||
red blue
|
||||
id:a10 name6:aaaaa
|
||||
|
||||
name4: '
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
|
||||
//somecomment
|
||||
//
|
||||
//multiline
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
fn test_export_10() {
|
||||
params := parse(textin10) or { panic(err) }
|
||||
o := params.export_helper(oneline: false, pre: '!!remark.define') or { panic(err) }
|
||||
console.print_debug('${o}')
|
||||
|
||||
paramsout := params.export(oneline: false, pre: '!!remark.define')
|
||||
|
||||
console.print_debug(paramsout)
|
||||
|
||||
// WE EXPECT
|
||||
|
||||
console.print_debug("EXPECT:
|
||||
// mycomment
|
||||
!!remark.define blue red id:a10 name6:aaaaa
|
||||
name4:'
|
||||
multiline1
|
||||
in
|
||||
|
||||
multiline2
|
||||
'
|
||||
// somecomment
|
||||
//
|
||||
// multiline
|
||||
name5:aab
|
||||
")
|
||||
|
||||
assert sha256.hexhash(paramsout) == 'bf583f6b9afe84476eb3ade1bdd60ba4a6f1196d95a6e7d0fbe6f8b9fb5779d2'
|
||||
}
|
||||
|
||||
fn test_export_list() {
|
||||
params := parse("list0: 'Kiwi'\nlist1: 'Apple', 'Banana'") or { panic(err) }
|
||||
paramsout := params.export()
|
||||
assert paramsout.trim_space() == 'list0:Kiwi list1:Apple,Banana'
|
||||
}
|
||||
|
||||
fn test_export_text() {
|
||||
params := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'text'
|
||||
value: "This content contains the character ' in it"
|
||||
},
|
||||
]
|
||||
}
|
||||
paramsout := params.export()
|
||||
assert paramsout.trim_space() == "text:'This content contains the character \\' in it'"
|
||||
}
|
||||
110
lib/data/paramsparser/params_filter.v
Normal file
110
lib/data/paramsparser/params_filter.v
Normal file
@@ -0,0 +1,110 @@
|
||||
module paramsparser
|
||||
|
||||
@[params]
|
||||
pub struct ParamsFilter {
|
||||
pub mut:
|
||||
include []string
|
||||
exclude []string
|
||||
}
|
||||
|
||||
// will return true if the params object match the filter (include and excludes)
|
||||
// will first do the include filter then exclude, which means if matched and exclude is then matched won't count
|
||||
// uses the filter_item function for each include or excluse (see further)
|
||||
pub fn (params Params) filter_match(myfilter ParamsFilter) !bool {
|
||||
mut inclok := true
|
||||
if myfilter.include.len > 0 {
|
||||
inclok = false
|
||||
for incl in myfilter.include {
|
||||
ok := params.filter_match_item(incl)!
|
||||
// console.print_debug(params)
|
||||
// console.print_debug(myfilter)
|
||||
// console.print_debug(" - filter match: ok:$ok $incl")
|
||||
if ok {
|
||||
inclok = true
|
||||
break // not more needed to check includes, we found one
|
||||
}
|
||||
}
|
||||
}
|
||||
if inclok == false {
|
||||
return false
|
||||
}
|
||||
// no need to continue
|
||||
if myfilter.exclude.len > 0 {
|
||||
for excl in myfilter.exclude {
|
||||
ok2 := params.filter_match_item(excl)!
|
||||
if ok2 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// match params for 1 string based match
|
||||
// can be e.g.
|
||||
// - hr+development, means look for argument hr or development
|
||||
// - devel*, look for an argument which starts with devel (see match_glob)
|
||||
// - color:*red*, look for a value with key color, which has 'red' string inside
|
||||
// match_glob matches the string, with a Unix shell-style wildcard pattern
|
||||
// The special characters used in shell-style wildcards are:
|
||||
// * - matches everything
|
||||
// ? - matches any single character
|
||||
// [seq] - matches any of the characters in the sequence
|
||||
// [^seq] - matches any character that is NOT in the sequence
|
||||
// Any other character in pattern, is matched 1:1 to the corresponding character in name, including / and .
|
||||
// You can wrap the meta-characters in brackets too, i.e. [?] matches ? in the string, and [*] matches * in the string.
|
||||
pub fn (params Params) filter_match_item(myfilter string) !bool {
|
||||
mut tests := [myfilter]
|
||||
if myfilter.contains('+') {
|
||||
tests = myfilter.split('+')
|
||||
}
|
||||
mut totalfound := 0
|
||||
for test in tests {
|
||||
mut found := false
|
||||
mut key := ''
|
||||
mut value := test.trim_space()
|
||||
if test.contains(':') {
|
||||
splitted := test.split(':')
|
||||
key = splitted[0]
|
||||
value = splitted[1]
|
||||
key = key.trim_space()
|
||||
value = value.trim_space()
|
||||
}
|
||||
if key == '' {
|
||||
for arg in params.args {
|
||||
if value.contains('*') || value.contains('[]') || value.contains('?') {
|
||||
// we will do match_glob
|
||||
if arg.match_glob(value) {
|
||||
found = true
|
||||
}
|
||||
} else {
|
||||
if arg == value {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for param in params.params {
|
||||
if param.key == key {
|
||||
if value.contains('*') || value.contains('[]') || value.contains('?') {
|
||||
// we will do match_glob
|
||||
if param.value.match_glob(value) {
|
||||
found = true
|
||||
}
|
||||
} else {
|
||||
if param.value == value {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if found {
|
||||
totalfound += 1
|
||||
}
|
||||
}
|
||||
if tests.len == totalfound {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
39
lib/data/paramsparser/params_filter_test.v
Normal file
39
lib/data/paramsparser/params_filter_test.v
Normal file
@@ -0,0 +1,39 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_macro_args() {
|
||||
mut text := "arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok'"
|
||||
mut params := parse(text) or { panic(err) }
|
||||
|
||||
assert params.filter_match(include: ['description:*see*'])!
|
||||
|
||||
assert params.filter_match(include: ['priority:incredible'])!
|
||||
assert params.filter_match(include: ['priority:incredible+color:red'])!
|
||||
assert params.filter_match(include: ['priority:incredible+color:green', 'arg1'])!
|
||||
assert params.filter_match(include: ['priority:incredible+color:red', 'arg1+arg3'])!
|
||||
|
||||
assert params.filter_match(include: ['arg2'])!
|
||||
|
||||
c := params.filter_match(include: ['arg'])!
|
||||
assert c == false
|
||||
|
||||
d := params.filter_match(include: ['a*rg'])!
|
||||
assert d == false
|
||||
|
||||
e := params.filter_match(include: ['arg*'])!
|
||||
assert e
|
||||
|
||||
f := params.filter_match(include: ['arg*'])!
|
||||
assert f
|
||||
|
||||
f_ := params.filter_match(include: ['arg1+arg2'])!
|
||||
assert f_
|
||||
|
||||
g := params.filter_match(include: ['arg1+arg3'])!
|
||||
assert g == false
|
||||
|
||||
h := params.filter_match(include: ['priority:incredible+color:green'])!
|
||||
assert h == false
|
||||
|
||||
h2 := params.filter_match(include: ['priority:incredible'], exclude: ['color:red'])!
|
||||
assert h2 == false
|
||||
}
|
||||
49
lib/data/paramsparser/params_get_args.v
Normal file
49
lib/data/paramsparser/params_get_args.v
Normal file
@@ -0,0 +1,49 @@
|
||||
module paramsparser
|
||||
|
||||
import strconv
|
||||
|
||||
pub fn (params &Params) len_arg() int {
|
||||
return params.args.len
|
||||
}
|
||||
|
||||
// return the arg with nr, 0 is the first
|
||||
pub fn (params &Params) get_arg(nr int) !string {
|
||||
if nr >= params.args.len {
|
||||
return error('Looking for arg nr ${nr}, not enough args available.\n${params}')
|
||||
}
|
||||
return params.args[nr] or { panic('error, above should have catched') }
|
||||
}
|
||||
|
||||
// return the arg with nr, 0 is the first
|
||||
// check the length of the args
|
||||
pub fn (params &Params) get_arg_check(nr int, checknrargs int) !string {
|
||||
params.check_arg_len(checknrargs)!
|
||||
return params.get_arg(nr)
|
||||
}
|
||||
|
||||
pub fn (params &Params) check_arg_len(checknrargs int) ! {
|
||||
if checknrargs != params.args.len {
|
||||
return error('the amount of expected args is ${checknrargs}, we found different.\n${params}')
|
||||
}
|
||||
}
|
||||
|
||||
// return arg, if the nr is larger than amount of args, will return the defval
|
||||
pub fn (params &Params) get_arg_default(nr int, defval string) !string {
|
||||
if nr >= params.args.len {
|
||||
return defval
|
||||
}
|
||||
r := params.get_arg(nr)!
|
||||
return r
|
||||
}
|
||||
|
||||
// get arg return as int, if checknrargs is not 0, it will make sure the nr of args corresponds
|
||||
pub fn (params &Params) get_arg_int(nr int) !int {
|
||||
r := params.get_arg(nr)!
|
||||
return strconv.atoi(r) or { return error('failed to convert argument ${r} to int: ${err}') }
|
||||
}
|
||||
|
||||
// get arg return as int. defval is the default value specified
|
||||
pub fn (params &Params) get_arg_int_default(nr int, defval int) !int {
|
||||
r := params.get_arg_default(nr, '${defval}')!
|
||||
return strconv.atoi(r) or { return error('failed to convert argument ${r} to int: ${err}') }
|
||||
}
|
||||
122
lib/data/paramsparser/params_get_args_test.v
Normal file
122
lib/data/paramsparser/params_get_args_test.v
Normal file
@@ -0,0 +1,122 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_get_arg() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
|
||||
arg1
|
||||
arg2
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
assert params.get_arg(0)! == 'arg1'
|
||||
assert params.get_arg(1)! == 'arg2'
|
||||
arg3 := params.get_arg(2) or { 'arg3 does not exists' }
|
||||
assert arg3 == 'arg3 does not exists'
|
||||
}
|
||||
|
||||
fn test_get_arg_check() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
|
||||
arg1
|
||||
arg2
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get_arg_check(0, 2)! == 'arg1'
|
||||
assert params.get_arg_check(1, 2)! == 'arg2'
|
||||
t3 := params.get_arg_check(1, 3) or { 'len is 2' }
|
||||
assert t3 == 'len is 2'
|
||||
t4 := params.get_arg_check(2, 2) or { 'len is 2' }
|
||||
assert t4 == 'len is 2'
|
||||
}
|
||||
|
||||
fn test_check_arg_len() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
|
||||
arg1
|
||||
arg2
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.check_arg_len(0) {
|
||||
assert false, 'arg len should be 2'
|
||||
}
|
||||
if _ := params.check_arg_len(1) {
|
||||
assert false, 'arg len should be 2'
|
||||
}
|
||||
params.check_arg_len(2) or { assert false }
|
||||
if _ := params.check_arg_len(3) {
|
||||
assert false, 'arg len should be 2'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_arg_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
|
||||
arg1
|
||||
arg2
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get_arg_default(0, 'arg3')! == 'arg1'
|
||||
assert params.get_arg_default(1, 'arg3')! == 'arg2'
|
||||
assert params.get_arg_default(2, 'arg3')! == 'arg3'
|
||||
assert params.get_arg_default(3, 'arg3')! == 'arg3'
|
||||
}
|
||||
|
||||
fn test_get_arg_int() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
|
||||
arg1
|
||||
arg2
|
||||
13
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_arg_int(0) {
|
||||
assert false, 'first argument is a string, not an int'
|
||||
}
|
||||
if _ := params.get_arg_int(1) {
|
||||
assert false, 'second argument is a string, not an int'
|
||||
}
|
||||
assert params.get_arg_int(2)! == 13
|
||||
if _ := params.get_arg_int(3) {
|
||||
assert false, 'there is no 4th argument'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_arg_int_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: val2
|
||||
|
||||
arg1
|
||||
arg2
|
||||
13
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_arg_int_default(0, 5) {
|
||||
assert false, '1st argument is a string, not an int'
|
||||
}
|
||||
if _ := params.get_arg_int_default(1, 5) {
|
||||
assert false, '2nd argument is a string, not an int'
|
||||
}
|
||||
assert params.get_arg_int_default(2, 5)! == 13
|
||||
assert params.get_arg_int_default(3, 5)! == 5
|
||||
}
|
||||
194
lib/data/paramsparser/params_get_kwargs.v
Normal file
194
lib/data/paramsparser/params_get_kwargs.v
Normal file
@@ -0,0 +1,194 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import strconv
|
||||
|
||||
// see if the kwarg with the key exists
|
||||
// if yes return as string trimmed
|
||||
pub fn (params &Params) get(key_ string) !string {
|
||||
key := texttools.name_fix(key_)
|
||||
for p in params.params {
|
||||
if p.key == key {
|
||||
return p.value.trim(' ')
|
||||
}
|
||||
}
|
||||
// print_backtrace()
|
||||
return error('Did not find key:${key} in ${params}')
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_map() map[string]string {
|
||||
mut r := map[string]string{}
|
||||
for p in params.params {
|
||||
r[p.key] = p.value
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// get kwarg return as string, ifn't exist return the defval
|
||||
// line:
|
||||
// arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok
|
||||
// arg1 is an arg
|
||||
// description is a kwarg
|
||||
pub fn (params &Params) get_default(key string, defval string) !string {
|
||||
if params.exists(key) {
|
||||
valuestr := params.get(key)!
|
||||
return valuestr.trim(' ')
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
// get kwarg return as int
|
||||
// line:
|
||||
// arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok
|
||||
// arg1 is an arg
|
||||
// description is a kwarg
|
||||
pub fn (params &Params) get_int(key string) !int {
|
||||
valuestr := params.get(key)!
|
||||
return strconv.atoi(valuestr) or {
|
||||
return error('Parameter ${key} = ${valuestr} is not a valid signed 32-bit integer')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_float(key string) !f64 {
|
||||
valuestr := params.get(key)!
|
||||
return strconv.atof64(valuestr) or {
|
||||
return error('Parameter ${key} = ${valuestr} is not a valid 64-bit float')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_float_default(key string, defval f64) !f64 {
|
||||
if params.exists(key) {
|
||||
valuestr := params.get_float(key)!
|
||||
return valuestr
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_percentage(key string) !f64 {
|
||||
mut valuestr := params.get(key)!
|
||||
valuestr = valuestr.replace('%', '')
|
||||
v := strconv.atof64(valuestr) or {
|
||||
return error('Parameter ${key} = ${valuestr} is not a valid 64-bit float')
|
||||
}
|
||||
|
||||
if v > 100 || v < 0 {
|
||||
return error('percentage "${v}" needs to be between 0 and 100')
|
||||
}
|
||||
return v / 100
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_percentage_default(key string, defval string) !f64 {
|
||||
mut v := params.get_default(key, defval)!
|
||||
v = v.replace('%', '')
|
||||
v2 := strconv.atof64(v) or {
|
||||
return error('Parameter ${key} = ${v} is not a valid 64-bit float')
|
||||
}
|
||||
if v2 > 100 || v2 < 0 {
|
||||
return error('percentage "${v2}" needs to be between 0 and 100')
|
||||
}
|
||||
return v2 / 100
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_u64(key string) !u64 {
|
||||
valuestr := params.get(key)!
|
||||
return strconv.parse_uint(valuestr, 10, 64) or {
|
||||
return error('Parameter ${key} = ${valuestr} is not a valid unsigned 64-bit integer')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_u64_default(key string, defval u64) !u64 {
|
||||
if params.exists(key) {
|
||||
valuestr := params.get_u64(key)!
|
||||
return valuestr
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_u32(key string) !u32 {
|
||||
valuestr := params.get(key)!
|
||||
return u32(strconv.parse_uint(valuestr, 10, 32) or {
|
||||
return error('Parameter ${key} = ${valuestr} is not a valid unsigned 32-bit integer')
|
||||
})
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_u32_default(key string, defval u32) !u32 {
|
||||
if params.exists(key) {
|
||||
valuestr := params.get_u32(key)!
|
||||
return valuestr
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_u8(key string) !u8 {
|
||||
valuestr := params.get(key)!
|
||||
return u8(strconv.parse_uint(valuestr, 10, 8) or {
|
||||
return error('Parameter ${key} = ${valuestr} is not a valid unsigned 8-bit integer')
|
||||
})
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_u8_default(key string, defval u8) !u8 {
|
||||
if params.exists(key) {
|
||||
valuestr := params.get_u8(key)!
|
||||
return valuestr
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
// get kwarg return as int, if it doesnt' exist return a default
|
||||
// line:
|
||||
// arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok
|
||||
// arg1 is an arg
|
||||
// description is a kwarg
|
||||
pub fn (params &Params) get_int_default(key string, defval int) !int {
|
||||
if params.exists(key) {
|
||||
valuestr := params.get_int(key)!
|
||||
return valuestr
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_default_true(key string) bool {
|
||||
mut r := params.get(key) or { '' }
|
||||
r = texttools.name_fix_no_underscore(r)
|
||||
if r == '' || r == '1' || r == 'true' || r == 'y' || r == 'yes' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_default_false(key string) bool {
|
||||
mut r := params.get(key) or { '' }
|
||||
r = texttools.name_fix_no_underscore(r)
|
||||
if r == '' || r == '0' || r == 'false' || r == 'n' || r == 'no' {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn matchhashmap(hashmap map[string]string, tofind_ string) string {
|
||||
tofind := tofind_.to_lower().trim_space()
|
||||
for key, val in hashmap {
|
||||
for key2 in key.split(',') {
|
||||
if key2.to_lower().trim_space() == tofind {
|
||||
return val
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_from_hashmap(key_ string, defval string, hashmap map[string]string) !string {
|
||||
key := texttools.name_fix(key_)
|
||||
if val := params.get(key) {
|
||||
r := matchhashmap(hashmap, val)
|
||||
if r.len > 0 {
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
r := matchhashmap(hashmap, defval)
|
||||
if r.len > 0 {
|
||||
return r
|
||||
}
|
||||
return error('Did not find key:${key} in ${params} with hashmap:${hashmap} and default:${defval}')
|
||||
}
|
||||
326
lib/data/paramsparser/params_get_kwargs_test.v
Normal file
326
lib/data/paramsparser/params_get_kwargs_test.v
Normal file
@@ -0,0 +1,326 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_get() {
|
||||
text := '
|
||||
key1: val1
|
||||
arg1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get('key1')! == 'val1'
|
||||
if _ := params.get('key2') {
|
||||
assert false, 'there is no param with key "key2"'
|
||||
}
|
||||
if _ := params.get('arg1') {
|
||||
assert false, 'there is no param with key "arg1"'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
arg1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get_default('key1', 'def')! == 'val1'
|
||||
assert params.get_default('key2', 'def')! == 'def'
|
||||
assert params.get_default('arg1', 'def')! == 'def'
|
||||
}
|
||||
|
||||
fn test_get_int() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
arg1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_int('key1') {
|
||||
assert false, 'param with key "key1" is a string, not an int'
|
||||
}
|
||||
assert params.get_int('key2')! == 19
|
||||
if _ := params.get_int('arg1') {
|
||||
assert false, 'there is no param with key "arg1"'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_int_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
arg1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_int_default('key1', 10) {
|
||||
assert false, 'the param with key "key1" is a string, not an int'
|
||||
}
|
||||
assert params.get_int_default('key2', 10)! == 19
|
||||
assert params.get_int_default('arg1', 10)! == 10
|
||||
}
|
||||
|
||||
fn test_get_float() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
key3: 1.9
|
||||
arg1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_float('key1') {
|
||||
assert false, 'the param with key "key1" is a string, not a float'
|
||||
}
|
||||
assert params.get_float('key2')! == 19
|
||||
assert params.get_float('key3')! == 1.9
|
||||
if _ := params.get_float('arg1') {
|
||||
assert false, 'there is no param with key "arg1"'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_float_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
key3: 1.9
|
||||
arg1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_float_default('key1', 1.23) {
|
||||
assert false, 'the param with key "key1" is a string, not a float'
|
||||
}
|
||||
assert params.get_float_default('key2', 1.23)! == 19
|
||||
assert params.get_float_default('key3', 1.23)! == 1.9
|
||||
assert params.get_float_default('arg1', 1.23)! == 1.23
|
||||
}
|
||||
|
||||
fn test_get_percentage() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
key3: %1.9
|
||||
key4: %500
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_percentage('key1') {
|
||||
assert false, 'the param with key "key1" is a string, not a percentage'
|
||||
}
|
||||
assert params.get_percentage('key2')! == 0.19
|
||||
assert params.get_percentage('key3')! == .019
|
||||
if _ := params.get_percentage('key4') {
|
||||
assert false, 'the param with key "key4" has an invalid percentage value "%500", it must be between 0 and 100'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_percentage_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
key3: %1.9
|
||||
key4: %500
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_percentage_default('key1', '.17') {
|
||||
assert false, 'the param with key "key1" is a string, not a percentage'
|
||||
}
|
||||
assert params.get_percentage_default('key2', '.17')! == 0.19
|
||||
assert params.get_percentage_default('key3', '.17')! == .019
|
||||
if _ := params.get_percentage_default('key4', '.17') {
|
||||
assert false, 'the param with key "key4" has an invalid percentage vale "%500", it must be between 0 and 100'
|
||||
}
|
||||
assert params.get_percentage_default('key5', '17')! == 0.17
|
||||
}
|
||||
|
||||
fn test_get_u64() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_u64('key1') {
|
||||
assert false, 'the param with key "key1" is a string, not a u64'
|
||||
}
|
||||
assert params.get_u64('key2')! == 19
|
||||
if _ := params.get_u64('key3') {
|
||||
assert false, 'there is no param with key "key3"'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_u64_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_u64_default('key1', 17) {
|
||||
assert false, 'the param with key "key1" is a string, not a u64'
|
||||
}
|
||||
assert params.get_u64_default('key2', 17)! == 19
|
||||
assert params.get_u64_default('key3', 17)! == 17
|
||||
}
|
||||
|
||||
fn test_get_u32() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_u32('key1') {
|
||||
assert false, 'the param with key "key1" is a string, not a u32'
|
||||
}
|
||||
assert params.get_u32('key2')! == 19
|
||||
if _ := params.get_u32('key3') {
|
||||
assert false, 'there is no param with key "key3"'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_u32_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_u32_default('key1', 17) {
|
||||
assert false, 'the param with key "key1" is a string, not a u32'
|
||||
}
|
||||
assert params.get_u32_default('key2', 17)! == 19
|
||||
assert params.get_u32_default('key3', 17)! == 17
|
||||
}
|
||||
|
||||
fn test_get_u8() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_u8('key1') {
|
||||
assert false, 'the param with key "key1" is a string, not a u8'
|
||||
}
|
||||
assert params.get_u8('key2')! == 19
|
||||
if _ := params.get_u8('key3') {
|
||||
assert false, 'there is no param with key "key3"'
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_u8_default() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_u8_default('key1', 17) {
|
||||
assert false, 'the param with key "key1" is a string, not a u8'
|
||||
}
|
||||
assert params.get_u8_default('key2', 17)! == 19
|
||||
assert params.get_u8_default('key3', 17)! == 17
|
||||
}
|
||||
|
||||
fn test_get_default_true() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: true
|
||||
key3: 1
|
||||
key4: 2
|
||||
key5: y
|
||||
key6: yes
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get_default_true('key1') == false
|
||||
assert params.get_default_true('key2') == true
|
||||
assert params.get_default_true('key3') == true
|
||||
assert params.get_default_true('key4') == false
|
||||
assert params.get_default_true('key5') == true
|
||||
assert params.get_default_true('key6') == true
|
||||
assert params.get_default_true('key7') == true
|
||||
}
|
||||
|
||||
fn test_get_default_false() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: false
|
||||
key3: 0
|
||||
key4: 1
|
||||
key5: n
|
||||
key6: no
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get_default_false('key1') == true
|
||||
assert params.get_default_false('key2') == false
|
||||
assert params.get_default_false('key3') == false
|
||||
assert params.get_default_false('key4') == true
|
||||
assert params.get_default_false('key5') == false
|
||||
assert params.get_default_false('key6') == false
|
||||
assert params.get_default_false('key7') == false
|
||||
}
|
||||
|
||||
fn test_get_from_hashmap() {
|
||||
text := '
|
||||
key1: val1
|
||||
key2: 19
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
mp := {
|
||||
'key1,19, val1': 'val2'
|
||||
}
|
||||
|
||||
assert params.get_from_hashmap('key1', 'def', mp)! == 'val2'
|
||||
assert params.get_from_hashmap('key2', 'def', mp)! == 'val2'
|
||||
assert params.get_from_hashmap('key3', 'key1', mp)! == 'val2'
|
||||
}
|
||||
|
||||
fn test_matchhashmap() {
|
||||
mp := {
|
||||
'key1,key2,key3': 'val1'
|
||||
}
|
||||
|
||||
assert matchhashmap(mp, 'key1') == 'val1'
|
||||
assert matchhashmap(mp, 'key2') == 'val1'
|
||||
assert matchhashmap(mp, 'key3') == 'val1'
|
||||
assert matchhashmap(mp, 'key4') == ''
|
||||
}
|
||||
|
||||
fn test_url() {
|
||||
text := "url:'https://git.ourworld.tf/despiegk/cfg/src/branch/main/myit/hetzner.md'"
|
||||
params := new(text)!
|
||||
|
||||
myurl := params.get('url')!
|
||||
assert myurl == 'https://git.ourworld.tf/despiegk/cfg/src/branch/main/myit/hetzner.md'
|
||||
}
|
||||
|
||||
fn test_url2() {
|
||||
text := "url: 'https://git.ourworld.tf/despiegk/cfg/src/branch/main/myit/hetzner.md'"
|
||||
params := new(text)!
|
||||
|
||||
myurl := params.get('url')!
|
||||
assert myurl == 'https://git.ourworld.tf/despiegk/cfg/src/branch/main/myit/hetzner.md'
|
||||
}
|
||||
36
lib/data/paramsparser/params_getemail.v
Normal file
36
lib/data/paramsparser/params_getemail.v
Normal file
@@ -0,0 +1,36 @@
|
||||
module paramsparser
|
||||
|
||||
pub fn (params &Params) get_email(key string) !string {
|
||||
mut valuestr := params.get(key)!
|
||||
return normalize_email(valuestr)
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_emails(key string) ![]string {
|
||||
mut valuestr := params.get(key)!
|
||||
valuestr = valuestr.trim('[] ')
|
||||
|
||||
split := valuestr.split(',')
|
||||
mut res := []string{}
|
||||
for item in split {
|
||||
res << normalize_email(item)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_emails_default(key string, default []string) ![]string {
|
||||
if params.exists(key) {
|
||||
return params.get_emails(key)!
|
||||
}
|
||||
|
||||
mut res := []string{}
|
||||
for item in default {
|
||||
res << normalize_email(item)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
fn normalize_email(email string) string {
|
||||
return email.trim(' ').to_lower()
|
||||
}
|
||||
255
lib/data/paramsparser/params_getlist.v
Normal file
255
lib/data/paramsparser/params_getlist.v
Normal file
@@ -0,0 +1,255 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import strconv
|
||||
|
||||
// Looks for a list of strings in the parameters. If it doesn't exist this function will return an error. Furthermore an error will be returned if the list is not properly formatted
|
||||
// Examples of valid lists:
|
||||
// ["example", "another_example", "yes"]
|
||||
// ['example', 'another_example']
|
||||
// ['example "yes yes"', "another_example", "yes"]
|
||||
// Invalid examples:
|
||||
// [example, example, example]
|
||||
// ['example, example, example]
|
||||
pub fn (params &Params) get_list(key string) ![]string {
|
||||
mut res := []string{}
|
||||
mut valuestr := params.get(key)!
|
||||
valuestr = valuestr.trim('[] ')
|
||||
mut splitted := valuestr.split(',')
|
||||
for mut item in splitted {
|
||||
item = item.trim('"\' ')
|
||||
if item != '' {
|
||||
res << item
|
||||
}
|
||||
}
|
||||
|
||||
// THE IMPLEMENTATION BELOW IS TOO COMPLEX AND ALSO NOT DEFENSIVE ENOUGH
|
||||
|
||||
// mut res := []string{}
|
||||
// mut valuestr := params.get(key)!
|
||||
// valuestr = valuestr.trim('[] ,')
|
||||
// if valuestr==""{
|
||||
// return []
|
||||
// }
|
||||
// mut j := 0
|
||||
// mut i := 0
|
||||
// for i < valuestr.len {
|
||||
// if valuestr[i] == 34 || valuestr[i] == 39 { // handle single or double quotes
|
||||
// // console.print_debug("::::${valuestr[i]}")
|
||||
// quote := valuestr[i..i + 1]
|
||||
// j = valuestr.index_after('${quote}', i + 1)
|
||||
// if j == -1 {
|
||||
// return error('Invalid list at index ${i}: strings should surrounded by single or double quote')
|
||||
// }
|
||||
// if i + 1 < j {
|
||||
// res << valuestr[i + 1..j]
|
||||
// i = j + 1
|
||||
// if i < valuestr.len && valuestr[i] != 44 { // handle comma
|
||||
// return error('Invalid list at index ${i}: strings should be separated by a comma')
|
||||
// }
|
||||
// }
|
||||
// } else if valuestr[i] == 32 { // handle space
|
||||
// } else {
|
||||
// res << valuestr[i..i + 1]
|
||||
// }
|
||||
// i += 1
|
||||
// }
|
||||
return res
|
||||
}
|
||||
|
||||
// Looks for a list of strings in the parameters. If it doesn't exist this function the provided default value. Furthermore an error will be returned if the parameter exists and it's not a valid list.
|
||||
// Please look at get_list for examples of valid and invalid lists
|
||||
pub fn (params &Params) get_list_default(key string, def []string) ![]string {
|
||||
if params.exists(key) {
|
||||
return params.get_list(key)
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of strings in the parameters. If it doesn't exist this function returns an error. Furthermore an error will be returned if the parameter exists and it's not a valid list.
|
||||
// The items in the list will be namefixed
|
||||
pub fn (params &Params) get_list_namefix(key string) ![]string {
|
||||
mut res := params.get_list(key)!
|
||||
return res.map(texttools.name_fix(it))
|
||||
}
|
||||
|
||||
// Looks for a list of strings in the parameters. If it doesn't exist this function returns the provided default value. Furthermore an error will be returned if the parameter exists and it's not a valid list.
|
||||
// The items in the list will be namefixed
|
||||
pub fn (params &Params) get_list_namefix_default(key string, def []string) ![]string {
|
||||
if params.exists(key) {
|
||||
res := params.get_list(key)!
|
||||
return res.map(texttools.name_fix(it))
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
fn (params &Params) get_list_numbers(key string) ![]string {
|
||||
mut valuestr := params.get(key)!
|
||||
return valuestr.split(',').map(it.trim_space())
|
||||
}
|
||||
|
||||
// Looks for a list of u8 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_u8(key string) ![]u8 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(u8(strconv.parse_uint(it, 10, 8) or {
|
||||
return error('${key} list entry ${it} is not a valid unsigned 8-bit integer')
|
||||
}))
|
||||
}
|
||||
|
||||
// Looks for a list of u8 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_u8_default(key string, def []u8) []u8 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.u8())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of u16 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_u16(key string) ![]u16 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(u16(strconv.parse_uint(it, 10, 16) or {
|
||||
return error('${key} list entry ${it} is not a valid unsigned 16-bit integer')
|
||||
}))
|
||||
}
|
||||
|
||||
// Looks for a list of u16 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_u16_default(key string, def []u16) []u16 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.u16())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of u32 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_u32(key string) ![]u32 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(u32(strconv.parse_uint(it, 10, 32) or {
|
||||
return error('${key} list entry ${it} is not a valid unsigned 32-bit integer')
|
||||
}))
|
||||
}
|
||||
|
||||
// Looks for a list of u32 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_u32_default(key string, def []u32) []u32 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.u32())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of u64 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_u64(key string) ![]u64 {
|
||||
res := params.get_list_numbers(key)!
|
||||
return res.map(strconv.parse_uint(it, 10, 64) or {
|
||||
return error('${key} list entry ${it} is not a valid unsigned 64-bit integer')
|
||||
})
|
||||
}
|
||||
|
||||
// Looks for a list of u64 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_u64_default(key string, def []u64) []u64 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.u64())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of i8 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_i8(key string) ![]i8 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(i8(strconv.atoi(it) or {
|
||||
return error('${key} list entry ${it} is not a valid signed 8-bit integer')
|
||||
}))
|
||||
}
|
||||
|
||||
// Looks for a list of i8 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_i8_default(key string, def []i8) []i8 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.i8())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of i16 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_i16(key string) ![]i16 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(i16(strconv.atoi(it) or {
|
||||
return error('${key} list entry ${it} is not a valid signed 16-bit integer')
|
||||
}))
|
||||
}
|
||||
|
||||
// Looks for a list of i16 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_i16_default(key string, def []i16) []i16 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.i16())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of int with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_int(key string) ![]int {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(strconv.atoi(it) or {
|
||||
return error('${key} list entry ${it} is not a valid signed 32-bit integer')
|
||||
})
|
||||
}
|
||||
|
||||
// Looks for a list of int with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_int_default(key string, def []int) []int {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.int())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of i64 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_i64(key string) ![]i64 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(strconv.parse_int(it, 10, 64) or {
|
||||
return error('${key} list entry ${it} is not a valid signed 64-bit integer')
|
||||
})
|
||||
}
|
||||
|
||||
// Looks for a list of i64 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_i64_default(key string, def []i64) []i64 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.i64())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of f32 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_f32(key string) ![]f32 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(f32(strconv.atof64(it)!))
|
||||
}
|
||||
|
||||
// Looks for a list of f32 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_f32_default(key string, def []f32) []f32 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.f32())
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Looks for a list of f64 with the provided key. If it does not exist an error is returned.
|
||||
pub fn (params &Params) get_list_f64(key string) ![]f64 {
|
||||
mut res := params.get_list_numbers(key)!
|
||||
return res.map(strconv.atof64(it)!)
|
||||
}
|
||||
|
||||
// Looks for a list of f64 with the provided key. If it does not exist the provided default value is returned.
|
||||
pub fn (params &Params) get_list_f64_default(key string, def []f64) []f64 {
|
||||
if params.exists(key) {
|
||||
res := params.get_list_numbers(key) or { return def }
|
||||
return res.map(it.f64())
|
||||
}
|
||||
return def
|
||||
}
|
||||
304
lib/data/paramsparser/params_getlist_test.v
Normal file
304
lib/data/paramsparser/params_getlist_test.v
Normal file
@@ -0,0 +1,304 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_get_list_single_quotes() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: 'A,A,A,A'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list('mylist')!
|
||||
assert list == ['A', 'A', 'A', 'A']
|
||||
}
|
||||
|
||||
fn test_get_list_smallstr() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: 'a'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list('mylist') or { panic(err) }
|
||||
assert list == ['a']
|
||||
// if true{panic("sdsdsdsdsdsdsdsd")}
|
||||
}
|
||||
|
||||
fn test_get_list_smallstr2() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: 'a,b,dddeegggdf ,e'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list('mylist') or { panic(err) }
|
||||
assert list == ['a', 'b', 'dddeegggdf', 'e']
|
||||
}
|
||||
|
||||
fn test_get_list_double_quotes() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '["A","A","A","A"]'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list('mylist')!
|
||||
assert list == ['A', 'A', 'A', 'A']
|
||||
}
|
||||
|
||||
fn test_get_list_single_and_double_quotes() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '["A","A",\'A\',"A"]'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list('mylist')!
|
||||
assert list == ['A', 'A', 'A', 'A']
|
||||
}
|
||||
|
||||
fn test_get_list_double_quote_inside_single() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '["A",\'"A"\',"A","A"]'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list('mylist')!
|
||||
assert list == ['A', 'A', 'A', 'A']
|
||||
}
|
||||
|
||||
// we need to be more defensive this succeeds
|
||||
// fn test_get_list_invalid() {
|
||||
// testparams := Params{
|
||||
// params: [
|
||||
// Param{
|
||||
// key: 'mylist'
|
||||
// value: '["A,"A","A","A"]'
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// list := testparams.get_list('mylist') or { return }
|
||||
// assert false, 'expected get_list to throw an error'
|
||||
// }
|
||||
|
||||
fn test_get_list_u8() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, 5, 7, 2'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_u8('mylist')!
|
||||
assert list == [u8(1), u8(5), u8(7), u8(2)]
|
||||
}
|
||||
|
||||
fn test_get_list_u8_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_u8_default('mylist', []u8{})
|
||||
assert list == []u8{}
|
||||
}
|
||||
|
||||
fn test_get_list_u16() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, 5, 7, 2'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_u16('mylist')!
|
||||
assert list == [u16(1), u16(5), u16(7), u16(2)]
|
||||
}
|
||||
|
||||
fn test_get_list_u16_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_u16_default('mylist', []u16{})
|
||||
assert list == []u16{}
|
||||
}
|
||||
|
||||
fn test_get_list_u32() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, 5, 7, 15148'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_u32('mylist')!
|
||||
assert list == [u32(1), u32(5), u32(7), u32(15148)]
|
||||
}
|
||||
|
||||
fn test_get_list_u32_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_u32_default('mylist', []u32{})
|
||||
assert list == []u32{}
|
||||
}
|
||||
|
||||
fn test_get_list_u64() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, 5, 7, 15148'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_u64('mylist')!
|
||||
assert list == [u64(1), u64(5), u64(7), u64(15148)]
|
||||
}
|
||||
|
||||
fn test_get_list_u64_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_u64_default('mylist', []u64{})
|
||||
assert list == []u64{}
|
||||
}
|
||||
|
||||
fn test_get_list_i8() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, -5, 10, -2'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_i8('mylist')!
|
||||
assert list == [i8(1), i8(-5), i8(10), i8(-2)]
|
||||
}
|
||||
|
||||
fn test_get_list_i8_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_i8_default('mylist', []i8{})
|
||||
assert list == []i8{}
|
||||
}
|
||||
|
||||
fn test_get_list_i16() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, -25, 165, -148'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_i16('mylist')!
|
||||
assert list == [i16(1), i16(-25), i16(165), i16(-148)]
|
||||
}
|
||||
|
||||
fn test_get_list_i16_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_i16_default('mylist', []i16{})
|
||||
assert list == []i16{}
|
||||
}
|
||||
|
||||
fn test_get_list_int() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, -25, 165, -1484984'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_int('mylist')!
|
||||
assert list == [1, -25, 165, -1484984]
|
||||
}
|
||||
|
||||
fn test_get_list_int_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_int_default('mylist', []int{})
|
||||
assert list == []int{}
|
||||
}
|
||||
|
||||
fn test_get_list_i64() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1, -25, 165, -148'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_i64('mylist')!
|
||||
assert list == [i64(1), i64(-25), i64(165), i64(-148)]
|
||||
}
|
||||
|
||||
fn test_get_list_i64_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_i64_default('mylist', []i64{})
|
||||
assert list == []i64{}
|
||||
}
|
||||
|
||||
fn test_get_list_f32() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1.5, 5.78, 7.478, 15148.4654'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_f32('mylist')!
|
||||
assert list == [f32(1.5), f32(5.78), f32(7.478), f32(15148.4654)]
|
||||
}
|
||||
|
||||
fn test_get_list_f32_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_f32_default('mylist', []f32{})
|
||||
assert list == []f32{}
|
||||
}
|
||||
|
||||
fn test_get_list_f64() {
|
||||
testparams := Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'mylist'
|
||||
value: '1.5, 5.78, 7.478, 15148.4654'
|
||||
},
|
||||
]
|
||||
}
|
||||
list := testparams.get_list_f64('mylist')!
|
||||
assert list == [1.5, 5.78, 7.478, 15148.4654]
|
||||
}
|
||||
|
||||
fn test_get_list_f64_default() {
|
||||
testparams := Params{
|
||||
params: []
|
||||
}
|
||||
list := testparams.get_list_f64_default('mylist', []f64{})
|
||||
assert list == []f64{}
|
||||
}
|
||||
29
lib/data/paramsparser/params_getpath.v
Normal file
29
lib/data/paramsparser/params_getpath.v
Normal file
@@ -0,0 +1,29 @@
|
||||
module paramsparser
|
||||
|
||||
import os
|
||||
// will get path and check it exists
|
||||
|
||||
pub fn (params &Params) get_path(key string) !string {
|
||||
mut path := params.get(key)!
|
||||
|
||||
path = path.replace('~', os.home_dir())
|
||||
|
||||
if !os.exists(path) {
|
||||
return error('Cannot find path: ${path} was for key:${key}')
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// create the path if it doesn't exist
|
||||
pub fn (params &Params) get_path_create(key string) !string {
|
||||
mut path := params.get(key)!
|
||||
|
||||
path = path.replace('~', os.home_dir())
|
||||
|
||||
if !os.exists(path) {
|
||||
os.mkdir_all(path)!
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
30
lib/data/paramsparser/params_getpath_test.v
Normal file
30
lib/data/paramsparser/params_getpath_test.v
Normal file
@@ -0,0 +1,30 @@
|
||||
module paramsparser
|
||||
|
||||
import os
|
||||
|
||||
fn test_get_path() {
|
||||
os.create('/tmp/f1')!
|
||||
|
||||
text := '
|
||||
key1: v1
|
||||
key2: /tmp/f1
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
if _ := params.get_path('key1') {
|
||||
assert false, '"path "v1" is invalid'
|
||||
}
|
||||
assert params.get_path('key2')! == '/tmp/f1'
|
||||
}
|
||||
|
||||
fn test_get_path_create() {
|
||||
text := '
|
||||
key1: val2
|
||||
key2: /tmp/f2
|
||||
'
|
||||
|
||||
params := new(text)!
|
||||
|
||||
assert params.get_path_create('key2')! == '/tmp/f2'
|
||||
}
|
||||
81
lib/data/paramsparser/params_getresource.v
Normal file
81
lib/data/paramsparser/params_getresource.v
Normal file
@@ -0,0 +1,81 @@
|
||||
module paramsparser
|
||||
|
||||
import strconv
|
||||
|
||||
// convert GB, MB, KB to bytes
|
||||
// e.g. 10 GB becomes bytes in u64
|
||||
pub fn (params &Params) get_storagecapacity_in_bytes(key string) !u64 {
|
||||
valuestr := params.get(key)!
|
||||
mut times := 1
|
||||
mut units_string_size := 0
|
||||
if valuestr.len > 2 && !valuestr[valuestr.len - 2].is_digit()
|
||||
&& !valuestr[valuestr.len - 1].is_digit() {
|
||||
times = match valuestr[valuestr.len - 2..].to_upper() {
|
||||
'GB' {
|
||||
1024 * 1024 * 1024
|
||||
}
|
||||
'MB' {
|
||||
1024 * 1024
|
||||
}
|
||||
'KB' {
|
||||
1024
|
||||
}
|
||||
else {
|
||||
0
|
||||
}
|
||||
}
|
||||
if times == 0 {
|
||||
return error('not valid: should end with kb, mb or gb')
|
||||
}
|
||||
units_string_size = 2
|
||||
}
|
||||
val := strconv.parse_uint(valuestr[0..valuestr.len - units_string_size], 10, 64) or {
|
||||
return error('Parameter ${key} = ${valuestr} does not include a valid unsigned 64-bit integer')
|
||||
}
|
||||
return val * u64(times)
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_storagecapacity_in_bytes_default(key string, defval u64) !u64 {
|
||||
if params.exists(key) {
|
||||
return params.get_storagecapacity_in_bytes(key)!
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
// Parses the provided value to gigabytes, the value is rounded up while doing so.
|
||||
pub fn (params &Params) get_storagecapacity_in_gigabytes(key string) !u64 {
|
||||
valuestr := params.get(key)!
|
||||
mut units := 1
|
||||
mut units_string_size := 0
|
||||
if valuestr.len > 2 && !valuestr[valuestr.len - 2].is_digit()
|
||||
&& !valuestr[valuestr.len - 1].is_digit() {
|
||||
units = match valuestr[valuestr.len - 2..].to_upper() {
|
||||
'GB' {
|
||||
1
|
||||
}
|
||||
'MB' {
|
||||
1024
|
||||
}
|
||||
'KB' {
|
||||
1024 * 1024
|
||||
}
|
||||
else {
|
||||
0
|
||||
}
|
||||
}
|
||||
if units == 0 {
|
||||
return error('not valid: should end with kb, mb or gb')
|
||||
}
|
||||
units_string_size = 2
|
||||
}
|
||||
|
||||
val := strconv.parse_uint(valuestr[0..valuestr.len - units_string_size], 10, 64) or {
|
||||
return error('Parameter ${key} = ${valuestr} does not include a valid unsigned 64-bit integer')
|
||||
}
|
||||
mut ret := val / u64(units)
|
||||
if val % u64(units) != 0 {
|
||||
ret += 1
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
28
lib/data/paramsparser/params_getresource_test.v
Normal file
28
lib/data/paramsparser/params_getresource_test.v
Normal file
@@ -0,0 +1,28 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_resource_capacity_in_bytes() {
|
||||
text := 'memory: 10KB\ndisk: 10MB\nstorage: 10GB\nssd: 10'
|
||||
params := parse(text)!
|
||||
assert params.get_storagecapacity_in_bytes('memory')! == 10 * 1024
|
||||
assert params.get_storagecapacity_in_bytes('disk')! == 10 * 1024 * 1024
|
||||
assert params.get_storagecapacity_in_bytes('storage')! == u64(10) * 1024 * 1024 * 1024
|
||||
assert params.get_storagecapacity_in_bytes('ssd')! == 10
|
||||
}
|
||||
|
||||
fn test_resource_capacity_in_bytes_default() {
|
||||
text := 'memory: 10KB\ndisk: 10MB\nstorage: 10GB'
|
||||
params := parse(text)!
|
||||
assert params.get_storagecapacity_in_bytes_default('memory', 10)! == 10 * 1024
|
||||
assert params.get_storagecapacity_in_bytes_default('disk', 10)! == 10 * 1024 * 1024
|
||||
assert params.get_storagecapacity_in_bytes_default('storage', 10)! == u64(10) * 1024 * 1024 * 1024
|
||||
assert params.get_storagecapacity_in_bytes_default('nonexistent', 10)! == 10
|
||||
}
|
||||
|
||||
fn test_resource_capacity_in_gigabytes() {
|
||||
text := 'memory: 10KB\ndisk: 10MB\nstorage: 10GB\nssd: 10'
|
||||
p := parse(text)!
|
||||
assert p.get_storagecapacity_in_gigabytes('memory')! == 1
|
||||
assert p.get_storagecapacity_in_gigabytes('disk')! == 1
|
||||
assert p.get_storagecapacity_in_gigabytes('storage')! == 10
|
||||
assert p.get_storagecapacity_in_gigabytes('ssd')! == 10
|
||||
}
|
||||
44
lib/data/paramsparser/params_gettelnr.v
Normal file
44
lib/data/paramsparser/params_gettelnr.v
Normal file
@@ -0,0 +1,44 @@
|
||||
module paramsparser
|
||||
|
||||
pub fn (params &Params) get_telnr(key string) !string {
|
||||
mut valuestr := params.get(key)!
|
||||
return normalize_telnr(valuestr)
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_telnrs(key string) ![]string {
|
||||
mut valuestr := params.get(key)!
|
||||
valuestr = valuestr.trim('[] ')
|
||||
|
||||
split := valuestr.split(',')
|
||||
mut res := []string{}
|
||||
for item in split {
|
||||
res << normalize_telnr(item)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_telnrs_default(key string, default []string) ![]string {
|
||||
if params.exists(key) {
|
||||
return params.get_telnrs(key)!
|
||||
}
|
||||
|
||||
mut res := []string{}
|
||||
for item in default {
|
||||
res << normalize_telnr(item)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
fn normalize_telnr(telnr string) string {
|
||||
mut value := telnr.trim('+ ')
|
||||
|
||||
mut res := ''
|
||||
mut splitted := value.split('-')
|
||||
for item in splitted {
|
||||
res += item
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
96
lib/data/paramsparser/params_gettime.v
Normal file
96
lib/data/paramsparser/params_gettime.v
Normal file
@@ -0,0 +1,96 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.data.ourtime
|
||||
// import freeflowuniverse.herolib.core.texttools
|
||||
// import os
|
||||
import time { Duration }
|
||||
|
||||
// Get Expiration object from time string input
|
||||
// input can be either relative or absolute
|
||||
// ## Relative time
|
||||
// #### time periods:
|
||||
// - s -> second
|
||||
// - h -> hour
|
||||
// - d -> day
|
||||
// - w -> week
|
||||
// - M -> month
|
||||
// - Q -> quarter
|
||||
// - Y -> year
|
||||
// 0 means right now
|
||||
// input string example: "+1w +2d -4h"
|
||||
// ## Absolute time
|
||||
// inputs must be of the form: "YYYY-MM-DD HH:mm:ss" or "YYYY-MM-DD"
|
||||
// input string examples:
|
||||
//'2022-12-5 20:14:35'
|
||||
//'2022-12-5' - sets hours, mins, seconds to 00
|
||||
pub fn (params &Params) get_time(key string) !ourtime.OurTime {
|
||||
valuestr := params.get(key)!
|
||||
return ourtime.new(valuestr)!
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime {
|
||||
if params.exists(key) {
|
||||
return params.get_time(key)!
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
// calculate difference in time, returled as u64 (is Duration type)
|
||||
// format e.g.
|
||||
// QUESTION: splitting by - doesn't work? Alternative?
|
||||
pub fn (params &Params) get_time_interval(key string) !Duration {
|
||||
valuestr := params.get(key)!
|
||||
data := valuestr.split('-')
|
||||
if data.len != 2 {
|
||||
return error('Invalid time interval: begin and end time required')
|
||||
}
|
||||
start := params.get_time(data[0])!
|
||||
end := params.get_time(data[1])!
|
||||
if end.unix() < start.unix() {
|
||||
return error('Invalid time interval: begin time cannot be after end time')
|
||||
}
|
||||
return end.unix() - start.unix()
|
||||
// NEXT: document and give examples, make sure there is test
|
||||
}
|
||||
|
||||
pub fn (params &Params) get_timestamp_default(key string, defval Duration) !Duration {
|
||||
if params.exists(key) {
|
||||
return params.get_timestamp(key)!
|
||||
}
|
||||
return defval
|
||||
}
|
||||
|
||||
// Parses a timestamp. Can be 12h or 24h format
|
||||
pub fn (params &Params) get_timestamp(key string) !Duration {
|
||||
valuestr := params.get(key)!
|
||||
return params.parse_timestamp(valuestr)!
|
||||
}
|
||||
|
||||
// Parses a timestamp. Can be 12h or 24h format
|
||||
fn (params &Params) parse_timestamp(value string) !Duration {
|
||||
is_am := value.ends_with('AM')
|
||||
is_pm := value.ends_with('PM')
|
||||
is_am_pm := is_am || is_pm
|
||||
data := if is_am_pm { value[..value.len - 2].split(':') } else { value.split(':') }
|
||||
if data.len > 2 {
|
||||
return error('Invalid duration value')
|
||||
}
|
||||
minute := if data.len == 2 { data[1].int() } else { 0 }
|
||||
mut hour := data[0].int()
|
||||
if is_am || is_pm {
|
||||
if hour < 0 || hour > 12 {
|
||||
return error('Invalid duration value')
|
||||
}
|
||||
if is_pm {
|
||||
hour += 12
|
||||
}
|
||||
} else {
|
||||
if hour < 0 || hour > 24 {
|
||||
return error('Invalid duration value')
|
||||
}
|
||||
}
|
||||
if minute < 0 || minute > 60 {
|
||||
return error('Invalid duration value')
|
||||
}
|
||||
return Duration(time.hour * hour + time.minute * minute)
|
||||
}
|
||||
126
lib/data/paramsparser/params_gettime_test.v
Normal file
126
lib/data/paramsparser/params_gettime_test.v
Normal file
@@ -0,0 +1,126 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.data.ourtime
|
||||
import time
|
||||
|
||||
const testparams = Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'when'
|
||||
value: '2022-12-5 20:14:35'
|
||||
},
|
||||
Param{
|
||||
key: 'date'
|
||||
value: '2022-12-5'
|
||||
},
|
||||
Param{
|
||||
key: 'interval'
|
||||
value: '2022-12-5'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_12h_format_am'
|
||||
value: '10AM'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_12h_format_pm'
|
||||
value: '8PM'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_12h_format_am_minutes'
|
||||
value: '10:13AM'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_12h_format_pm_minutes'
|
||||
value: '8:07PM'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_12h_format_invalid'
|
||||
value: '15AM'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_24h_format'
|
||||
value: '16:21'
|
||||
},
|
||||
Param{
|
||||
key: 'timestamp_24h_format_invalid'
|
||||
value: '25:12'
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn test_get_time() ! {
|
||||
sometime := testparams.get_time('when')!
|
||||
assert sometime.unixt == 1670271275
|
||||
|
||||
anothertime := testparams.get_time('date')!
|
||||
assert anothertime.unixt == 1670198400
|
||||
}
|
||||
|
||||
fn test_get_time_default() ! {
|
||||
now := ourtime.now()
|
||||
notime := testparams.get_time_default('now', now)!
|
||||
assert notime.day() == now.day()
|
||||
}
|
||||
|
||||
fn test_get_time_interval() ! {
|
||||
//
|
||||
}
|
||||
|
||||
fn test_get_timestamp_12h_am() ! {
|
||||
parsed_time := testparams.get_timestamp('timestamp_12h_format_am')!
|
||||
expected := time.Duration(time.hour * 10)
|
||||
assert parsed_time == expected
|
||||
}
|
||||
|
||||
fn test_get_timestamp_12h_pm() ! {
|
||||
parsed_time := testparams.get_timestamp('timestamp_12h_format_pm')!
|
||||
assert parsed_time == time.Duration(time.hour * 20)
|
||||
}
|
||||
|
||||
fn test_get_timestamp_12h_am_minutes() ! {
|
||||
parsed_time := testparams.get_timestamp('timestamp_12h_format_am_minutes')!
|
||||
assert parsed_time == time.Duration(time.hour * 10 + time.minute * 13)
|
||||
}
|
||||
|
||||
fn test_get_timestamp_12h_pm_minutes() ! {
|
||||
parsed_time := testparams.get_timestamp('timestamp_12h_format_pm_minutes')!
|
||||
assert parsed_time == time.Duration(time.hour * 20 + time.minute * 7)
|
||||
}
|
||||
|
||||
fn test_get_timestamp_12h_pm_fails() ! {
|
||||
mut passed := true
|
||||
parsed_time := testparams.get_timestamp('timestamp_12h_format_invalid') or {
|
||||
passed = false
|
||||
time.Duration(time.hour)
|
||||
}
|
||||
if passed {
|
||||
return error('Did not throw error, it should')
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_timestamp_24h_format() ! {
|
||||
parsed_time := testparams.get_timestamp('timestamp_24h_format')!
|
||||
assert parsed_time == time.Duration(time.hour * 16 + time.minute * 21)
|
||||
}
|
||||
|
||||
fn test_get_timestamp_24h_format_fails() ! {
|
||||
mut passed := true
|
||||
parsed_time := testparams.get_timestamp('timestamp_24h_format_invalid') or {
|
||||
passed = false
|
||||
time.Duration(time.hour)
|
||||
}
|
||||
if passed {
|
||||
return error('Did not throw error, it should')
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_timestamp_default() ! {
|
||||
default_duration := time.Duration(time.hour * 8 + time.minute * 30)
|
||||
|
||||
parsed_time := testparams.get_timestamp_default('timestamp_24h_format', default_duration)!
|
||||
assert parsed_time == time.Duration(time.hour * 16 + time.minute * 21)
|
||||
|
||||
parsed_time_default := testparams.get_timestamp_default('non_existing_timestamp',
|
||||
default_duration)!
|
||||
assert parsed_time_default == default_duration
|
||||
}
|
||||
23
lib/data/paramsparser/params_json.v
Normal file
23
lib/data/paramsparser/params_json.v
Normal file
@@ -0,0 +1,23 @@
|
||||
module paramsparser
|
||||
|
||||
import json
|
||||
|
||||
// pub struct ParamsPub {
|
||||
// pub mut:
|
||||
// params []Param
|
||||
// args []string //are commands without key/val, best not to use
|
||||
// }
|
||||
|
||||
// pub struct ParamPub {
|
||||
// pub:
|
||||
// key string
|
||||
// value string
|
||||
// }
|
||||
|
||||
pub fn (mut params Params) export_json() string {
|
||||
return json.encode(params)
|
||||
}
|
||||
|
||||
pub fn json_import(data string) !Params {
|
||||
return json.decode(Params, data)
|
||||
}
|
||||
186
lib/data/paramsparser/params_reflection.v
Normal file
186
lib/data/paramsparser/params_reflection.v
Normal file
@@ -0,0 +1,186 @@
|
||||
module paramsparser
|
||||
|
||||
import time
|
||||
import v.reflection
|
||||
// import freeflowuniverse.herolib.data.encoderhero
|
||||
// TODO: support more field types
|
||||
|
||||
pub fn (params Params) decode[T]() !T {
|
||||
// work around to allow recursive decoding
|
||||
// otherwise v cant infer generic type for child fields that are structs
|
||||
return params.decode_struct[T](T{})!
|
||||
}
|
||||
|
||||
pub fn (params Params) decode_struct[T](_ T) !T {
|
||||
mut t := T{}
|
||||
$for field in T.fields {
|
||||
$if field.is_enum {
|
||||
t.$(field.name) = params.get_int(field.name) or { 0 }
|
||||
} $else {
|
||||
if field.name[0].is_capital() {
|
||||
// embed := params.decode_struct(t.$(field.name))!
|
||||
t.$(field.name) = params.decode_struct(t.$(field.name))!
|
||||
} else {
|
||||
t.$(field.name) = params.decode_value(t.$(field.name), field.name)!
|
||||
}
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
pub fn (params Params) decode_value[T](_ T, key string) !T {
|
||||
// $if T is $option {
|
||||
// // unwrap and encode optionals
|
||||
// workaround := t
|
||||
// if workaround != none {
|
||||
// encode(t, args)!
|
||||
// }
|
||||
// }
|
||||
// value := params.get(field.name)!
|
||||
|
||||
// TODO: handle required fields
|
||||
if !params.exists(key) {
|
||||
return T{}
|
||||
}
|
||||
|
||||
$if T is string {
|
||||
return params.get(key)!
|
||||
} $else $if T is int {
|
||||
return params.get_int(key)!
|
||||
} $else $if T is u32 {
|
||||
return params.get_u32(key)!
|
||||
} $else $if T is bool {
|
||||
return params.get_default_true(key)
|
||||
} $else $if T is []string {
|
||||
return params.get_list(key)!
|
||||
} $else $if T is []int {
|
||||
return params.get_list_int(key)!
|
||||
} $else $if T is []u32 {
|
||||
lst := params.get_list_u32(key)!
|
||||
return lst
|
||||
} $else $if T is time.Time {
|
||||
time_str := params.get(key)!
|
||||
// todo: 'handle other null times'
|
||||
if time_str == '0000-00-00 00:00:00' {
|
||||
return time.Time{}
|
||||
}
|
||||
return time.parse(time_str)!
|
||||
} $else $if T is $struct {
|
||||
child_params := params.get_params(key)!
|
||||
child := child_params.decode_struct(T{})!
|
||||
return child
|
||||
}
|
||||
return T{}
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct EncodeArgs {
|
||||
pub:
|
||||
recursive bool = true
|
||||
}
|
||||
|
||||
pub fn encode[T](t T, args EncodeArgs) !Params {
|
||||
$if t is $option {
|
||||
// unwrap and encode optionals
|
||||
workaround := t
|
||||
if workaround != none {
|
||||
encode(t, args)!
|
||||
}
|
||||
}
|
||||
mut params := Params{}
|
||||
|
||||
// struct_attrs := attrs_get_reflection(mytype)
|
||||
|
||||
$for field in T.fields {
|
||||
val := t.$(field.name)
|
||||
field_attrs := attrs_get(field.attrs)
|
||||
mut key := field.name
|
||||
if 'alias' in field_attrs {
|
||||
key = field_attrs['alias']
|
||||
}
|
||||
$if val is string || val is int || val is bool || val is i64 || val is u32
|
||||
|| val is time.Time {
|
||||
params.set(key, '${val}')
|
||||
} $else $if field.is_enum {
|
||||
params.set(key, '${int(val)}')
|
||||
} $else $if field.typ is []string {
|
||||
mut v2 := ''
|
||||
for i in val {
|
||||
if i.contains(' ') {
|
||||
v2 += "\"${i}\","
|
||||
} else {
|
||||
v2 += '${i},'
|
||||
}
|
||||
}
|
||||
v2 = v2.trim(',')
|
||||
params.params << Param{
|
||||
key: field.name
|
||||
value: v2
|
||||
}
|
||||
} $else $if field.typ is []int {
|
||||
mut v2 := ''
|
||||
for i in val {
|
||||
v2 += '${i},'
|
||||
}
|
||||
v2 = v2.trim(',')
|
||||
params.params << Param{
|
||||
key: field.name
|
||||
value: v2
|
||||
}
|
||||
} $else $if field.typ is []u32 {
|
||||
mut v2 := ''
|
||||
for i in val {
|
||||
v2 += '${i},'
|
||||
}
|
||||
v2 = v2.trim(',')
|
||||
params.params << Param{
|
||||
key: field.name
|
||||
value: v2
|
||||
}
|
||||
} $else $if field.typ is $struct {
|
||||
// TODO: Handle embeds better
|
||||
is_embed := field.name[0].is_capital()
|
||||
if is_embed {
|
||||
$if val is string || val is int || val is bool || val is i64 || val is u32
|
||||
|| val is time.Time {
|
||||
params.set(key, '${val}')
|
||||
}
|
||||
} else {
|
||||
if args.recursive {
|
||||
child_params := encode(val)!
|
||||
params.params << Param{
|
||||
key: field.name
|
||||
value: child_params.export()
|
||||
}
|
||||
}
|
||||
}
|
||||
} $else {
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
// BACKLOG: can we do the encode recursive?
|
||||
|
||||
// if at top of struct we have: @[name:"teststruct " ; params] .
|
||||
// will return {'name': 'teststruct', 'params': ''}
|
||||
fn attrs_get_reflection(mytype reflection.Type) map[string]string {
|
||||
if mytype.sym.info is reflection.Struct {
|
||||
return attrs_get(mytype.sym.info.attrs)
|
||||
}
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// will return {'name': 'teststruct', 'params': ''}
|
||||
fn attrs_get(attrs []string) map[string]string {
|
||||
mut out := map[string]string{}
|
||||
for i in attrs {
|
||||
if i.contains('=') {
|
||||
kv := i.split('=')
|
||||
out[kv[0].trim_space().to_lower()] = kv[1].trim_space().to_lower()
|
||||
} else {
|
||||
out[i.trim_space().to_lower()] = ''
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
116
lib/data/paramsparser/params_reflection_test.v
Normal file
116
lib/data/paramsparser/params_reflection_test.v
Normal file
@@ -0,0 +1,116 @@
|
||||
module paramsparser
|
||||
|
||||
import time
|
||||
|
||||
struct TestStruct {
|
||||
name string
|
||||
nick ?string
|
||||
birthday time.Time
|
||||
number int
|
||||
yesno bool
|
||||
liststr []string
|
||||
listint []int
|
||||
listbool []bool
|
||||
child TestChild
|
||||
}
|
||||
|
||||
struct TestChild {
|
||||
child_name string
|
||||
child_number int
|
||||
child_yesno bool
|
||||
child_liststr []string
|
||||
child_listint []int
|
||||
child_listbool []bool
|
||||
}
|
||||
|
||||
const test_child = TestChild{
|
||||
child_name: 'test_child'
|
||||
child_number: 3
|
||||
child_yesno: false
|
||||
child_liststr: ['three', 'four']
|
||||
child_listint: [3, 4]
|
||||
}
|
||||
|
||||
const test_struct = TestStruct{
|
||||
name: 'test'
|
||||
nick: 'test_nick'
|
||||
birthday: time.new(
|
||||
day: 12
|
||||
month: 12
|
||||
year: 2012
|
||||
)
|
||||
number: 2
|
||||
yesno: true
|
||||
liststr: ['one', 'two']
|
||||
listint: [1, 2]
|
||||
child: test_child
|
||||
}
|
||||
|
||||
const test_child_params = Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'child_name'
|
||||
value: 'test_child'
|
||||
},
|
||||
Param{
|
||||
key: 'child_number'
|
||||
value: '3'
|
||||
},
|
||||
Param{
|
||||
key: 'child_yesno'
|
||||
value: 'false'
|
||||
},
|
||||
Param{
|
||||
key: 'child_liststr'
|
||||
value: 'three,four'
|
||||
},
|
||||
Param{
|
||||
key: 'child_listint'
|
||||
value: '3,4'
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const test_params = Params{
|
||||
params: [Param{
|
||||
key: 'name'
|
||||
value: 'test'
|
||||
}, Param{
|
||||
key: 'nick'
|
||||
value: 'test_nick'
|
||||
}, Param{
|
||||
key: 'birthday'
|
||||
value: '2012-12-12 00:00:00'
|
||||
}, Param{
|
||||
key: 'number'
|
||||
value: '2'
|
||||
}, Param{
|
||||
key: 'yesno'
|
||||
value: 'true'
|
||||
}, Param{
|
||||
key: 'liststr'
|
||||
value: 'one,two'
|
||||
}, Param{
|
||||
key: 'listint'
|
||||
value: '1,2'
|
||||
}, Param{
|
||||
key: 'child'
|
||||
value: test_child_params.export()
|
||||
}]
|
||||
}
|
||||
|
||||
fn test_decode() {
|
||||
// test single level struct
|
||||
decoded_child := test_child_params.decode[TestChild]()!
|
||||
assert decoded_child == test_child
|
||||
|
||||
// test recursive decode struct with child
|
||||
decoded := test_params.decode[TestStruct]()!
|
||||
assert decoded == test_struct
|
||||
}
|
||||
|
||||
fn test_encode() {
|
||||
// test single level struct
|
||||
encoded_child := encode[TestChild](test_child)!
|
||||
assert encoded_child == test_child_params
|
||||
}
|
||||
52
lib/data/paramsparser/params_replace.v
Normal file
52
lib/data/paramsparser/params_replace.v
Normal file
@@ -0,0 +1,52 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.core.texttools.regext
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
// find parts of text in PARAM values which are of form {NAME}, and replace those .
|
||||
// .
|
||||
// will walk over all elements of the params, and then replace all the values .
|
||||
// .
|
||||
// NAME is as follows: .
|
||||
// Uppercase letters: A-Z .
|
||||
// Lowercase letters: a-z .
|
||||
// Digits: 0-9 .
|
||||
// Underscore: _ .
|
||||
// .
|
||||
// the NAME is key of the map, the val of the map is what we replace with
|
||||
pub fn (mut params Params) replace(args map[string]string) {
|
||||
for mut p in params.params {
|
||||
for i in regext.find_simple_vars(p.value) {
|
||||
i2 := texttools.name_fix(i)
|
||||
if i2 in args {
|
||||
console.print_debug('${i} -> ${args[i2]}')
|
||||
p.value = p.value.replace('{${i}}', args[i2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut params Params) replace_from_params(params_ Params) {
|
||||
p := params_.get_map()
|
||||
params.replace(p)
|
||||
}
|
||||
|
||||
// func main() {
|
||||
// // Sample string
|
||||
// str := "This is a sample string with ${ROOT} and another ${ROOT} instance."
|
||||
|
||||
// // Regex pattern to match `${ROOT}`
|
||||
// pattern := `\$\\{(\w+)\\}`
|
||||
// re := regexp.MustCompile(pattern)
|
||||
|
||||
// // Find all matches
|
||||
// matches := re.FindAllStringSubmatch(str, -1)
|
||||
|
||||
// // Iterate over matches and print the captured group
|
||||
// for _, match := range matches {
|
||||
// if len(match) > 1 {
|
||||
// fmt.Println(match[1]) // This will print "ROOT" for each instance found
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
44
lib/data/paramsparser/params_replace_test.v
Normal file
44
lib/data/paramsparser/params_replace_test.v
Normal file
@@ -0,0 +1,44 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_replace() {
|
||||
text := "
|
||||
key1:'{replace_me}'
|
||||
key2: {Value}
|
||||
key3: value
|
||||
"
|
||||
|
||||
mut params := new(text)!
|
||||
|
||||
mp := {
|
||||
'value': 'replaced_value'
|
||||
'replace_me': 'also_replaced_value'
|
||||
}
|
||||
|
||||
params.replace(mp)
|
||||
|
||||
assert params.get('key1')! == 'also_replaced_value'
|
||||
assert params.get('key2')! == 'replaced_value'
|
||||
assert params.get('key3')! == 'value'
|
||||
}
|
||||
|
||||
fn test_replace2() {
|
||||
params_to_replace_txt := "
|
||||
key1:'{replace_me}'
|
||||
key2: {Value}
|
||||
key3: value
|
||||
"
|
||||
|
||||
mut params_to_replace := new(params_to_replace_txt)!
|
||||
|
||||
params_args_txt := '
|
||||
value:replaced_value
|
||||
replace_me:also_replaced_value
|
||||
'
|
||||
mut params_args := new(params_args_txt)!
|
||||
|
||||
params_to_replace.replace_from_params(params_args)
|
||||
|
||||
assert params_to_replace.get('key1')! == 'also_replaced_value'
|
||||
assert params_to_replace.get('key2')! == 'replaced_value'
|
||||
assert params_to_replace.get('key3')! == 'value'
|
||||
}
|
||||
53
lib/data/paramsparser/params_resp.v
Normal file
53
lib/data/paramsparser/params_resp.v
Normal file
@@ -0,0 +1,53 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.data.resp
|
||||
|
||||
// TODO: fix this. encoding some params and redecoding them does not work.
|
||||
|
||||
// encode using resp (redis procotol)
|
||||
pub fn (mut p Params) to_resp() ![]u8 {
|
||||
mut b_main := resp.builder_new()
|
||||
mut b_param := resp.builder_new()
|
||||
for param in p.params {
|
||||
b_param.add(resp.r_list_string([param.key, param.value]))
|
||||
}
|
||||
mut b_arg := resp.builder_new()
|
||||
for arg in p.args {
|
||||
b_arg.add(resp.r_string(arg))
|
||||
}
|
||||
b_main.add(resp.r_list_bytestring([b_param.data, b_arg.data]))
|
||||
|
||||
return b_main.data
|
||||
}
|
||||
|
||||
pub fn from_resp(data []u8) !Params {
|
||||
mut p := Params{}
|
||||
|
||||
mut top_array_ := resp.decode(data)![0]
|
||||
top_array := top_array_ as resp.RArray
|
||||
|
||||
params_string := top_array.values[0] as resp.RBString
|
||||
params_array := resp.decode(params_string.value)!
|
||||
|
||||
for param_string_ in params_array {
|
||||
param_string := param_string_ as resp.RArray
|
||||
key_rstring := param_string.values[0] as resp.RString
|
||||
value_rstring := param_string.values[1] as resp.RString
|
||||
p.params << Param{
|
||||
key: key_rstring.value
|
||||
value: value_rstring.value
|
||||
}
|
||||
}
|
||||
|
||||
args_string := top_array.values[1] as resp.RBString
|
||||
args_array := resp.decode(args_string.value)!
|
||||
|
||||
for arg_string_ in args_array {
|
||||
arg_string := arg_string_ as resp.RString
|
||||
p.args << arg_string.value
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// NEXT: needs to do a good test, this protocol is much smaller than default text format
|
||||
19
lib/data/paramsparser/params_resp_test.v
Normal file
19
lib/data/paramsparser/params_resp_test.v
Normal file
@@ -0,0 +1,19 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_to_resp() {
|
||||
text := '
|
||||
key1: {replace_me}
|
||||
key2: {Value}
|
||||
key3: value
|
||||
arg1
|
||||
arg2
|
||||
'
|
||||
|
||||
mut params := new(text)!
|
||||
|
||||
encoded := params.to_resp()!
|
||||
|
||||
decoded_params := from_resp(encoded)!
|
||||
|
||||
assert params == decoded_params
|
||||
}
|
||||
369
lib/data/paramsparser/params_test.v
Normal file
369
lib/data/paramsparser/params_test.v
Normal file
@@ -0,0 +1,369 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import json
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
const textin = "
|
||||
id:a1 name6:aaaaa
|
||||
name:'need to do something 1'
|
||||
//comment
|
||||
description:'
|
||||
## markdown works in it
|
||||
|
||||
description can be multiline
|
||||
lets see what happens
|
||||
|
||||
- a
|
||||
- something else
|
||||
|
||||
### subtitle
|
||||
|
||||
```python
|
||||
#even code block in the other block, crazy parsing for sure
|
||||
def test():
|
||||
console.print_debug()
|
||||
```
|
||||
'
|
||||
|
||||
name2: test
|
||||
name3: hi name10:'this is with space' name11:aaa11
|
||||
|
||||
//some comment
|
||||
|
||||
name4: 'aaa'
|
||||
|
||||
//somecomment
|
||||
name5: 'aab'
|
||||
"
|
||||
|
||||
const textin2 = "
|
||||
//this is a cool piece of text
|
||||
//
|
||||
//now end of comment
|
||||
id:a1 name6:aaaaa
|
||||
name:'need to do something 1'
|
||||
description:'something<BR>yes' //comment 1
|
||||
|
||||
aa //arg comment
|
||||
bb
|
||||
name2: test
|
||||
name3: hi name10:'this is with space' name11:aaa11
|
||||
|
||||
// some comment 2
|
||||
|
||||
name4: 'aaa'
|
||||
|
||||
name5: 'aab' //somecomment 3
|
||||
"
|
||||
|
||||
const textin3 = '
|
||||
zz //comment 1
|
||||
id:a1 name6:aaaaa //comment 2
|
||||
'
|
||||
|
||||
fn test_hexhash() {
|
||||
mut params := parse(textin2)!
|
||||
console.print_debug('${params}')
|
||||
h := params.hexhash()
|
||||
assert h == 'fca5c320391e7a91ec91999b1b3d66bf5cb7658905284c431777ff6d2fa4a4c3'
|
||||
}
|
||||
|
||||
fn test_textin3() {
|
||||
params := parse(textin3) or { panic(err) }
|
||||
assert params == Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'id'
|
||||
value: 'a1'
|
||||
comment: 'comment 2'
|
||||
},
|
||||
Param{
|
||||
key: 'name6'
|
||||
value: 'aaaaa'
|
||||
comment: ''
|
||||
},
|
||||
]
|
||||
args: ['zz']
|
||||
comments: ['comment 1']
|
||||
}
|
||||
}
|
||||
|
||||
fn test_macro_args() {
|
||||
mut text := "arg1 arg2 color:red priority:'incredible' description:'with spaces, lets see if ok'"
|
||||
params := parse(text) or { panic(err) }
|
||||
|
||||
expexted_res := Params{
|
||||
params: [Param{
|
||||
key: 'color'
|
||||
value: 'red'
|
||||
}, Param{
|
||||
key: 'priority'
|
||||
value: 'incredible'
|
||||
}, Param{
|
||||
key: 'description'
|
||||
value: 'with spaces, lets see if ok'
|
||||
}]
|
||||
args: ['arg1', 'arg2']
|
||||
}
|
||||
|
||||
assert expexted_res == params
|
||||
|
||||
mut text2 := "arg1 color:red priority:'incredible' arg2 description:'with spaces, lets see if ok'"
|
||||
params2 := parse(text2) or { panic(err) }
|
||||
|
||||
assert expexted_res == params2
|
||||
}
|
||||
|
||||
fn test_args_get() {
|
||||
mut text := "arg1 color:red priority:'2' description:'with spaces, lets see if ok' x:5 arg2"
|
||||
mut params := parse(text) or { panic(err) }
|
||||
|
||||
assert params.exists_arg('arg1')
|
||||
assert params.exists_arg('arg2')
|
||||
assert !params.exists_arg('arg')
|
||||
|
||||
mut x := params.get_int('x') or { panic(err) }
|
||||
assert x == 5
|
||||
x = params.get_int('y') or { 6 }
|
||||
assert x == 6
|
||||
x = params.get_int('priority') or { panic(err) }
|
||||
assert x == 2
|
||||
|
||||
mut y := params.get('priority') or { panic(err) }
|
||||
assert y == '2'
|
||||
}
|
||||
|
||||
fn test_url1() {
|
||||
mut text := "color:red url:'https://github.com/freeflowuniverse/herolib/tree/development/examples/mdbook/books_to_include1'"
|
||||
mut params := parse(text) or { panic(err) }
|
||||
mut text2 := 'color:red url:"https://github.com/freeflowuniverse/herolib/tree/development/examples/mdbook/books_to_include1 "'
|
||||
mut params2 := parse(text2) or { panic(err) }
|
||||
assert params.get('url')? == 'https://github.com/freeflowuniverse/herolib/tree/development/examples/mdbook/books_to_include1'
|
||||
assert params2.get('url')? == 'https://github.com/freeflowuniverse/herolib/tree/development/examples/mdbook/books_to_include1'
|
||||
}
|
||||
|
||||
// // fn test_json() {
|
||||
|
||||
// // mut params := parse(textin) or { panic(err) }
|
||||
|
||||
// // d:=params.export_json()
|
||||
|
||||
// // mut params2 := json_import(d) or {panic(err)}
|
||||
|
||||
// // panic("ssss")
|
||||
|
||||
// // }
|
||||
|
||||
// fn test_export() {
|
||||
// mut params := parse(textin)!
|
||||
|
||||
// d := params.export()
|
||||
|
||||
// mut out := "
|
||||
// description:'## markdown works in it\\n\\ndescription can be multiline\\nlets see what happens\\n\\n- a\\n- something else\\n\\n### subtitle\\n\\n```python\\n#even code block in the other block, crazy parsing for sure\\ndef test():\\n console.print_debug()\\n```'
|
||||
// id:a1
|
||||
// name:'need to do something 1'
|
||||
// name10:'this is with space'
|
||||
// name11:aaa11
|
||||
// name2:test
|
||||
// name3:hi
|
||||
// name4:aaa
|
||||
// name5:aab
|
||||
// name6:aaaaa
|
||||
// "
|
||||
// assert texttools.dedent(d) == texttools.dedent(out).trim_space()
|
||||
// }
|
||||
|
||||
// fn test_export2() {
|
||||
// mut params := parse(textin2) or { panic(err) }
|
||||
|
||||
// d := params.export()
|
||||
|
||||
// mut out := "
|
||||
// description:something\\nyes
|
||||
// id:a1
|
||||
// name:'need to do something 1'
|
||||
// name10:'this is with space'
|
||||
// name11:aaa11
|
||||
// name2:test
|
||||
// name3:hi
|
||||
// name4:aaa
|
||||
// name5:aab
|
||||
// name6:aaaaa
|
||||
// aa
|
||||
// bb
|
||||
// zz
|
||||
// "
|
||||
// assert texttools.dedent(d) == texttools.dedent(out).trim_space()
|
||||
// }
|
||||
|
||||
// fn test_import1() {
|
||||
// mut params := parse(textin2) or { panic(err) }
|
||||
|
||||
// d := params.export()
|
||||
// mut params2 := importparams(d) or { panic(err) }
|
||||
|
||||
// assert params.equal(params2)
|
||||
// }
|
||||
|
||||
// fn test_import2() {
|
||||
// mut params := parse(textin2) or { panic(err) }
|
||||
|
||||
// d := "
|
||||
// id:a1
|
||||
// zz
|
||||
// name:'need to do something 1'
|
||||
// name10:'this is with space'
|
||||
// name11:aaa11
|
||||
// name2:test
|
||||
// name3:hi
|
||||
// name4:aaa
|
||||
// name5:aab
|
||||
// name6:aaaaa
|
||||
// aa
|
||||
// bb
|
||||
// description:something\\nyes
|
||||
|
||||
// "
|
||||
// mut params2 := importparams(d)!
|
||||
|
||||
// assert params.equal(params2)
|
||||
// }
|
||||
|
||||
// fn test_params_default_false() {
|
||||
// mut params := parse('
|
||||
// certified:false
|
||||
// certified1:no
|
||||
// certified2:n
|
||||
// certified3:0
|
||||
// ')!
|
||||
|
||||
// assert params.get_default_false('certified') == false
|
||||
// assert params.get_default_false('certified1') == false
|
||||
// assert params.get_default_false('certified2') == false
|
||||
// assert params.get_default_false('certified3') == false
|
||||
// assert params.get_default_false('certified4') == false
|
||||
// }
|
||||
|
||||
// fn test_params_default_true() {
|
||||
// mut params := parse('
|
||||
// certified:true
|
||||
// certified1:yes
|
||||
// certified2:y
|
||||
// certified3:1
|
||||
// ')!
|
||||
|
||||
// assert params.get_default_true('certified') == true
|
||||
// assert params.get_default_true('certified1') == true
|
||||
// assert params.get_default_true('certified2') == true
|
||||
// assert params.get_default_true('certified3') == true
|
||||
// assert params.get_default_true('certified4') == true
|
||||
// }
|
||||
|
||||
// fn test_kwargs_add() {
|
||||
// mut params := parse(textin2) or { panic(err) }
|
||||
|
||||
// console.print_debug(params.params)
|
||||
|
||||
// assert params.params.len == 10
|
||||
|
||||
// params.set('name3', 'anotherhi')
|
||||
// assert params.params.len == 10
|
||||
// params.set('name7', 'anotherhi')
|
||||
// assert params.params.len == 11 // because is new one
|
||||
|
||||
// assert params.get('name3') or { '' } == 'anotherhi'
|
||||
// }
|
||||
|
||||
// fn test_args_add() {
|
||||
// mut params := parse('urgency:yes red green') or { panic(err) }
|
||||
|
||||
// console.print_debug(params.args)
|
||||
|
||||
// assert params.params.len == 1
|
||||
// assert params.args.len == 2
|
||||
|
||||
// params.set_arg('red')
|
||||
// assert params.args.len == 2
|
||||
// params.set_arg('yellow')
|
||||
// assert params.args.len == 3
|
||||
// }
|
||||
|
||||
// fn test_merge() {
|
||||
// mut params := parse('urgency:yes red green') or { panic(err) }
|
||||
|
||||
// console.print_debug(params.args)
|
||||
|
||||
// params.merge('urgency:green blue') or { panic('s') }
|
||||
|
||||
// console.print_debug(params.args)
|
||||
|
||||
// assert params.params.len == 1
|
||||
// assert params.args.len == 3
|
||||
|
||||
// assert params.get('urgency') or { '' } == 'green'
|
||||
// }
|
||||
|
||||
// fn test_textin2() {
|
||||
// params := parse(paramsparser.textin2) or { panic(err) }
|
||||
// console.print_debug(params)
|
||||
// assert params == Params{
|
||||
// params: [
|
||||
// Param{
|
||||
// key: 'id'
|
||||
// value: 'a1'
|
||||
// comment: 'this is a cool piece of text
|
||||
|
||||
// now end of comment'
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name6'
|
||||
// value: 'aaaaa'
|
||||
// comment: ''
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name'
|
||||
// value: 'need to do something 1'
|
||||
// comment: ''
|
||||
// },
|
||||
// Param{
|
||||
// key: 'description'
|
||||
// value: 'something\\nyes'
|
||||
// comment: 'comment 1'
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name2'
|
||||
// value: 'test'
|
||||
// comment: ''
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name3'
|
||||
// value: 'hi'
|
||||
// comment: ''
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name10'
|
||||
// value: 'this is with space'
|
||||
// comment: ''
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name11'
|
||||
// value: 'aaa11'
|
||||
// comment: ''
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name4'
|
||||
// value: 'aaa'
|
||||
// comment: 'some comment 2'
|
||||
// },
|
||||
// Param{
|
||||
// key: 'name5'
|
||||
// value: 'aab'
|
||||
// comment: 'somecomment 3'
|
||||
// },
|
||||
// ]
|
||||
// args: ['aa', 'bb']
|
||||
// comments: ['arg comment']
|
||||
// }
|
||||
// }
|
||||
226
lib/data/paramsparser/parser.v
Normal file
226
lib/data/paramsparser/parser.v
Normal file
@@ -0,0 +1,226 @@
|
||||
module paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
|
||||
enum ParamStatus {
|
||||
start
|
||||
name // found name of the var (could be an arg)
|
||||
value_wait // wait for value to start (can be quote or end of spaces and first meaningful char)
|
||||
value // value started, so was no quote
|
||||
quote // quote found means value in between ''
|
||||
value_end // quote found means value in between ''
|
||||
comment
|
||||
}
|
||||
|
||||
// convert text with e.g. color:red or color:'red' to arguments
|
||||
// multiline is supported
|
||||
// result is params object which allows you to query the info you need
|
||||
// params is following:
|
||||
//
|
||||
// struct Params {
|
||||
// params []Param
|
||||
// args []Arg
|
||||
// }
|
||||
// struct Arg {
|
||||
// value string
|
||||
// }
|
||||
// struct Param {
|
||||
// key string
|
||||
// value string
|
||||
// }
|
||||
// it has nice methods to query the params
|
||||
pub fn parse(text string) !Params {
|
||||
mut text2 := texttools.dedent(text)
|
||||
// mut text2 := text
|
||||
// console.print_debug("****PARSER")
|
||||
// console.print_debug(text2)
|
||||
// console.print_debug("****PARSER END")
|
||||
text2 = text2.replace('"', "'")
|
||||
text2 = texttools.multiline_to_single(text2)!
|
||||
// console.print_debug("1")
|
||||
validchars := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_,./'
|
||||
|
||||
mut ch := ''
|
||||
mut ch_prev := ''
|
||||
mut state := ParamStatus.start
|
||||
mut result := Params{}
|
||||
mut key := ''
|
||||
mut value := ''
|
||||
mut list := false
|
||||
mut comment := ''
|
||||
|
||||
for i in 0 .. text2.len {
|
||||
ch = text2[i..i + 1]
|
||||
// println(" - '${ch_prev}${ch}' ${state}")
|
||||
|
||||
if state == .value_end {
|
||||
if ch == ' ' {
|
||||
ch_prev = ch
|
||||
continue
|
||||
} else if ch == ',' {
|
||||
list = true
|
||||
// means we are in list, must wait for next value
|
||||
last_item := value.all_after_last(',')
|
||||
if requires_quotes(last_item) {
|
||||
value = '${value.all_before_last(',')},"${last_item}"'
|
||||
}
|
||||
state = .value_wait
|
||||
} else if ch == '\n' && list {
|
||||
list = false
|
||||
} else {
|
||||
state = .start
|
||||
result.set_with_comment(key, value, comment)
|
||||
key = ''
|
||||
value = ''
|
||||
comment = ''
|
||||
}
|
||||
}
|
||||
|
||||
// check for comments end
|
||||
if state == .start {
|
||||
if ch == ' ' {
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
state = .name
|
||||
}
|
||||
if state == .name {
|
||||
if ch_prev == '/' && ch == '/' {
|
||||
// we are now comment
|
||||
state = .comment
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
|
||||
if ch == ' ' && key == '' {
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
// waiting for :
|
||||
if ch == ':' {
|
||||
state = ParamStatus.value_wait
|
||||
ch_prev = ch
|
||||
continue
|
||||
} else if ch == ' ' {
|
||||
state = ParamStatus.start
|
||||
result.set_arg_with_comment(key, comment)
|
||||
key = ''
|
||||
comment = ''
|
||||
value = ''
|
||||
ch_prev = ch
|
||||
continue
|
||||
} else if !validchars.contains(ch) {
|
||||
print_backtrace()
|
||||
return error("text to params processor: parameters can only be A-Za-z0-9 and _., found illegal char: '${key}${ch}' in\n${text2}\n\n")
|
||||
} else {
|
||||
key += ch
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
}
|
||||
if state == .value_wait {
|
||||
if ch == "'" {
|
||||
state = .quote
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
// if ch == '[' {
|
||||
// state = .array
|
||||
// ch_prev = ch
|
||||
// value = ''
|
||||
// continue
|
||||
// }
|
||||
// means the value started, we can go to next state
|
||||
if ch != ' ' {
|
||||
state = .value
|
||||
}
|
||||
}
|
||||
|
||||
if state == .value {
|
||||
if ch == ',' {
|
||||
// means in list and our value has ended
|
||||
value += ch
|
||||
list = true
|
||||
state = .value_wait
|
||||
}
|
||||
}
|
||||
|
||||
if state == .value {
|
||||
if ch == ' ' {
|
||||
state = .value_end
|
||||
list = false
|
||||
} else {
|
||||
value += ch
|
||||
}
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
if state == .quote {
|
||||
if ch == "'" && ch_prev != '\\' {
|
||||
state = .value_end
|
||||
} else {
|
||||
value += ch
|
||||
}
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
|
||||
// if state == .array {
|
||||
// if ch == ']' {
|
||||
// state = .start
|
||||
// result.set_with_comment(key, value, comment)
|
||||
// key = ''
|
||||
// value = ''
|
||||
// comment = ''
|
||||
// } else {
|
||||
// value += ch
|
||||
// }
|
||||
// ch_prev = ch
|
||||
// continue
|
||||
// }
|
||||
|
||||
if state == .value || state == ParamStatus.start {
|
||||
if ch == '/' && ch_prev == '/' {
|
||||
// we are now comment
|
||||
state = .comment
|
||||
}
|
||||
}
|
||||
|
||||
if state == ParamStatus.comment {
|
||||
if ch == '/' && ch_prev == '-' {
|
||||
state = .start
|
||||
ch_prev = ch
|
||||
continue
|
||||
}
|
||||
comment += ch
|
||||
}
|
||||
|
||||
ch_prev = ch
|
||||
}
|
||||
|
||||
// last value
|
||||
if state == ParamStatus.value || state == ParamStatus.quote || state == .value_end {
|
||||
if list {
|
||||
last_item := value.all_after_last(',')
|
||||
if requires_quotes(last_item) {
|
||||
value = '${value.all_before_last(',')},"${last_item}"'
|
||||
}
|
||||
}
|
||||
result.set_with_comment(key, value, comment)
|
||||
}
|
||||
|
||||
if state == ParamStatus.name {
|
||||
if key != '' {
|
||||
result.set_arg_with_comment(key, comment)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// returns wether a provided value requires quotes
|
||||
fn requires_quotes(value string) bool {
|
||||
if value.contains(' ') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
101
lib/data/paramsparser/parser_test.v
Normal file
101
lib/data/paramsparser/parser_test.v
Normal file
@@ -0,0 +1,101 @@
|
||||
module paramsparser
|
||||
|
||||
fn test_parse_list() ! {
|
||||
mut params := parse("list0: 'Apple'")!
|
||||
|
||||
// Test parsing lists with single string item
|
||||
mut fruit_list := [
|
||||
"list0: 'Apple'",
|
||||
'list1: Apple',
|
||||
'list2:Apple',
|
||||
'list3: Apple ',
|
||||
]
|
||||
|
||||
for i, param in fruit_list {
|
||||
params = parse(param)!
|
||||
assert params == Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'list${i}'
|
||||
value: 'Apple'
|
||||
comment: ''
|
||||
},
|
||||
]
|
||||
args: []
|
||||
comments: []
|
||||
}
|
||||
}
|
||||
|
||||
// Test parsing lists with multiple string items
|
||||
fruit_list = [
|
||||
'list0: Apple, Banana',
|
||||
'list1: Apple ,Banana',
|
||||
'list2: Apple , Banana',
|
||||
'list3: Apple , Banana',
|
||||
"list4: 'Apple', Banana",
|
||||
"list5: Apple, 'Banana'",
|
||||
"list6: 'Apple', 'Banana'",
|
||||
]
|
||||
|
||||
for i, param in fruit_list {
|
||||
params = parse(param)!
|
||||
assert params == Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'list${i}'
|
||||
value: 'Apple,Banana'
|
||||
comment: ''
|
||||
},
|
||||
]
|
||||
args: []
|
||||
comments: []
|
||||
}
|
||||
}
|
||||
|
||||
// Test parsing lists with multi-word items
|
||||
fruit_list = [
|
||||
'list0: Apple, "Dragon Fruit", "Passion Fruit"',
|
||||
'list1: "Apple", "Dragon Fruit", "Passion Fruit"',
|
||||
"list2: Apple, 'Dragon Fruit', 'Passion Fruit'",
|
||||
"list3: 'Apple', 'Dragon Fruit', 'Passion Fruit'",
|
||||
]
|
||||
|
||||
for i, param in fruit_list {
|
||||
params = parse(param)!
|
||||
assert params == Params{
|
||||
params: [
|
||||
Param{
|
||||
key: 'list${i}'
|
||||
value: 'Apple,"Dragon Fruit","Passion Fruit"'
|
||||
comment: ''
|
||||
},
|
||||
]
|
||||
args: []
|
||||
comments: []
|
||||
}
|
||||
}
|
||||
|
||||
// // test parsing lists in square brackets
|
||||
// params = parse("list1: ['Kiwi']")!
|
||||
// assert params == Params{
|
||||
// params: [Param{
|
||||
// key: 'list1'
|
||||
// value: "['Kiwi']"
|
||||
// comment: ''
|
||||
// }]
|
||||
// args: []
|
||||
// comments: []
|
||||
// }
|
||||
// params = parse("list2: 'Apple', 'Banana'")!
|
||||
// assert params == Params{
|
||||
// params: [
|
||||
// Param{
|
||||
// key: 'list2'
|
||||
// value: "['Apple', 'Banana']"
|
||||
// comment: ''
|
||||
// },
|
||||
// ]
|
||||
// args: []
|
||||
// comments: []
|
||||
// }
|
||||
}
|
||||
271
lib/data/paramsparser/readme.md
Normal file
271
lib/data/paramsparser/readme.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# ParamsParser Module Documentation
|
||||
|
||||
The ParamsParser module provides a powerful way to parse and handle parameter strings in V. It's particularly useful for parsing command-line style arguments and key-value pairs from text.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
|
||||
// Create new params from text
|
||||
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
|
||||
|
||||
// Or create empty params and add later
|
||||
mut params := paramsparser.new_params()
|
||||
params.set("color", "red")
|
||||
```
|
||||
|
||||
## Parameter Format
|
||||
|
||||
The parser supports several formats:
|
||||
|
||||
1. Key-value pairs: `key:value`
|
||||
2. Quoted values: `key:'value with spaces'`
|
||||
3. Arguments without keys: `arg1 arg2`
|
||||
4. Comments: `// this is a comment`
|
||||
|
||||
Example:
|
||||
```v
|
||||
text := "name:'John Doe' age:30 active:true // user details"
|
||||
params := paramsparser.new(text)!
|
||||
```
|
||||
|
||||
## Getting Values
|
||||
|
||||
The module provides various methods to retrieve values:
|
||||
|
||||
```v
|
||||
// Get string value
|
||||
name := params.get("name")! // returns "John Doe"
|
||||
|
||||
// Get with default value
|
||||
color := params.get_default("color", "blue")! // returns "blue" if color not set
|
||||
|
||||
// Get as integer
|
||||
age := params.get_int("age")! // returns 30
|
||||
|
||||
// Get as boolean (true if value is "1", "true", "y", "yes")
|
||||
is_active := params.get_default_true("active")
|
||||
|
||||
// Get as float
|
||||
score := params.get_float("score")!
|
||||
|
||||
// Get as percentage (converts "80%" to 0.8)
|
||||
progress := params.get_percentage("progress")!
|
||||
```
|
||||
|
||||
## Type Conversion Methods
|
||||
|
||||
The module supports various type conversions:
|
||||
|
||||
### Basic Types
|
||||
- `get_int()`: Convert to int32
|
||||
- `get_u32()`: Convert to unsigned 32-bit integer
|
||||
- `get_u64()`: Convert to unsigned 64-bit integer
|
||||
- `get_u8()`: Convert to unsigned 8-bit integer
|
||||
- `get_float()`: Convert to 64-bit float
|
||||
- `get_percentage()`: Convert percentage string to float (e.g., "80%" → 0.8)
|
||||
|
||||
### Boolean Values
|
||||
- `get_default_true()`: Returns true if value is empty, "1", "true", "y", or "yes"
|
||||
- `get_default_false()`: Returns false if value is empty, "0", "false", "n", or "no"
|
||||
|
||||
### Lists
|
||||
The module provides robust support for parsing and converting lists:
|
||||
|
||||
```v
|
||||
// Basic list parsing
|
||||
names := params.get_list("users")! // parses ["user1", "user2", "user3"]
|
||||
|
||||
// With default value
|
||||
tags := params.get_list_default("tags", ["default"])!
|
||||
|
||||
// Lists with type conversion
|
||||
numbers := params.get_list_int("ids")! // converts each item to int
|
||||
amounts := params.get_list_f64("prices")! // converts each item to f64
|
||||
|
||||
// Name-fixed lists (normalizes each item)
|
||||
clean_names := params.get_list_namefix("categories")!
|
||||
```
|
||||
|
||||
Supported list types:
|
||||
- `get_list()`: String list
|
||||
- `get_list_u8()`, `get_list_u16()`, `get_list_u32()`, `get_list_u64()`: Unsigned integers
|
||||
- `get_list_i8()`, `get_list_i16()`, `get_list_int()`, `get_list_i64()`: Signed integers
|
||||
- `get_list_f32()`, `get_list_f64()`: Floating point numbers
|
||||
|
||||
Each list method has a corresponding `_default` version that accepts a default value.
|
||||
|
||||
Valid list formats:
|
||||
```v
|
||||
users: ["john", "jane", "bob"]
|
||||
ids: 1,2,3,4,5
|
||||
names: ['John Doe', 'Jane Smith']
|
||||
```
|
||||
|
||||
## Working with Arguments
|
||||
|
||||
Arguments are values without keys:
|
||||
|
||||
```v
|
||||
// Parse text with arguments
|
||||
params := paramsparser.new("arg1 arg2 key:value")!
|
||||
|
||||
// Add an argument
|
||||
params.set_arg("arg3")
|
||||
|
||||
// Check if argument exists
|
||||
if params.exists_arg("arg1") {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
## Additional Features
|
||||
|
||||
1. Case insensitive keys:
|
||||
```v
|
||||
params.set("Color", "red")
|
||||
value := params.get("color")! // works
|
||||
```
|
||||
|
||||
2. Map conversion:
|
||||
```v
|
||||
// Convert params to map
|
||||
map_values := params.get_map()
|
||||
```
|
||||
|
||||
3. Merging params:
|
||||
```v
|
||||
mut params1 := paramsparser.new("color:red")!
|
||||
params2 := paramsparser.new("size:large")!
|
||||
params1.merge(params2)!
|
||||
```
|
||||
|
||||
4. Delete parameters:
|
||||
```v
|
||||
params.delete("color") // delete key-value pair
|
||||
params.delete_arg("arg1") // delete argument
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Most methods return results that should be handled with V's error handling:
|
||||
|
||||
```v
|
||||
// Using ! operator for methods that can fail
|
||||
name := params.get("name")!
|
||||
|
||||
// Or with or {} block for custom error handling
|
||||
name := params.get("name") or {
|
||||
println("Error: ${err}")
|
||||
"default_name"
|
||||
}
|
||||
```
|
||||
|
||||
## Parameter Validation
|
||||
|
||||
The parser enforces certain rules:
|
||||
- Keys can only contain A-Z, a-z, 0-9, underscore, dot, and forward slash
|
||||
- Values can contain any characters
|
||||
- Spaces in values must be enclosed in quotes
|
||||
- Lists are supported with comma separation
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always handle potential errors with `!` or `or {}`
|
||||
2. Use type-specific getters (`get_int`, `get_float`, etc.) when you know the expected type
|
||||
3. Provide default values when appropriate using the `_default` methods
|
||||
4. Use quotes for values containing spaces
|
||||
5. Use lowercase keys for consistency (though the parser is case-insensitive)
|
||||
|
||||
|
||||
# Params Details
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
|
||||
mut p:=paramsparser.new('
|
||||
id:a1 name6:aaaaa
|
||||
name:'need to do something 1'
|
||||
)!
|
||||
|
||||
assert "a1"==p.get_default("id","")!
|
||||
|
||||
|
||||
```
|
||||
|
||||
example text to parse
|
||||
|
||||
```yaml
|
||||
id:a1 name6:aaaaa
|
||||
name:'need to do something 1'
|
||||
description:
|
||||
## markdown works in it
|
||||
|
||||
description can be multiline
|
||||
lets see what happens
|
||||
|
||||
- a
|
||||
- something else
|
||||
|
||||
### subtitle
|
||||
|
||||
|
||||
name2: test
|
||||
name3: hi name10:'this is with space' name11:aaa11
|
||||
|
||||
#some comment
|
||||
|
||||
name4: 'aaa'
|
||||
|
||||
//somecomment
|
||||
name5: 'aab'
|
||||
```
|
||||
|
||||
results in
|
||||
|
||||
```go
|
||||
Params{
|
||||
params: [Param{
|
||||
key: 'id'
|
||||
value: 'a1'
|
||||
}, Param{
|
||||
key: 'name6'
|
||||
value: 'aaaaa'
|
||||
}, Param{
|
||||
key: 'name'
|
||||
value: 'need to do something 1'
|
||||
}, Param{
|
||||
key: 'description'
|
||||
value: '## markdown works in it
|
||||
|
||||
description can be multiline
|
||||
lets see what happens
|
||||
|
||||
- a
|
||||
- something else
|
||||
|
||||
### subtitle
|
||||
'
|
||||
}, Param{
|
||||
key: 'name2'
|
||||
value: 'test'
|
||||
}, Param{
|
||||
key: 'name3'
|
||||
value: 'hi'
|
||||
}, Param{
|
||||
key: 'name10'
|
||||
value: 'this is with space'
|
||||
}, Param{
|
||||
key: 'name11'
|
||||
value: 'aaa11'
|
||||
}, Param{
|
||||
key: 'name4'
|
||||
value: 'aaa'
|
||||
}, Param{
|
||||
key: 'name5'
|
||||
value: 'aab'
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user