Attached is a pretty complete implementation.
use v5.16;
use B;
sub aoaooono {
my ($hash, $style, $quote_keys) = @_;
my $process_element = sub {
my $element = shift;
ref $element eq 'HASH'
? aoaooono($element, $style, $quote_keys)
: sprintf(
$style,
$quote_keys && $element !~ /\A[a-z_][a-z0-9_]*\z/i
? B::cstring($element)
: $element,
);
};
my $process_elements = sub {
my ($arrayref, $join) = @_;
return $arrayref->[0]->$process_element if @$arrayref == 1;
sprintf '(%s)', join " $join " => map $_->$process_element, @$arrayref;
};
if ($hash->{any_of}) {
$hash->{any_of}->$process_elements('or');
}
elsif ($hash->{all_of}) {
$hash->{all_of}->$process_elements('and');
}
elsif ($hash->{one_of}) {
$hash->{one_of}->$process_elements('xor');
}
elsif ($hash->{none_of}) {
'!' . $hash->{none_of}->$process_elements('or');
}
}
say aoaooono({
any_of => [
'foo',
{ all_of => ['bar', 'baz', { none_of => ['instant-death'] }] },
{ one_of => [qw/ quux quuux quuuux /] },
],
},'exists $_{%s}', !!1);