File Coverage

blib/lib/Data/DynamicValidator/Path.pm
Criterion Covered Total %
statement 79 80 98.7
branch 12 16 75.0
condition 13 22 59.0
subroutine 16 16 100.0
pod 1 7 14.2
total 121 141 85.8


line stmt bran cond sub pod time code
1             package Data::DynamicValidator::Path;
2             {
3             $Data::DynamicValidator::Path::VERSION = '0.03';
4             }
5             # ABSTRACT: Class represents "splitted" to labelled componets path.
6              
7 8     8   5467 use strict;
  8         18  
  8         286  
8 8     8   45 use warnings;
  8         14  
  8         204  
9              
10 8     8   44 use Carp;
  8         15  
  8         589  
11 8     8   47 use Scalar::Util qw/looks_like_number/;
  8         22  
  8         582  
12              
13 8     8   46 use overload fallback => 1, q/""/ => sub { $_[0]->to_string };
  8     168   188  
  8         74  
  168         629381  
14              
15 8   50 8   610 use constant DEBUG => $ENV{DATA_DYNAMICVALIDATOR_DEBUG} || 0;
  8         14  
  8         10987  
16              
17             sub new {
18 87     87 0 22012 my ($class, $path) = @_;
19 87         171 my $self = { };
20 87         233 bless $self => $class;
21 87         222 $self->_build_components($path);
22 87         291 return $self;
23             }
24              
25             sub _build_components {
26 87     87   139 my ($self, $path) = @_;
27              
28             # handle escaped path components
29 87         131 $_ = $path;
30             # substitute all '/'-symbols to "`" and strip
31             # surrounding(wraping) `
32 87         260 s[`(.+?)`][my $x=$1;$x=~ tr{/}{`};$x]ge;
  21         70  
  21         760  
  21         242  
33 87         380 my @elements = split '/';
34 87         192 for(@elements) {
35 289         479 tr {`}{/}; # roll back slashes again
36             }
37 87         293 for my $i (0..@elements-1) {
38 289         605 my @parts = split(':', $elements[$i]);
39 289 100       820 if (@parts > 1) {
40 40         98 $elements[$i] = $parts[1];
41 40         204 $self->{_labels}->{ $parts[0] } = $i;
42             }
43             }
44             # special name _ for the last route component
45 87         540 $self->{_labels}->{'_'} = @elements-1;
46 87         304 $self->{_components} = \@elements;
47             }
48              
49 288     288 0 793 sub components { shift->{_components} }
50              
51             sub to_string {
52 590 100       2185 join('/',
53 178         421 map { /\// ? "`$_`" : $_ }
54 178     178 0 2941 @{ shift->{_components} })
55             }
56              
57             sub labels {
58 24     24 0 40 my $self = shift;
59 24         39 my $labels = $self->{_labels};
60 24         73 sort { $labels->{$a} <=> $labels->{$b} } grep { $_ ne '_' } keys %$labels;
  18         63  
  50         165  
61             }
62              
63             sub named_route {
64 6     6 0 13 my ($self, $label) = @_;
65 6 50       21 croak("No label '$label' in path '$self'")
66             unless exists $self->{_labels}->{$label};
67 6         18 return $self->_clone_to($self->{_labels}->{$label});
68             }
69              
70             sub named_component {
71 38     38 0 67 my ($self, $label) = @_;
72 38 50       122 croak("No label '$label' in path '$self'")
73             unless exists $self->{_labels}->{$label};
74 38         69 my $idx = $self->{_labels}->{$label};
75 38         373 return $self->{_components}->[$idx];
76             }
77              
78             sub _clone_to {
79 6     6   8 my ($self, $index) = @_;
80 6         7 my @components;
81 6         13 for my $i (0 .. $index) {
82 19         42 push @components, $self->{_components}->[$i]
83             }
84 6         8 while ( my ($name, $idx) = each(%{ $self->{_labels} })) {
  26         82  
85 20 100 100     95 $components[$idx] = join(':', $name, $components[$idx])
86             if( $idx <= $index && $name ne '_');
87             }
88 6         12 my $path = join('/', @components);
89 6         24 return Data::DynamicValidator::Path->new($path);
90             }
91              
92              
93             sub value {
94 95     95 1 181 my ($self, $data, $label) = @_;
95 95   100     338 $label //= '_';
96 95 50       258 croak("No label '$label' in path '$self'")
97             if(!exists $self->{_labels}->{$label});
98 95         176 my $idx = $self->{_labels}->{$label};
99 95         117 my $value = $data;
100 95         184 for my $i (1 .. $idx) {
101 221         366 my $element = $self->{_components}->[$i];
102 221 100 66     1998 if (ref($value) && ref($value) eq 'HASH' && exists $value->{$element}) {
    50 66        
      33        
      33        
      33        
103 147         227 $value = $value->{$element};
104 147         276 next;
105             }
106             elsif (ref($value) && ref($value) eq 'ARRAY'
107             && looks_like_number($element) && $element < @$value) {
108 74         121 $value = $value->[$element];
109 74         242 next;
110             }
111 0         0 croak "I don't know how to get element#$i ($element) at $self";
112             }
113 95         137 if (DEBUG) {
114             warn "-- value for $self is "
115             . (defined($value)? $value : 'undefined') . "\n"
116             }
117 95         402 return $value;
118             }
119              
120             1;
121              
122             __END__
123              
124             =pod
125              
126             =encoding UTF-8
127              
128             =head1 NAME
129              
130             Data::DynamicValidator::Path - Class represents "splitted" to labelled componets path.
131              
132             =head1 VERSION
133              
134             version 0.03
135              
136             =head1 METHODS
137              
138             =head2 value
139              
140             Returns data value under named label or (if undefined)
141             the value under path itself
142              
143             =head1 AUTHOR
144              
145             Ivan Baidakou <dmol@gmx.com>
146              
147             =head1 COPYRIGHT AND LICENSE
148              
149             This software is copyright (c) 2014 by Ivan Baidakou.
150              
151             This is free software; you can redistribute it and/or modify it under
152             the same terms as the Perl 5 programming language system itself.
153              
154             =cut