Skip to content

Commit

Permalink
custom-set: Stub, order of methods, rename some methods (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
sshine authored and Daniel Mita committed May 10, 2019
1 parent d4014ab commit aaba081
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 125 deletions.
83 changes: 33 additions & 50 deletions exercises/custom-set/.meta/solutions/CustomSet.pm
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
73 changes: 73 additions & 0 deletions exercises/custom-set/CustomSet.pm
Original file line number Diff line number Diff line change
@@ -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;
148 changes: 73 additions & 75 deletions exercises/custom-set/custom-set.t
Original file line number Diff line number Diff line change
Expand Up @@ -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(@_) };
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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;

Expand All @@ -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" );
};

0 comments on commit aaba081

Please sign in to comment.