From 4894f619980c6928ff6861ee95e9da68ac6988f7 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 28 May 2022 09:17:28 +0300 Subject: [PATCH] toml: add `pub fn (d Doc) value_opt(key string) ?Any {` and some tests for toml.parse_dotted_key/1 --- vlib/toml/any.v | 23 ++++++++++++++++------ vlib/toml/tests/key_test.v | 39 +++++++++++++++++++++++++++++--------- vlib/toml/toml.v | 27 +++++++++++++++++++------- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/vlib/toml/any.v b/vlib/toml/any.v index 12df98e8b..c7a8f3a9a 100644 --- a/vlib/toml/any.v +++ b/vlib/toml/any.v @@ -281,24 +281,35 @@ pub fn (a []Any) to_toml() string { // quoted keys are supported as `a."b.c"` or `a.'b.c'`. // Arrays can be queried with `a[0].b[1].[2]`. pub fn (a Any) value(key string) Any { - key_split := parse_dotted_key(key) or { return Any(Null{}) } + key_split := parse_dotted_key(key) or { return null } return a.value_(a, key_split) } +pub fn (a Any) value_opt(key string) ?Any { + key_split := parse_dotted_key(key) or { return error('invalid dotted key') } + x := a.value_(a, key_split) + if x is Null { + return error('no value for key') + } + return x +} + // value_ returns the `Any` value found at `key`. fn (a Any) value_(value Any, key []string) Any { - assert key.len > 0 - mut any_value := Any(Null{}) + if key.len == 0 { + return null + } + mut any_value := null k, index := parse_array_key(key[0]) if k == '' { arr := value as []Any - any_value = arr[index] or { return Any(Null{}) } + any_value = arr[index] or { return null } } if value is map[string]Any { - any_value = value[k] or { return Any(Null{}) } + any_value = value[k] or { return null } if index > -1 { arr := any_value as []Any - any_value = arr[index] or { return Any(Null{}) } + any_value = arr[index] or { return null } } } if key.len <= 1 { diff --git a/vlib/toml/tests/key_test.v b/vlib/toml/tests/key_test.v index ceb3c8906..9f3dc2913 100644 --- a/vlib/toml/tests/key_test.v +++ b/vlib/toml/tests/key_test.v @@ -2,11 +2,12 @@ import os import toml import toml.to -fn test_keys() { - toml_file := - os.real_path(os.join_path(os.dir(@FILE), 'testdata', os.file_name(@FILE).all_before_last('.'))) + - '.toml' - toml_doc := toml.parse_file(toml_file) or { panic(err) } +fn path_by_extension(ext string) string { + return os.join_path(os.dir(@VEXE), 'vlib/toml/tests/testdata/key_test.$ext') +} + +fn test_keys() ? { + toml_doc := toml.parse_file(path_by_extension('toml'))? mut value := toml_doc.value('34-11') assert value.int() == 23 @@ -18,10 +19,30 @@ fn test_keys() { assert value.int() == 42 toml_json := to.json(toml_doc) - out_file := - os.real_path(os.join_path(os.dir(@FILE), 'testdata', os.file_name(@FILE).all_before_last('.'))) + - '.out' - out_file_json := os.read_file(out_file) or { panic(err) } + out_file_json := os.read_file(path_by_extension('out'))? println(toml_json) assert toml_json == out_file_json + // + if x := toml_doc.value_opt('unknown key') { + assert false + } else { + assert err.msg() == 'no value for key' + } + if x := toml_doc.value_opt("'a") { + assert false + } else { + assert err.msg() == 'invalid dotted key' + } +} + +fn test_parse_dotted_key() ? { + assert toml.parse_dotted_key('')? == [] + assert toml.parse_dotted_key('abc')? == ['abc'] + assert toml.parse_dotted_key('tube.test."test.test".h."i.j."."k"')? == ['tube', 'test', + 'test.test', 'h', 'i.j.', 'k'] + if x := toml.parse_dotted_key("'some unclosed string") { + assert false + } else { + assert err.msg().starts_with('parse_dotted_key: could not parse key, missing closing string delimiter') + } } diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index c26b9fb6a..c32fe9442 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -201,26 +201,39 @@ pub fn (d Doc) reflect() T { // quoted keys are supported as `a."b.c"` or `a.'b.c'`. // Arrays can be queried with `a[0].b[1].[2]`. pub fn (d Doc) value(key string) Any { - key_split := parse_dotted_key(key) or { return Any(Null{}) } + key_split := parse_dotted_key(key) or { return toml.null } return d.value_(d.ast.table, key_split) } +pub const null = Any(Null{}) + +pub fn (d Doc) value_opt(key string) ?Any { + key_split := parse_dotted_key(key) or { return error('invalid dotted key') } + x := d.value_(d.ast.table, key_split) + if x is Null { + return error('no value for key') + } + return x +} + // value_ returns the value found at `key` in the map `values` as `Any` type. fn (d Doc) value_(value ast.Value, key []string) Any { - assert key.len > 0 + if key.len == 0 { + return toml.null + } mut ast_value := ast.Value(ast.Null{}) k, index := parse_array_key(key[0]) if k == '' { a := value as []ast.Value - ast_value = a[index] or { return Any(Null{}) } + ast_value = a[index] or { return toml.null } } if value is map[string]ast.Value { - ast_value = value[k] or { return Any(Null{}) } + ast_value = value[k] or { return toml.null } if index > -1 { a := ast_value as []ast.Value - ast_value = a[index] or { return Any(Null{}) } + ast_value = a[index] or { return toml.null } } } @@ -298,11 +311,11 @@ pub fn ast_to_any(value ast.Value) Any { return aa } else { - return Any(Null{}) + return toml.null } } - return Any(Null{}) + return toml.null // TODO decide this // panic(@MOD + '.' + @STRUCT + '.' + @FN + ' can\'t convert "$value"') // return Any('') -- 2.30.2