File Coverage

blib/lib/MooseX/Method/Signatures.pm
Criterion Covered Total %
statement 215 215 100.0
branch 53 64 82.8
condition 13 20 65.0
subroutine 37 39 94.8
pod 0 7 0.0
total 318 345 92.1


line stmt bran cond sub pod time code
1 28     28   9276004 use strict;
  28         71  
  28         866  
2 28     28   171 use warnings;
  28         56  
  28         4152  
3              
4             package MooseX::Method::Signatures; # git description: v0.48-15-gd03dfc1
5             # ABSTRACT: (DEPRECATED) Method declarations with type constraints and no source filter
6             # KEYWORDS: moose extension method declaration signature prototype syntax sugar deprecated
7              
8             our $VERSION = '0.49';
9              
10 28     28   8904 use Moose 0.89;
  28         4907319  
  28         210  
11 28     28   198616 use Devel::Declare 0.005011 ();
  28         131682  
  28         920  
12 28     28   17557 use B::Hooks::EndOfScope 0.10;
  28         91731  
  28         178  
13 28     28   2276 use Moose::Meta::Class;
  28         60  
  28         774  
14 28     28   18002 use MooseX::LazyRequire 0.06;
  28         520357  
  28         185  
15 28     28   337846 use MooseX::Types::Moose 0.19 qw/Str Bool CodeRef/;
  28         1312393  
  28         327  
16 28     28   179946 use Text::Balanced qw/extract_quotelike/;
  28         511552  
  28         2602  
17 28     28   21274 use MooseX::Method::Signatures::Meta::Method;
  28         119  
  28         1761  
18 28     28   267 use MooseX::Method::Signatures::Types qw/PrototypeInjections/;
  28         128  
  28         361  
19 28     28   38861 use Sub::Name;
  28         68  
  28         1703  
20 28     28   152 use Moose::Util 'find_meta';
  28         56  
  28         256  
21 28     28   5213 use Module::Runtime 'use_module';
  28         58  
  28         207  
22 28     28   1172 use Carp;
  28         61  
  28         1746  
23              
24 28     28   152 use aliased 'Devel::Declare::Context::Simple', 'ContextSimple';
  28         65  
  28         260  
25              
26 28     28   86994 use namespace::autoclean;
  28         80  
  28         327  
27              
28             has package => (
29             is => 'ro',
30             isa => Str,
31             lazy_required => 1,
32             );
33              
34             has context => (
35             is => 'ro',
36             isa => ContextSimple,
37             lazy => 1,
38             builder => '_build_context',
39             );
40              
41             has initialized_context => (
42             is => 'ro',
43             isa => Bool,
44             default => 0,
45             );
46              
47             has custom_method_application => (
48             is => 'ro',
49             isa => CodeRef,
50             predicate => 'has_custom_method_application',
51             );
52              
53             has prototype_injections => (
54             is => 'ro',
55             isa => PrototypeInjections,
56             predicate => 'has_prototype_injections',
57             );
58              
59             sub _build_context {
60 87     87   202 my ($self) = @_;
61 87         3399 return ContextSimple->new(into => $self->package);
62             }
63              
64             sub import {
65 88     88   415262 my ($class, %args) = @_;
66 88         289 my $caller = caller();
67 88         459 $class->setup_for($caller, \%args);
68             }
69              
70             sub setup_for {
71 88     88 0 228 my ($class, $pkg, $args) = @_;
72              
73             # process arguments to import
74 88         209 while (my ($declarator, $injections) = each %{ $args }) {
  91         626  
75 3         157 my $obj = $class->new(
76             package => $pkg,
77             prototype_injections => {
78             declarator => $declarator,
79             injections => $injections,
80             },
81             );
82              
83             Devel::Declare->setup_for($pkg, {
84 3     3   592 $declarator => { const => sub { $obj->parser(@_) } },
85 3         44 });
86              
87             {
88 28     28   10412 no strict 'refs';
  28         66  
  28         3577  
  3         96  
89 3     0   13 *{ "${pkg}::$declarator" } = sub {};
  3         30  
90             }
91             }
92              
93 88         3557 my $self = $class->new(package => $pkg);
94              
95             Devel::Declare->setup_for($pkg, {
96 152     152   162120 method => { const => sub { $self->parser(@_) } },
97 88         1252 });
98              
99             {
100 28     28   150 no strict 'refs';
  28         63  
  28         53188  
  88         4052  
101 88     1   475 *{ "${pkg}::method" } = sub {};
  88         591  
102             }
103              
104 88         7776 return;
105             }
106              
107             sub strip_name {
108 155     155 0 325 my ($self) = @_;
109 155         5559 my $ctx = $self->context;
110 155         839 my $ret = $ctx->strip_name;
111 155 100       5432 return $ret if defined $ret;
112              
113 20         66 my $line = $ctx->get_linestr;
114 20         134 my $offset = $ctx->offset;
115 20         91 local $@;
116 20         59 my $copy = substr($line, $offset);
117 20         115 my ($str) = extract_quotelike($copy);
118 20 100       1848 return unless defined $str;
119              
120 2 50 33     10 return if ($@ && $@ =~ /^No quotelike operator found/);
121 2 50       8 die $@ if $@;
122              
123 2         6 substr($line, $offset, length $str) = '';
124 2         11 $ctx->set_linestr($line);
125              
126 2         15 return \$str;
127             }
128              
129             sub strip_traits {
130 155     155 0 304 my ($self) = @_;
131              
132 155         5611 my $ctx = $self->context;
133 155         595 my $linestr = $ctx->get_linestr;
134              
135 155 100 100     1164 unless (substr($linestr, $ctx->offset, 2) eq 'is' ||
136             substr($linestr, $ctx->offset, 4) eq 'does') {
137             # No 'is' means no traits
138 148         2074 return;
139             }
140              
141 7         66 my @traits;
142              
143 7         12 while (1) {
144 17 100       79 if (substr($linestr, $ctx->offset, 2) eq 'is') {
    100          
145             # Eat the 'is' so we can call strip_names_and_args
146 6         39 substr($linestr, $ctx->offset, 2) = '';
147             } elsif (substr($linestr, $ctx->offset, 4) eq 'does') {
148             # Eat the 'does' so we can call strip_names_and_args
149 4         44 substr($linestr, $ctx->offset, 4) = '';
150             } else {
151 7         66 last;
152             }
153              
154 10         59 $ctx->set_linestr($linestr);
155 10         45 push @traits, @{ $ctx->strip_names_and_args };
  10         33  
156             # Get the current linestr so that the loop can look for more 'is'
157 10         749 $ctx->skipspace;
158 10         91 $linestr = $ctx->get_linestr;
159             }
160              
161 7 50       30 confess "expected traits after 'is' or 'does', found nothing"
162             unless scalar(@traits);
163              
164             # Let's check to make sure these traits aren't aliased locally
165 7         18 for my $t (@traits) {
166 12 50       37 next if $t->[0] =~ /::/;
167 12         38 my $class = $ctx->get_curstash_name;
168 12   33     75 my $meta = find_meta($class) || Moose::Meta::Class->initialize($class);
169 12         154 my $func = $meta->get_package_symbol('&' . $t->[0]);
170 12 100       156 next unless $func;
171              
172 7         21 my $proto = prototype $func;
173 7 50 33     38 next if !defined $proto || length $proto;
174              
175 7         25 $t->[0] = $func->();
176             }
177              
178 7         16 return \@traits;
179             }
180              
181             sub strip_return_type_constraint {
182 155     155 0 259 my ($self) = @_;
183 155         5583 my $ctx = $self->context;
184 155         540 my $returns = $ctx->strip_name;
185 155 100       3197 return unless defined $returns;
186 2 50       6 confess "expected 'returns', found '${returns}'"
187             unless $returns eq 'returns';
188 2         5 return $ctx->strip_proto;
189             }
190              
191             sub parser {
192 155     155 0 359 my $self = shift;
193 155         296 my $err;
194              
195             # Keep any previous compile errors from getting stepped on. But report
196             # errors from inside MXMS nicely.
197             {
198 155         264 local $@;
  155         380  
199 155         437 eval { $self->_parser(@_) };
  155         626  
200 155         54168 $err = $@;
201             }
202              
203 155 100       4007 die $err if $err;
204             }
205              
206             my $anon_counter = 1;
207             sub _parser {
208 155     155   270 my $self = shift;
209 155         6599 my $ctx = $self->context;
210 155 50       6309 $ctx->init(@_) unless $self->initialized_context;
211              
212 155         2022 $ctx->skip_declarator;
213 155         5273 my $name = $self->strip_name;
214 155         810 my $proto = $ctx->strip_proto;
215 155   100     6779 my $attrs = $ctx->strip_attrs || '';
216 155         3751 my $traits = $self->strip_traits;
217 155         602 my $ret_tc = $self->strip_return_type_constraint;
218              
219 155         615 my $compile_stash = $ctx->get_curstash_name;
220              
221 155         1013 my %args = (
222             # This might get reset later, but its where we search for exported
223             # symbols at compile time
224             package_name => $compile_stash,
225             );
226 155 100       830 $args{ signature } = qq{($proto)} if defined $proto;
227 155 100       408 $args{ traits } = $traits if $traits;
228 155 100       410 $args{ return_signature } = $ret_tc if defined $ret_tc;
229              
230             # Class::MOP::Method requires a name
231 155   66     640 $args{ name } = $name || '__ANON__'.($anon_counter++).'__';
232              
233 155 100       7251 if ($self->has_prototype_injections) {
234             confess('Configured declarator does not match context declarator')
235 3 50       12 if $ctx->declarator ne $self->prototype_injections->{declarator};
236 3         146 $args{prototype_injections} = $self->prototype_injections->{injections};
237             }
238              
239 155         347 my $meth_class = 'MooseX::Method::Signatures::Meta::Method';
240 155 100       492 if ($args{traits}) {
241 7         14 my @traits = ();
242 7         12 foreach my $t (@{$args{traits}}) {
  7         20  
243 12         44 use_module($t->[0]);
244 12 100       308 if ($t->[1]) {
245 1         75 %args = (%args, eval $t->[1]);
246             };
247 12         38 push @traits, $t->[0];
248             }
249 7         70 my $meta = Moose::Meta::Class->create_anon_class(
250             superclasses => [ $meth_class ],
251             roles => [ @traits ],
252             cache => 1,
253             );
254 7         36659 $meth_class = $meta->name;
255 7         23 delete $args{traits};
256             }
257              
258 155     0   1896 my $proto_method = $meth_class->wrap(sub { }, %args);
259              
260 152         655 my $after_block = ')';
261              
262 152 100       489 if ($traits) {
263 7 100       14 if (my @trait_args = grep { defined } map { $_->[1] } @{ $traits }) {
  12         45  
  12         34  
  7         24  
264 1         9 $after_block = q{, } . join(q{,} => @trait_args) . $after_block;
265             }
266             }
267              
268 152 100       488 if (defined $name) {
269 136 100       782 my $name_arg = q{, } . (ref $name ? ${$name} : qq{q[${name}]});
  2         8  
270 136         381 $after_block = $name_arg . $after_block . q{;};
271             }
272              
273 152         6733 my $inject = $proto_method->injectable_code;
274 152         998 $inject = $self->scope_injector_call($after_block) . $inject;
275              
276 152         1339 $ctx->inject_if_block($inject, "(sub ${attrs} ");
277              
278             my $create_meta_method = sub {
279 154     154   407 my ($code, $pkg, $meth_name, @args) = @_;
280 154         1343 subname $pkg . "::" .$meth_name, $code;
281              
282             # we want to reinitialize with all the args,
283             # so we give the opportunity for traits to wrap the correct
284             # closure.
285 154         288 my %other_args = %{$proto_method};
  154         4947  
286 154         466 delete $other_args{body};
287 154         288 delete $other_args{actual_body};
288              
289 154         1384 my $ret = $meth_class->wrap(
290             $code,
291             %other_args, @args
292             );
293 152         9455 };
294              
295 152 100       479 if (defined $name) {
296             my $apply = $self->has_custom_method_application
297             ? $self->custom_method_application
298             : sub {
299 136     136   301 my ($meta, $name, $method) = @_;
300              
301 136 100 100     17437 if (warnings::enabled("redefine") && (my $meta_meth = $meta->get_method($name))) {
302 2 100       177 warnings::warn("redefine", "Method $name redefined on package ${ \$meta->name }")
  1         256  
303             if $meta_meth->isa('MooseX::Method::Signatures::Meta::Method');
304             }
305              
306 136         9792 $meta->add_method($name => $method);
307 136 50       6793 };
308              
309             $ctx->shadow(sub {
310 136     136   8811 my ($code, $name, @args) = @_;
311              
312 136         282 my $pkg = $compile_stash;
313 136 50       508 ($pkg, $name) = $name =~ /^(.*)::([^:]+)$/
314             if $name =~ /::/;
315              
316 136         435 my $meth = $create_meta_method->($code, $pkg, $name, @args);
317 136         868 my $meta = Moose::Meta::Class->initialize($pkg);
318              
319 136         6053 $meta->$apply($name, $meth);
320 136         10244 return;
321 136         1364 });
322             }
323             else {
324             $ctx->shadow(sub {
325 18     18   7345 return $create_meta_method->(shift, $compile_stash, '__ANON__', @_);
326 16         134 });
327             }
328             }
329              
330             sub scope_injector_call {
331 152     152 0 317 my ($self, $code) = @_;
332 152         415 $code =~ s/'/\\'/g; # we're generating code that's quoted with single quotes
333 152         227 return qq[BEGIN { ${\ref $self}->inject_scope('${code}') }];
  152         956  
334             }
335              
336             sub inject_scope {
337 152     152 0 14750 my ($class, $inject) = @_;
338             on_scope_end {
339 152     152   10312 my $line = Devel::Declare::get_linestr();
340 152 50       676 return unless defined $line;
341 152         786 my $offset = Devel::Declare::get_linestr_offset();
342 152         421 substr($line, $offset, 0) = $inject;
343 152         937 Devel::Declare::set_linestr($line);
344 152         1539 };
345             }
346              
347             __PACKAGE__->meta->make_immutable;
348              
349             1;
350              
351             __END__
352              
353             =pod
354              
355             =encoding UTF-8
356              
357             =head1 NAME
358              
359             MooseX::Method::Signatures - (DEPRECATED) Method declarations with type constraints and no source filter
360              
361             =head1 VERSION
362              
363             version 0.49
364              
365             =head1 SYNOPSIS
366              
367             package Foo;
368              
369             use Moose;
370             use MooseX::Method::Signatures;
371              
372             method morning (Str $name) {
373             $self->say("Good morning ${name}!");
374             }
375              
376             method hello (Str :$who, Int :$age where { $_ > 0 }) {
377             $self->say("Hello ${who}, I am ${age} years old!");
378             }
379              
380             method greet (Str $name, Bool :$excited = 0) {
381             if ($excited) {
382             $self->say("GREETINGS ${name}!");
383             }
384             else {
385             $self->say("Hi ${name}!");
386             }
387             }
388              
389             $foo->morning('Resi'); # This works.
390              
391             $foo->hello(who => 'world', age => 42); # This too.
392              
393             $foo->greet('Resi', excited => 1); # And this as well.
394              
395             $foo->hello(who => 'world', age => 'fortytwo'); # This doesn't.
396              
397             $foo->hello(who => 'world', age => -23); # This neither.
398              
399             $foo->morning; # Won't work.
400              
401             $foo->greet; # Will fail.
402              
403             =head1 DESCRIPTION
404              
405             Provides a proper method keyword, like "sub" but specifically for making methods
406             and validating their arguments against Moose type constraints.
407              
408             =head1 DEPRECATION NOTICE
409              
410             =for stopwords mst
411              
412             =for comment rafl agreed we should have a warning, and mst wrote this for MooseX::Declare, but it applies equally well here:
413              
414             B<Warning:> MooseX::Method::Signatures and L<MooseX::Declare> are based on
415             L<Devel::Declare>, a giant bag of crack originally implemented by mst with the
416             goal of upsetting the perl core developers so much by its very existence that
417             they implemented proper keyword handling in the core.
418              
419             As of perl5 version 14, this goal has been achieved, and modules such as
420             L<Devel::CallParser>, L<Function::Parameters>, and L<Keyword::Simple> provide
421             mechanisms to mangle perl syntax that don't require hallucinogenic drugs to
422             interpret the error messages they produce.
423              
424             If you want to use declarative syntax in new code, please for the love
425             of kittens get yourself a recent perl and look at L<Moops> and
426             L<core signatures|perlsub/Signatures> instead.
427              
428             =head1 SIGNATURE SYNTAX
429              
430             The signature syntax is heavily based on Perl 6. However not the full Perl 6
431             signature syntax is supported yet and some of it never will be.
432              
433             =head2 Type Constraints
434              
435             method foo ( $affe) # no type checking
436             method bar (Animal $affe) # $affe->isa('Animal')
437             method baz (Animal|Human $affe) # $affe->isa('Animal') || $affe->isa('Human')
438              
439             =head2 Positional vs. Named
440              
441             method foo ( $a, $b, $c) # positional
442             method bar (:$a, :$b, :$c) # named
443             method baz ( $a, $b, :$c) # combined
444              
445             =head2 Required vs. Optional
446              
447             method foo ($a , $b!, :$c!, :$d!) # required
448             method bar ($a?, $b?, :$c , :$d?) # optional
449              
450             =head2 Defaults
451              
452             method foo ($a = 42) # defaults to 42
453              
454             =head2 Constraints
455              
456             method foo ($foo where { $_ % 2 == 0 }) # only even
457              
458             =for stopwords Invocant
459              
460             =head2 Invocant
461              
462             method foo ( $moo) # invocant is called $self and is required
463             method bar ($self: $moo) # same, but explicit
464             method baz ($class: $moo) # invocant is called $class
465              
466             =head2 Labels
467              
468             method foo (: $affe ) # called as $obj->foo(affe => $value)
469             method bar (:apan($affe)) # called as $obj->foo(apan => $value)
470              
471             =head2 Traits
472              
473             method foo (Affe $bar does trait)
474             method foo (Affe $bar is trait)
475              
476             The only currently supported trait is C<coerce>, which will attempt to coerce
477             the value provided if it doesn't satisfy the requirements of the type
478             constraint.
479              
480             =head2 Placeholders
481              
482             method foo ($bar, $, $baz)
483              
484             =for stopwords sigil
485              
486             Sometimes you don't care about some parameters you're being called with. Just put
487             the bare sigil instead of a full variable name into the signature to avoid an
488             extra lexical variable to be created.
489              
490             =head2 Complex Example
491              
492             method foo ( SomeClass $thing where { $_->can('stuff') }:
493             Str $bar = "apan",
494             Int :$baz! = 42 where { $_ % 2 == 0 } where { $_ > 10 } )
495              
496             # the invocant is called $thing, must be an instance of SomeClass and
497             has to implement a 'stuff' method
498             # $bar is positional, required, must be a string and defaults to "apan"
499             # $baz is named, required, must be an integer, defaults to 42 and needs
500             # to be even and greater than 10
501              
502             =head1 CAVEATS AND NOTES
503              
504             This module is as stable now, but this is not to say that it is entirely bug
505             free. If you notice any odd behaviour (messages not being as good as they could
506             for example) then please raise a bug.
507              
508             =head2 Fancy signatures
509              
510             L<Parse::Method::Signatures> is used to parse the signatures. However, some
511             signatures that can be parsed by it aren't supported by this module (yet).
512              
513             =head2 No source filter
514              
515             While this module does rely on the hairy black magic of L<Devel::Declare> it
516             does not depend on a source filter. As such, it doesn't try to parse and
517             rewrite your source code and there should be no weird side effects.
518              
519             Devel::Declare only effects compilation. After that, it's a normal subroutine.
520             As such, for all that hairy magic, this module is surprisingly stable.
521              
522             =head2 What about regular subroutines?
523              
524             L<Devel::Declare> cannot yet change the way C<sub> behaves. However, the
525             L<signatures|signatures> module can. Right now it only provides very basic
526             signatures, but it's extendable enough that plugging MooseX::Method::Signatures
527             signatures into that should be quite possible.
528              
529             =head2 What about the return value?
530              
531             Type constraints for return values can be declared using
532              
533             method foo (Int $x, Str $y) returns (Bool) { ... }
534              
535             however, this feature only works with scalar return values and is still
536             considered to be experimental.
537              
538             =head2 Interaction with L<Moose::Role>
539              
540             =head3 Methods not seen by a role's C<requires>
541              
542             Because the processing of the L<MooseX::Method::Signatures>
543             C<method> and the L<Moose> C<with> keywords are both
544             done at runtime, it can happen that a role will require
545             a method before it is declared (which will cause
546             Moose to complain very loudly and abort the program).
547              
548             For example, the following will not work:
549              
550             # in file Canine.pm
551              
552             package Canine;
553              
554             use Moose;
555             use MooseX::Method::Signatures;
556              
557             with 'Watchdog';
558              
559             method bark { print "Woof!\n"; }
560              
561             1;
562              
563              
564             # in file Watchdog.pm
565              
566             package Watchdog;
567              
568             use Moose::Role;
569              
570             requires 'bark'; # will assert! evaluated before 'method' is processed
571              
572             sub warn_intruder {
573             my $self = shift;
574             my $intruder = shift;
575              
576             $self->bark until $intruder->gone;
577             }
578              
579             1;
580              
581             A workaround for this problem is to use C<with> only
582             after the methods have been defined. To take our previous
583             example, B<Canine> could be reworked thus:
584              
585             package Canine;
586              
587             use Moose;
588             use MooseX::Method::Signatures;
589              
590             method bark { print "Woof!\n"; }
591              
592             with 'Watchdog';
593              
594             1;
595              
596             A better solution is to use L<MooseX::Declare> instead of plain
597             L<MooseX::Method::Signatures>. It defers application of roles until the end
598             of the class definition. With it, our example would becomes:
599              
600             # in file Canine.pm
601              
602             use MooseX::Declare;
603              
604             class Canine with Watchdog {
605             method bark { print "Woof!\n"; }
606             }
607              
608             1;
609              
610             # in file Watchdog.pm
611              
612             use MooseX::Declare;
613              
614             role Watchdog {
615             requires 'bark';
616              
617             method warn_intruder ( $intruder ) {
618             $self->bark until $intruder->gone;
619             }
620             }
621              
622             1;
623              
624             =head3 I<Subroutine redefined> warnings
625              
626             When composing a L<Moose::Role> into a class that uses
627             L<MooseX::Method::Signatures>, you may get a "Subroutine redefined"
628             warning. This happens when both the role and the class define a
629             method/subroutine of the same name. (The way roles work, the one
630             defined in the class takes precedence.) To eliminate this warning,
631             make sure that your C<with> declaration happens after any
632             method/subroutine declarations that may have the same name as a
633             method/subroutine within a role.
634              
635             =head1 SEE ALSO
636              
637             =over 4
638              
639             =item *
640              
641             L<MooseX::Declare>
642              
643             =item *
644              
645             L<Method::Signatures::Simple>
646              
647             =item *
648              
649             L<Method::Signatures>
650              
651             =item *
652              
653             L<Devel::Declare>
654              
655             =item *
656              
657             L<Parse::Method::Signatures>
658              
659             =item *
660              
661             L<Moose>
662              
663             =item *
664              
665             L<signatures>
666              
667             =back
668              
669             =head1 SUPPORT
670              
671             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Method-Signatures>
672             (or L<bug-MooseX-Method-Signatures@rt.cpan.org|mailto:bug-MooseX-Method-Signatures@rt.cpan.org>).
673              
674             There is also a mailing list available for users of this distribution, at
675             L<http://lists.perl.org/list/moose.html>.
676              
677             There is also an irc channel available for users of this distribution, at
678             irc://irc.perl.org/#moose.
679              
680             I am also usually active on irc, as 'ether' at C<irc.perl.org>.
681              
682             =head1 AUTHOR
683              
684             Florian Ragwitz <rafl@debian.org>
685              
686             =head1 CONTRIBUTORS
687              
688             =for stopwords Karen Etheridge Ash Berlin Daniel Ruoso Justin Hunter Nicholas Perez Dagfinn Ilmari MannsÃ¥ker Rhesa Rozendaal Yanick Champoux Cory Watson Kent Fredric Lukas Mai Matt Kraai Jonathan Scott Duff Jesse Luehrs Hakim Cassimally Dave Rolsky Ricardo SIGNES Sebastian Willert Steffen Schwigon
689              
690             =over 4
691              
692             =item *
693              
694             Karen Etheridge <ether@cpan.org>
695              
696             =item *
697              
698             Ash Berlin <ash@cpan.org>
699              
700             =item *
701              
702             Daniel Ruoso <daniel@ruoso.com>
703              
704             =item *
705              
706             Justin Hunter <justin.d.hunter@gmail.com>
707              
708             =item *
709              
710             Nicholas Perez <nperez@cpan.org>
711              
712             =item *
713              
714             Dagfinn Ilmari MannsÃ¥ker <ilmari@ilmari.org>
715              
716             =item *
717              
718             Rhesa Rozendaal <rhesa@cpan.org>
719              
720             =item *
721              
722             Yanick Champoux <yanick@babyl.dyndns.org>
723              
724             =item *
725              
726             Cory Watson <gphat@cpan.org>
727              
728             =item *
729              
730             Kent Fredric <kentfredric@gmail.com>
731              
732             =item *
733              
734             Lukas Mai <l.mai@web.de>
735              
736             =item *
737              
738             Matt Kraai <kraai@ftbfs.org>
739              
740             =item *
741              
742             Jonathan Scott Duff <duff@pobox.com>
743              
744             =item *
745              
746             Jesse Luehrs <doy@tozt.net>
747              
748             =item *
749              
750             Hakim Cassimally <osfameron@cpan.org>
751              
752             =item *
753              
754             Dave Rolsky <autarch@urth.org>
755              
756             =item *
757              
758             Ricardo SIGNES <rjbs@cpan.org>
759              
760             =item *
761              
762             Sebastian Willert <willert@cpan.org>
763              
764             =item *
765              
766             Steffen Schwigon <ss5@renormalist.net>
767              
768             =back
769              
770             =head1 COPYRIGHT AND LICENCE
771              
772             This software is copyright (c) 2008 by Florian Ragwitz.
773              
774             This is free software; you can redistribute it and/or modify it under
775             the same terms as the Perl 5 programming language system itself.
776              
777             =cut