/usr/share/perl5/MooX/BuildArgsHooks.pm is in libmoox-buildargs-perl 0.04-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | package MooX::BuildArgsHooks;
$MooX::BuildArgsHooks::VERSION = '0.04';
=head1 NAME
MooX::BuildArgsHooks - Structured BUILDARGS.
=head1 SYNOPSIS
package Foo;
use Moo;
with 'MooX::BuildArgsHooks';
has bar => (is=>'ro');
around NORMALIZE_BUILDARGS => sub{
my ($orig, $class, @args) = @_;
@args = $class->$orig( @args );
return( bar=>$args[0] ) if @args==1 and ref($args[0]) ne 'HASH';
return @args;
};
around TRANSFORM_BUILDARGS => sub{
my ($orig, $class, $args) = @_;
$args = $class->$orig( $args );
$args->{bar} = ($args->{bar}||0) + 10;
return $args;
};
around FINALIZE_BUILDARGS => sub{
my ($orig, $class, $args) = @_;
$args = $class->$orig( $args );
$args->{bar}++;
return $args;
};
print Foo->new( 3 )->bar(); # 14
=head1 DESCRIPTION
This module installs some hooks directly into L<Moo> which allow
for more fine-grained access to the phases of C<BUILDARGS>. The
reason this is important is because if you have various roles and
classes modifying BUILDARGS you will often end up with weird
behaviors depending on what order the various BUILDARGS wrappers
are applied in. By breaking up argument processing into three
steps (normalize, transform, and finalize) these conflicts are
much less likely to arise.
To further avoid these kinds of issues, and this applies to any
system where you would C<around> methods from a consuming role or
super class not just BUILDARGS, it is recommended that you implement
your extensions via methods. This way if something inherits from your
role or class they can treat your method as a hook. For example:
around TRANSFORM_BUILDARGS => sub{
my ($class, $orig, $args) = @_;
$args = $class->$orig( $args );
return $class->TRANSFORM_FOO_BUILDARGS( $args );
};
sub TRANSFORM_FOO_BUILDARGS {
my ($class, $args) = @_;
$args->{bar} = ($args->{bar}||0) + 10;
return $args;
}
Then if some other code wishes to inject code before or after
the C<Foo> class transforming BUILDARGS they can do so at very
specific points.
=cut
use Class::Method::Modifiers qw( install_modifier );
use Moo::Object qw();
use Moo::Role;
use strictures 2;
use namespace::clean;
BEGIN {
package MooX::BuildArgsHooks::Test;
$MooX::BuildArgsHooks::Test::VERSION = '0.04';
use Moo;
around BUILDARGS => sub{
my $orig = shift;
my $class = shift;
return $class->$orig( @_ );
};
has normalize => ( is=>'rw' );
has transform => ( is=>'rw' );
has finalize => ( is=>'rw' );
sub NORMALIZE_BUILDARGS { $_[0]->normalize(1); shift; @_ }
sub TRANSFORM_BUILDARGS { $_[0]->transform(1); $_[1] }
sub FINALIZE_BUILDARGS { $_[0]->finalize(1); $_[1] }
}
# When installing these modifiers we're going to be super defensive
# and not overwrite anything that may have already declared these
# methods or even provides this functionality already. This should
# hopefully make this module relatively future proof.
BEGIN {
my $moo = 'Moo::Object';
install_modifier(
$moo, 'fresh',
'NORMALIZE_BUILDARGS' => sub{ shift; @_ },
) unless $moo->can('NORMALIZE_BUILDARGS');
install_modifier(
$moo, 'fresh',
'TRANSFORM_BUILDARGS' => sub{ $_[1] },
) unless $moo->can('TRANSFORM_BUILDARGS');
install_modifier(
$moo, 'fresh',
'FINALIZE_BUILDARGS' => sub{ $_[1] },
) unless $moo->can('FINALIZE_BUILDARGS');
my $test = MooX::BuildArgsHooks::Test->new();
my $does_normalize = $test->normalize();
my $does_transform = $test->transform();
my $does_finalize = $test->finalize();
$test = undef;
unless ($does_normalize and $does_transform and $does_finalize) {
install_modifier(
$moo, 'around',
'BUILDARGS' => sub{
my ($orig, $class, @args) = @_;
@args = $class->NORMALIZE_BUILDARGS( @args ) unless $does_normalize;
my $args = $class->$orig( @args );
$args = $class->TRANSFORM_BUILDARGS( { %$args } ) unless $does_transform;
$args = $class->FINALIZE_BUILDARGS( { %$args } ) unless $does_finalize;
return $args;
},
);
}
}
# Must declare a custom no-op BUILDARGS otherwise
# Method::Generate::Constructor gets in the way.
# Alternatively we could modify its inlined BUILDARGS
# to include our logic, but that's making things even
# more brittle.
around BUILDARGS => sub{
my $orig = shift;
my $class = shift;
return $class->$orig( @_ );
};
1;
__END__
=head1 HOOKS
A hook in the context of this module is just a method that has
been declared in the inheritance hierarchy and is made available
for consuming roles and classes to apply method modifiers to.
=head2 NORMALIZE_BUILDARGS
around NORMALIZE_BUILDARGS => sub{
my ($orig, $class, @args) = @_;
# Make sure you let other normalizations happen.
@args = $class->$orig( @args );
# Do your normalization logic.
...
return @args;
};
Used to do some basic normalization of arguments from some
custom format to a format acceptable to Moo (a hash or a
hashref).
This is useful, for example, when you want to support single
arguments. For example:
around NORMALIZE_BUILDARGS => sub{
my ($orig, $class, @args) = @_;
# If only one argument is passed in assume that it is
# the value for the foo attribute.
if (@args==1 and ref($args[0]) ne 'HASH') {
@args = { foo => $args[0] };
}
@args = $class->$orig( @args );
return @args;
};
Or you could just use L<MooX::SingleArg>.
=head2 TRANSFORM_BUILDARGS
around TRANSFORM_BUILDARGS => sub{
my ($orig, $class, $args) = @_;
# Make sure you let any other transformations happen.
$args = $class->$orig( $args );
# Do your transformations.
...
return $args;
};
This hook is the workhorse where much of the C<BUILDARGS> work
typically happens. By the time this hook is called the arguments
will always be in hashref form, not a list, and a hashref must be
returned.
=head2 FINALIZE_BUILDARGS
around FINAL_BUILDARGS => sub{
my ($orig, $class, $args) = @_;
# Let any other hooks have a turn.
$args = $class->$orig( $args );
# Do your finalization logic.
...
return $args;
};
This hook works just like L</TRANFORM_BUILDARGS> except that it happens
after it and is meant to be used by hooks that are the last step in the
argument building process and need access to the arguments after most
all other steps have completed.
=head1 SEE ALSO
=over
=item *
L<MooX::BuildArgs>
=item *
L<MooX::MethodProxyArgs>
=item *
L<MooX::Rebuild>
=item *
L<MooX::SingleArg>
=back
=head1 AUTHOR
Aran Clary Deltac <bluefeetE<64>gmail.com>
=head1 CONTRIBUTORS
=over
=item *
Peter Pentchev <roamE<64>ringlet.net>
=back
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
|