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   154718 use strict;
  33         59  
  33         1332  
4 33     33   157 use warnings;
  33         47  
  33         1144  
5 33     33   20984 use NetAddr::IP qw(Zero Zeros Ones V4mask V4net netlimit);
  33         931749  
  33         215  
6 33     33   5994 use NetAddr::IP::Util;
  33         57  
  33         190  
7 33     33   2355 use v5.10.1;
  33         112  
  33         36017  
8              
9             our $VERSION = eval '0.7';
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 6865163 sub new { my $class = shift; bless {x=>[@_]}, $class }
  1576         7653  
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 8 my $self = shift;
110 4 50       77 if ($self->{x}->[0] =~ /^(.*?)(?:\/|$)/) {
111 4         22 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 10807654 for (@_) {
146 14363 100       19360 $_->inflate if (ref($_) eq 'NetAddr::IP::LazyInit');
147             }
148 11         409 return NetAddr::IP::Compact(@_);
149             }
150              
151              
152              
153             sub Coalesce {
154 6     6 0 586343 for (@_) {
155 4622 100       7470 $_->inflate if (ref($_) eq 'NetAddr::IP::LazyInit');
156             }
157 6         93 return NetAddr::IP::Coalesce(@_);
158             }
159              
160             sub import {
161 35 100   35   56501 if (grep { $_ eq ':rfc3021' } @_)
  46         224  
162             {
163 1         2 $NetAddr::IP::rfc3021 = 1;
164 1         3 @_ = grep { $_ ne ':rfc3021' } @_;
  1         5  
165             }
166 35 100       64 if (grep { $_ eq ':old_storable' } @_) {
  45         302  
167 1         1 @_ = grep { $_ ne ':old_storable' } @_;
  2         4  
168             }
169 35 100       64 if (grep { $_ eq ':old_nth' } @_)
  44         172  
170             {
171 1         2 $NetAddr::IP::Lite::Old_nth = 1;
172 1         3 @_ = grep { $_ ne ':old_nth' } @_;
  2         9  
173             }
174 35 100       52 if (grep { $_ eq ':lower' } @_)
  43         120  
175             {
176 1         5 NetAddr::IP::Util::lower();
177 1         9 @_ = grep { $_ ne ':lower' } @_;
  2         5  
178             }
179 35 50       52 if (grep { $_ eq ':upper' } @_)
  42         115  
180             {
181 0         0 NetAddr::IP::Util::upper();
182 0         0 @_ = grep { $_ ne ':upper' } @_;
  0         0  
183             }
184              
185 35         29110 NetAddr::IP::LazyInit->export_to_level(1, @_);
186             }
187              
188             # need to support everything that NetAddr::IP does
189             use overload (
190 3     3   101 '@{}' => sub { return [ $_[0]->inflate->hostenum ]; },
191 151     151   5796 '""' => sub { return $_[0]->inflate->cidr() },
192 12     12   60 '<=>' => 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   8 '++' => sub { inflate_args_and_run(\&NetAddr::IP::Lite::plusplus, @_); },
195 1     1   12 '+' => 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   1019 my $a = $_[0];
222 2 50       10 $a->inflate if ref($_[0]) eq 'NetAddr::IP::LazyInit';
223 2         3 my $b = $_[1];
224 2 50       6 $b->inflate if ref($_[1]) eq 'NetAddr::IP::LazyInit';
225 2         8 return ($a eq $b);
226             },
227 9 100   9   82 '>' => 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   219 );
  33         58  
  33         990  
233              
234             sub comp_addr_mask {
235 9     9 0 18 return inflate_args_and_run(\&NetAddr::IP::Lite::comp_addr_mask, @_);
236             }
237              
238             sub inflate_args_and_run {
239 23     23 0 24 my $func = shift;
240 23 50       84 $_[0]->inflate if ref($_[0]) eq 'NetAddr::IP::LazyInit';
241 23 100       74 $_[1]->inflate if ref($_[1]) eq 'NetAddr::IP::LazyInit';
242 23         28 return &{$func}(@_);
  23         63  
243             }
244              
245             sub AUTOLOAD {
246 321     321   120995 my $self = shift;
247 321         566 my $obj = NetAddr::IP->new(@{ $self->{x} });
  321         2484  
248 321         45873 %$self = %$obj;
249 321         864 bless $self, 'NetAddr::IP';
250 321         1666 our $AUTOLOAD =~ /::(\w+)$/;
251 321         5463 return $self->$1(@_);
252             }
253              
254             sub inflate {
255 1253     1253 0 1353 my $self = shift;
256 1253         1053 my $method = shift;
257 1253         1100 my $obj = NetAddr::IP->new(@{ $self->{x} });
  1253         4221  
258 1253         117639 %$self = %$obj;
259 1253         2216 bless $self, 'NetAddr::IP';
260 1253 50       4222 return $method ? $self->method( @_ ) : $self;
261             }
262              
263             1;