File Coverage

lib/NetAddr/IP/LazyInit.pm
Criterion Covered Total %
statement 82 113 72.5
branch 22 48 45.8
condition 0 3 0.0
subroutine 22 34 64.7
pod 3 9 33.3
total 129 207 62.3


line stmt bran cond sub pod time code
1             package NetAddr::IP::LazyInit;
2              
3 33     33   227319 use strict;
  33         149  
  33         1343  
4 33     33   194 use warnings;
  33         63  
  33         1202  
5 33     33   46617 use NetAddr::IP qw(Zero Zeros Ones V4mask V4net netlimit);
  33         1435503  
  33         237  
6 33     33   7411 use NetAddr::IP::Util;
  33         80  
  33         241  
7 33     33   2644 use v5.10.1;
  33         120  
  33         53691  
8              
9             our $VERSION = eval '0.6';
10              
11             =head1 NAME
12              
13             NetAddr::IP::LazyInit - NetAddr::IP objects with deferred validation B
14              
15             =head1 VERSION
16              
17             0.6
18              
19             =head1 SYNOPSIS
20              
21             use NetAddr::IP::LazyInit;
22              
23             my $ip = new NetAddr::IP::LazyInit( '10.10.10.5' );
24              
25             =head1 DESCRIPTION
26              
27             This module is designed to quickly create objects that may become NetAddr::IP
28             objects. It accepts anything you pass to it without validation. Once a
29             method is called that requires operating on the value, the full NetAddr::IP
30             object is constructed.
31              
32             You can see from the benchmarks that once you need to instantiate NetAddr::IP
33             the speed becomes worse than if you had not used this module. What I mean is
34             that this adds unneeded overhead if you intend to do IP operations on every
35             object you create.
36              
37             =head1 WARNING
38              
39              
40             Because validation is deferred, this module assumes you will B
41             it valid data>. If you try to give it anything else, it will happily accept it
42             and then die once it needs to inflate into a NetAddr::IP object.
43              
44              
45             =head1 CREDITS
46              
47             This module was inspired by discussion with Jan Henning Thorsen, Ejhthorsen
48             at cpan.orgE, and example code he provided. The namespace and part of the
49             documentation/source is inspired by DateTime::LazyInit by
50             Rick Measham, Erickm@cpan.orgE
51              
52             I didn't have to do much so I hate to take author credit, but I am providing
53             the module, so complaints can go to me.
54              
55             Robert Drake, Erdrake@cpan.orgE
56              
57             =head1 TODO
58              
59             If we could actually load NetAddr::IP objects in the background while nothing
60             is going on that would be neat. Or we could create shortcut methods when the
61             user knows what type of input he has. new_from_ipv4('ip','mask'). We might
62             be able to use Socket to build the raw materials and bless a new NetAddr::IP
63             object without going through it's validation.
64              
65             =head1 COPYRIGHT AND LICENSE
66              
67             Copyright (C) 2014 by Robert Drake
68              
69             This library is free software; you can redistribute it and/or modify
70             it under the same terms as Perl itself, either Perl version 5.8.7 or,
71             at your option, any later version of Perl 5 you may have available.
72              
73             =cut
74              
75             require Exporter;
76             our @ISA = qw(Exporter);
77             our @EXPORT_OK = qw(Compact Coalesce Zero Zeros Ones V4mask V4net netlimit);
78              
79             =head1 METHODS
80              
81             =head2 new
82              
83             This replaces the NetAddr::IP->new method with a stub that stores the
84             arguments supplied in a temporary variable and returns immediately. No
85             validation is performed.
86              
87             Once you call a method that can't be handled by LazyInit, a full NetAddr::IP
88             object is built and the request passed into that object.
89              
90             my $ip = NetAddr::IP::LazyInit->new("127.0.0.1");
91              
92             =cut
93              
94 1576     1576 1 16328482 sub new { my $class = shift; bless {x=>[@_]}, $class }
  1576         8796  
95              
96             =head2 addr
97              
98             Returns the IP address of the object. If we can extract the IP as a string
99             without converting to a real NetAddr::IP object, then we return that.
100             Currently it only returns IPv6 strings in lower case, which may break your
101             application if you aren't using the new standard.
102              
103             my $ip = NetAddr::IP::LazyInit->new("127.0.0.1");
104             print $ip->addr;
105              
106             =cut
107              
108             sub addr {
109 4     4 1 11 my $self = shift;
110 4 50       104 if ($self->{x}->[0] =~ /^(.*?)(?:\/|$)/) {
111 4         29 return lc($1);
112             } else {
113 0         0 return $self->inflate->addr;
114             }
115             }
116              
117             =head2 mask
118              
119             Returns the subnet mask of the object. If the user used the two argument
120             option then it returns the string they provided for the second argument.
121             Otherwise this will inflate to build a real NetAddr::IP object and return the
122             mask.
123              
124             my $ip = NetAddr::IP::LazyInit->new("127.0.0.1", "255.255.255.0");
125             print $ip->mask;
126              
127             =cut
128              
129             sub mask {
130 0     0 1 0 my $self = shift;
131 0 0 0     0 if ($self->{x}->[1] && $self->{x}->[1] =~ /\D/) {
132 0         0 return $self->{x}->[1];
133             } else {
134 0         0 return $self->inflate->mask;
135             }
136             }
137              
138             # everything below here aren't ment for speed or for users to reference.
139             # They're purely for compatibility with NetAddr::IP so that users can use this
140             # module like the real one.
141              
142 0     0 0 0 sub can { NetAddr::IP->can($_[1]); }
143              
144             sub Compact {
145 11     11 0 14345575 for (@_) {
146 14363 100       27870 $_->inflate if (ref($_) eq 'NetAddr::IP::LazyInit');
147             }
148 11         573 return NetAddr::IP::Compact(@_);
149             }
150              
151              
152              
153             sub Coalesce {
154 6     6 0 806397 for (@_) {
155 4622 100       9468 $_->inflate if (ref($_) eq 'NetAddr::IP::LazyInit');
156             }
157 6         126 return NetAddr::IP::Coalesce(@_);
158             }
159              
160             sub import {
161 35 100   35   67997 if (grep { $_ eq ':rfc3021' } @_)
  46         271  
162             {
163 1         2 $NetAddr::IP::rfc3021 = 1;
164 1         3 @_ = grep { $_ ne ':rfc3021' } @_;
  1         4  
165             }
166 35 100       130 if (grep { $_ eq ':old_storable' } @_) {
  45         385  
167 1         2 @_ = grep { $_ ne ':old_storable' } @_;
  2         5  
168             }
169 35 100       108 if (grep { $_ eq ':old_nth' } @_)
  44         238  
170             {
171 1         3 $NetAddr::IP::Lite::Old_nth = 1;
172 1         3 @_ = grep { $_ ne ':old_nth' } @_;
  2         10  
173             }
174 35 100       78 if (grep { $_ eq ':lower' } @_)
  43         204  
175             {
176 1         5 NetAddr::IP::Util::lower();
177 1         9 @_ = grep { $_ ne ':lower' } @_;
  2         7  
178             }
179 35 50       72 if (grep { $_ eq ':upper' } @_)
  42         294  
180             {
181 0         0 NetAddr::IP::Util::upper();
182 0         0 @_ = grep { $_ ne ':upper' } @_;
  0         0  
183             }
184              
185 35         39832 NetAddr::IP::LazyInit->export_to_level(1, @_);
186             }
187              
188             # need to support everything that NetAddr::IP does
189             use overload (
190 3     3   94 '@{}' => sub { return [ $_[0]->inflate->hostenum ]; },
191 151     151   7174 '""' => sub { return $_[0]->inflate->cidr() },
192 12     12   203 '<=>' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::comp_addr_mask, @_); },
193 0     0   0 'cmp' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::comp_addr_mask, @_); },
194 1     1   10 '++' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::plusplus, @_); },
195 1     1   14 '+' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::plus, @_); },
196 0     0   0 '--' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::minusminus, @_); },
197 0     0   0 '-' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::minus, @_); },
198 0     0   0 '=' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::copy, @_); },
199             '==' => sub {
200 0     0   0 my $a = $_[0];
201 0 0       0 $a->inflate if ref($_[0]) =~ /NetAddr::IP::LazyInit/;
202 0         0 my $b = $_[1];
203 0 0       0 $b->inflate if ref($_[1]) =~ /NetAddr::IP::LazyInit/;
204 0         0 return ($a eq $b);
205             },
206             '!=' => sub {
207 0     0   0 my $a = $_[0];
208 0 0       0 $a->inflate if ref($_[0]) eq 'NetAddr::IP::LazyInit';
209 0         0 my $b = $_[1];
210 0 0       0 $b->inflate if ref($_[1]) eq 'NetAddr::IP::LazyInit';
211 0         0 return ($a ne $b);
212             },
213             'ne' => sub {
214 0     0   0 my $a = $_[0];
215 0 0       0 $a->inflate if ref($_[0]) eq 'NetAddr::IP::LazyInit';
216 0         0 my $b = $_[1];
217 0 0       0 $b->inflate if ref($_[1]) eq 'NetAddr::IP::LazyInit';
218 0         0 return ($a ne $b);
219             },
220             'eq' => sub {
221 2     2   1922 my $a = $_[0];
222 2 50       14 $a->inflate if ref($_[0]) eq 'NetAddr::IP::LazyInit';
223 2         4 my $b = $_[1];
224 2 50       7 $b->inflate if ref($_[1]) eq 'NetAddr::IP::LazyInit';
225 2         9 return ($a eq $b);
226             },
227 9 100   9   193 '>' => sub { return &comp_addr_mask > 0 ? 1 : 0; },
228 0 0   0   0 '<' => sub { return &comp_addr_mask < 0 ? 1 : 0; },
229 0 0   0   0 '>=' => sub { return &comp_addr_mask < 0 ? 0 : 1; },
230 0 0   0   0 '<=' => sub { return &comp_addr_mask > 0 ? 0 : 1; },
231              
232 33     33   237 );
  33         70  
  33         1164  
233              
234             sub comp_addr_mask {
235 9     9 0 35 return inflate_args_and_run(\&NetAddr::IP::Lite::comp_addr_mask, @_);
236             }
237              
238             sub inflate_args_and_run {
239 23     23 0 41 my $func = shift;
240 23 50       126 $_[0]->inflate if ref($_[0]) eq 'NetAddr::IP::LazyInit';
241 23 100       100 $_[1]->inflate if ref($_[1]) eq 'NetAddr::IP::LazyInit';
242 23         37 return &{$func}(@_);
  23         81  
243             }
244              
245             sub AUTOLOAD {
246 321     321   140539 my $self = shift;
247 321         639 my $obj = NetAddr::IP->new(@{ $self->{x} });
  321         2768  
248 321         54219 %$self = %$obj;
249 321         955 bless $self, 'NetAddr::IP';
250 321         1781 our $AUTOLOAD =~ /::(\w+)$/;
251 321         5785 return $self->$1(@_);
252             }
253              
254             sub inflate {
255 1253     1253 0 10260 my $self = shift;
256 1253         1512 my $method = shift;
257 1253         1537 my $obj = NetAddr::IP->new(@{ $self->{x} });
  1253         5723  
258 1253         165853 %$self = %$obj;
259 1253         3957 bless $self, 'NetAddr::IP';
260 1253 50       5466 return $method ? $self->method( @_ ) : $self;
261             }
262              
263             1;