NAME
MooseX::AccessorsOnly - React when users root around inside your objects
SYNOPSIS
package Foo;
use Moose;
use MooseX::AccessorsOnly;
sub BUILD {
my $self = shift;
my %saved = %$self;
tie %$self, "MooseX::AccessorsOnly";
%$self = %saved;
}
DESCRIPTION
Call a function every time the elements of the hash which underlies a regular Moose object are accessed directly.
BUGS
- There should be no need to write the BUILD sub's boilerplate.
- It is almost certainly too slow.
- Not compatible with Moo.
- Edge cases have undoubtedly been missed.
- There are no tests.
USAGE
The simplest way to use this module is to copy the BUILD sub from the SYNOPSIS into your class.
If you can be sure that none of your attributes have a default value (lazy attributes with a builder should be fine) then there is no need to save and restore its contents; only the tie
line is necessary:
sub BUILD { tie %{$_[0]}, "MooseX::AccessorsOnly" }
ADVANCED USAGE
You may optionally pass a callback as the third option to tie()
will be called instead of emitting the regular warning. It will be called with three argument: The package and line number from which the errant access took place, the access type being attempted and the key that is being accessed, or undef
:
$cb->($who, $how, $what);
The default callback is simply:
sub {
my ($who, $how, $what) = @_;
carp "DIRECT ACCESS from $who: $how " . $what || 'NOKEY'
};
Example:
sub BUILD {
my $self = shift;
tie %$self, 'MooseX::AccessorsOnly',
sub { $self->log("DEPRECATED API USED", @_) };
}
As a shortcut, you can pass any of the strings carp
, croak
, confess
, cluck
, die
or warn
as tie's 3rd argument and the default callback will be modified to use that function to do the reporting.
WHY
I'm shepherding a terrible codebase and attempting to drag it into at least the 20th if not the 21st century. We've all been there. A significant part of that work involved converting our ancient modules to use Moo but of course out of the 300,000 lines I'm bound to miss some places where the code reaches into the hash directly.
This module exists so that I have partially-converted code deploy4ed to production and have it report all the places I missed. I can then trawl through the logs and make the necessary repairs. After enough time passes without any messages being logged I can remove this module and continue to refactor the code safely.
(And convert the module back to using Moo)
Moo
Unfortunately because of the magic Moo uses to eke more speed out of its accessors I could not get this technique to work with it. I'm sure it's possible but I have work to do so this will have to suffice.
Conveniently, thanks to the hard work of Matt Trout and others, Moo is entirely compatible with Moose. Provided you're disciplined not to use Moose-specific features in your class, you can simply take the speed hit during the conversion period and then switch back to Moo when you've finished.
If anybody can come up with a way to write MooX::AccessorsOnly, I will gladly include it in this package.
HISTORY
- MooseX::AccessorsOnly 1
-
First Moose-only implementation.
SEE ALSO
AUTHOR
Matthew King (cpan:CHOHAG) <chohag@jtan.com>
COPYRIGHT
Copyright © 2017 Matthew King
LICENSE
This library is free software and may be distributed under the terms of the Do What the Fuck You Want To Public License version 2 or, at your option, any version of any license you choose.