Set::Groups - A set of groups.


Set-Groups documentation Contained in the Set-Groups distribution.

Index


Code Index:

NAME

Top

Set::Groups - A set of groups.

SYNOPSIS

Top

  use Set::Groups ;

  # create a set of groups
  $groups = new Set::Groups ;

  # create a group MyGroup with a single member
  $groups->addOwnSingleTo("single1","MyGroup") ;

  # add a group member into MyGroup
  $groups->addOwnGroupTo("Member1Group","MyGroup") ; 

  # add a single members into the previous member group
  $groups->addOwnSingleTo("single2","Member1Group") ;

  # add a group member into the previous member group
  $groups->addOwnGroupTo("Member2Group","Member1Group") ; 

  # add a single members into the previous member group
  $groups->addOwnSingleTo("single3","Member2Group") ;

  # flatten the group MyGroup
  @singles = $groups->getSinglesOf("MyGroup") ; 
  @groups = $groups->getGroupsOf("MyGroup") ; 
  $present = $groups->isSingleOf("single3","MyGroup") ; 
  $present = $groups->isGroupOf("Member2Group","MyGroup") ; 

DESCRIPTION

Top

The Groups object implements a set of groups. Each group can own single members and group members. A group can be flattened, i.e. expansed until each of his members is a single one.

CONSTRUCTORS

Top

new

Create a new group set.

  my $groups = new Set::Groups

INSTANCE METHODS

Top

setDebug

Set a debug level (0 or 1).

  $groups->setDebug(1) ;

Set management

newGroup

Create a new empty group and add it into the set. A group is everything which can be a key of a hash. Returns 1 on success, 0 otherwise.

  $groups->newGroup("a_group") ;
  $groups->newGroup(1) ;

deleteGroup

Delete a group from the set. Return 1 on success, 0 otherwise.

  $groups->deleteGroup("a_group") ;

getGroups

Return the list of the groups present into the set.

  @groups = $groups->getGroups() ; 

getCyclicGroups

Return the list of the cyclic groups (i.e. self-contained) present into the set.

  @groups = $groups->getGroups() ; 

getAcyclicGroups

Return the list of the acyclic groups (i.e. not self-contained) present into the set.

  @groups = $groups->getGroups() ; 

hasGroup

Check if a group is present into the set.

  $present = $groups->hasGroup("a_group") ;

Groups management

addOwnSingleTo

Add a single member to a group. A single is everything which can be a key of a hash. If the group doesn't exist in the set, it is created. Return 1 on success, 0 otherwise.

  $groups->addOwnSingleTo("single","a_group") ;

addOwnGroupTo

Add a group member to a group. If the embedding group doesn't exist in the set, it is created. If the member group doesn't exist in the set, it is created as an empty group. Return 1 on success, 0 otherwise.

  $groups->addOwnGroupTo("group_member","a_group") ;

removeOwnSingleFrom

Remove an own single from a group. Return 1 on success, 0 otherwise.

  $groups->removeOwnSingleFrom("single","a_group") ;

removeOwnGroupFrom

Remove a group member from a group. Return 1 on success, 0 otherwise.

  $groups->removeOwnGroupFrom("a_member_group","a_group") ;

isAcyclic

Check if a group is acyclic.

  $is_acyclic = $groups->isAcyclic("a_group") ;

isOwnSingleOf

Check if a single is an own member of a group.

  $present = $groups->isOwnSingleOf("single","a_group") ;

isOwnGroupOf

Check if a group is an own member of a group.

  $present = $groups->isOwnGroupOf("a_group_member","a_group") ;

isSingleOf

Check if a single is a (own or not) member of a group.

  $present = $groups->isSingleOf("single","an_acyclic_group") ;

Warning - Calling this method with a cyclic group as argument gives a infinite recursion.

isGroupOf

Check if a group is a (own or not) member of a group.

  $present = $groups->isGroupOf("a_group_member","an_acyclic_group") ;

Warning - Calling this method with a cyclic group as argument gives a infinite recursion.

getOwnSinglesOf

Return the list of own singles of a group.

  @singles = $groups->getOwnSinglesOf("a_group") ;

getOwnGroupsOf

Return the list of own groups of a group.

  @groups = $groups->getOwnGroupsOf("a_group") ;

getSinglesOf

Return the list of (own or not) singles of an acyclic group.

  @singles = $groups->getSinglesOf("an_acyclic_group") ;

Warning - Calling this method with a cyclic group as argument gives a infinite recursion.

getGroupsOf

Return the list of (own or not) groups of an acyclic group.

  @groups = $groups->getGroupsOf("an_acyclic_group") ;

Warning - Calling this method with a cyclic group as argument gives a infinite recursion.

addGroupTo

Deprecated - Replaced by addOwnGroupTo.

addSingleTo

Deprecated - Replaced by addOwnSingleTo.

removeGroupFrom

Deprecated - Replaced by removeOwnGroupFrom.

removeSingleFrom

Deprecated - Replaced by removeOwnSingleFrom.

EXAMPLES

Top

Suppose a group file like :

	admin:root,adm
	team:piotr,lioudmila,adam,annette,jacquelin
	true-users:james,sophie,@team,mohammed
	everybody:@admin,operator,@true-users
	daemon:apache,smmsp,named,daemon
	virtual:nobody,halt,@daemon
	all:@everybody,@virtual

where @name means group name, then the following code :

	use Set::Groups ;

	$groups = new Set::Groups ;
	while(<>)
	{
	  ($group,$members) = /^(\S+):(.*)$/ ;
	  @members = split(/,/,$members) ;
	  for $member (@members)
	  {
	    if ($member=~/^@/)
	    {
	      $member=~s/^@// ;
	      $groups->addOwnGroupTo($member,$group) ;
	    }
	    else
	    {
	      $groups->addOwnSingleTo($member,$group) ;
	    }
	  }
	}
	die "some groups are cyclic" if scalar($groups->getCyclicGroups())>0 ;
	print "singles: ",join(', ',$groups->getSinglesOf("all")),"\n" ;
	print "groups: ",join(', ',$groups->getGroupsOf("all")),"\n" ;

gives :

	singles: apache, sophie, jacquelin, lioudmila, mohammed, smmsp, nobody, adm, annette, operator, james, named, adam, halt, root, daemon, piotr
	groups: admin, everybody, team, daemon, true-users, virtual

AUTHOR

Top

Jacquelin Charbonnel, <jacquelin.charbonnel at math.cnrs.fr>

BUGS

Top

Please report any bugs or feature requests to bug-Set-Groups at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Set-Groups. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

Top

You can find documentation for this module with the perldoc command.

    perldoc Set-Groups

You can also look for information at:

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/Set-Groups

* CPAN Ratings

http://cpanratings.perl.org/s/Set-Groups

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=Set-Groups

* Search CPAN

http://search.cpan.org/dist/Set-Groups

COPYRIGHT & LICENSE

Top


Set-Groups documentation Contained in the Set-Groups distribution.
package Set::Groups ;

#   ======================
# 
#           Jacquelin Charbonnel - CNRS/LAREMA
#  
#   $Id: Groups.pm 22 2007-11-06 20:58:14Z jaclin $
#   
#   ----
#  
#   A set of groups.
#   Each group can own single members and group members.
#   A group can be flattened, i.e. expansed until each of his members is a single one.
# 
#   ----
#   $LastChangedDate: 2007-11-06 21:58:14 +0100 (Tue, 06 Nov 2007) $ 
#   $LastChangedRevision: 22 $
#   $LastChangedBy: jaclin $
#   $URL: https://svn.math/system-tools/trunk/Set-Groups/Groups.pm $
#  
#   ======================

require Exporter ;
@ISA = qw(Exporter);
@EXPORT=qw() ;
@EXPORT_OK = qw( );

use 5.006;
use Carp;
use warnings;
use strict;

our $VERSION = 0.8 ; # $LastChangedRevision: 22 $
my $hfmt = "Set::Groups: HORROR: group '%s' is cyclic, the walk is infinite... Bye"  ;

sub new()
{ 
	my ($type) = @_ ;
	my $this = {
		"group" => {}
		, "debug" => 0
	} ;
  
	bless $this,$type ;
	return $this ;
}

sub setDebug($)
{
	my ($this,$level) = @_ ;
	$this->{"debug"} = $level ;
}

# -----------------
# Set management
# -----------------

sub newGroup($)
{
	my ($this,$group) = @_ ;

	if (exists $this->{"group"}{$group})
	{
		return 0 ;
	}
	else
	{
		$this->{"group"}{$group} = {} ;
		delete $this->{"partition"} if exists $this->{"partition"} ; 
		return 1 ;
	}
}

sub deleteGroup($)
{
	my ($this,$group) = @_ ;
	
	if (exists $this->{"group"}{$group})
	{
		delete $this->{"group"}{$group} ;
		delete $this->{"partition"} if exists $this->{"partition"} ;
		return 1 ;
	}
	else
	{
		return 0 ;
	}
}

sub getGroups()
{
	my ($this) = @_ ;
	return keys %{$this->{"group"}} ;
}

sub getCyclicGroups
{
	my($this) = @_ ;

	$this->_walk() unless exists $this->{"partition"} ;
	return keys(%{$this->{"partition"}{"cyclic"}}) ;
}

sub getAcyclicGroups
{
	my($this) = @_ ;

	$this->_walk() unless exists $this->{"partition"} ;
	return keys(%{$this->{"partition"}{"acyclic"}}) ;
}

sub hasGroup($)
{
	my($this,$group) = @_ ;
	return exists $this->{"group"}{$group} ;
}

# -----------------
# Group management
# -----------------

sub addSingleTo($$)
{
	my ($this,$single,$group) = @_ ;

	warn "Set::Groups: NOTICE: 'addSingleTo' is deprecated, use 'addOwnSingleTo' instead" if $this->{"debug"}>0 ;
	return $this->addOwnSingleTo($single,$group) ;
}

sub addOwnSingleTo($$)
{
	my ($this,$single,$group) = @_ ;

	return 0 if exists $this->{"group"}{$group}{"single"}{$single} ;
	$this->{"group"}{$group}{"single"}{$single} = 1 ;
	return 1 ;
}

sub addGroupTo($$)
{
	my ($this,$mgroup,$group) = @_ ;

	warn "Set::Groups: NOTICE: 'addGroupTo' is deprecated, use 'addOwnGroupTo' instead" if $this->{"debug"}>0 ;
	return $this->addOwnGroupTo($mgroup,$group) ;
}

sub addOwnGroupTo($$)
{
	my ($this,$mgroup,$group) = @_ ;

	return 0 if exists $this->{"group"}{$group}{"group"}{$mgroup} ;
	$this->{"group"}{$mgroup} = {} unless (exists $this->{"group"}{$mgroup}) ;
	$this->{"group"}{$group}{"group"}{$mgroup} = 2 ;
	delete $this->{"partition"} if exists $this->{"partition"} ;
	return 1 ;
}

sub removeSingleFrom($$)
{
	my ($this,$single,$group) = @_ ;

	warn "Set::Groups: NOTICE: 'removeSingleFrom' is deprecated, use 'removeOwnSingleFrom' instead" if $this->{"debug"}>0 ;
	return $this->removeOwnSingleFrom($single,$group) ;
}

sub removeOwnSingleFrom($$)
{
	my ($this,$single,$group) = @_ ;

	if ($this->isSingleOf($single,$group))
	{
		delete $this->{"group"}{$group}{"single"}{$single} ;
		return 1 ;
	}
	else { return 0 ; }
}

sub removeGroupFrom($$)
{
	my ($this,$sub,$group) = @_ ;

	warn "Set::Groups: NOTICE: 'removeGroupFrom' is deprecated, use 'removeOwnGroupFrom' instead" if $this->{"debug"}>0 ;
	return $this->removeOwnGroupFrom($sub,$group) ;
}

sub removeOwnGroupFrom($$)
{
	my ($this,$sub,$group) = @_ ;

	if ($this->isGroupOf($sub,$group))
	{
		delete $this->{"group"}{$group}{"group"}{$sub} ;
		delete $this->{"partition"} if exists $this->{"partition"} ;
		return 1 ;
	}
	else { return 0 ; }
}

# This function performs a total walk, if needeed
# At exit, the partition is always complete
sub isAcyclic
{
	my ($this,$group) = @_ ;

	$this->_walk() unless exists($this->{"partition"}) ;
	return exists($this->{"partition"}{"acyclic"}{$group}) ;
}  

sub isOwnSingleOf($$)
{
	my ($this,$candidate,$group) = @_ ;
	return exists $this->{"group"}{$group}{"single"}{$candidate} ;
}

sub isOwnGroupOf($$)
{
	my ($this,$candidate,$group) = @_ ;
	return exists $this->{"group"}{$group}{"group"}{$candidate} ;
}

sub isSingleOf($$)
{
	my ($this,$candidate,$group) = @_ ;

	carp sprintf($hfmt,$group) if $this->{"debug"}>0 && !$this->isAcyclic($group) ;
	my %fs = $this->_flattenedSinglesOf($group) ;
	return exists $fs{$candidate} ;
}  

sub isGroupOf($$)
{
	my ($this,$candidate,$group) = @_ ;

	carp sprintf($hfmt,$group) if $this->{"debug"}>0 && !$this->isAcyclic($group) ;
	my %fs = $this->_flattenedGroupsOf($group) ;
	return exists $fs{$candidate} ;
}  

sub getOwnSinglesOf($)
{
	my ($this,$group) = @_ ;
	return keys %{$this->{"group"}{$group}{"single"}} ;
}

sub getOwnGroupsOf($)
{
	my ($this,$group) = @_ ;
	return keys %{$this->{"group"}{$group}{"group"}} ;
}

sub getSinglesOf($)
{
	my ($this,$group) = @_ ;

	carp sprintf($hfmt,$group) if $this->{"debug"}>0 && !$this->isAcyclic($group) ;
	my %h = $this->_flattenedSinglesOf($group) ;
	return keys %h ;
}

sub getGroupsOf($)
{
	my ($this,$group) = @_ ;

	carp sprintf($hfmt,$group) if $this->{"debug"}>0 && !$this->isAcyclic($group) ;
	my %h = $this->_flattenedGroupsOf($group) ;
	return keys %h ;
}

# -----------------
# private methods
# -----------------

sub _flattenedSinglesOf()
{
	my ($this,$group) = @_ ;

	my %flat = () ;
	%flat = %{$this->{"group"}{$group}{"single"}} 
	  if exists $this->{"group"}{$group}{"single"} ;

	for my $k (keys %{$this->{"group"}{$group}{"group"}})
	{
		my %fs = $this->_flattenedSinglesOf($k) ;
		for my $kk (keys %fs)
		{
			$flat{$kk} = 1 ;
		}
	}
	return %flat ;
}  

sub _flattenedGroupsOf()
{
	my ($this,$group) = @_ ;

	my %flat = () ;
	for my $k (keys %{$this->{"group"}{$group}{"group"}})
	{
		$flat{$k} = 1 ;
		if (! exists $this->{"group"}{$k}{"group"} || scalar keys %{$this->{"group"}{$k}{"group"}}==0)
		{ 
		}
		else
		{
			my %fs = $this->_flattenedGroupsOf($k) ;
			for my $kk (keys %fs)
			{
				$flat{$kk} = 1 ;
			}
		}
	}
	return %flat ;
}  

# This function don't perform a total walk
# At exit, the partition is incomplete
sub _isAcyclic($$)
{
	my ($this,$group,$passed) = @_ ;

	if (exists $passed->{$group})
	{
		$this->{"partition"}{"cyclic"}{$group} = 1 ;
		return 0 ;
	}
	my %passed = ( %$passed, $group => 1 ) ;

	for my $k (keys %{$this->{"group"}{$group}{"group"}})
	{
		next if exists $this->{"partition"}{"acyclic"}{$k} ;
		if (exists $this->{"partition"}{"cyclic"}{$k})
		{
			$this->{"partition"}{"cyclic"}{$group} = 1 ;
			return 0 ;
		}
		if ($this->_isAcyclic($k,\%passed)==1)
		{
			$this->{"partition"}{"acyclic"}{$k} = 1 ;
		}
		else
		{
			$this->{"partition"}{"cyclic"}{$k} = 1 ;
			$this->{"partition"}{"cyclic"}{$group} = 1 ;
			return 0 ;
		}  
	}
	$this->{"partition"}{"acyclic"}{$group} = 1 ;
	return 1 ;
}  

# Perform an inconditionnal walk on the graph
sub _walk()
{
	my ($this) = @_ ;

	carp "Set::Groups: DEBUG: walking on the graph to find cycles..." if $this->{"debug"}>0 ;
	delete $this->{"partition"} if exists $this->{"partition"} ;
	for my $group ($this->getGroups())  
	{
		$this->_isAcyclic($group,{}) ;
	}
}  

1;