File Coverage

blib/lib/Lock/Socket.pm
Criterion Covered Total %
statement 172 197 87.3
branch 46 64 71.8
condition 11 20 55.0
subroutine 33 33 100.0
pod 1 6 16.6
total 263 320 82.1


line stmt bran cond sub pod time code
1             package Lock::Socket::Mo;
2              
3             #<<< Do not perltidy this
4             BEGIN {
5             # use Mo qw'builder default import is required';
6             # The following line of code was produced from the previous line by
7             # Mo::Inline version 0.39
8 2 50 50 2   1145 no warnings;my$M=__PACKAGE__.'::';*{$M.Object::new}=sub{my$c=shift;my$s=bless{@_},$c;my%n=%{$c.::.':E'};map{$s->{$_}=$n{$_}->()if!exists$s->{$_}}keys%n;$s};*{$M.import}=sub{import warnings;$^H|=1538;my($P,%e,%o)=caller.'::';shift;eval"no Mo::$_",&{$M.$_.::e}($P,\%e,\%o,\@_)for@_;return if$e{M};%e=(extends,sub{eval"no $_[0]()";@{$P.ISA}=$_[0]},has,sub{my$n=shift;my$m=sub{$#_?$_[0]{$n}=$_[1]:$_[0]{$n}};@_=(default,@_)if!($#_%2);$m=$o{$_}->($m,$n,@_)for sort keys%o;*{$P.$n}=$m},%e,);*{$P.$_}=$e{$_}for keys%e;@{$P.ISA}=$M.Object};*{$M.'builder::e'}=sub{my($P,$e,$o)=@_;$o->{builder}=sub{my($m,$n,%a)=@_;my$b=$a{builder}or return$m;my$i=exists$a{lazy}?$a{lazy}:!${$P.':N'};$i or ${$P.':E'}{$n}=\&{$P.$b}and return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$_[0]->$b:$m->(@_)}}};*{$M.'default::e'}=sub{my($P,$e,$o)=@_;$o->{default}=sub{my($m,$n,%a)=@_;exists$a{default}or return$m;my($d,$r)=$a{default};my$g='HASH'eq($r=ref$d)?sub{+{%$d}}:'ARRAY'eq$r?sub{[@$d]}:'CODE'eq$r?$d:sub{$d};my$i=exists$a{lazy}?$a{lazy}:!${$P.':N'};$i or ${$P.':E'}{$n}=$g and return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$g->(@_):$m->(@_)}}};my$i=\&import;*{$M.import}=sub{(@_==2 and not$_[1])?pop@_:@_==1?push@_,grep!/import/,@f:();goto&$i};*{$M.'is::e'}=sub{my($P,$e,$o)=@_;$o->{is}=sub{my($m,$n,%a)=@_;$a{is}or return$m;sub{$#_&&$a{is}eq'ro'&&caller ne'Mo::coerce'?die$n.' is ro':$m->(@_)}}};*{$M.'required::e'}=sub{my($P,$e,$o)=@_;$o->{required}=sub{my($m,$n,%a)=@_;if($a{required}){my$C=*{$P."new"}{CODE}||*{$M.Object::new}{CODE};no warnings 'redefine';*{$P."new"}=sub{my$s=$C->(@_);my%a=@_[1..$#_];if(!exists$a{$n}){require Carp;Carp::croak($n." required")}$s}}$m}};@f=qw[builder default import is required];use strict;use warnings;
  2 50 50 2   4  
  2 100 33 2   2365  
  2 50 33 2   10  
  2 100 50 2   3  
  2 50   2   348  
  2 50   2   10  
  2 0   2   6  
  2 0   2   70  
  2 100   2   9  
  2 50   2   3  
  2 50   2   68  
  2 50   2   4  
  2 100   6   14  
  2 100       19  
  27 100       53  
  27 50       118  
  27 50       37  
  27 50       149  
  27 50       53  
  34 50       154  
  27 100       76  
  2 100       20  
  2         7  
  4         32  
  4         6  
  4         13  
  4         5  
  4         575  
  16         63  
  4         14  
  4         27  
  0         0  
  0         0  
  0         0  
  12         22  
  12         39  
  114         1354  
  12         35  
  12         77  
  12         32  
  12         59  
  4         12  
  8         44  
  4         9  
  4         187  
  2         7  
  2         12  
  4         8  
  4         400  
  12         42  
  12         85  
  2         10  
  0         0  
  2         8  
  2         25  
  2         13  
  0         0  
  0         0  
  2         6  
  2         18  
  4         7  
  4         219  
  12         33  
  12         52  
  6         12  
  6         31  
  0         0  
  0         0  
  0         0  
  6         20  
  4         30  
  6         16  
  2         43  
  4         36  
  42         183  
  2         4  
  2         7  
  2         6  
  4         49  
  4         11  
  2         6  
  2         28  
  4         7  
  4         229  
  12         38  
  12         31  
  12         100  
  142         956  
  2         7  
  2         23  
  4         8  
  4         28  
  12         30  
  12         30  
  4         5  
  4         18  
  4         30  
  27         1648  
  27         105  
  27         80  
  1         10  
  1         274  
  26         137  
  12         42  
  2         6  
  2         868  
  0         0  
  0         0  
  2         738  
  0         0  
  0         0  
  2         741  
  0         0  
  0         0  
  2         835  
  0         0  
  0         0  
  2         736  
  0         0  
  0         0  
  2         805  
  0         0  
  0         0  
  2         720  
  0         0  
  0         0  
  2         710  
  0         0  
  0         0  
9 2         56 $INC{'Lock/Socket/Mo.pm'} = __FILE__;
10             }
11             1;
12             #>>>
13              
14             package Lock::Socket::Error;
15 2     2   10 use Lock::Socket::Mo;
  2         3  
  2         9  
16 2     2   3227 use overload '""' => sub { $_[0]->msg }, fallback => 1;
  2     8   2076  
  2         17  
  8         1125  
17              
18             has msg => (
19             is => 'ro',
20             required => 1,
21             );
22              
23             1;
24              
25             package Lock::Socket;
26 2     2   161 use strict;
  2         3  
  2         57  
27 2     2   9 use warnings;
  2         3  
  2         61  
28 2     2   9 use Carp ();
  2         3  
  2         28  
29 2     2   8 use Lock::Socket::Mo;
  2         2  
  2         9  
30 2     2   1949 use Socket;
  2         8338  
  2         1352  
31              
32             our @VERSION = '0.0.3_4';
33             our @CARP_NOT;
34              
35             @Lock::Socket::Error::Bind::ISA = ('Lock::Socket::Error');
36             @Lock::Socket::Error::Socket::ISA = ('Lock::Socket::Error');
37             @Lock::Socket::Error::Usage::ISA = ('Lock::Socket::Error');
38             @Lock::Socket::Error::Import::ISA = ('Lock::Socket::Error');
39              
40             ### Function Interface ###
41              
42             sub import {
43 3     3   353 my $class = shift;
44 3         6 my $caller = caller;
45 2     2   15 no strict 'refs';
  2         3  
  2         1824  
46              
47 3         36 foreach my $token (@_) {
48 3 100       12 if ( $token eq 'lock_socket' ) {
    100          
49 1         6 *{ $caller . '::lock_socket' } = sub {
50 6   66 6   899 my $port = shift
51             || __PACKAGE__->err( 'Usage', 'usage: lock_socket($PORT)' );
52 5         7 my $addr = shift;
53 5 100       33 my $sock = Lock::Socket->new(
54             port => $port,
55             defined $addr ? ( addr => $addr ) : (),
56             );
57 5         17 $sock->lock;
58 3         9 return $sock;
59 1         3 };
60             }
61             elsif ( $token eq 'try_lock_socket' ) {
62 1         27 *{ $caller . '::try_lock_socket' } = sub {
63 4   66 4   987 my $port = shift
64             || __PACKAGE__->err( 'Usage',
65             'usage: try_lock_socket($PORT)' );
66 3         6 my $addr = shift;
67 3 100       26 my $sock = Lock::Socket->new(
68             port => $port,
69             defined $addr ? ( addr => $addr ) : (),
70             );
71 3         11 $sock->try_lock;
72 3 100       11 return $sock if $sock->_is_locked;
73 1         20 return undef;
74             }
75 1         6 }
76             else {
77 1         5 __PACKAGE__->err( 'Import',
78             'not exported by Lock::Socket: ' . $token );
79             }
80             }
81             }
82              
83             ### Object Attributes ###
84              
85             has port => (
86             is => 'ro',
87             required => 1,
88             );
89              
90             has addr => (
91             is => 'ro',
92             default => sub {
93             return join( '.', 127, unpack( 'C2', pack( "n", $< ) ), 1 )
94             unless $^O =~ m/bsd$/;
95             return '127.0.0.1';
96             },
97             );
98              
99             has _inet_addr => (
100             is => 'ro',
101             default => sub {
102             my $self = shift;
103             return inet_aton( $self->addr );
104             },
105             );
106              
107             has _fh => (
108             is => 'rw',
109             lazy => 0,
110             builder => '_fh_builder',
111             );
112              
113             sub _fh_builder {
114 19     19   26 my $self = shift;
115 19 50       3828 socket( my $fh, PF_INET, SOCK_STREAM, getprotobyname('tcp') )
116             || $self->err( 'Socket', "socket: $!" );
117 19         116 return $fh;
118             }
119              
120             sub fh {
121 18     18 0 40 $_[0]->_fh;
122             }
123              
124             has _is_locked => (
125             is => 'rw',
126             lazy => 0,
127             default => sub { 0 },
128             );
129              
130             sub is_locked {
131 6     6 0 1052 $_[0]->_is_locked;
132             }
133              
134             ### Object Methods ###
135              
136             sub err {
137 9     9 0 18 my $self = shift;
138 9         20 my $class = 'Lock::Socket::Error::' . $_[0];
139 9         32 local @CARP_NOT = __PACKAGE__;
140 9         1364 die $class->new( msg => Carp::shortmess( $_[1] ) );
141             }
142              
143             sub lock {
144 20     20 1 41 my $self = shift;
145 20 100       43 return 1 if $self->_is_locked;
146              
147 18 100       48 bind( $self->fh, pack_sockaddr_in( $self->port, $self->_inet_addr ) )
148             || $self->err( 'Bind',
149             sprintf( 'bind: %s (%s:%d)', $!, $self->addr, $self->port ) );
150              
151 12         51 $self->_is_locked(1);
152             }
153              
154             sub try_lock {
155 6     6 0 17 my $self = shift;
156 6   100     10 return eval { $self->lock } || 0;
157             }
158              
159             sub unlock {
160 3     3 0 8 my $self = shift;
161 3 100       13 return 1 unless $self->_is_locked;
162              
163 2         8 close( $self->_fh );
164 2         10 $self->_fh( $self->_fh_builder );
165 2         11 $self->_is_locked(0);
166              
167 2         9 return 1;
168             }
169              
170             1;
171              
172             __END__