File Coverage

blib/lib/Set/Definition.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             package Set::Definition;
3              
4 1     1   609 use strict;
  1         2  
  1         37  
5 1     1   1638 use Class::Core qw/:all/;
  0            
  0            
6             use Data::Dumper;
7              
8             use vars qw( $VERSION );
9             $VERSION = "0.01";
10              
11             =head1 NAME
12              
13             Set::Definition - Class to handle simple logical set unions and intersections.
14              
15             =head1 VERSION
16              
17             0.01
18              
19             =cut
20              
21             sub construct {
22             my ( $core, $def ) = @_;
23             my $text = $def->{'text'};
24             my $parts = expr_to_parts( $text );
25             my $arr = parse_arr( $parts );
26             my $obj = $arr->[0];
27             my $parsed;
28             if( ref( $obj ) eq 'HASH' ) {
29             $def->{'ob'} = $obj;
30             $parsed = $obj->{'parsed'};
31             }
32             else {
33             $parsed = [ $obj ];
34             $def->{'ob'} = { parsed => $parsed, join => '|' };
35             }
36             $def->{'groups'} = uniq_parts( {}, $parsed );
37             }
38              
39             # Return the groups mentioned in the expression
40             sub expr_groups {
41             my ( $core, $def ) = @_;
42             return $def->{'groups'};
43             }
44              
45             sub contains {
46             my ( $core, $def, $mem ) = @_;
47             my $member = $mem || $core->get('member');
48             my $obj = $def->{'ob'};
49             my $check_list = $def->{'groups'};
50             my $membership = $def->check_membership( hash => $check_list, user => $member );
51             #print Dumper( $membership );
52             return eval_hash( $membership, $obj );
53             }
54              
55             sub members {
56             my ( $core, $def ) = @_;
57            
58             my $obj = $def->{'ob'};
59             my $check_list = $def->{'groups'};
60            
61             # get the membership of the groups that we depend on
62             my $membership = $def->get_membership( hash => $check_list );
63             #print "Membership\n";
64             #print Dumper( $membership );
65             #print "Call to members\n";
66             return eval_hash_members( $membership, $obj );
67             }
68              
69             sub expr_to_parts {
70             my $expr = shift;
71             $expr =~ s/ //g;
72             if( $expr !~ m/^\(/ || $expr !~ m/\)$/ ) { $expr = "($expr)"; }
73             my @parts = split(/([&|()])/, $expr );
74             my @ref;
75             for my $part ( @parts ) {
76             next if( !$part );
77             push( @ref, $part );
78             }
79             return \@ref;
80             }
81              
82             sub eval_hash {
83             my ( $user_membership, $hash ) = @_;
84             my $parsed = $hash->{'parsed'};
85             my $join = $hash->{'join'};
86             #print Dumper( { parsed => $parsed, join => $join } );
87             for my $item ( @$parsed ) {
88             my $cur = ( ref( $item ) eq 'HASH' ) ? eval_hash( $user_membership, $item ) : $user_membership->{ $item };
89             $cur = 0 if( ! defined $cur );
90             return 0 if( $join eq '&' && !$cur );
91             return 1 if( $join eq '|' && $cur );
92             }
93             return 1 if( $join eq '&' );
94             return 0;
95             }
96              
97             sub eval_hash_members {
98             my ( $membership, $hash ) = @_;
99             my $parsed = $hash->{'parsed'};
100             my $join = $hash->{'join'};
101            
102             my $a = $parsed->[0];
103             my $b = $parsed->[1];
104             #print Dumper( $a );
105             #print Dumper( $b );
106             my $alist = ( ref( $a ) eq 'HASH' ) ? eval_hash_members( $membership, $a ) : $membership->{ $a };
107            
108             if( !defined $b ) {
109             return $alist;
110             }
111             my $blist = ( ref( $b ) eq 'HASH' ) ? eval_hash_members( $membership, $b ) : $membership->{ $b };
112             if( $join eq '&' ) {
113             #print Dumper( $alist );
114             #print Dumper( $blist );
115             return intersect_groups( $alist, $blist );
116             }
117             if( $join eq '|' ) {
118             #print Dumper( $alist );
119             #print Dumper( $blist );
120             return join_groups( $alist, $blist );
121             }
122             }
123              
124             sub array_to_hash {
125             my $arr = shift;
126             #my %hash = map { ($a, 1) } @$arr;
127             my %hash;
128             for my $key ( @$arr ) {
129             $hash{ $key } = 1;
130             }
131             return \%hash;
132             }
133              
134             sub intersect_groups {
135             my ( $a, $b ) = @_;
136             my $bhash = array_to_hash( $b );
137             my @res;
138             for my $key ( @$a ) {
139             push( @res, $key ) if( $bhash->{ $key } );
140             }
141             return \@res;
142             }
143              
144             sub join_groups {
145             my ( $a, $b ) = @_;
146             my %res;
147             for my $key ( @$a ) { $res{ $key } = 1; }
148             for my $key ( @$b ) { $res{ $key } = 1; }
149             my @arr = keys %res;
150             return \@arr;
151             }
152              
153             sub check_membership {
154             my ( $core, $def ) = @_;
155             my $hash = $core->get('hash');
156             my $user = $core->get('user');
157            
158             my $res = {};
159             for my $key ( keys %$hash ) {
160             my $ingroup_ref = $def->{'ingroup_callback'};
161             my $temp = $res->{ $key } = &$ingroup_ref( $key, $user, $def );
162             $res->{ "!$key" } = $temp ? 0 : 1;
163             }
164             return $res;
165             }
166              
167             sub get_membership {
168             my ( $core, $def ) = @_;
169             my $hash = $core->get('hash');
170            
171             my $res = {};
172             for my $key ( keys %$hash ) {
173             my $ingroup_ref = $def->{'ingroup_callback'};
174             my $members = &$ingroup_ref( $key, undef, $def );
175             $res->{ $key } = $members;
176             }
177             return $res;
178             }
179              
180             # Find the parts mentioned in @$arr, and put them in the hash %$res
181             sub uniq_parts {
182             my ( $res, $arr ) = @_;
183             for my $item ( @$arr ) {
184             if( ref( $item ) eq 'HASH' ) {
185             uniq_parts( $res, $item->{'parsed'} );
186             }
187             else {
188             my $temp = $item;
189             $temp =~ s/^!//;
190             $res->{ $temp } = 1;
191             }
192             }
193             return $res;
194             }
195              
196             sub parse_arr {
197             my $in = shift;
198             my $sub = 0;
199             my $depth = 0;
200             my $out = [];
201             for my $part ( @$in ) {
202             next if( !$part );
203             my $ref = ref( $part );
204            
205             if( $ref ne 'HASH' ) { # is a name or a connector
206             if( $part eq '(' ) {
207             if( !$depth ) {
208             $sub = { parts => [] };
209             $depth++;
210             next;
211             }
212            
213             $depth++;
214             }
215             elsif( $part eq ')' ) {
216             $depth--;
217             if( !$depth ) {
218             my $parsed = parse_arr( $sub->{'parts'} );
219             push( @$out, treat_arr( $parsed ) );
220             $sub = 0;
221             next;
222             }
223             }
224             }
225            
226             if( $sub ) {
227             if( $depth == 1 ) {
228             if( $part eq '&' || $part eq '|' ) {
229             $sub->{'join'} = $part;
230             }
231             }
232             push( @{$sub->{'parts'}}, $part );
233             }
234             else {
235             push( @$out, $part );
236             }
237             }
238            
239             return $out;
240             }
241              
242             sub treat_arr {
243             my ( $arr, $lev ) = @_;
244             my $len = $#$arr;
245             return $arr->[0] if( $len == 0 );
246             my @res;
247             my $join = $lev ? '|' : '&';
248             for( my $i = 0; $i <= $len; $i++ ) {
249             my $part = $arr->[ $i ];
250             if( $i % 2 && $part eq $join ) {
251             push( @res, { parsed => [ pop( @res ), $arr->[ ++$i ] ], join => $join } );
252             next;
253             }
254             push( @res, $part );
255             }
256             return $lev ? $res[0] : treat_arr( \@res, 1 );
257             }
258              
259             1;
260              
261             __END__