summaryrefslogtreecommitdiff
path: root/lib/Moose/Exception.pm
blob: b52c9d81cdf5e352306b34b073bf0c2895b1b519 (plain)
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package Moose::Exception;
our $VERSION = '2.1405';

use Moose;
use Devel::StackTrace 1.33;

has 'trace' => (
    is            => 'ro',
    isa           => 'Devel::StackTrace',
    builder       => '_build_trace',
    lazy          => 1,
    documentation => "This attribute is read-only and isa L<Devel::StackTrace>. ".
                     'It is lazy & dependent on $exception->message.'
);

has 'message' => (
    is            => 'ro',
    isa           => 'Str',
    builder       => '_build_message',
    lazy          => 1,
    documentation => "This attribute is read-only and isa Str. ".
                     "It is lazy and has a default value 'Error'."
);

use overload(
    q{""}    => 'as_string',
    fallback => 1,
);

sub _build_trace {
    my $self = shift;

    # skip frames that are method calls on the exception object, which include
    # the object itself in the arguments (but Devel::LeakTrace really ought to
    # be weakening all references in its frames)
    my $skip = 0;
    while (my @c = caller(++$skip)) {
        last if $c[3] =~ /^(.*)::new$/ && $self->isa($1);
    }
    $skip++;

    Devel::StackTrace->new(
        message => $self->message,
        indent  => 1,
        skip_frames => $skip,
        no_refs => 1,
    );
}

sub _build_message {
    "Error";
}

sub BUILD {
    my $self = shift;
    $self->trace;
}

sub as_string {
    my $self = shift;

    if ( $ENV{MOOSE_FULL_EXCEPTION} ) {
        return $self->trace->as_string;
    }

    my @frames;
    my $last_frame;
    my $in_moose = 1;
    for my $frame ( $self->trace->frames ) {
        if ( $in_moose && $frame->package =~ /^(?:Moose|Class::MOP)(?::|$)/ )
        {
            $last_frame = $frame;
            next;
        }
        elsif ($last_frame) {
            push @frames, $last_frame;
            undef $last_frame;
        }

        $in_moose = 0;
        push @frames, $frame;
    }

    # This would be a somewhat pathological case, but who knows
    return $self->trace->as_string unless @frames;

    my $message = ( shift @frames )->as_string( 1, {} ) . "\n";
    $message .= join q{}, map { $_->as_string( 0, {} ) . "\n" } @frames;

    return $message;
}

1;

# ABSTRACT: Superclass for Moose internal exceptions

__END__

=pod

=encoding UTF-8

=head1 NAME

Moose::Exception - Superclass for Moose internal exceptions

=head1 VERSION

version 2.1405

=head1 DESCRIPTION

This class contains attributes which are common to all Moose internal
exception classes.

=head1 WARNING WARNING WARNING

If you're writing your own exception classes, you should instead prefer
the L<Throwable> role or the L<Throwable::Error> superclass - this is
effectively a cut-down internal fork of the latter, and not designed
for use in user code.

Of course if you're writing metaclass traits, it would then make sense to
subclass the relevant Moose exceptions - but only then.

=head1 METHODS

This class provides the following methods:

=head2 $exception->message

This methods returns the exception message.

=head2 $exception->trace

This method returns the stack trace for the given exception.

=head2 $exception->as_string

This method returns a stringified form of the exception, including a stack
trace. By default, this method skips Moose-internal stack frames until it sees
a caller outside of the Moose core. If the C<MOOSE_FULL_EXCEPTION> environment
variable is true, these frames are included.

=head1 SEE ALSO

=over 4

=item * L<Moose::Manual::Exceptions>

=back

=head1 AUTHORS

=over 4

=item *

Stevan Little <stevan.little@iinteractive.com>

=item *

Dave Rolsky <autarch@urth.org>

=item *

Jesse Luehrs <doy@tozt.net>

=item *

Shawn M Moore <code@sartak.org>

=item *

יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>

=item *

Karen Etheridge <ether@cpan.org>

=item *

Florian Ragwitz <rafl@debian.org>

=item *

Hans Dieter Pearcey <hdp@weftsoar.net>

=item *

Chris Prather <chris@prather.org>

=item *

Matt S Trout <mst@shadowcat.co.uk>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2006 by Infinity Interactive, Inc..

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut