2 package Moose::Meta::Method::Destructor;
7 use Devel::GlobalDestruction ();
8 use Scalar::Util 'blessed', 'weaken';
11 use base 'Moose::Meta::Method',
12 'Class::MOP::Method::Inlined';
18 (ref $options{options} eq 'HASH')
19 || $class->throw_error("You must pass a hash of options", data => $options{options});
21 ($options{package_name} && $options{name})
22 || $class->throw_error("You must supply the package_name and name parameters $Class::MOP::Method::UPGRADE_ERROR_TEXT");
27 'package_name' => $options{package_name},
28 'name' => $options{name},
30 'options' => $options{options},
31 'definition_context' => $options{definition_context},
32 'associated_metaclass' => $options{metaclass},
35 # we don't want this creating
36 # a cycle in the code, if not
38 weaken($self->{'associated_metaclass'});
40 $self->_initialize_body;
47 sub options { (shift)->{'options'} }
53 my $metaclass = shift;
55 ( blessed $metaclass && $metaclass->isa('Class::MOP::Class') )
56 || $self->throw_error(
57 "The is_needed method expected a metaclass object as its arugment");
59 return $metaclass->find_method_by_name("DEMOLISHALL");
63 Carp::cluck('The initialize_body method has been made private.'
64 . " The public version is deprecated and will be removed in a future release.\n");
65 shift->_initialize_body;
68 sub _initialize_body {
71 # the %options should also include a both
72 # a call 'initializer' and call 'SUPER::'
73 # options, which should cover approx 90%
74 # of the possible use cases (even if it
75 # requires some adaption on the part of
76 # the author, after all, nothing is free)
78 my $class = $self->associated_metaclass->name;
82 'return ' . $self->_generate_fallback_destructor('$self'),
83 'if Scalar::Util::blessed($self) ne \'' . $class . '\';',
85 $self->_generate_DEMOLISHALL('$self'),
89 warn join("\n", @source) if $self->options->{debug};
92 $self->_compile_code(source => \@source);
95 my $source = join("\n", @source);
97 "Could not eval the destructor :\n\n$source\n\nbecause :\n\n$_",
103 $self->{'body'} = $code;
106 sub _generate_fallback_destructor {
110 return $inv . '->Moose::Object::DESTROY(@_)';
113 sub _generate_DEMOLISHALL {
117 my @methods = $self->associated_metaclass->find_all_methods_by_name('DEMOLISH');
118 return unless @methods;
121 'my $igd = Devel::GlobalDestruction::in_global_destruction;',
123 (map { $inv . '->' . $_->{class} . '::DEMOLISH($igd);' } @methods),
125 'Try::Tiny::catch {',
134 # ABSTRACT: Method Meta Object for destructors
142 This class is a subclass of L<Class::MOP::Class::Generated> that
143 provides Moose-specific functionality for inlining destructors.
145 To understand this class, you should read the the
146 L<Class::MOP::Class::Generated> documentation as well.
150 C<Moose::Meta::Method::Destructor> is a subclass of
151 L<Moose::Meta::Method> I<and> L<Class::MOP::Method::Generated>.
157 =item B<< Moose::Meta::Method::Destructor->new(%options) >>
159 This constructs a new object. It accepts the following options:
165 The package for the class in which the destructor is being
166 inlined. This option is required.
170 The name of the destructor method. This option is required.
174 The metaclass for the class this destructor belongs to. This is
175 optional, as it can be set later by calling C<<
176 $metamethod->attach_to_class >>.
180 =item B<< Moose::Meta;:Method::Destructor->is_needed($metaclass) >>
182 Given a L<Moose::Meta::Class> object, this method returns a boolean
183 indicating whether the class needs a destructor. If the class or any
184 of its parents defines a C<DEMOLISH> method, it needs a destructor.
190 See L<Moose/BUGS> for details on reporting bugs.