File Coverage

blib/lib/Set/NestedGroups.pm
Criterion Covered Total %
statement 70 141 49.6
branch 6 34 17.6
condition 8 23 34.7
subroutine 14 21 66.6
pod 9 14 64.2
total 107 233 45.9


line stmt bran cond sub pod time code
1             package Set::NestedGroups;
2              
3 1     1   742 use strict;
  1         2  
  1         39  
4 1     1   5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  1         2  
  1         69  
5 1     1   514 use Set::NestedGroups::Member;
  1         2  
  1         20  
6 1     1   5 use Carp;
  1         3  
  1         206  
7              
8             @ISA = qw();
9             # Items to export into callers namespace by default. Note: do not export
10             # names by default without a very good reason. Use EXPORT_OK instead.
11             # Do not simply export all your public functions/methods/constants.
12             @EXPORT = qw(
13            
14             );
15             $VERSION = '0.01';
16              
17             # Constructor
18             sub new {
19 1     1 1 40 my $proto=shift;
20 1         2 my $fh=shift;
21 1   33     8 my $class=ref($proto) || $proto;
22 1         2 my $self = {};
23 1         4 bless($self,$class);
24            
25 1 50       3 if(defined $fh){
26 0 0       0 if(ref($fh) eq "DBI::st"){
27 0         0 $fh->execute();
28 0         0 for(my $i=0;$i<$fh->rows();$i++){
29 0         0 my ($member,$group)=$fh->fetchrow();
30 0         0 $self->add($member,$group);
31             }
32             } else {
33 1     1   5 no strict "refs"; # Can't use strict here,
  1         2  
  1         436  
34             # incase called with (DATA) instead
35             # of \*DATA
36 0         0 $fh=to_filehandle($fh);
37 0         0 while(<$fh>){
38 0         0 chomp;
39 0 0       0 last if(/^=$/);
40 0         0 my ($member,$group)=split(/=/,$_,2);
41 0         0 $self->add(unescape($member),unescape($group));
42             }
43             }
44             }
45 1         3 return $self;
46             }
47              
48             # Add a member to a group
49             sub add {
50 2     2 1 13 my $self=shift;
51 2         5 my ($member,$group)=@_;
52 2         10 my $was= $self->{'MEMBERS'}{$member}{$group};
53 2         6 $self->{'MEMBERS'}{$member}{$group}=1;
54 2         5 return $was;
55             }
56              
57             # And remove a member from a group
58             sub remove {
59 0     0 1 0 my $self=shift;
60 0         0 my ($member,$group)=@_;
61 0         0 my $was=$self->{'MEMBERS'}{$member}{$group};
62 0         0 delete $self->{'MEMBERS'}{$member}{$group};
63 0         0 $self->{'GROUPS'}{$group}--;
64 0 0       0 if($self->{'GROUPS'}{$group} == 0){
65 0         0 delete $self->{'GROUPS'}{$group};
66             }
67 0         0 return $was;
68             }
69              
70             # Create some sort of list object
71             sub list {
72 0     0 1 0 my $self=shift;
73 0         0 my %options=@_;
74 0         0 my $member_list=new Set::NestedGroups::MemberList;
75 0   0     0 my $nogroups = $options{'-nogroups'} || 0;
76            
77 0         0 foreach my $user (keys %{$self->{'MEMBERS'}}){
  0         0  
78 0 0 0     0 next if($nogroups && $self->group($user));
79 0         0 foreach my $group ($self->groups($user,%options)){
80 0         0 $member_list->add($user,$group);
81             }
82             }
83 0         0 return $member_list;
84             }
85              
86             sub to_filehandle {
87 1     1   5 no strict "refs"; # Can't use strict here,
  1         2  
  1         375  
88             # incase called with (DATA) instead
89             # of \*DATA
90 0     0 0 0 my $string = shift;
91 0 0 0     0 if ($string && !ref($string)) {
92 0         0 my($package) = caller(1);
93 0 0       0 my($tmp) = $string=~/[':]/ ? $string : "$package\:\:$string";
94 0 0       0 return $tmp if defined(fileno($tmp));
95             }
96 0         0 return $string;
97             }
98              
99             # unescape URL-encoded data
100             sub unescape {
101 0     0 0 0 my($todecode) = @_;
102 0         0 $todecode =~ tr/+/ /; # pluses become spaces
103 0         0 $todecode =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
  0         0  
104 0         0 return $todecode;
105             }
106              
107             # URL-encode data
108             sub escape {
109 0     0 0 0 my($toencode) = @_;
110 0         0 $toencode=~s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
  0         0  
111 0         0 return $toencode;
112             }
113              
114             # Save the current object
115             sub save {
116 0     0 1 0 my $self=shift;
117 0         0 my $fh=shift;
118              
119 0 0       0 if(ref($fh) eq "DBI::st"){
120 0         0 my $members=$self->list('-norecurse'=>1,-nomiddles=>0);
121 0         0 for(my $i=0;$i<$members->rows();$i++){
122 0 0       0 $fh->execute($members->next()) or return;
123             }
124 0         0 return 1;
125             } else {
126 1     1   6 no strict "refs"; # Can't use strict here,
  1         1  
  1         761  
127             # incase called with (DATA) instead
128             # of \*DATA
129 0         0 $fh=to_filehandle($fh);
130              
131 0         0 my $members=$self->list('-norecurse'=>1,-nomiddles=>0);
132 0         0 for(my $i=0;$i<$members->rows();$i++){
133 0         0 my ($member,$group)=$members->next();
134 0 0       0 print $fh escape($member),'=',escape($group),"\n" or return;
135             }
136 0 0       0 print $fh "=\n" or return;
137             }
138             }
139              
140             # Check a member
141             sub member {
142 4     4 1 17 my $self=shift;
143 4         6 my $member=shift;
144 4 50       10 if(@_){
145 0         0 my $want_group=shift;
146 0         0 foreach my $got_group ($self->groups($member,-norecurse=>0,-nomiddles=>0)){
147 0 0       0 return 1 if($got_group eq $want_group);
148             }
149 0         0 return undef;
150             }
151            
152 4         5 return (keys %{$self->{'MEMBERS'}{$member}})
  4         19  
153             }
154              
155             # Check a group
156             sub group {
157 2     2 1 17 my $self=shift;
158 2         4 my $group=shift;
159              
160             return
161 2         6 grep {$_ eq $group} $self->allgroups();
  4         10  
162             }
163              
164             # Return all the members
165             sub allmembers {
166 2     2 0 3 my $self=shift;
167 2         3 return (keys %{$self->{'MEMBERS'}});
  2         9  
168             }
169              
170             # Return all the groups
171             sub allgroups {
172 2     2 0 3 my $self=shift;
173 2         4 my $group=shift;
174 2         3 my %seen;
175              
176             return
177 4         12 grep { !$seen{$_}++ }
  6         14  
178 2         7 map { keys %{$self->{'MEMBERS'}{$_}} }
  6         8  
179             $self->allmembers()
180             };
181              
182              
183             # Returns the groups a member belongs to
184             sub groups {
185 3     3 1 32 my $self=shift;
186 3         5 my $member=shift;
187 3         6 my %options=@_;
188 3   100     11 my $norecurse = $options{'-norecurse'} || 0;
189 3   100     11 my $nomiddles= $options{'-nomiddles'} || 0;
190            
191 3         30 my %group=%{$self->{'MEMBERS'}{$member}};
  3         9  
192              
193 3 100       9 if(!$norecurse){
194 2         2 my $again = 1;
195 2         6 while($again){
196 4         4 $again=0;
197 4         9 foreach my $group (keys %group){
198 6         5 foreach my $newgroup ( keys %{$self->{'MEMBERS'}{$group}}){
  6         14  
199 4 100       15 if(!$group{$newgroup}){
200 2         9 $again=$group{$newgroup}=1;
201             }
202             }
203             }
204             }
205             }
206 3   100     5 return grep { !$nomiddles || !$self->member($_) }keys %group;
  5         20  
207             }
208              
209             # Returns the members in a group
210             sub members {
211 0     0 1   my $self=shift;
212 0           my $group=shift;
213 0           my %options=@_;
214 0   0       my $nomiddles= $options{'-nomiddles'} || 0;
215 0           my %members;
216              
217 0           foreach my $member ($self -> allmembers()){
218 0 0         $members{$member}++ if(grep {$_ eq $group} $self->groups($member,%options));
  0            
219             }
220              
221 0   0       return grep { !$nomiddles || !$self->group($_) }keys %members;
  0            
222             }
223              
224             # Autoload methods go after =cut, and are processed by the autosplit program.
225              
226             1;
227             __END__