Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom-set: Stub, order of methods, rename some methods #286

Merged
merged 11 commits into from
May 10, 2019
90 changes: 40 additions & 50 deletions exercises/custom-set/.meta/solutions/CustomSet.pm
Original file line number Diff line number Diff line change
@@ -1,91 +1,81 @@
package CustomSet;

use strict;
use warnings;
use Exporter 'import';
sshine marked this conversation as resolved.
Show resolved Hide resolved
our @EXPORT_OK = qw(
new add remove is_empty
is_member size to_list
union intersect difference
is_disjoint is_equal is_subset
);

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
77 changes: 77 additions & 0 deletions exercises/custom-set/CustomSet.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package CustomSet;
use strict;
use warnings;
use Exporter 'import';
sshine marked this conversation as resolved.
Show resolved Hide resolved
our @EXPORT_OK = qw(
new add remove is_empty
is_member size to_list
union intersect difference
is_disjoint is_equal is_subset
);

sub new {
my ($class, @members) = @_;
die "You need to implement this.";
sshine marked this conversation as resolved.
Show resolved Hide resolved
}

sub add {
my ($self, $member) = @_;
die "You need to implement this.";
}

sub remove {
my ($self, $member) = @_;
die "You need to implement this.";
}

sub is_empty {
my ($self) = @_;
die "You need to implement this.";
}

sub is_member {
my ($self, $member) = @_;
die "You need to implement this.";
}

sub size {
my ($self) = @_;
die "You need to implement this.";
}

sub to_list {
my ($self) = @_;
die "You need to implement this.";
}

sub union {
my ($self, $other) = @_;
die "You need to implement this.";
}

sub intersect {
my ($self, $other) = @_;
die "You need to implement this.";
}

sub difference {
my ($self, $other) = @_;
die "You need to implement this.";
}

sub is_disjoint {
my ($self, $other) = @_;
die "You need to implement this.";
}

sub is_subset {
my ($self, $other) = @_;
die "You need to implement this.";
}

sub is_equal {
my ($self, $other) = @_;
die "You need to implement this.";
}

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