File Coverage

blib/lib/Lim/RPC/URIMaps.pm
Criterion Covered Total %
statement 67 93 72.0
branch 17 44 38.6
condition 3 6 50.0
subroutine 8 9 88.8
pod 3 3 100.0
total 98 155 63.2


line stmt bran cond sub pod time code
1             package Lim::RPC::URIMaps;
2              
3 7     7   5629 use common::sense;
  7         16  
  7         60  
4 7     7   534 use Carp;
  7         19  
  7         509  
5              
6 7     7   45 use Log::Log4perl ();
  7         15  
  7         227  
7 7     7   42 use Scalar::Util qw(weaken);
  7         16  
  7         331  
8              
9 7     7   40 use Lim ();
  7         18  
  7         13864  
10              
11             =encoding utf8
12              
13             =head1 NAME
14              
15             ...
16              
17             =head1 VERSION
18              
19             See L for version.
20              
21             =cut
22              
23             our $VERSION = $Lim::VERSION;
24             our %_MAP_CACHE_CODE;
25              
26             =head1 SYNOPSIS
27              
28             ...
29              
30             =head1 SUBROUTINES/METHODS
31              
32             =head2 new
33              
34             =cut
35              
36             sub new {
37 6     6 1 23 my $this = shift;
38 6   33     56 my $class = ref($this) || $this;
39 6         43 my $self = {
40             logger => Log::Log4perl->get_logger,
41             maps => []
42             };
43 6         1140 bless $self, $class;
44            
45 6 50       31 Lim::OBJ_DEBUG and $self->{logger}->debug('new ', __PACKAGE__, ' ', $self);
46 6         5069 $self;
47             }
48              
49             sub DESTROY {
50 6     6   5783 my ($self) = @_;
51 6 50       27 Lim::OBJ_DEBUG and $self->{logger}->debug('destroy ', __PACKAGE__, ' ', $self);
52             }
53              
54             =head2 add
55              
56             =cut
57              
58             sub add {
59 10     10 1 23 my ($self, $map) = @_;
60 10         18 my (@regexps, @variables, $regexp, $n, $code, $call, $predata);
61              
62             #
63             # See if this is a redirect call and check if we have the map in cache
64             #
65              
66 10 100       110 if ($map =~ /^(\S+)\s+=>\s+(\w+)(?:\s+(\S+))?$/o) {
    50          
67 4         20 ($map, $call, $predata) = ($1, $2, $3);
68             }
69             elsif ($map =~ /^(\S+)\s+(\S+)$/o) {
70 0         0 ($map, $call, $predata) = ($1, '', $2);
71             }
72             else {
73 6         27 $call = '';
74             }
75            
76 10 100 66     67 if (exists $_MAP_CACHE_CODE{$map} and defined $_MAP_CACHE_CODE{$map}) {
77 4         6 push(@{$self->{maps}}, $_MAP_CACHE_CODE{$map});
  4         16  
78 4         21 return $call;
79             }
80            
81             #
82             # Validate and pull out parts of the map used to generate regexp and code
83             #
84            
85 6         26 foreach my $map_part (split(/\//o, $map)) {
86 10 100       109 if ($map_part =~ /^\w+$/o) {
    50          
87 4         15 push(@regexps, $map_part);
88             }
89             elsif ($map_part =~ /^((?:\w+\.)*\w+)=(.+)$/o) {
90 6         20 push(@variables, $1);
91 6         32 push(@regexps, '('.$2.')');
92             }
93             else {
94 0 0       0 Lim::DEBUG and $self->{logger}->debug('Validation of map "', $map, '" failed');
95 0         0 $@ = 'Map is not valid';
96 0         0 return;
97             }
98             }
99            
100             #
101             # Validate the regexp made from the map by compiling it with qr
102             #
103              
104 6         26 $regexp = '^'.join('\/', @regexps).'$';
105 6         11 eval {
106 6         296 my $dummy = qr/$regexp/;
107             };
108 6 50       48 if ($@) {
109 0 0       0 Lim::DEBUG and $self->{logger}->debug('Regexp compilation of map "', $map, '" failed: ', $@);
110 0         0 return;
111             }
112            
113             #
114             # Generate the code that checked given URI with generated regexp and adds
115             # data gotten by the regexp to the data structure defined by the map
116             #
117            
118 6 50       22 if ($predata) {
119 0         0 foreach my $predata_variable (split(/,/o, $predata)) {
120 0 0       0 if ($predata_variable =~ /^([^=]+)=(.+)$/o) {
121 0         0 my ($variable, $value) = ($1, $2);
122              
123 0         0 $code .= '$data->{'.join('}->{', split(/\./o, $variable)).'} = \''.$value.'\'';
124             }
125             else {
126 0 0       0 Lim::DEBUG and $self->{logger}->debug('Predata of map "', $map, '" invalid');
127 0         0 $@ = 'Predata is not valid';
128 0         0 return;
129             }
130             }
131             }
132              
133 6 50       18 if (scalar @variables) {
134 6         26 $code = 'my (';
135            
136 6         12 $n = 1;
137 6         20 while ($n <= scalar @variables) {
138 6 50       27 $code .= '$v'.$n.($n != scalar @variables ? ',' : '');
139 6         18 $n++;
140             }
141            
142 6         13 $code .= ')=(';
143            
144 6         11 $n = 1;
145 6         16 while ($n <= scalar @variables) {
146 6 50       20 $code .= '$'.$n.($n != scalar @variables ? ',' : '');
147 6         19 $n++;
148             }
149            
150 6         11 $code .= ');';
151            
152 6         10 $n = 1;
153 6         12 foreach my $variable (@variables) {
154 6         42 $code .= '$data->{'.join('}->{', split(/\./o, $variable)).'} = $v'.($n++).';';
155             }
156             }
157             else {
158 0         0 $code = '';
159             }
160              
161             #
162             # Create the subroutine from the generated code
163             #
164            
165 6         2027 eval '$code = sub { my ($uri, $data)=@_; if($uri =~ /'.$regexp.'/o) { '.$code.' return \''.$call.'\';} return; };';
166 6 50       42 if ($@) {
167 0 0       0 Lim::DEBUG and $self->{logger}->debug('Code generation of map "', $map, '" failed: ', $@);
168 0         0 return;
169             }
170            
171             #
172             # Verify code by calling it in eval
173             #
174            
175 6         38 eval {
176 6         164 $code->('', {});
177             };
178 6 50       22 if ($@) {
179 0 0       0 Lim::DEBUG and $self->{logger}->debug('Verify code of map "', $map, '" failed: ', $@);
180 0         0 return;
181             }
182            
183             #
184             # Store the generated subroutine and return success
185             #
186              
187 6         181 $_MAP_CACHE_CODE{$map} = $code;
188 6         715 weaken($_MAP_CACHE_CODE{$map});
189 6         8 push(@{$self->{maps}}, $code);
  6         29  
190 6         49 return $call;
191             }
192              
193             =head2 process
194              
195             =cut
196              
197             sub process {
198 0     0 1   my ($self, $uri, $data) = @_;
199            
200 0 0         unless (ref($data) eq 'HASH') {
201 0           confess '$data parameter is not a hash';
202             }
203            
204 0           foreach my $map (@{$self->{maps}}) {
  0            
205 0 0         if (defined (my $ret = $map->($uri, $data))) {
206 0           return $ret;
207             }
208             }
209 0           return;
210             }
211              
212             =head1 AUTHOR
213              
214             Jerry Lundström, C<< >>
215              
216             =head1 BUGS
217              
218             Please report any bugs or feature requests to L.
219              
220             =head1 SUPPORT
221              
222             You can find documentation for this module with the perldoc command.
223              
224             perldoc Lim
225              
226             You can also look for information at:
227              
228             =over 4
229              
230             =item * Lim issue tracker (report bugs here)
231              
232             L
233              
234             =back
235              
236             =head1 ACKNOWLEDGEMENTS
237              
238             =head1 LICENSE AND COPYRIGHT
239              
240             Copyright 2013 Jerry Lundström.
241              
242             This program is free software; you can redistribute it and/or modify it
243             under the terms of either: the GNU General Public License as published
244             by the Free Software Foundation; or the Artistic License.
245              
246             See http://dev.perl.org/licenses/ for more information.
247              
248              
249             =cut
250              
251             1; # End of Lim::RPC::URIMaps