Set-Tiny-0.01/0000755000076400007640000000000011242036775010763 5ustar ststSet-Tiny-0.01/README0000644000076400007640000000173611241051164011636 0ustar ststSet-Tiny Set::Tiny is a thin wrapper around regular Perl hashes to perform often needed set operations, such as testing two sets of strings for equality, or checking whether one is contained within the other. INSTALLATION To install this module, run the following commands: perl Build.PL ./Build ./Build test ./Build install SUPPORT AND DOCUMENTATION After installing, you can find documentation for this module with the perldoc command. perldoc Set::Tiny You can also look for information at: RT, CPAN's request tracker http://rt.cpan.org/NoAuth/Bugs.html?Dist=Set-Tiny AnnoCPAN, Annotated CPAN documentation http://annocpan.org/dist/Set-Tiny CPAN Ratings http://cpanratings.perl.org/d/Set-Tiny Search CPAN http://search.cpan.org/dist/Set-Tiny/ COPYRIGHT AND LICENCE Copyright (C) 2009 Stanis Trendelenburg This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Set-Tiny-0.01/META.yml0000664000076400007640000000070511242036775012240 0ustar stst--- #YAML:1.0 name: Set-Tiny version: 0.01 abstract: Simple sets of strings license: perl author: - Stanis Trendelenburg generated_by: ExtUtils::MakeMaker version 6.42 distribution_type: module requires: Test::More: 0 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.3.html version: 1.3 Set-Tiny-0.01/Changes0000644000076400007640000000015511241051152012240 0ustar ststRevision history for Set-Tiny 0.01 2009-03-18 First version, released on an unsuspecting world. Set-Tiny-0.01/examples/0000755000076400007640000000000011242036775012601 5ustar ststSet-Tiny-0.01/examples/benchmark.pl0000755000076400007640000000724711241074612015074 0ustar stst#!/usr/bin/perl use strict; use lib 'lib'; # non-representative benchmark of different Set:: modules use Benchmark qw( cmpthese ); use Set::Tiny; use Set::Scalar; use Set::Object; my @a = 1 .. 100; my @b = 51 .. 150; my $s_t1 = Set::Tiny->new(@a); my $s_t2 = Set::Tiny->new(@b); my $s_s1 = Set::Scalar->new(@a); my $s_s2 = Set::Scalar->new(@b); my $s_o1 = Set::Object->new(@a); my $s_o2 = Set::Object->new(@b); my %tests = ( new => { t => sub { Set::Tiny->new(@a) }, s => sub { Set::Scalar->new(@a) }, o => sub { Set::Object->new(@a) }, }, # Set::Object doesn't have a clone() method #clone => { # t => sub { $s_t1->clone }, # s => sub { $s_s1->clone }, # o => sub { }, #}, insert => { t => sub { Set::Tiny->new->insert(@a) }, s => sub { Set::Scalar->new->insert(@a) }, o => sub { Set::Object->new->insert(@a) }, }, delete => { t => sub { Set::Tiny->new(@a)->delete(@b) }, s => sub { Set::Scalar->new(@a)->delete(@b) }, o => sub { Set::Object->new(@a)->delete(@b) }, }, invert => { t => sub { Set::Tiny->new(@a)->invert(@b) }, s => sub { Set::Scalar->new(@a)->invert(@b) }, o => sub { Set::Object->new(@a)->invert(@b) }, }, is_equal => { t => sub { $s_t1->is_equal($s_t2) }, s => sub { $s_s1->is_equal($s_s2) }, o => sub { $s_o1->equal($s_o2) }, }, is_subset => { t => sub { $s_t1->is_subset($s_t2) }, s => sub { $s_s1->is_subset($s_s2) }, o => sub { $s_o1->subset($s_o2) }, }, is_proper_subset => { t => sub { $s_t1->is_proper_subset($s_t2) }, s => sub { $s_s1->is_proper_subset($s_s2) }, o => sub { $s_o1->proper_subset($s_o2) }, }, is_superset => { t => sub { $s_t1->is_superset($s_t2) }, s => sub { $s_s1->is_superset($s_s2) }, o => sub { $s_o1->superset($s_o2) }, }, is_proper_superset => { t => sub { $s_t1->is_proper_superset($s_t2) }, s => sub { $s_s1->is_proper_superset($s_s2) }, o => sub { $s_o1->proper_superset($s_o2) }, }, is_disjoint => { t => sub { $s_t1->is_disjoint($s_t2) }, s => sub { $s_s1->is_disjoint($s_s2) }, o => sub { $s_o1->is_disjoint($s_o2) }, }, # The $set->contains(@elemets) methods are not identical: # Set::Tiny's and Set::Object's contains() returns true if $set contains # *all* of @elements # Set::Scalar's contains() returns true if $set contains *any* of @elements #contains => { # t => sub { $s_t1->contains(@b) }, # s => sub { $s_s1->contains(@b) }, # o => sub { $s_o1->contains(@b) }, #}, difference => { t => sub { $s_t1->difference($s_t2) }, s => sub { $s_s1->difference($s_s2) }, o => sub { $s_o1->difference($s_o2) }, }, union => { t => sub { $s_t1->union($s_t2) }, s => sub { $s_s1->union($s_s2) }, o => sub { $s_o1->union($s_o2) }, }, intersection => { t => sub { $s_t1->intersection($s_t2) }, s => sub { $s_s1->intersection($s_s2) }, o => sub { $s_o1->intersection($s_o2) }, }, symmetric_difference => { t => sub { $s_t1->symmetric_difference($s_t2) }, s => sub { $s_s1->symmetric_difference($s_s2) }, o => sub { $s_o1->symmetric_difference($s_o2) }, }, ); print "running benchmarks with sets of size ", scalar @a, " and ", scalar @b, "\n"; for my $test (sort keys %tests) { print "\n$test:\n"; cmpthese( -1, { 'Set::Tiny' => $tests{$test}{t}, 'Set::Scalar' => $tests{$test}{s}, 'Set::Object' => $tests{$test}{o}, }); } Set-Tiny-0.01/t/0000755000076400007640000000000011242036775011226 5ustar ststSet-Tiny-0.01/t/meta.t0000644000076400007640000000116411241041302012320 0ustar stst#!/usr/bin/perl # Test that our META.yml file matches the specification use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Test::CPAN::Meta 0.12', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } meta_yaml_ok(); 1; Set-Tiny-0.01/t/set.t0000644000076400007640000001021011241203551012163 0ustar stst#!/usr/bin/perl use strict; use Test::More tests => 59; use_ok 'Set::Tiny'; my $a = Set::Tiny->new; my $b = Set::Tiny->new(qw( a b c )); isa_ok $a, 'Set::Tiny'; sub to_s { join '', map { ref $_ eq 'Set::Tiny' ? $_->as_string : $_ } @_ } is $a->as_string, '()', "empty set stringification"; is $b->as_string, '(a b c)', "non-empty set stringification"; is $a->size, 0, to_s("size of ", $a, " is 0"); is $b->size, 3, to_s("size of ", $b, " is 3"); is $b->element('a'), 'a', "element()"; is $b->element('z'), undef, "element() on non-existing element"; is $b->member('a'), 'a', "member() is an alias for element()"; is_deeply [$a->elements], [], "elements() of emtpy set"; is_deeply [sort $b->elements], [qw( a b c )], "elements()"; is_deeply [sort $b->members], [qw( a b c )], "members() is an alias for elements()"; ok $b->contains(qw( a c )), to_s($b, " contains 'a' and 'c'"); ok $b->has(qw( a c )), "has() is an alias for contains()"; ok ! $a->contains('b'), to_s($a, " does not contain 'b'"); ok $a->contains(), to_s($a, " contains the empty list"); ok $a->is_null, to_s($a, " is empty"); ok ! $b->is_null, to_s($b, " is not empty"); ok $a->is_empty, "is_empty() is an alias for is_null"; ok $a->is_equal($a), to_s($a, " is equal to ", $a); ok $b->is_equal($b), to_s($b, " is equal to ", $b); ok ! $a->is_equal($b), to_s($a, " is not equal to ", $b); ok $a->is_subset($a), to_s($a, " is a subset of ", $a); ok $a->is_subset($b), to_s($a, " is a subset of ", $b); ok $b->is_subset($b), to_s($b, " is a subset of ", $b); ok ! $b->is_subset($a), to_s($b, " is not a subset of ", $a); ok $a->is_proper_subset($b), to_s($a, " is a proper subset of ", $b); ok ! $a->is_proper_subset($a), to_s($a, " is not a proper subset of ", $a); ok ! $b->is_proper_subset($b), to_s($b, " is not a proper subset of ", $b); ok ! $b->is_proper_subset($a), to_s($b, " is not a proper subset of ", $a); ok $b->is_superset($b), to_s($b, " is a superset of ", $b); ok $b->is_superset($a), to_s($b, " is a superset of ", $a); ok $a->is_superset($a), to_s($a, " is a superset of ", $a); ok ! $a->is_superset($b), to_s($a, " is not a superset of ", $b); ok $b->is_proper_superset($a), to_s($b, " is a proper superset of ", $a); ok ! $b->is_proper_superset($b), to_s($b, " is not a proper superset of ", $b); ok ! $a->is_proper_superset($a), to_s($a, " is not a proper superset of ", $a); ok ! $a->is_proper_superset($b), to_s($a, " is not a proper superset of ", $b); ok $a->is_disjoint($a), to_s($a, " and ", $a, " are disjoint"); ok $a->is_disjoint($b), to_s($a, " and ", $b, " are disjoint"); ok ! $b->is_disjoint($b), to_s($b, " and ", $b, " are not disjoint"); ok ! $a->is_properly_intersecting($b), to_s($a, " is not properly intersecting ", $b); ok ! $a->is_properly_intersecting($a), to_s($a, " is not properly intersecting ", $a); ok ! $b->is_properly_intersecting($b), to_s($b, " is not properly intersecting ", $b); my $c = Set::Tiny->new(qw( c d e )); ok $b->is_properly_intersecting($c), to_s($b, " is properly intersecting ", $c); my $d1 = $b->difference($c); my $d2 = $c->difference($b); is $d1->as_string, '(a b)', to_s("difference of ", $b, " and ", $c, " is ", $d1); is $d2->as_string, '(d e)', to_s("difference of ", $c, " and ", $b, " is ", $d2); my $u = $b->union($c); my $i = $b->intersection($c); my $s = $b->symmetric_difference($c); is $u->as_string, '(a b c d e)', to_s("union of ", $b, " and ", $c, " is ", $u); is $i->as_string, '(c)', to_s("intersection of ", $b, " and ", $c, " is ", $i); is $s->as_string, '(a b d e)', to_s("symmetric difference of ", $b, " and ", $c, " is ", $s); $s = $b->unique($c); is $s->as_string, '(a b d e)', "unique() is an alias for symmetric_difference()"; $b->clear; is $b->as_string, "()", "clear()"; $b->insert(qw( a b c d )); is $b->as_string, "(a b c d)", "insert()"; $b->remove(qw( a b )); is $b->as_string, "(c d)", "remove()"; $b->delete('c'); is $b->as_string, "(d)", "delete() is an alias for remove()"; $b->invert(qw( c d )); is $b->as_string, "(c)", "invert()"; my $x = $b->clone; is $x->as_string, "(c)", "clone()"; my $y = $b->copy; is $y->as_string, "(c)", "clone() is an alias for copy()"; $x->clear; is $b->as_string, "(c)", "clone is unchanged()"; Set-Tiny-0.01/t/minimumversion.t0000644000076400007640000000126711241041302014457 0ustar stst#!/usr/bin/perl # Test that our declared minimum Perl version matches our syntax use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Perl::MinimumVersion 1.20', 'Test::MinimumVersion 0.008', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_minimum_version_from_metayml_ok(); 1; Set-Tiny-0.01/t/pod.t0000644000076400007640000000120711241041302012152 0ustar stst#!/usr/bin/perl # Test that the syntax of our POD documentation is valid use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Pod::Simple 3.07', 'Test::Pod 1.26', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_pod_files_ok(); 1; Set-Tiny-0.01/lib/0000755000076400007640000000000011242036775011531 5ustar ststSet-Tiny-0.01/lib/Set/0000755000076400007640000000000011242036775012264 5ustar ststSet-Tiny-0.01/lib/Set/Tiny.pm0000644000076400007640000001536711241242672013553 0ustar ststpackage Set::Tiny; use 5.004; use strict; $Set::Tiny::VERSION = '0.01'; sub new { my $class = shift; my %self; @self{@_} = (); return bless \%self, $class; } sub as_string { "(" . join(" ", sort keys %{$_[0]}) . ")" } sub size { scalar keys %{$_[0]} } sub element { exists $_[0]->{$_[1]} ? $_[1] : () } sub elements { keys %{$_[0]} } sub contains { my $self = shift; exists $self->{$_} or return for @_; return 1; } sub clone { my $class = ref $_[0]; return $class->new( keys %{$_[0]} ); } sub clear { %{$_[0]} = (); return $_[0]; } sub insert { my $self = shift; @{$self}{@_} = (); return $self; } sub remove { my $self = shift; delete @{$self}{@_}; return $self; } sub invert { my $self = shift; exists $self->{$_} ? delete $self->{$_} : ($self->{$_} = undef) for @_; return $self; } sub is_null { ! %{$_[0]} } sub is_subset { $_[1]->contains( keys %{$_[0]} ) } sub is_proper_subset { $_[0]->size < $_[1]->size && $_[0]->is_subset($_[1]) } sub is_superset { $_[1]->is_subset($_[0]) } sub is_proper_superset { $_[0]->size > $_[1]->size && $_[1]->is_subset($_[0]) } sub is_equal { $_[1]->is_subset($_[0]) && $_[0]->is_subset($_[1]) } sub is_disjoint { ! $_[0]->intersection($_[1])->size } sub is_properly_intersecting { ! $_[0]->is_disjoint($_[1]) && $_[0]->difference($_[1])->size && $_[1]->difference($_[0])->size } sub difference { $_[0]->clone->remove(keys %{$_[1]}) } sub union { my $class = ref $_[0]; return $class->new( keys %{$_[0]}, keys %{$_[1]} ); } sub intersection { $_[0]->difference( $_[0]->clone->difference($_[1]) ) } sub symmetric_difference { $_[0]->clone->invert(keys %{$_[1]}) } { *copy = \&clone; *has = \&contains; *member = \&element; *members = \&elements; *delete = \&remove; *is_empty = \&is_null; *unique = \&symmetric_difference; } 1; __END__ =head1 NAME Set::Tiny - Simple sets of strings =head1 VERSION Version 0.01 =head1 SYNOPSIS use Set::Tiny; my $s1 = Set::Tiny->new(qw( a b c )); my $s2 = Set::Tiny->new(qw( b c d )); my $u = $s1->union($s2); my $i = $s1->intersection($s2); my $s = $s1->symmetric_difference($s2); print $u->as_string; # (a b c d) print $i->as_string; # (b c) print $s->as_string; # (a d) print "i is a subset of s1" if $i->is_subset($s1); print "u is a superset of s1" if $u->is_superset($s1); =head1 DESCRIPTION Set::Tiny is a thin wrapper around regular Perl hashes to perform often needed set operations, such as testing two sets of strings for equality, or checking whether one is contained within the other. For a more complete implementation of mathematical set theory, see L. For sets of arbitrary objects, see L. =head2 Why Set::Tiny? =over =item Convenience Set::Tiny aims to provide a convenient interface to commonly used set operations, which you would usually implement using regular hashes and a couple of C loops (in fact, that's exactly what Set::Tiny does). =item Speed The price in performance you pay for this convenience when using a full-featured set implementation like L is way too high if you don't actually need the advanced functionality it offers. Run F for a (non-representative) comparison between different C modules. =item Ease of use L offers better performance than L, but needs a C compiler to install. Set::Tiny has no dependencies and contains no C code. =back =head1 METHODS Note that all methods that expect a I of set elements stringify their arguments before inserting them into the set. =head2 new( [I] ) Class method. Returns a new Set::Tiny object, initialized with the strings in I, or the empty set if I is empty. =head2 clone =head2 copy Returns a new set with the same elements as this one. =head2 insert( [I] ) Inserts the elements in I into the set. =head2 delete( [I] ) =head2 remove( [I] ) Removes the elements in I from the set. Elements that are not members of the set are ignored. =head2 invert( [I] ) For each element in I, if it is already a member of the set, deletes it from the set, else insert it into the set. =head2 clear Removes all elements from the set. =head2 as_string Returns a string representation of the set. =head2 elements =head2 members Returns the (unordered) list of elements. =head2 size Returns the number of elements. =head2 has( [I] ) =head2 contains( [I] ) Returns true if B of the elements in I are members of the set. If I is empty, returns true. =head2 element( [I] ) =head2 member( [I] ) Returns the string if it is contained in the set. =head2 is_null =head2 is_empty Returns true if the set is the empty set. =head2 union( I ) Returns a new set containing both the elements of this set and I. =head2 intersection( I ) Returns a new set containing the elements that are present in both this set and I. =head2 difference( I ) Returns a new set containing the elements of this set with the elements of I removed. =head2 unique( I ) =head2 symmetric_difference( I ) Returns a new set containing the elements that are present in either this set or I, but not in both. =head2 is_equal( I ) Returns true if this set contains the same elements as I. =head2 is_disjoint( I ) Returns true if this set has no elements in common with I. Note that the empty set is disjoint to any other set. =head2 is_properly_intersecting( I ) Returns true if this set has elements in common with I, but both also contain elements that they have not in common with each other. =head2 is_proper_subset( I ) Returns true if this set is a proper subset of I. =head2 is_proper_superset( I ) Returns true if this set is a proper superset of I. =head2 is_subset( I ) Returns true if this set is a subset of I. =head2 is_superset( I ) Returns true if this set is a superset of I. =head1 AUTHOR Stanis Trendelenburg, C<< >> =head1 CREDITS Thanks to Adam Kennedy for advice on how to make this module C. =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE Copyright 2009 Stanis Trendelenburg, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L Set-Tiny-0.01/MANIFEST0000644000076400007640000000033211242036775012112 0ustar ststChanges examples/benchmark.pl lib/Set/Tiny.pm Makefile.PL MANIFEST This list of files README t/meta.t t/minimumversion.t t/pod.t t/set.t META.yml Module meta-data (added by MakeMaker) Set-Tiny-0.01/Makefile.PL0000644000076400007640000000050411241041301012710 0ustar stst#!/usr/bin/perl use strict; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Set::Tiny', ABSTRACT_FROM => 'lib/Set/Tiny.pm', VERSION_FROM => 'lib/Set/Tiny.pm', AUTHOR => 'Stanis Trendelenburg ', LICENSE => 'perl', PREREQ_PM => { 'Test::More' => 0, }, );