File Coverage

blib/lib/Data/Tree.pm
Criterion Covered Total %
statement 11 13 84.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 16 18 88.8


line stmt bran cond sub pod time code
1             package Data::Tree;
2             {
3             $Data::Tree::VERSION = '0.16';
4             }
5             BEGIN {
6 1     1   24108 $Data::Tree::AUTHORITY = 'cpan:TEX';
7             }
8             # ABSTRACT: a hash-based tree-like data structure
9              
10 1     1   29 use 5.010_000;
  1         5  
  1         43  
11 1     1   1043 use mro 'c3';
  1         753  
  1         6  
12 1     1   38 use feature ':5.10';
  1         2  
  1         118  
13              
14 1     1   438 use Moose;
  0            
  0            
15             use namespace::autoclean;
16              
17             # use IO::Handle;
18             # use autodie;
19             # use MooseX::Params::Validate;
20             # use Carp;
21             # use English qw( -no_match_vars );
22             # use Try::Tiny;
23              
24             # extends ...
25             # has ...
26             has 'data' => (
27             'is' => 'rw',
28             'isa' => 'HashRef',
29             'lazy' => 1,
30             'builder' => '_init_data',
31             );
32              
33             has 'debug' => (
34             'is' => 'rw',
35             'isa' => 'Bool',
36             'lazy' => 1,
37             'builder' => '_init_debug',
38             );
39             # with ...
40             # initializers ...
41             sub _init_data {
42             return {};
43             }
44              
45             sub _init_debug {
46             my $self = shift;
47              
48             if($ENV{'DATA_TREE_DEBUG'}) {
49             return 1;
50             }
51              
52             return 0;
53             }
54              
55             # your code here ...
56             ############################################
57             # Usage : $C->set('Path::To::Key','Value');
58             # Purpose : Set a value to the given key.
59             # Returns :
60             # Parameters :
61             # Throws : no exceptions
62             # Comments : none
63             # See Also : n/a
64             ## no critic (ProhibitAmbiguousNames)
65             sub set {
66             my $self = shift;
67             my $key = shift;
68             my $value = shift;
69             my $force = shift || 0;
70              
71             my ( $ref, $last_key ) = $self->_find_leaf($key);
72             if ( ref( $ref->{$last_key} ) eq 'HASH' && !$force ) {
73             return;
74             }
75             $ref->{$last_key} = $value;
76             return $value;
77             }
78             ## use critic
79              
80             sub increment {
81             my $self = shift;
82             my $key = shift;
83             my $increment = shift // 1;
84              
85             my $value = $self->get($key) || 0;
86              
87             # bail out if value != numeric
88             if($value !~ m/^\d+$/) {
89             return $value;
90             }
91              
92             $value += $increment;
93             $self->set( $key, $value );
94              
95             return $value;
96             }
97              
98             sub decrement {
99             my $self = shift;
100             my $key = shift;
101             my $decrement = shift || 1;
102              
103             my $value = $self->get($key) || 0;
104              
105             # bail out if value != numeric
106             if($value !~ m/^\d+$/) {
107             return $value;
108             }
109              
110             $value -= $decrement;
111             $self->set( $key, $value );
112              
113             return $value;
114             }
115              
116             ############################################
117             # THIS METHOD IS NOT PART OF OUR PUBLIC API!
118             # Usage :
119             # Purpose :
120             # Returns :
121             # Parameters :
122             # Throws : no exceptions
123             # Comments : none
124             # See Also : n/a
125             # THIS METHOD IS NOT PART OF OUR PUBLIC API!
126             sub _find_leaf {
127             my $self = shift;
128             my $key = shift;
129              
130             my @path = ();
131             if ( ref($key) eq 'ARRAY' ) {
132             @path = map { lc($_); } @{$key};
133             }
134             else {
135             $key = lc($key);
136             @path = split /::/, $key;
137             }
138              
139             my $ref = $self->data();
140             my $last_step = undef;
141             while ( my $step = shift @path ) {
142             $last_step = $step;
143             if ( @path < 1 ) {
144             last;
145             }
146             elsif ( ref( $ref->{$step} ) eq 'HASH' ) {
147             $ref = $ref->{$step};
148             }
149             elsif ( @path >= 1 ) {
150             $ref->{$step} = {};
151             $ref = $ref->{$step};
152             }
153             else {
154             warn "Unhandled condition in _find_leaf w/ key $key in step $step in Data::Tree::_find_leaf().\n" if $self->debug();
155             }
156             }
157              
158             # ref contains the hash ref one step above the wanted entry,
159             # last_step is the key in this hash to access the wanted
160             # entry.
161             # this is necessary or
162             return ( $ref, $last_step );
163             }
164              
165             ############################################
166             # Usage : my $value = $C->get('Path::To::Key');
167             # Purpose : Retrieve a value from the config.
168             # Returns : The value.
169             # Parameters : The name of the key.
170             # Throws : no exceptions
171             # Comments : none
172             # See Also : n/a
173             sub get {
174             my $self = shift;
175             my $key = shift;
176             my $opts = shift || {};
177              
178             my ( $ref, $last_key ) = $self->_find_leaf($key);
179              
180             if ( exists( $ref->{$last_key} ) ) {
181             return $ref->{$last_key};
182             }
183             else {
184             if ( exists( $opts->{'Default'} ) ) {
185             return $opts->{'Default'};
186             }
187             else {
188             return;
189             }
190             }
191             }
192              
193             # return a single value out of an array
194             sub get_scalar {
195             my $self = shift;
196             my $key = shift;
197              
198             my $value = $self->get($key);
199              
200             if ( $value && ref($value) && ref($value) eq 'ARRAY' ) {
201             return $value->[0];
202             }
203             elsif ( $value && ref($value) && ref($value) eq 'HASH' ) {
204             return ( keys %{$value} )[0];
205             }
206             else {
207             return $value;
208             }
209             }
210              
211             ############################################
212             # Usage : my @values = $C->get_array('Path::To::Key');
213             # Purpose : Retrieve an array of values from config.
214             # Returns : The values as an array.
215             # Parameters : The name of the key.
216             # Throws : no exceptions
217             # Comments : none
218             # See Also : n/a
219             sub get_array {
220             my $self = shift;
221             my $key = shift;
222             my $opts = shift || {};
223              
224             my $ref = $self->get($key);
225              
226             if ( $ref && ref($ref) eq 'HASH' ) {
227             warn "Returning only the keys of a hashref in Data::Tree::get_array($key).\n" if $self->debug();
228             return ( keys %{$ref} );
229             }
230             elsif ( $ref && ref($ref) eq 'ARRAY' ) {
231             return @{$ref};
232             }
233             elsif ($ref) {
234             return ($ref);
235             }
236             elsif ( defined( $opts->{'Default'} ) && ref($opts->{'Default'}) eq 'ARRAY' ) {
237             return @{$opts->{'Default'}};
238             }
239             else {
240             ## no critic (ProhibitMagicNumbers)
241             my $caller = ( caller(1) )[3] || 'n/a';
242             ## use critic
243             warn "Returning empty array in Data::Tree::get_array($key) to $caller.\n" if $self->debug();
244             return ();
245             }
246             }
247             ## no critic (ProhibitBuiltinHomonyms)
248             sub delete {
249             ## use critic
250             my $self = shift;
251             my $key = shift;
252              
253             my ( $ref, $last_key ) = $self->_find_leaf($key);
254              
255             if ( ref($ref) eq 'HASH' ) {
256             delete $ref->{$last_key};
257             return 1;
258             }
259             else {
260              
261             # don't know how to handle non hash refs
262             return;
263             }
264             }
265              
266             no Moose;
267             __PACKAGE__->meta->make_immutable;
268              
269             1;
270              
271             =pod
272              
273             =encoding utf-8
274              
275             =head1 NAME
276              
277             Data::Tree - a hash-based tree-like data structure
278              
279             =head1 SYNOPSIS
280              
281             use Data::Tree;
282             my $DT = Data::Tree::->new();
283              
284             $DT->set('First::Key',[qw(a b c]);
285             $DT->get('First::Key'); # should return [a b c]
286             $DT->get_scalar('First::Key'); # should return a
287             $DT->get_array('First::Key'); # should return (a, b, c)
288              
289             =head1 DESCRIPTION
290              
291             A simple hash-based nested tree.
292              
293             =head1 METHODS
294              
295             =head2 decrement
296              
297             Decrement the numeric value of the given key by one.
298              
299             =head2 delete
300              
301             Remove the given key and all subordinate keys.
302              
303             =head2 get
304              
305             Return the value associated with the given key. May be an SCALAR, HASH or ARRAY.
306              
307             =head2 get_array
308              
309             Return the values associated with the given key as a list.
310              
311             =head2 get_scalar
312              
313             Return the value associated with the given key as an SCALAR.
314              
315             =head2 increment
316              
317             Increment the numeric value of the given key by one.
318              
319             =head2 set
320              
321             Set the value of the given key to the given value.
322              
323             =head1 NAME
324              
325             Data::Tree - A simple hash-based tree.
326              
327             =head1 AUTHOR
328              
329             Dominik Schulz <dominik.schulz@gauner.org>
330              
331             =head1 COPYRIGHT AND LICENSE
332              
333             This software is copyright (c) 2012 by Dominik Schulz.
334              
335             This is free software; you can redistribute it and/or modify it under
336             the same terms as the Perl 5 programming language system itself.
337              
338             =cut
339              
340             __END__
341              
342              
343             1; # End of Data::Pwgen