File Coverage

blib/lib/FTN/Addr.pm
Criterion Covered Total %
statement 150 164 91.4
branch 99 150 66.0
condition 37 77 48.0
subroutine 34 34 100.0
pod 19 19 100.0
total 339 444 76.3


line stmt bran cond sub pod time code
1             package FTN::Addr;
2             $FTN::Addr::VERSION = '20250717';
3              
4 6     6   1690912 use strict;
  6         13  
  6         261  
5 6     6   74 use utf8;
  6         10  
  6         37  
6 6     6   193 use warnings;
  6         10  
  6         279  
7              
8 6     6   34 use Carp ();
  6         12  
  6         129  
9 6     6   30 use Scalar::Util ();
  6         10  
  6         483  
10              
11             =encoding utf8
12              
13             =head1 NAME
14              
15             FTN::Addr - working with FTN addresses
16              
17             =head1 VERSION
18              
19             version 20250717
20              
21             =head1 SYNOPSIS
22              
23             use FTN::Addr ();
24              
25             my $a = FTN::Addr -> new( '1:23/45' )
26             or die "this is not a correct address";
27              
28             my ( $b, $error ) = FTN::Addr -> new( '1:23/45@fidonet' );
29             if ( $error
30             ) { # process the error (notify, log, die, ...)
31             die 'cannot create address because: ' . $error;
32             }
33              
34             print "Hey! They are the same!\n"
35             if $a eq $b; # they actually are, because default domain is 'fidonet'
36              
37             if ( my $error = $b -> set_domain( 'othernet' )
38             ) {
39             # process the error (notify, log, die, ...)
40              
41             }
42              
43             print "Hey! They are the same!\n"
44             if $a eq $b; # no output as we changed domain
45              
46             $b = FTN::Addr -> new( '44.22', $a )
47             or die "cannot create address"; # takes the missing information from optional $a
48              
49             # or the same if you want to know what was the reason of failure (if there was a failure)
50             ( $b, $error ) = FTN::Addr -> new( '44.22', $a );
51             if ( $error
52             ) {
53             # process the error (notify, log, die, ...)
54              
55             }
56              
57             # can also be called as object method
58             ( $b, $error ) = $a -> new( '44.22' );
59             if ( $error
60             ) {
61             # process the error (notify, log, die, ...)
62              
63             }
64              
65             print $a -> f4, "\n"; # 1:23/45.0
66              
67             print $a -> s4, "\n"; # 1:23/45
68              
69             print $a -> f5, "\n"; # 1:23/45.0@fidonet
70              
71             print $a -> s5, "\n"; # 1:23/45@fidonet
72              
73             =head1 DESCRIPTION
74              
75             FTN::Addr is a module for working with FTN addresses. Supports domains, different representations and comparison operators.
76              
77             =cut
78              
79             use overload
80 6         80 'eq' => \ &_eq,
81             'cmp' => \ &_cmp,
82 6     6   36 'fallback' => 1;
  6         9  
83              
84             use constant
85 6     6   721 'DEFAULT_DOMAIN' => 'fidonet';
  6         11  
  6         39135  
86              
87             my $domain_re = qr/[a-z\d_~-]{1,8}/;
88             # frl-1028.002:
89             # The Domain Name
90             # ---------------
91              
92             # The domain name MUST be a character string not more than 8
93             # characters long and MUST include only characters as defined below in
94             # BNF. Any other character cannot be used in a domain name.
95              
96             # domain = *pchar
97             # pchar = alphaLC | digit | safe
98             # alphaLC = "a" | "b" | ... | "z"
99             # digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
100             # safe = '-' | '_' | '~'
101              
102              
103             sub _remove_presentations {
104 23     23   41 my $t = shift;
105              
106 23         45 delete @{ $t }{ qw/ full4d
  23         104  
107             full5d
108             short4d
109             short5d
110             fqfa
111             brake_style
112             / };
113             }
114              
115             =head1 OBJECT CREATION
116              
117             =head2 new
118              
119             Can be called as class or object method. Performs fields validation.
120              
121             In scalar context an object is returned. Or undef in case of an error.
122              
123             In list context the pair ( $object, $error ) is returned. If $error is false - $object is good to be used.
124             In case of error $object isn't usable and $error holds information about the failure.
125              
126             my $t = FTN::Addr -> new( '1:23/45' )
127             or die 'something wrong!';
128              
129             my $k = $t -> new( '22/33.44@fidonet' ) # the missing information will be taken from the $t object
130             or die 'something wrong!';
131              
132             my ( $l, $error ) = FTN::Addr -> new( '1:22/33.44@fidonet' );
133             if ( $error
134             ) { # do something about the error
135             die 'cannot created an address because: ' . $error;
136             }
137              
138             Default domain is 'fidonet'. If point isn't specified, it's considered to be 0.
139              
140             Address can be:
141              
142             3d/4d 1:23/45 or 1:23/45.0
143             5d 1:23/45@fidonet or 1:23/45.0@fidonet
144             fqfa fidonet#1:23/45.0
145             The Brake! FTN-compatible mailer for OS/2 style fidonet.1.23.45.0
146              
147             If passed address misses any part except point and domain, the base is needed to get the missing information from (including domain). It can be an optional second parameter (already created FTN::Addr object) in case of class method call or an object itself in case of object method call.
148              
149             my $an = FTN::Addr -> new( '99', $k ); # class call. address in $an is 1:22/99.0@fidonet
150             $an = $k -> new( '99' ); # object call. the same resulting address.
151              
152             or use list context if you want to know the details of validation failure:
153              
154             ( $an, $error ) = $k -> new( '99' );
155              
156             =cut
157              
158             sub new {
159 37     37 1 1386811 my $either = shift;
160 37   66     195 my $class = ref( $either ) || $either;
161 37         85 my $addr = shift;
162              
163 37 50       118 unless ( defined $addr
164             ) {
165             return undef
166 0 0       0 unless wantarray;
167              
168 0         0 return ( undef, 'address should be provided' );
169             }
170              
171 37         70 my %new;
172              
173 37 50       2167 if ( $addr =~ m!^($domain_re)\.(\d{1,5})\.(\d{1,5})\.(-?\d{1,5})\.(-?\d{1,5})$!
    50          
    100          
174             ) { # fidonet.2.451.31.0
175 0         0 @new{ qw/ domain
176             zone
177             net
178             node
179             point
180             /
181             } = ( $1, $2, $3, $4, $5 );
182             } elsif ( $addr =~ m!^($domain_re)#(\d{1,5}):(\d{1,5})/(-?\d{1,5})\.(-?\d{1,5})$!
183             ) { # fidonet#2:451/31.0
184 0         0 @new{ qw/ domain
185             zone
186             net
187             node
188             point
189             /
190             } = ( $1, $2, $3, $4, $5 );
191             } elsif ( $addr =~ m!^(\d{1,5}):(\d{1,5})/(-?\d{1,5})(?:\.(-?\d{1,5}))?(?:@($domain_re))?$!
192             ) { # 2:451/31.0@fidonet 2:451/31@fidonet 2:451/31.0 2:451/31
193 21   100     491 @new{ qw/ domain
      100        
194             zone
195             net
196             node
197             point
198             /
199             } = ( $5 || DEFAULT_DOMAIN(),
200             $1, $2, $3,
201             $4 || 0,
202             );
203             } else { # partials. need base. 451/31.0 451/31 31.1 31 .1
204 16 100       55 my $base = ref $either ? $either : shift;
205              
206 16 50 33     232 unless ( $base
      33        
      33        
207             && ref $base
208             && Scalar::Util::blessed( $base )
209             && $base -> isa( 'FTN::Addr' )
210             ) {
211             return undef
212 0 0       0 unless wantarray;
213              
214 0         0 return ( undef, 'a base should be provided for partial address' );
215             }
216              
217 16 100       151 if ( $addr =~ m!^(\d{1,5})/(-?\d{1,5})(?:\.(-?\d{1,5}))?$!
    100          
    50          
218             ) { # 451/31.0 451/31
219 4   50     14 @new{ qw/ domain
220             zone
221             net
222             node
223             point
224             /
225             } = ( $base -> domain,
226             $base -> zone,
227             $1,
228             $2,
229             $3 || 0,
230             );
231             } elsif ( $addr =~ m!^(-?\d{1,5})(?:\.(-?\d{1,5}))?$!
232             ) { # 31.1 31
233 11   100     38 @new{ qw/ domain
234             zone
235             net
236             node
237             point
238             /
239             } = ( $base -> domain,
240             $base -> zone,
241             $base -> net,
242             $1,
243             $2 || 0,
244             );
245             } elsif ( $addr =~ m!^\.(-?\d{1,5})$!
246             ) { # .1
247 1         5 @new{ qw/ domain
248             zone
249             net
250             node
251             point
252             /
253             } = ( $base -> domain,
254             $base -> zone,
255             $base -> net,
256             $base -> node,
257             $1,
258             );
259             } else { # not recognizable
260             return undef
261 0 0       0 unless wantarray;
262              
263 0         0 return ( undef, 'unrecognized address format: ' . $addr );
264             }
265             }
266              
267 37         389 for my $f
268             ( [ \ &_validate_domain, $new{ 'domain' } ],
269             [ \ &_validate_zone, $new{ 'zone' } ],
270             [ \ &_validate_net, $new{ 'net' } ],
271             [ \ &_validate_node, $new{ 'node' } ],
272             [ \ &_validate_point, $new{ 'point' } ],
273             ) {
274 185         298 my ( $sub, $val ) = @{ $f };
  185         436  
275              
276 185 50       427 if ( my $error = $sub -> ( $val )
277             ) {
278             return undef
279 0 0       0 unless wantarray;
280              
281 0         0 return ( undef, $error );
282             }
283             }
284              
285             # node application
286 37 50 33     241 if ( $new{ 'node' } == -1
287             && $new{ 'point' } != 0
288             ) {
289             return undef
290 0 0       0 unless wantarray;
291              
292 0         0 return ( undef, 'node cannot be -1 for a point' );
293             }
294              
295             # point application
296 37 50 33     142 if ( $new{ 'point' } == -1
297             && $new{ 'node' } <= 0
298             ) {
299             return undef
300 0 0       0 unless wantarray;
301              
302 0         0 return ( undef, 'point should be -1 only for a regular node' );
303             }
304              
305 37         243 bless \ %new, $class;
306             }
307              
308             sub _validate_domain {
309 42 50   42   123 return 'domain should be defined'
310             unless defined $_[ 0 ];
311              
312 42 100       781 return 'invalid domain: ' . $_[ 0 ]
313             unless $_[ 0 ] =~ m/^$domain_re$/; # frl-1028.002
314              
315 41         187 undef;
316             }
317              
318             sub _validate_zone {
319             # [ 1 .. 32767 ] by FRL-1002.001, frl-1028.002. why not 1 .. 65535?
320 44 50   44   122 return 'zone should be defined'
321             unless defined $_[ 0 ];
322              
323 44 100       228 return 'zone should be a number, but it is ' . $_[ 0 ]
324             unless $_[ 0 ] =~ m/^\d{1,5}$/;
325              
326 42 100       135 return 'zone should be at least 1, but it is ' . $_[ 0 ]
327             unless 1 <= $_[ 0 ];
328              
329 41 100       110 return 'zone should be at most 32767, but it is ' . $_[ 0 ]
330             unless $_[ 0 ] <= 32767;
331              
332 40         164 undef;
333             }
334              
335             sub _validate_net {
336             # [ 1 .. 32767 ] by FRL-1002.001, frl-1028.002. why not 1 .. 65535?
337 44 50   44   138 return 'net should be defined'
338             unless defined $_[ 0 ];
339              
340 44 100       246 return 'net should be a number, but it is ' . $_[ 0 ]
341             unless $_[ 0 ] =~ m/^\d{1,5}$/;
342              
343 42 100       140 return 'net should be at least 1, but it is ' . $_[ 0 ]
344             unless 1 <= $_[ 0 ];
345              
346 41 100       127 return 'net should be at most 32767, but it is ' . $_[ 0 ]
347             unless $_[ 0 ] <= 32767;
348              
349 40         171 undef;
350             }
351              
352             sub _validate_node {
353             # [ -1 .. 32767 ] by FRL-1002.001, frl-1028.002. why not 0 .. 65534, and 65535 special == -1?
354 46 50   46   124 return 'node should be defined'
355             unless defined $_[ 0 ];
356              
357 46 50       4292 return 'node should be a number, but it is ' . $_[ 0 ]
358             unless $_[ 0 ] =~ m/^-?(?:\d{1,5})$/;
359              
360 46 100       802 return 'node should be at least -1, but it is ' . $_[ 0 ]
361             unless -1 <= $_[ 0 ];
362              
363 45 100       160 return 'node should be at most 32767, but it is ' . $_[ 0 ]
364             unless $_[ 0 ] <= 32767;
365              
366 44         143 undef;
367             }
368              
369             sub _validate_point {
370             # [ 0 .. 32767 ] by FRL-1002.001
371             # [ -1 .. 32767 ] by frl-1028.002. why not 0 .. 65534, and 65535 special == -1?
372 48 50   48   135 return 'point should be defined'
373             unless defined $_[ 0 ];
374              
375 48 50       277 return 'point should be a number, but it is ' . $_[ 0 ]
376             unless $_[ 0 ] =~ m/^-?(?:\d{1,5})$/;
377              
378 48 100       178 return 'point should be at least -1, but it is ' . $_[ 0 ]
379             unless -1 <= $_[ 0 ];
380              
381 47 100       155 return 'point should be at most 32767, but it is ' . $_[ 0 ]
382             unless $_[ 0 ] <= 32767;
383              
384 46         145 undef;
385             }
386              
387             =head2 clone
388              
389             my $clone_addr = $an -> clone;
390              
391             =cut
392              
393             sub clone {
394 2 50   2 1 330 ref( my $inst = shift )
395             or Carp::croak( "I'm only an object method!" );
396              
397 2         4 bless { %{ $inst } }, ref $inst;
  2         38  
398             }
399              
400             =head1 FIELD ACCESS
401              
402             Direct access to object fields.
403              
404             =head2 domain
405              
406             Returns current domain.
407              
408             my $domain = $an -> domain;
409              
410             =cut
411              
412             sub domain {
413 64 50   64 1 85751 ref( my $inst = shift )
414             or Carp::croak( "I'm only an object method!" );
415              
416 64         472 $inst -> { 'domain' };
417             }
418              
419             =head2 set_domain
420              
421             Sets new domain to the current address. Validation is performed. Returned true value is a string describing failure in validation. False value means new value is valid.
422              
423             if ( my $error = $an -> set_domain( 'mynet' )
424             ) {
425             # deal with error here (notify, log, request valid, ...)
426              
427             }
428              
429             =cut
430              
431             sub set_domain {
432 5 50   5 1 917 ref( my $inst = shift )
433             or Carp::croak( "I'm only an object method!" );
434              
435 5         13 my $value = shift;
436              
437 5 100       21 if ( my $error = _validate_domain( $value )
438             ) {
439 1         7 return $error;
440             }
441              
442 4         14 $inst -> { 'domain' } = $value;
443 4         20 $inst -> _remove_presentations;
444              
445 4         19 undef;
446             }
447              
448             =head2 zone
449              
450             Returns current zone value.
451              
452             my $zone = $an -> zone;
453              
454             =cut
455              
456             sub zone {
457 62 50   62 1 593 ref( my $inst = shift )
458             or Carp::croak( "I'm only an object method!" );
459              
460 62         413 $inst -> { 'zone' };
461             }
462              
463             =head2 set_zone
464              
465             Sets new zone to the current address. Validation is performed. Returned true value is a string describing failure in validation. False value means new value is valid.
466              
467             if ( my $error = $an -> set_zone( 2 )
468             ) {
469             # deal with error here (notify, log, request valid, ...)
470              
471             }
472              
473             =cut
474              
475             sub set_zone {
476 7 50   7 1 2120 ref( my $inst = shift )
477             or Carp::croak( "I'm only an object method!" );
478              
479 7         14 my $value = shift;
480              
481 7 100       25 if ( my $error = _validate_zone( $value )
482             ) {
483 4         20 return $error;
484             }
485              
486 3         9 $inst -> { 'zone' } = $value;
487 3         12 $inst -> _remove_presentations;
488              
489 3         13 undef;
490             }
491              
492             =head2 net
493              
494             Returns current net value.
495              
496             my $net = $an -> net;
497              
498             =cut
499              
500             sub net {
501 58 50   58 1 482 ref( my $inst = shift )
502             or Carp::croak( "I'm only an object method!" );
503              
504 58         430 $inst -> { 'net' };
505             }
506              
507             =head2 set_net
508              
509             Sets new net to the current address. Validation is performed. Returned true value is a string describing failure in validation. False value means new value is valid.
510              
511             if ( my $error = $an -> set_net( 456 )
512             ) {
513             # deal with error here (notify, log, request valid, ...)
514              
515             }
516              
517             =cut
518              
519             sub set_net {
520 7 50   7 1 2050 ref( my $inst = shift )
521             or Carp::croak( "I'm only object method!" );
522              
523 7         14 my $value = shift;
524              
525 7 100       25 if ( my $error = _validate_net( $value )
526             ) {
527 4         17 return $error;
528             }
529              
530 3         9 $inst -> { 'net' } = $value;
531 3         31 $inst -> _remove_presentations;
532              
533 3         13 undef;
534             }
535              
536             =head2 node
537              
538             Returns current node value.
539              
540             my $node = $an -> node;
541              
542             =cut
543              
544             sub node {
545 50 50   50 1 493 ref( my $inst = shift )
546             or Carp::croak( "I'm only an object method!" );
547              
548 50         365 $inst -> { 'node' };
549             }
550              
551             =head2 set_node
552              
553             Sets new node to the current address. Validation is performed. Returned true value is a string describing failure in validation. False value means new value is valid.
554              
555             if ( my $error = $an -> set_node( 33 )
556             ) {
557             # deal with error here (notify, log, request valid, ...)
558              
559             }
560              
561             =cut
562              
563             sub set_node {
564 9 50   9 1 7887 ref( my $inst = shift )
565             or Carp::croak( "I'm only object method!" );
566              
567 9         16 my $value = shift;
568              
569 9 100       42 if ( my $error = _validate_node( $value )
570             ) {
571 2         7 return $error;
572             }
573              
574 7 100 100     31 return 'cannot assign node value to -1 while point is not 0'
575             if $value == -1
576             && $inst -> point != 0;
577              
578 6         17 $inst -> { 'node' } = $value;
579 6         22 $inst -> _remove_presentations;
580              
581 6         27 undef;
582             }
583              
584             =head2 point
585              
586             my $point = $an -> point;
587              
588             =cut
589              
590             sub point {
591 49 50   49 1 823 ref( my $inst = shift )
592             or Carp::croak( "I'm only an object method!" );
593              
594 49         335 $inst -> { 'point' };
595             }
596              
597             =head2 set_point
598              
599             Sets new point to the current address. Validation is performed. Returned true value is a string describing failure in validation. False value means new value is valid.
600              
601             if ( my $error = $an -> set_point( 6 )
602             ) {
603             # deal with error here (notify, log, request valid, ...)
604              
605             }
606              
607             if ( my $error = $an -> set_point( 0 )
608             ) {
609             # deal with error here (notify, log, request valid, ...)
610              
611             }
612              
613             =cut
614              
615             sub set_point {
616 11 50   11 1 5918 ref( my $inst = shift )
617             or Carp::croak( "I'm only object method!" );
618              
619 11         23 my $value = shift;
620              
621 11 100       39 if ( my $error = _validate_point( $value )
622             ) {
623 2         8 return $error;
624             }
625              
626 9 100 100     40 return 'cannot assign point to -1 for not a regular node'
627             if $value == -1
628             && $inst -> node <= 0;
629              
630 7         20 $inst -> { 'point' } = $value;
631 7         29 $inst -> _remove_presentations;
632              
633 7         46 undef;
634             }
635              
636             =head1 REPRESENTATION
637              
638             =head2 f4
639              
640             Full 4d address (without domain):
641              
642             print $an -> f4; # 2:456/33.0
643              
644             =cut
645              
646             sub f4 {
647 24 50   24 1 428 ref( my $inst = shift )
648             or Carp::croak( "I'm only an object method!" );
649              
650             $inst -> { 'full4d' } = sprintf( '%d:%d/%d.%d',
651 23         144 @{ $inst }{ qw/ zone net node point / }
652             )
653 24 100       90 unless exists $inst -> { 'full4d' };
654              
655 24         141 $inst -> { 'full4d' };
656             }
657              
658             =head2 s4
659              
660             Short form (if possible) of 4d address:
661              
662             print $an -> s4; # 2:456/33
663              
664             =cut
665              
666             sub s4 {
667 24 50   24 1 100 ref( my $inst = shift )
668             or Carp::croak( "I'm only an object method!" );
669              
670             $inst -> { 'short4d' } = sprintf( '%d:%d/%d%s',
671 23         216 @{ $inst }{ qw/ zone net node / },
672             $inst -> { 'point' } ? '.' . $inst -> { 'point' } : ''
673             )
674 24 100       86 unless exists $inst -> { 'short4d' };
    100          
675              
676 24         139 $inst -> { 'short4d' };
677             }
678              
679             =head2 f5
680              
681             Full 5d address (with domain):
682              
683             print $an -> f5; # 2:456/33.0@mynet
684              
685             =cut
686              
687             sub f5 {
688 24 50   24 1 96 ref( my $inst = shift )
689             or Carp::croak( "I'm only an object method!" );
690              
691             $inst -> { 'full5d' } = sprintf( '%d:%d/%d.%d@%s',
692 23         163 @{ $inst }{ qw/ zone net node point domain / }
693             )
694 24 100       93 unless exists $inst -> { 'full5d' };
695              
696 24         1579 $inst -> { 'full5d' };
697             }
698              
699             =head2 s5
700              
701             Short form (if possible - only for nodes) of 5d address:
702              
703             print $an -> s5; # 2:456/33@mynet
704              
705             =cut
706              
707             sub s5 {
708 24 50   24 1 97 ref( my $inst = shift )
709             or Carp::croak( "I'm only an object method!" );
710              
711             $inst -> { 'short5d' } = sprintf( '%d:%d/%d%s@%s',
712 23         242 @{ $inst }{ qw/ zone net node / },
713             $inst -> { 'point' } ? '.' . $inst -> { 'point' } : '',
714             $inst -> { 'domain' }
715             )
716 24 100       86 unless exists $inst -> { 'short5d' };
    100          
717              
718 24         146 $inst -> { 'short5d' };
719             }
720              
721             =head2 fqfa
722              
723             Full qualified FTN address:
724              
725             print $an -> fqfa; # mynet#2:456/33.0
726              
727             =cut
728              
729             sub fqfa {
730 5 50   5 1 735 ref( my $inst = shift )
731             or Carp::croak( "I'm only an object method!" );
732              
733             $inst -> { 'fqfa' } = sprintf( '%s#%d:%d/%d.%d',
734 4         32 @{ $inst }{ qw/ domain zone net node point / }
735             )
736 5 100       18 unless exists $inst -> { 'fqfa' };
737              
738 5         30 $inst -> { 'fqfa' };
739             }
740              
741             =head2 bs
742              
743             The Brake! FTN-compatible mailer for OS/2 style representation:
744              
745             print $an -> bs; # mynet.2.456.33.0
746              
747             =cut
748              
749             sub bs {
750 13 50   13 1 65 ref( my $inst = shift )
751             or Carp::croak( "I'm only an object method!" );
752              
753             $inst -> { 'brake_style' } = sprintf( '%s.%d.%d.%d.%d',
754 12         92 @{ $inst }{ qw/ domain zone net node point / }
755             )
756 13 100       59 unless exists $inst -> { 'brake_style' };
757              
758 13         76 $inst -> { 'brake_style' };
759             }
760              
761             =head1 COMPARISON
762              
763             =head2 equal, eq, cmp
764              
765             Two addresses can be compared.
766              
767             ( my $one, $error ) = FTN::Addr -> new( '1:23/45.66@fidonet' );
768             die "cannot create: " . $error
769             if $error;
770              
771             my $two = FTN::Addr -> new( '1:23/45.66@fidonet' )
772             or die "cannot create";
773              
774             print "the same address!\n"
775             if FTN::Addr -> equal( $one, $two ); # should print the message
776              
777             print "the same address!\n"
778             if $one eq $two; # the same result
779              
780             print "but objects are different\n"
781             if $one != $two; # should print the message
782              
783             The same way (comparison rules) as 'eq' works 'cmp' operator.
784              
785             =cut
786              
787             sub _eq { # eq operator
788             return
789 5 50 33 5   788 unless $_[ 1 ]
      33        
      33        
790             && ref $_[ 1 ]
791             && Scalar::Util::blessed( $_[ 1 ] )
792             && $_[ 1 ] -> isa( 'FTN::Addr' );
793              
794 5 50 33     22 $_[ 0 ] -> domain eq $_[ 1 ] -> domain
      33        
      33        
795             && $_[ 0 ] -> zone == $_[ 1 ] -> zone
796             && $_[ 0 ] -> net == $_[ 1 ] -> net
797             && $_[ 0 ] -> node == $_[ 1 ] -> node
798             && $_[ 0 ] -> point == $_[ 1 ] -> point;
799             }
800              
801             sub _cmp { # cmp operator
802             return
803 2 50 33 2   66 unless $_[ 1 ]
      33        
      33        
804             && ref $_[ 1 ]
805             && Scalar::Util::blessed( $_[ 1 ] )
806             && $_[ 1 ] -> isa( 'FTN::Addr' );
807              
808 2         9 my ( $i, $j ) = ( 0, 1 );
809              
810 2 50       8 ( $i, $j ) = ( $j, $i )
811             if $_[ 2 ]; # arguments were swapped
812              
813 2 50 66     9 $_[ $i ] -> domain cmp $_[ $j ] -> domain
      66        
      33        
814             || $_[ $i ] -> zone <=> $_[ $j ] -> zone
815             || $_[ $i ] -> net <=> $_[ $j ] -> net
816             || $_[ $i ] -> node <=> $_[ $j ] -> node
817             || $_[ $i ] -> point <=> $_[ $j ] -> point;
818             }
819              
820             sub equal {
821 1 50   1 1 332 ref( my $class = shift )
822             and Carp::croak( "I'm only a class method!" );
823              
824             return
825 1 50 33     19 unless $_[ 0 ]
      33        
      33        
826             && ref $_[ 0 ]
827             && Scalar::Util::blessed( $_[ 0 ] )
828             && $_[ 0 ] -> isa( 'FTN::Addr' );
829              
830 1         5 _eq( @_ );
831             }
832              
833             =head1 AUTHOR
834              
835             Valery Kalesnik, C<< >>
836              
837             =head1 BUGS
838              
839             Please report any bugs or feature requests to C, or through
840             the web interface at L. I will be notified, and then you'll
841             automatically be notified of progress on your bug as I make changes.
842              
843             =head1 SUPPORT
844              
845             You can find documentation for this module with the perldoc command.
846              
847             perldoc FTN::Addr
848              
849             =cut
850              
851             1;