diff options
Diffstat (limited to 'lib/Data')
-rw-r--r-- | lib/Data/MultiValued.pod | 70 | ||||
-rw-r--r-- | lib/Data/MultiValued/Ranges.pm | 101 | ||||
-rw-r--r-- | lib/Data/MultiValued/Tags.pm | 67 | ||||
-rw-r--r-- | lib/Data/MultiValued/TagsAndRanges.pm | 60 |
4 files changed, 296 insertions, 2 deletions
diff --git a/lib/Data/MultiValued.pod b/lib/Data/MultiValued.pod new file mode 100644 index 0000000..ebae360 --- /dev/null +++ b/lib/Data/MultiValued.pod @@ -0,0 +1,70 @@ +# PODNAME: Data::MultiValued +# ABSTRACT: store tag- and range-dependant data in a scalar or Moose attribute + +=head1 SYNOPSIS + + use Data::MultiValued::Tags; + + my $obj = Data::MultiValued::Tags->new(); + $obj->set({ + tag => 'tag1', + value => 'a string', + }); + say $obj->get({tag=>'tag1'}); # prints 'a string' + say $obj->get({tag=>'tag2'}); # dies + +Also: + + package My::Class; + use Moose; + use Data::MultiValued::AttributeTrait::Tags; + + has stuff => ( + is => 'rw', + isa => 'Int', + traits => ['MultiValued::Tags'], + ); + + # later + + my $obj = My::Class->new(); + $obj->stuff_multi({tag=>'tag1'},123); + say $obj->stuff_multi({tag=>'tag1'}); # prints 123 + +=head1 DESCRIPTION + +This set of classes allows you to store different values inside a +single object, and access them by tag and / or by a numeric value. + +Yes, you could do the same with hashes and some clever use of +arrays. Or you could use L<Array::IntSpan>. Or some other CPAN +module. Why use these? + +=over 4 + +=item * + +they are optimised for serialisation, see +L<Data::MultiValued::UglySerializationHelperRole> and F<t/json.t>. + +=item * + +you get accessors generated for your Moose attributes just by setting +a trait + +=item * + +tags and ranges interact in sensible ways, including clearing ranges + +=back + +=head1 Where to go from here + +Look at the tests for detailed examples of usage. Look at +L<Data::MultiValued::Tags>, L<Data::MultiValued::Ranges> and +L<Data::MultiValued::TagsAndRanges> for the containers +themselves. Look at L<Data::MultiValued::AttributeTrait::Tags>, +L<Data::MultiValued::AttributeTrait::Ranges> and +L<Data::MultiValued::AttributeTrait::TagsAndRanges> for the Moose +attribute traits. + diff --git a/lib/Data/MultiValued/Ranges.pm b/lib/Data/MultiValued/Ranges.pm index 9c69626..21898af 100644 --- a/lib/Data/MultiValued/Ranges.pm +++ b/lib/Data/MultiValued/Ranges.pm @@ -6,7 +6,24 @@ use MooseX::Types::Moose qw(Num Str Undef Any); use Data::MultiValued::Exceptions; use Data::MultiValued::RangeContainer; -# ABSTRACT: Handle values with tags and validity ranges +# ABSTRACT: Handle values with validity ranges + +=head1 SYNOPSIS + + use Data::MultiValued::Ranges; + + my $obj = Data::MultiValued::Ranges->new(); + $obj->set({ + from => 10, + to => 20, + value => 'foo', + }); + say $obj->get({at => 15}); # prints 'foo' + say $obj->get({at => 35}); # dies + +=head1 METHODS + +=cut has _storage => ( is => 'rw', @@ -32,6 +49,39 @@ sub _as_hash { return {_storage=>\%ret}; } +=head2 C<set> + + $obj->set({ from => $min, to => $max, value => $the_value }); + +Stores the given value for the given range. Does not throw exceptions. + +The range is defined as C<< Num $x : $min <= $x < $max >>. A C<< from +=> undef >> means "from -Inf", and a C<< to => undef >> means "to ++Inf". Not passing in C<from> or C<to> is equivalent to passing +C<undef>. + +If the given range intersects existing ranges, these are spliced to +avoid overlaps. In other words: + + $obj->set({ + from => 10, + to => 20, + value => 'foo', + }); + $obj->set({ + from => 15, + to => 25, + value => 'bar', + }); + say $obj->get({at => 12}); # prints 'foo' + say $obj->get({at => 15}); # prints 'bar' + say $obj->get({at => 25}); # dies + +No cloning is done: if you pass in a reference, the reference is +just stored. + +=cut + sub set { my ($self,%args) = validated_hash( \@_, @@ -44,6 +94,23 @@ sub set { ->{value} = $args{value}; } +=head2 C<get> + + my $value = $obj->get({ at => $point }); + +Retrieves the value for the given point. Throws a +L<Data::MultiValued::Exceptions::RangeNotFound> exception if no ranges +exist in this object that include the point (remember that a range +does not include its C<to> point). + +A C<< at => undef >> means "at -Inf". Not passing in C<at> is +equivalent to passing C<undef>. + +No cloning is done: if a reference was stored, you get it back +untouched. + +=cut + sub get { my ($self,%args) = validated_hash( \@_, @@ -54,6 +121,33 @@ sub get { ->{value}; } +=head2 C<clear> + + $obj->clear({ from => $min, to => $max }); + +Deletes all values for the given range. Does not throw exceptions. + +A C<< from => undef >> means "from -Inf", and a C<< to => undef >> +means "to +Inf". Not passing in C<from> or C<to> is equivalent to +passing C<undef>. Thus, C<< $obj->clear() >> clears everything. + +If the given range intersects existing ranges, these are spliced. In +other words: + + $obj->set({ + from => 10, + to => 20, + value => 'foo', + }); + $obj->clear({ + from => 15, + to => 25, + }); + say $obj->get({at => 12}); # prints 'foo' + say $obj->get({at => 15}); # dies + +=cut + sub clear { my ($self,%args) = validated_hash( \@_, @@ -64,5 +158,10 @@ sub clear { $self->_storage->clear(\%args); } +=head1 SEE ALSO + +L<Data::MultiValued::RangeContainer>, L<Data::MultiValued::Exceptions> + +=cut 1; diff --git a/lib/Data/MultiValued/Tags.pm b/lib/Data/MultiValued/Tags.pm index fbf7948..083bbb8 100644 --- a/lib/Data/MultiValued/Tags.pm +++ b/lib/Data/MultiValued/Tags.pm @@ -6,7 +6,23 @@ use MooseX::Types::Moose qw(Num Str Undef Any); use Data::MultiValued::Exceptions; use Data::MultiValued::TagContainer; -# ABSTRACT: Handle values with tags and validity ranges +# ABSTRACT: Handle values with tags + +=head1 SYNOPSIS + + use Data::MultiValued::Tags; + + my $obj = Data::MultiValued::Tags->new(); + $obj->set({ + tag => 'tag1', + value => 'a string', + }); + say $obj->get({tag=>'tag1'}); # prints 'a string' + say $obj->get({tag=>'tag2'}); # dies + +=head1 METHODS + +=cut has _storage => ( is => 'rw', @@ -32,6 +48,21 @@ sub _as_hash { return {_storage=>\%ret}; } +=head2 C<set> + + $obj->set({ tag => $the_tag, value => $the_value }); + +Stores the given value for the given tag. Replaces existing +values. Does not throw exceptions. + +Not passing in a C<tag> is equivalent to passing in C<< tag => undef +>>. + +No cloning is done: if you pass in a reference, the reference is +just stored. + +=cut + sub set { my ($self,%args) = validated_hash( \@_, @@ -43,6 +74,22 @@ sub set { ->{value} = $args{value}; } +=head2 C<get> + + my $value = $obj->get({ tag => $the_tag }); + +Retrieves the value for the given tag. Throws a +L<Data::MultiValued::Exceptions::TagNotFound> exception if the tag +does not exists in this object. + +Not passing in a C<tag> is equivalent to passing in C<< tag => undef +>>. + +No cloning is done: if a reference was stored, you get it back +untouched. + +=cut + sub get { my ($self,%args) = validated_hash( \@_, @@ -53,6 +100,18 @@ sub get { ->{value}; } +=head2 C<clear> + + $obj->clear({ tag => $the_tag }); + +Deletes the given tag and all data associated with it. Does not throw +exceptions: if the tag does not exist, nothing happens. + +Not passing in a C<tag> clears everything. Yes, this means that there +is no way to just clear the value for the C<undef> tag. + +=cut + sub clear { my ($self,%args) = validated_hash( \@_, @@ -62,4 +121,10 @@ sub clear { $self->_storage->clear(\%args); } +=head1 SEE ALSO + +L<Data::MultiValued::TagContainer>, L<Data::MultiValued::Exceptions> + +=cut + 1; diff --git a/lib/Data/MultiValued/TagsAndRanges.pm b/lib/Data/MultiValued/TagsAndRanges.pm index 6208435..32e2acb 100644 --- a/lib/Data/MultiValued/TagsAndRanges.pm +++ b/lib/Data/MultiValued/TagsAndRanges.pm @@ -8,6 +8,25 @@ use Data::MultiValued::TagContainerForRanges; # ABSTRACT: Handle values with tags and validity ranges +=head1 SYNOPSIS + + use Data::MultiValued::TagsAndRanges; + + my $obj = Data::MultiValued::TagsAndRanges->new(); + $obj->set({ + tag => 'tag1', + from => 10, + to => 20, + value => 'foo', + }); + say $obj->get({tag => 'tag1', at => 15}); # prints 'foo' + say $obj->get({tag => 'tag1', at => 35}); # dies + say $obj->get({tag => 'tag2', at => 15}); # dies + +=head1 METHODS + +=cut + has _storage => ( is => 'rw', isa => class_type('Data::MultiValued::TagContainerForRanges'), @@ -33,6 +52,18 @@ sub _as_hash { return {_storage=>$ret}; } +=head2 C<set> + + $obj->set({ tag => $the_tag, from => $min, to => $max, value => $the_value }); + +Stores the given value for the given tag and range. Does not throw +exceptions. + +See L<Data::MultiValued::Tags/set> and +L<Data::MultiValued::Ranges/set> for more details. + +=cut + sub set { my ($self,%args) = validated_hash( \@_, @@ -47,6 +78,21 @@ sub set { ->{value} = $args{value}; } +=head2 C<get> + + my $value = $obj->get({ tag => $the_tag, at => $point }); + +Retrieves the value for the given tag and point. Throws a +L<Data::MultiValued::Exceptions::RangeNotFound> exception if no ranges +exist in this object that include the point, and +L<Data::MultiValued::Exceptions::TagNotFound> exception if the tag +does not exists in this object. + +See L<Data::MultiValued::Tags/get> and +L<Data::MultiValued::Ranges/get> for more details. + +=cut + sub get { my ($self,%args) = validated_hash( \@_, @@ -59,6 +105,20 @@ sub get { ->{value}; } +=head2 C<clear> + + $obj->clear({ tag => $the_tag, from => $min, to => $max }); + +If a range is specified, deletes all values for the given range and +tag. If no range is specified, delete all values for the given tag. + +Does not throw exceptions. + +See L<Data::MultiValued::Tags/clear> and +L<Data::MultiValued::Ranges/clear> for more details. + +=cut + sub clear { my ($self,%args) = validated_hash( \@_, |