From aaba081e2438f2ffe29c204e55e8ce5315423b5b Mon Sep 17 00:00:00 2001 From: Simon Shine Date: Fri, 10 May 2019 14:47:47 +0200 Subject: [PATCH] custom-set: Stub, order of methods, rename some methods (#286) --- .../custom-set/.meta/solutions/CustomSet.pm | 83 ++++------ exercises/custom-set/CustomSet.pm | 73 +++++++++ exercises/custom-set/custom-set.t | 148 +++++++++--------- 3 files changed, 179 insertions(+), 125 deletions(-) create mode 100644 exercises/custom-set/CustomSet.pm diff --git a/exercises/custom-set/.meta/solutions/CustomSet.pm b/exercises/custom-set/.meta/solutions/CustomSet.pm index 95a75c6d..37fdd047 100644 --- a/exercises/custom-set/.meta/solutions/CustomSet.pm +++ b/exercises/custom-set/.meta/solutions/CustomSet.pm @@ -1,91 +1,74 @@ package CustomSet; - use strict; use warnings; sub new { - my $class = shift; - + my ($class, @members) = @_; my %set; - @set{ @_ } = (); - + @set{ @members } = (); bless \%set, $class; } sub add { - my( $self, $new ) = @_; - - $self->{$new} = 1; + my ($self, $member) = @_; + $self->{$member} = 1; return $self; } -sub delete :method { - my( $self, $member ) = @_; - +sub remove { + my ($self, $member) = @_; delete $self->{$member}; return $self; } -sub union { - my( $self, $other ) = @_; - - return __PACKAGE__->new( keys %$self, keys %$other ); +sub is_empty { + my ($self) = @_; + return !%$self; } -sub difference { - my( $self, $other ) = @_; - - return __PACKAGE__->new( grep { ! $other->is_member($_) } keys %$self ); +sub is_member { + my ($self, $member) = @_; + return exists $self->{$member}; } - -sub is_disjoint { - my( $self, $other ) = @_; - - return $self->intersect( $other )->size() == 0; +sub size { + my ($self) = @_; + return scalar keys %$self; } -sub empty { - my $self = shift; +sub to_list { + my ($self) = @_; + return keys %$self; +} - %$self = (); - return $self; +sub union { + my ($self, $other) = @_; + return __PACKAGE__->new( keys %$self, keys %$other ); } sub intersect { - my( $self, $other ) = @_; - + my ($self, $other) = @_; return __PACKAGE__->new( grep { $self->is_member($_) } keys %$other ); } -sub is_member { - my( $self, $member ) = @_; - - return exists $self->{$member}; +sub difference { + my ($self, $other) = @_; + return __PACKAGE__->new( grep { !$other->is_member($_) } keys %$self ); } -sub size { - my $self = shift; - - return scalar keys %$self; +sub is_disjoint { + my ($self, $other) = @_; + return $self->intersect($other)->is_empty; } sub is_subset { - my( $self, $other ) = @_; - - return $self->intersect( $other )->size() == $other->size(); -} - -sub to_list { - my $self = shift; - - return keys %$self; + my ($self, $other) = @_; + return $other->difference($self)->is_empty; } sub is_equal { - my( $self, $other ) = @_; - - return $self->intersect($other)->size() == $self->size() && $self->size() == $other->size(); + my ($self, $other) = @_; + return $self->is_subset($other) && $other->is_subset($self); } 1; diff --git a/exercises/custom-set/CustomSet.pm b/exercises/custom-set/CustomSet.pm new file mode 100644 index 00000000..4ebd473e --- /dev/null +++ b/exercises/custom-set/CustomSet.pm @@ -0,0 +1,73 @@ +package CustomSet; +use strict; +use warnings; + +# Replace `...` with a correct implementation. +# https://perldoc.pl/perlsyn#The-Ellipsis-Statement + +sub new { + my ($class, @members) = @_; + ...; +} + +sub add { + my ($self, $member) = @_; + ...; +} + +sub remove { + my ($self, $member) = @_; + ...; +} + +sub is_empty { + my ($self) = @_; + ...; +} + +sub is_member { + my ($self, $member) = @_; + ...; +} + +sub size { + my ($self) = @_; + ...; +} + +sub to_list { + my ($self) = @_; + ...; +} + +sub union { + my ($self, $other) = @_; + ...; +} + +sub intersect { + my ($self, $other) = @_; + ...; +} + +sub difference { + my ($self, $other) = @_; + ...; +} + +sub is_disjoint { + my ($self, $other) = @_; + ...; +} + +sub is_subset { + my ($self, $other) = @_; + ...; +} + +sub is_equal { + my ($self, $other) = @_; + ...; +} + +1; diff --git a/exercises/custom-set/custom-set.t b/exercises/custom-set/custom-set.t index 0e55ba6d..f858c759 100755 --- a/exercises/custom-set/custom-set.t +++ b/exercises/custom-set/custom-set.t @@ -10,9 +10,12 @@ my $module = 'CustomSet'; use_ok($module) or BAIL_OUT("You need to create a module called $module.pm"); -foreach my $f (qw/new delete difference is_disjoint empty intersect - is_member add size is_subset to_list union is_equal/) { - can_ok($module, $f) or BAIL_OUT("You need to implement the function '$f'"); +for my $method (qw( + new add remove is_empty + is_member size to_list + union intersect difference + is_disjoint is_equal is_subset)) { + can_ok($module, $method) or BAIL_OUT("You need to implement the method '$method'"); } sub set { return $module->new(@_) }; @@ -23,15 +26,65 @@ subtest 'Tested new()' => sub { isa_ok( $module->new(), $module, "return value of new()" ); }; -subtest 'Tested equal()' => sub { - plan tests => 6; +subtest 'Tested add()' => sub { + plan tests => 4; - ok( set(1,3)->is_equal( set(3,1) ), "order doesn't matter" ); - ok( set()->is_equal( set() ), "empty sets are equal" ); - ok( ! set(1..3)->is_equal( set(3..5) ), "different sets are not equal" ); - ok( ! set()->is_equal( set(1..3) ), "empty set is not equal to non-empty set" ); - ok( ! set(1..3)->is_equal( set() ), "non-empty set is not equal to empty set" ); - ok( ! set(1..4)->is_equal( set(3..6) ), "partial subsets are not equal" ); + isa_ok( set()->add(1), $module, "return value of add()" ); + ok( set()->add(1)->is_equal( set(1) ), "adding to empty set" ); + ok( set(1,2,4)->add(3)->is_equal( set(1..4) ), "adding to non-empty set" ); + ok( set(1,2,3)->add(3)->is_equal( set(1..3) ), "adding existing member is noop" ); +}; + +subtest 'Tested remove()' => sub { + plan tests => 3; + + isa_ok( set(3,2,1)->remove(2), $module, "return value of remove()" ); + ok( set(3,2,1)->remove(2)->is_equal( set(1,3) ), "removing single element" ); + ok( set(3,2,1)->remove(4)->is_equal( set(1..3) ), "removing non-existant element" ); +}; + +subtest 'Tested is_empty()' => sub { + plan tests => 2; + + ok( set()->is_empty(), "sets with no elements are empty" ); + ok( !set(1)->is_empty(), "sets with elements are not empty" ); +}; + +subtest 'Tested is_member()' => sub { + plan tests => 4; + + ok( set(1,2,3)->is_member(2), "element is member" ); + ok( set(1..10)->is_member(10), "edge element is also member" ); + ok( ! set(1..10)->is_member(11), "element is not member" ); + ok( ! set()->is_member(1), "nothing is member of the empty set" ); +}; + +subtest 'Tested size()' => sub { + plan tests => 3; + + is( set()->size(), 0, "size of empty set is 0" ); + is( set(1..3)->size(), 3, "size of set with 3 members is 3!" ); + is( set(1,2,3,2)->size(), 3, "size of set with 3 members is still 3!" ); +}; + +subtest 'Tested to_list()' => sub { + plan tests => 3; + + is_deeply( [ sort +set()->to_list() ], [], "empty set results in empty list" ); + is_deeply( [ sort +set(1..3)->to_list() ], [1,2,3], "set with elements results in list with elements" ); + is_deeply( [ sort +set(3,1,2,1)->to_list() ], [1,2,3], "set with duplicate elements still results in list with uniq elements" ); +}; + +subtest 'Tested union()' => sub { + plan tests => 7; + + isa_ok( set()->union( set() ), $module, "return value of union()" ); + ok( set()->union( set() )->is_equal( set() ), "union of empty sets is an empty set" ); + ok( set(2)->union( set() )->is_equal( set(2) ), "union of non-empty set and empty set is non-empty set" ); + ok( set()->union( set(2) )->is_equal( set(2) ), "union of empty set and non-empty set is non-empty set" ); + ok( set(1,3)->union( set(3,1) )->is_equal( set(1,3) ), "union with self is self" ); + ok( set(1,3)->union( set(2,4) )->is_equal( set(1..4) ), "small union" ); + ok( set(1..10, 20..30)->union( set(5..25) )->is_equal( set(1..30) ), "large union" ); }; subtest 'Tested intersect()' => sub { @@ -43,24 +96,7 @@ subtest 'Tested intersect()' => sub { ok( set(1..3)->intersect( set(4..6) )->is_equal( set() ), "nothing in common" ); ok( set(1,3,5,7,9)->intersect( set(3..7) )->is_equal( set(3,5,7) ), "intersect with odd numbers" ); ok( set()->intersect( set() )->is_equal( set() ), "an empty set is an empty set" ); - ok( set(1..3)->intersect( set(3) )->is_equal( set(3) ), "Intersect with unary set results in unary set" ); -}; - -subtest 'Tested delete()' => sub { - plan tests => 3; - - isa_ok( set(3,2,1)->delete(2), $module, "return value of delete()" ); - ok( set(3,2,1)->delete(2)->is_equal( set(1,3) ), "removing single element" ); - ok( set(3,2,1)->delete(4)->is_equal( set(1..3) ), "removing non-existant element" ); -}; - -subtest 'Tested add()' => sub { - plan tests => 4; - - isa_ok( set()->add(1), $module, "return value of add()" ); - ok( set()->add(1)->is_equal( set(1) ), "adding to empty set" ); - ok( set(1,2,4)->add(3)->is_equal( set(1..4) ), "adding to non-empty set" ); - ok( set(1,2,3)->add(3)->is_equal( set(1..3) ), "adding existing member is noop" ); + ok( set(1..3)->intersect( set(3) )->is_equal( set(3) ), "Intersect with unary set results in unary set" ); }; subtest 'Tested difference()' => sub { @@ -84,35 +120,6 @@ subtest 'Tested is_disjoint()' => sub { ok( set(1..3)->is_disjoint( set() ), "a non-empty set is disjoint to an empty set" ); }; -subtest 'Tested empty()' => sub { - plan tests => 4; - - isa_ok( set()->empty(), $module, "return value of empty()" ); - ok( set()->empty()->is_equal( set() ), "emptying empty set results in an empty set" ); - ok( set(1..3)->empty()->is_equal( set() ), "set empty after emptying (duh!)" ); - - my $set = set(1..3); - $set->empty(); - ok( $set->is_equal( set() ), "not just an empty set returned, but set was emptied" ); -}; - -subtest 'Tested is_member()' => sub { - plan tests => 4; - - ok( set(1,2,3)->is_member(2), "element is member" ); - ok( set(1..10)->is_member(10), "edge element is also member" ); - ok( ! set(1..10)->is_member(11), "element is not member" ); - ok( ! set()->is_member(1), "nothing is member of the empty set" ); -}; - -subtest 'Tested size()' => sub { - plan tests => 3; - - is( set()->size(), 0, "size of empty set is 0" ); - is( set(1..3)->size(), 3, "size of set with 3 members is 3!" ); - is( set(1,2,3,2)->size(), 3, "size of set with 3 members is still 3!" ); -}; - subtest 'Tested is_subset()' => sub { plan tests => 8; @@ -126,22 +133,13 @@ subtest 'Tested is_subset()' => sub { ok( ! set(1..10)->is_subset( set(1..3, 11) ), "smaller number of elements but still not a subset" ); }; -subtest 'Tested union()' => sub { - plan tests => 7; - - isa_ok( set()->union( set() ), $module, "return value of union()" ); - ok( set()->union( set() )->is_equal( set() ), "union of empty sets is an empty set" ); - ok( set(2)->union( set() )->is_equal( set(2) ), "union of non-empty set and empty set is non-empty set" ); - ok( set()->union( set(2) )->is_equal( set(2) ), "union of empty set and non-empty set is non-empty set" ); - ok( set(1,3)->union( set(3,1) )->is_equal( set(1,3) ), "union with self is self" ); - ok( set(1,3)->union( set(2,4) )->is_equal( set(1..4) ), "small union" ); - ok( set(1..10, 20..30)->union( set(5..25) )->is_equal( set(1..30) ), "large union" ); -}; - -subtest 'Tested to_list()' => sub { - plan tests => 3; +subtest 'Tested equal()' => sub { + plan tests => 6; - is_deeply( [ sort +set()->to_list() ], [], "empty set results in empty list" ); - is_deeply( [ sort +set(1..3)->to_list() ], [1,2,3], "set with elements results in list with elements" ); - is_deeply( [ sort +set(3,1,2,1)->to_list() ], [1,2,3], "set with duplicate elements still results in list with uniq elements" ); + ok( set(1,3)->is_equal( set(3,1) ), "order doesn't matter" ); + ok( set()->is_equal( set() ), "empty sets are equal" ); + ok( ! set(1..3)->is_equal( set(3..5) ), "different sets are not equal" ); + ok( ! set()->is_equal( set(1..3) ), "empty set is not equal to non-empty set" ); + ok( ! set(1..3)->is_equal( set() ), "non-empty set is not equal to empty set" ); + ok( ! set(1..4)->is_equal( set(3..6) ), "partial subsets are not equal" ); };