summaryrefslogtreecommitdiffstats
path: root/lib/MooseX/ABC.pm
blob: 452446a1712144688821e07ef87bd97f4e3c5999 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package MooseX::ABC;
use Moose ();
use Moose::Exporter;
# ABSTRACT: abstract base classes for Moose

=head1 SYNOPSIS

  package Shape;
  use Moose;
  use MooseX::ABC;

  requires 'draw';

  package Circle;
  use Moose;
  extends 'Shape';

  sub draw {
      # stuff
  }

  my $shape = Shape->new; # dies
  my $circle = Circle->new; # succeeds

  package Square;
  use Moose;
  extends 'Shape'; # dies, since draw is unimplemented

=head1 DESCRIPTION

This module adds basic abstract base class functionality to Moose. Doing C<use
MooseX::ABC> turns the using class into an abstract class - it cannot be
instantiated. It also allows you to mark certain methods in the class as
L</required>, meaning that if a class inherits from this class without
implementing that method, it will die at compile time. Abstract subclasses are
exempt from this, however - if you extend a class with another class which uses
C<MooseX::ABC>, it will not be required to implement every required method (and
it can also add more required methods of its own). Only concrete classes
(classes which do not use C<MooseX::ABC>) are required to implement all of
their ancestors' required methods.

=cut

=func requires METHOD_NAMES

Takes a list of methods that classes inheriting from this one must implement.
If a class inherits from this class without implementing each method listed
here, an error will be thrown when compiling the class.

=cut

sub requires {
    shift->add_required_method(@_);
}

my ($import, $unimport, $init_meta) = Moose::Exporter->build_import_methods(
    with_meta        => [qw(requires)],
    install          => [qw(import unimport)],
    class_metaroles  => {
        class        => ['MooseX::ABC::Trait::Class'],
    },
    base_class_roles => ['MooseX::ABC::Role::Object'],
);

sub init_meta {
    my ($package, %options) = @_;
    Carp::confess("Can't make a role into an abstract base class")
        if Class::MOP::class_of($options{for_class})->isa('Moose::Meta::Role');
    my $ret = $init_meta->(@_);
    Class::MOP::class_of($options{for_class})->is_abstract(1);
    return $ret;
}

=head1 SEE ALSO

L<Moose>
L<Moose::Role>

=begin Pod::Coverage

  init_meta

=end Pod::Coverage

=cut

1;