Make sure we always local-ize $@ and $SIG{__DIE__} for code evals.
[gitmo/Class-MOP.git] / lib / Class / MOP / Method / Generated.pm
1
2 package Class::MOP::Method::Generated;
3
4 use strict;
5 use warnings;
6
7 use Carp 'confess';
8
9 our $VERSION   = '0.86';
10 $VERSION = eval $VERSION;
11 our $AUTHORITY = 'cpan:STEVAN';
12
13 use base 'Class::MOP::Method';
14
15 ## accessors
16
17 sub new {
18     confess __PACKAGE__ . " is an abstract base class, you must provide a constructor.";
19 }
20
21 sub is_inline { $_[0]{is_inline} }
22
23 sub definition_context { $_[0]{definition_context} }
24
25 sub _initialize_body {
26     confess "No body to initialize, " . __PACKAGE__ . " is an abstract base class";
27 }
28
29 sub _eval_closure {
30     # my ($self, $captures, $sub_body) = @_;
31     my $__captures = $_[1];
32
33     my $code;
34
35     my $e = do {
36         local $@;
37         local $SIG{__DIE__};
38         $code = eval join
39             "\n", (
40             map {
41                 /^([\@\%\$])/
42                     or die "capture key should start with \@, \% or \$: $_";
43                 q[my ] 
44                     . $_ . q[ = ] 
45                     . $1
46                     . q[{$__captures->{']
47                     . $_ . q['}};];
48                 } keys %$__captures
49             ),
50             $_[2];
51         $@;
52     };
53
54     return ( $code, $e );
55 }
56
57 sub _add_line_directive {
58     my ( $self, %args ) = @_;
59
60     my ( $line, $file );
61
62     if ( my $ctx = ( $args{context} || $self->definition_context ) ) {
63         $line = $ctx->{line};
64         if ( my $desc = $ctx->{description} ) {
65             $file = "$desc defined at $ctx->{file}";
66         } else {
67             $file = $ctx->{file};
68         }
69     } else {
70         ( $line, $file ) = ( 0, "generated method (unknown origin)" );
71     }
72
73     my $code = $args{code};
74
75     # if it's an array of lines, join it up
76     # don't use newlines so that the definition context is more meaningful
77     $code = join(@$code, ' ') if ref $code;
78
79     return qq{#line $line "$file"\n} . $code;
80 }
81
82 sub _compile_code {
83     my ( $self, %args ) = @_;
84
85     my $code = $self->_add_line_directive(%args);
86
87     $self->_eval_closure($args{environment}, $code);
88 }
89
90 1;
91
92 __END__
93
94 =pod
95
96 =head1 NAME 
97
98 Class::MOP::Method::Generated - Abstract base class for generated methods
99
100 =head1 DESCRIPTION
101
102 This is a C<Class::MOP::Method> subclass which is subclassed by
103 C<Class::MOP::Method::Accessor> and
104 C<Class::MOP::Method::Constructor>.
105
106 It is not intended to be used directly.
107
108 =head1 AUTHORS
109
110 Stevan Little E<lt>stevan@iinteractive.comE<gt>
111
112 =head1 COPYRIGHT AND LICENSE
113
114 Copyright 2006-2009 by Infinity Interactive, Inc.
115
116 L<http://www.iinteractive.com>
117
118 This library is free software; you can redistribute it and/or modify
119 it under the same terms as Perl itself. 
120
121 =cut
122