File Coverage

blib/lib/MooseX/AbstractMethod.pm
Criterion Covered Total %
statement 38 40 95.0
branch 2 2 100.0
condition n/a
subroutine 13 16 81.2
pod 2 4 50.0
total 55 62 88.7


line stmt bran cond sub pod time code
1             #
2             # This file is part of MooseX-AbstractMethod
3             #
4             # This software is Copyright (c) 2011 by Chris Weyl.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package MooseX::AbstractMethod;
11             {
12             $MooseX::AbstractMethod::VERSION = '0.004';
13             }
14              
15             # ABSTRACT: Declare methods requirements that must be satisfied
16              
17 4     4   1814966 use Moose 0.94 ();
  4         612836  
  4         107  
18 4     4   2010 use namespace::autoclean;
  4         2563  
  4         25  
19 4     4   242 use Moose::Exporter;
  4         9  
  4         39  
20 4     4   200 use Moose::Util::MetaRole;
  4         9  
  4         223  
21              
22             # debugging...
23             #use Smart::Comments;
24              
25             {
26             package MooseX::AbstractMethod::Trait::Class;
27             {
28             $MooseX::AbstractMethod::Trait::Class::VERSION = '0.004';
29             }
30 4     4   3521 use Moose::Role;
  4         20934  
  4         29  
31 4     4   26070 use namespace::autoclean;
  4         11  
  4         41  
32 4     4   297 use Moose::Util qw{ does_role english_list };
  4         8  
  4         28  
33              
34             sub abstract_method_metaclass {
35 2     2 0 4 my $self = shift @_;
36              
37 2         55 return Moose::Meta::Class
38             ->create_anon_class(
39             # XXX should this just be Moose::Meta::Method as the superclass??
40             superclasses => [ $self->method_metaclass ],
41             roles => [ 'MooseX::AbstractMethod::Trait::Method' ],
42             cache => 1,
43             )
44             ->name
45             ;
46             }
47              
48             sub add_abstract_method {
49 2     2 0 7 my ($self, @names) = @_;
50              
51 2         10 my $abstract_meta = $self->abstract_method_metaclass;
52              
53 2         8546 for my $name (@names) {
54              
55             my $method = $abstract_meta->wrap(
56 0     0   0 sub { Moose->throw_error("Method $name is not implemented!") },
        0      
57 2         46 name => $name,
58             package_name => $self->name,
59             );
60              
61 2         1616 $self->add_method($name => $method);
62             }
63              
64 2         238 return;
65             }
66              
67             # blow up if we're being asked to become immutable, we're a subclasss,
68             # and we don't implement an abstract method
69              
70             before make_immutable => sub {
71             my $self = shift @_;
72              
73             my @abstract_methods = sort
74             map { $_->name . ' (from ' . $_->original_package_name . ')' }
75             grep { $_->original_package_name ne $self->name }
76             grep { does_role($_, 'MooseX::AbstractMethod::Trait::Method') }
77             $self->get_all_methods
78             ;
79              
80             Moose->throw_error(
81             'These abstract methods have not been implemented in '
82             . $self->name . ': '
83             . english_list(@abstract_methods)
84             ) if @abstract_methods;
85              
86             return;
87             };
88              
89             }
90             {
91             package MooseX::AbstractMethod::Trait::Method;
92             {
93             $MooseX::AbstractMethod::Trait::Method::VERSION = '0.004';
94             }
95 4     4   12330 use Moose::Role;
  4         10  
  4         33  
96 4     4   24203 use namespace::autoclean;
  4         11  
  4         27  
97              
98             # well, hello there handsome :)
99             }
100              
101 0     0 1 0 sub abstract { _abstract(@_) }
102 3     3 1 113 sub requires { _abstract(@_) }
103              
104             sub _abstract {
105              
106             ### meta isa: ref $_[0]
107 3 100   3   131 return shift->add_abstract_method(@_)
108             unless $_[0]->isa('Moose::Meta::Role');
109              
110 1         11 goto \&Moose::Role::requires;
111             }
112              
113             Moose::Exporter->setup_import_methods(
114             with_meta => [ qw{ abstract requires } ],
115              
116             trait_aliases => [
117             [ 'MooseX::AbstractMethod::Trait::Method' => 'AbstractMethod' ],
118             ],
119             class_metaroles => {
120             class => [ 'MooseX::AbstractMethod::Trait::Class' ],
121             },
122             );
123              
124             !!42;
125              
126             __END__
127              
128             =pod
129              
130             =encoding utf-8
131              
132             =for :stopwords Chris Weyl
133              
134             =head1 NAME
135              
136             MooseX::AbstractMethod - Declare methods requirements that must be satisfied
137              
138             =head1 VERSION
139              
140             This document describes version 0.004 of MooseX::AbstractMethod - released August 31, 2012 as part of MooseX-AbstractMethod.
141              
142             =head1 SYNOPSIS
143              
144             use Moose;
145             use MooseX::Abstract;
146              
147             requires 'bar';
148              
149             # synonm to 'requires'
150             abstract 'foo';
151              
152             =head1 DESCRIPTION
153              
154             This extensions allows classes to flag certain methods as being required to be
155             implemented by a subclass, much as a L<Moose::Role> does with 'requires'.
156              
157             =head1 USAGE
158              
159             As in the synopsis, simply mark certain methods as being required by
160             subclasses by passing their names to "abstract" or "requires". This will
161             cause a method of the same name to be installed in the class that will die
162             horribly if it's ever called. Additionally, when a class is made immutable,
163             all of its methods are checked to see if they're marked as abstract; if any
164             abstract methods exists that were not created in the current class, we die
165             horribly.
166              
167             Checking for method satisfaction on make_immutable isn't perfect, but AFAICT
168             it's the most reasonable approach possible at the moment. (Corrections
169             welcome.)
170              
171             =head1 NEW SUGAR
172              
173             =head2 abstract
174              
175             abstract() allows one to declare a method dependency that must be satisfied by a
176             subclass before it is invoked, and before the subclass is made immutable.
177              
178             abstract 'method_name_that_must_be_satisfied';
179              
180             =head2 requires
181              
182             requires() is a synonym for abstract() and works in the way you'd expect.
183              
184             =head1 SOURCE
185              
186             The development version is on github at L<http://github.com/RsrchBoy/moosex-abstractmethod>
187             and may be cloned from L<git://github.com/RsrchBoy/moosex-abstractmethod.git>
188              
189             =head1 BUGS
190              
191             Please report any bugs or feature requests on the bugtracker website
192             https://github.com/RsrchBoy/moosex-abstractmethod/issues
193              
194             When submitting a bug or request, please include a test-file or a
195             patch to an existing test-file that illustrates the bug or desired
196             feature.
197              
198             =head1 AUTHOR
199              
200             Chris Weyl <cweyl@alumni.drew.edu>
201              
202             =head1 COPYRIGHT AND LICENSE
203              
204             This software is Copyright (c) 2011 by Chris Weyl.
205              
206             This is free software, licensed under:
207              
208             The GNU Lesser General Public License, Version 2.1, February 1999
209              
210             =cut