package Morpheus::Key; BEGIN { $Morpheus::Key::VERSION = '0.40'; } use strict; # ABSTRACT: class representing config key use overload 'eq' => sub { @_ = upgrade(@_); ${$_[0]} eq ${$_[1]} }, 'lt' => \&less, 'le' => sub { @_ = upgrade(@_); $_[0] lt $_[1] or $_[0] eq $_[1] }, 'gt' => sub { @_ = upgrade(@_); $_[1] lt $_[0] }, 'ge' => sub { @_ = upgrade(@_); $_[1] lt $_[0] or $_[0] eq $_[1] }, #ATTN 'not $x < $y' does not mean '$x >= $y' '""' => sub { ${$_[0]} }, '@{}' => \&parts; use base qw(Exporter); our @EXPORT_OK = qw(key); sub new { my $class = shift; my $key = shift; $key =~ s{/+}{/}g; $key =~ s{^/*}{/}; #TODO: support relative keys? $key =~ s{/+$}{}; bless \$key => $class; } sub upgrade { map { ref $_ ? $_ : __PACKAGE__->new($_) } @_; } sub less ($$) { @_ = upgrade(@_); my ($key1, $key2) = @_; $key1 = "$key1"; $key2 = "$key2"; return length $key1 < length $key2 && substr($key2, 0, 1 + length $key1) eq "$key1/"; } sub parts ($) { my ($key) = @_; $key = "$key"; $key =~ s{^/}{}; return [split qr{/}, $key]; } sub key { __PACKAGE__->new($_[0]); } 1; __END__ =pod =head1 NAME Morpheus::Key - class representing config key =head1 VERSION version 0.40 =head1 SYNOPSIS use Morpheus::Key qw(key); $key = Morpheus::Key->new("/foo/bar/x"); $key = key("/foo/bar/y"); say "key: $key"; say "parts: ", join '/', @{ $key->parts }; key("/foo/bar") ge key("/foo"); # true key("/foo") gt key("/bar"); # false key("/bar") gt key("/foo"); # also false =head1 DESCRIPTION Morpheus configuration tree looks very much like a file system with directory structure and files. The names of these "directories" and "files" are called I. They are either represented by a string of the form C (like a file path) or by the C object. In fact Morpheus always casts the string key representation into an object to simplify its further usage. Morpheus::Key class provides the following features: =head2 Normalization The string representation of a key has a disadvantage that unequal strings may refer to the same namespace. Morpheus::Key class does a normalization of the key string so that equal namespaces were represented by equal strings. That normalization includes: =over =item * Removal of a trailing slash if present ("/a/b/c/" -> "/a/b/c"). =item * Removal of repeated slashes ("/a//b///c" -> "/a/b/c"). =item * Appending of a leading "/" if it is missing ("a/b" -> "/a/b"). We plan to remove this normalization step in the future as soon as we introduce a notion of "relative" keys. =back We also consider the idea of making configuration keys case insensitive, but at the moment the key case is completely preserved. =head2 Comparison operators It is often required to check if two namespaces are equal or one namespace is a part of another one. Morpheus::Key class overloads the following operators to help do so: eq, ne, lt, le, gt, ge. Note that the set of configuration keys is only partially ordered, that is both $key1 ge $key2 and $key1 le $key2 may be false. Consider $key1 = "/a/b" and $key2 = "/a/c" for instance. =head2 Transparent access to string key representation Morpheus::Key objects return their string representation when stringified. =head2 Splitting into namespace parts C<< $key->parts >> return an arrayref of key parts. =head1 AUTHOR Andrei Mishchenko =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011 by Yandex LLC. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut