mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: More robust schema matching.
* Fixed some weirdness with partial matching in shaped. * Added an all matcher for bundling multiple partial matches together.
This commit is contained in:
parent
643b597e35
commit
524f85102f
@ -23,12 +23,12 @@ let must = func (m, msg) => select m, fail msg, {
|
||||
true = m,
|
||||
};
|
||||
|
||||
// Any does a boolean match against a set of allowed shapes for a type.
|
||||
// All does a boolean match against all of set of allowed shapes for a type.
|
||||
// This module uses the shape module below so the same rules for checking
|
||||
// the types against the source value apply for each example in the list.
|
||||
//
|
||||
// This module does not do partial matches for the shapes.
|
||||
let any = module {
|
||||
// This module does partial matches for the shapes.
|
||||
let all = module {
|
||||
// The source value to check.
|
||||
val=NULL,
|
||||
// The set of allowed type shapes it can be.
|
||||
@ -37,7 +37,30 @@ let any = module {
|
||||
let schema = mod.pkg();
|
||||
|
||||
let reducer = func (acc, t) => acc{
|
||||
ok = acc.ok || (schema.shaped{val=acc.val, shape=t, partial=false}),
|
||||
ok = acc.ok && (schema.shaped{val=acc.val, shape=t, partial=true}),
|
||||
};
|
||||
let any = func (val, types) => reduce(reducer, {ok=true, val=val}, types);
|
||||
|
||||
let result = any(mod.val, mod.types).ok;
|
||||
};
|
||||
|
||||
// Any does a boolean match against a set of allowed shapes for a type.
|
||||
// This module uses the shape module below so the same rules for checking
|
||||
// the types against the source value apply for each example in the list.
|
||||
//
|
||||
// This module does not do partial matches for the shapes by default.
|
||||
let any = module {
|
||||
// The source value to check.
|
||||
val=NULL,
|
||||
// The set of allowed type shapes it can be.
|
||||
types=[],
|
||||
// Whether to do partial matches for the shapes
|
||||
partial=false
|
||||
} => (result) {
|
||||
let schema = mod.pkg();
|
||||
|
||||
let reducer = func (acc, t) => acc{
|
||||
ok = acc.ok || (schema.shaped{val=acc.val, shape=t, partial=mod.partial}),
|
||||
};
|
||||
let any = func (val, types) => reduce(reducer, {ok=false, val=val}, types);
|
||||
|
||||
@ -74,23 +97,37 @@ let shaped = module {
|
||||
|
||||
let tuple_handler = func (acc, name, value) => acc{
|
||||
ok = select (name) in acc.shape, mod.partial, {
|
||||
true = schema.shaped{val=value, shape=acc.shape.(name)},
|
||||
true = schema.shaped{val=value, shape=acc.shape.(name), partial=mod.partial},
|
||||
},
|
||||
};
|
||||
|
||||
let list_handler = func(acc, value) => acc{
|
||||
ok = false || schema.any{val=value, types=acc.shape},
|
||||
let shape_tuple_handler = func (acc, name, value) => acc{
|
||||
ok = select (name) in acc.val, false, {
|
||||
true = schema.shaped{val=value, shape=acc.val.(name), partial=false},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
let match_shape_fields = func(val, shape) => reduce(
|
||||
shape_tuple_handler, {val=val, ok=false}, shape).ok;
|
||||
|
||||
let match_tuple_fields = func(val, shape) =>
|
||||
reduce(tuple_handler, {shape=shape, ok=false}, val).ok;
|
||||
|
||||
let list_handler = func(acc, value) => acc{
|
||||
ok = acc.ok && schema.any{val=value, types=acc.shape},
|
||||
};
|
||||
|
||||
let result =select schema.base_type_of(mod.val), false, {
|
||||
str = simple_handler(mod.val, mod.shape),
|
||||
int = simple_handler(mod.val, mod.shape),
|
||||
float = simple_handler(mod.val, mod.shape),
|
||||
bool = simple_handler(mod.val, mod.shape),
|
||||
null = simple_handler(mod.val, mod.shape),
|
||||
tuple = (mod.shape is "tuple") && reduce(tuple_handler, {shape=mod.shape, ok=false}, mod.val).ok,
|
||||
list = select mod.shape == [], true, {
|
||||
false = reduce(list_handler, {shape=mod.shape, ok=false}, mod.val).ok,
|
||||
tuple = (mod.shape is "tuple") &&
|
||||
match_shape_fields(mod.val, mod.shape) &&
|
||||
match_tuple_fields(mod.val, mod.shape),
|
||||
list = (mod.shape is "list") && select mod.shape == [], true, {
|
||||
false = reduce(list_handler, {shape=mod.shape, ok=true}, mod.val).ok,
|
||||
},
|
||||
func = simple_handler(mod.val, mod.shape),
|
||||
module = simple_handler(mod.val, mod.shape),
|
||||
|
@ -131,12 +131,42 @@ assert t.ok{
|
||||
desc="inner list with valid types matches empty list shape",
|
||||
};
|
||||
|
||||
assert t.not_ok{
|
||||
test = schema.shaped{val={list=[1, "foo"]}, shape={list="foo"}},
|
||||
desc="inner list with with non list shape does not match",
|
||||
};
|
||||
|
||||
assert t.not_ok{
|
||||
test = schema.shaped{val={foo="bar"}, shaped=1.0},
|
||||
desc = "a tuple is not a float",
|
||||
};
|
||||
|
||||
assert t.not_ok{
|
||||
test = schema.any{val={foo="bar", quux="baz"}, types=[1.0, {foo="bar", qux="baz"}]},
|
||||
desc = "any doesn't match against missing fields for tuples.",
|
||||
test = schema.any{val={foo="bar", quux="baz"}, types=[1.0, {foo="bar"}]},
|
||||
desc = "any doesn't match against missing fields for tuples for value tuple.",
|
||||
};
|
||||
|
||||
assert t.ok{
|
||||
test = schema.any{val={foo="bar", quux="baz"}, types=[1.0, {foo="bar"}], partial=true},
|
||||
desc = "any can do partial matching against missing fields for tuples shapes.",
|
||||
};
|
||||
|
||||
assert t.not_ok{
|
||||
test = schema.any{val={foo="bar"}, types=[1.0, {foo="", quux=""}]},
|
||||
desc = "any does match against missing fields for tuples shape tuple.",
|
||||
};
|
||||
|
||||
assert t.not_ok{
|
||||
test = schema.shaped{val={foo="bar", baz="quux"}, shape={bear=""}, partial=true},
|
||||
desc = "even with partial all of the shape fields must be present.",
|
||||
};
|
||||
|
||||
assert t.ok{
|
||||
test = schema.all{val={foo="bar", baz="quux"}, types=[{foo=""}, {baz=""}]},
|
||||
desc = "all enforces that all of the valid types are partial matches (success)",
|
||||
};
|
||||
|
||||
assert t.not_ok{
|
||||
test = schema.all{val={foo="bar", baz="quux"}, types=[{foo=""}, {baz=""}, {quux=""}]},
|
||||
desc = "all enforces that all of the valid shapes must be partial matches (fail)",
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user