The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

use strict;
use utf8;
=encoding utf8
=head1 NAME
Acrux::Pointer - The Acrux pointer
=head1 SYNOPSIS
use Acrux::Pointer;
my $pointer = Acrux::Pointer->new(data => {foo => [123, 'bar']});
say $pointer->get('/foo/1');
say 'Contains "/foo".' if $pointer->contains('/foo');
=head1 DESCRIPTION
This class is an implementation of L<RFC 6901|https://tools.ietf.org/html/rfc6901>
for perl hash-structures
=head2 new
my $pointer = Acrux::Pointer->new;
my $pointer = Acrux::Pointer->new(data => {foo => 'bar'});
Build new Acrux::Pointer object
=head1 ATTRIBUTES
This class implements the following attributes
=head2 data
my $data = $pointer->data;
$pointer = $pointer->data({foo => 'bar'});
Data structure to be processed
=head1 METHODS
This class implements the following methods
=head2 contains
my $bool = $pointer->contains('/foo/1');
Check if L</"data"> contains a value that can be identified with the given pointer
=head2 get
my $value = $pointer->get('/foo/bar');
Extract value from L</"data"> identified by the given pointer
# "just a string"
Acrux::Pointer->new(data => 'just a string')->get();
# "bar"
Acrux::Pointer->new(data => {foo => 'bar', baz => [4, 5, 6]})->get('/foo');
# "4"
Acrux::Pointer->new(data => {foo => 'bar', baz => [4, 5, 6]})->get('/baz/0');
# "6"
Acrux::Pointer->new(data => {foo => 'bar', baz => [4, 5, 6]})->get('/baz/2');
=head1 HISTORY
See C<Changes> file
=head1 TO DO
See C<TODO> file
=head1 SEE ALSO
L<Mojo::JSON::Pointer>
=head1 AUTHOR
Serż Minus (Sergey Lepenkov) L<https://www.serzik.com> E<lt>abalama@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1998-2024 D&D Corporation. All Rights Reserved
=head1 LICENSE
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See C<LICENSE> file and L<https://dev.perl.org/licenses/>
=cut
our $VERSION = '0.01';
sub new {
my $class = shift;
my $args = @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {};
my $self = bless {
data => $args->{data}
}, $class;
return $self;
}
sub data {
my $self = shift;
if (scalar(@_) >= 1) {
$self->{data} = shift;
return $self;
}
return $self->{data};
}
sub contains { shift->_p(0, @_) }
sub get { shift->_p(1, @_) }
sub _p {
my $self = shift;
my $get = shift;
my $pointer = shift // '';
$pointer =~ s|^/||;
my $data = $self->data;
return $get ? $data : 1 unless length($pointer);
foreach my $p (length($pointer) ? (split /\//, $pointer, -1) : ($pointer)) {
$p =~ s|~1|/|g;
$p =~ s|~0|~|g;
if ((ref($data) eq 'HASH') && exists $data->{$p}) { # Hash ref
$data = $data->{$p}
} elsif ((ref($data) eq 'ARRAY') && ($p =~ /^[0-9]+$/) && @$data > $p) { # Array ref
$data = $data->[$p]
} else { # Not found
return undef;
}
}
return $get ? $data : 1;
}
1;
__END__