← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 15:33:55 2022
Reported on Wed Dec 14 15:40:03 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/MooX/HandlesVia.pm
StatementsExecuted 338 statements in 1.86ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
3611615µs11.5msMooX::HandlesVia::::process_hasMooX::HandlesVia::process_has
36315268µs94.3msMooX::HandlesVia::::hasMooX::HandlesVia::has
55591µs346µsMooX::HandlesVia::::importMooX::HandlesVia::import
11149µs58µsMooX::HandlesVia::::BEGIN@4MooX::HandlesVia::BEGIN@4
1119µs34µsMooX::HandlesVia::::BEGIN@9MooX::HandlesVia::BEGIN@9
1117µs32µsMooX::HandlesVia::::BEGIN@26MooX::HandlesVia::BEGIN@26
1116µs11µsMooX::HandlesVia::::BEGIN@25MooX::HandlesVia::BEGIN@25
1115µs66µsMooX::HandlesVia::::BEGIN@5MooX::HandlesVia::BEGIN@5
1113µs3µsMooX::HandlesVia::::BEGIN@7MooX::HandlesVia::BEGIN@7
1113µs3µsMooX::HandlesVia::::BEGIN@8MooX::HandlesVia::BEGIN@8
0000s0sMooX::HandlesVia::::__ANON__[:32]MooX::HandlesVia::__ANON__[:32]
0000s0sMooX::HandlesVia::::__ANON__[:84]MooX::HandlesVia::__ANON__[:84]
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package MooX::HandlesVia;
2# ABSTRACT: NativeTrait-like behavior for Moo.
310s$MooX::HandlesVia::VERSION = '0.001009';
4240µs267µs
# spent 58µs (49+9) within MooX::HandlesVia::BEGIN@4 which was called: # once (49µs+9µs) by JSON::Schema::Modern::BEGIN@30 at line 4
use strict;
# spent 58µs making 1 call to MooX::HandlesVia::BEGIN@4 # spent 9µs making 1 call to strict::import
5233µs2127µs
# spent 66µs (5+61) within MooX::HandlesVia::BEGIN@5 which was called: # once (5µs+61µs) by JSON::Schema::Modern::BEGIN@30 at line 5
use warnings;
# spent 66µs making 1 call to MooX::HandlesVia::BEGIN@5 # spent 61µs making 1 call to warnings::import
6
7227µs13µs
# spent 3µs within MooX::HandlesVia::BEGIN@7 which was called: # once (3µs+0s) by JSON::Schema::Modern::BEGIN@30 at line 7
use Moo ();
# spent 3µs making 1 call to MooX::HandlesVia::BEGIN@7
8229µs13µs
# spent 3µs within MooX::HandlesVia::BEGIN@8 which was called: # once (3µs+0s) by JSON::Schema::Modern::BEGIN@30 at line 8
use Moo::Role ();
# spent 3µs making 1 call to MooX::HandlesVia::BEGIN@8
9289µs259µs
# spent 34µs (9+25) within MooX::HandlesVia::BEGIN@9 which was called: # once (9µs+25µs) by JSON::Schema::Modern::BEGIN@30 at line 9
use Module::Runtime qw/require_module/;
# spent 34µs making 1 call to MooX::HandlesVia::BEGIN@9 # spent 25µs making 1 call to Module::Runtime::import
10
11# reserved hardcoded mappings for classname shortcuts.
1215µsmy %RESERVED = (
13 'Array' => 'Data::Perl::Collection::Array::MooseLike',
14 'Hash' => 'Data::Perl::Collection::Hash::MooseLike',
15 'String' => 'Data::Perl::String::MooseLike',
16 'Bool' => 'Data::Perl::Bool::MooseLike',
17 'Number' => 'Data::Perl::Number::MooseLike',
18 'Code' => 'Data::Perl::Code',
19);
2014µsmy %REVERSED = reverse %RESERVED;
21
22
# spent 346µs (91+255) within MooX::HandlesVia::import which was called 5 times, avg 69µs/call: # once (30µs+76µs) by JSON::Schema::Modern::BEGIN@30 at line 30 of JSON/Schema/Modern.pm # once (16µs+55µs) by JSON::Schema::Modern::Result::BEGIN@19 at line 19 of JSON/Schema/Modern/Result.pm # once (16µs+51µs) by OpenAPI::Modern::BEGIN@29 at line 29 of OpenAPI/Modern.pm # once (12µs+46µs) by JSON::Schema::Modern::Document::OpenAPI::BEGIN@24 at line 24 of JSON/Schema/Modern/Document/OpenAPI.pm # once (17µs+27µs) by JSON::Schema::Modern::Document::BEGIN@23 at line 23 of JSON/Schema/Modern/Document.pm
sub import {
2351µs my ($class) = @_;
24
25226µs216µs
# spent 11µs (6+5) within MooX::HandlesVia::BEGIN@25 which was called: # once (6µs+5µs) by JSON::Schema::Modern::BEGIN@30 at line 25
no strict 'refs';
# spent 11µs making 1 call to MooX::HandlesVia::BEGIN@25 # spent 5µs making 1 call to strict::unimport
262486µs257µs
# spent 32µs (7+25) within MooX::HandlesVia::BEGIN@26 which was called: # once (7µs+25µs) by JSON::Schema::Modern::BEGIN@30 at line 26
no warnings 'redefine';
# spent 32µs making 1 call to MooX::HandlesVia::BEGIN@26 # spent 25µs making 1 call to warnings::unimport
27
2853µs my $target = caller;
295100µs57µs if (my $has = $target->can('has')) {
# spent 7µs making 5 calls to UNIVERSAL::can, avg 1µs/call
30
# spent 94.3ms (268µs+94.0) within MooX::HandlesVia::has which was called 36 times, avg 2.62ms/call: # 4 times (30µs+6.77ms) by JSON::Schema::Modern::Document::OpenAPI::has at line 6 of (eval 380)[Class/Method/Modifiers.pm:148], avg 1.70ms/call # 2 times (18µs+12.4ms) by JSON::Schema::Modern::BEGIN@34 at line 60 of JSON/Schema/Modern/Result.pm, avg 6.23ms/call # 2 times (13µs+3.03ms) by OpenAPI::Modern::has at line 6 of (eval 395)[Class/Method/Modifiers.pm:148], avg 1.52ms/call # once (24µs+13.1ms) by JSON::Schema::Modern::BEGIN@35 at line 79 of JSON/Schema/Modern/Document.pm # once (8µs+11.0ms) by OpenAPI::Modern::BEGIN@26 at line 611 of JSON/Schema/Modern.pm # once (11µs+10.5ms) by OpenAPI::Modern::BEGIN@26 at line 122 of JSON/Schema/Modern.pm # once (7µs+4.58ms) by JSON::Schema::Modern::BEGIN@35 at line 91 of JSON/Schema/Modern/Document.pm # once (8µs+3.56ms) by OpenAPI::Modern::BEGIN@26 at line 713 of JSON/Schema/Modern.pm # once (9µs+2.80ms) by OpenAPI::Modern::BEGIN@26 at line 897 of JSON/Schema/Modern.pm # once (5µs+2.65ms) by JSON::Schema::Modern::BEGIN@35 at line 111 of JSON/Schema/Modern/Document.pm # once (5µs+2.61ms) by JSON::Schema::Modern::BEGIN@35 at line 40 of JSON/Schema/Modern/Document.pm # once (7µs+2.60ms) by OpenAPI::Modern::BEGIN@26 at line 671 of JSON/Schema/Modern.pm # once (8µs+2.39ms) by OpenAPI::Modern::BEGIN@26 at line 930 of JSON/Schema/Modern.pm # once (4µs+1.51ms) by JSON::Schema::Modern::BEGIN@35 at line 46 of JSON/Schema/Modern/Document.pm # once (7µs+1.34ms) by OpenAPI::Modern::BEGIN@26 at line 871 of JSON/Schema/Modern.pm # once (8µs+1.18ms) by JSON::Schema::Modern::BEGIN@34 at line 65 of JSON/Schema/Modern/Result.pm # once (11µs+1.14ms) by OpenAPI::Modern::BEGIN@26 at line 70 of JSON/Schema/Modern.pm # once (6µs+1.13ms) by JSON::Schema::Modern::BEGIN@34 at line 48 of JSON/Schema/Modern/Result.pm # once (8µs+1.09ms) by OpenAPI::Modern::BEGIN@26 at line 57 of JSON/Schema/Modern.pm # once (6µs+1.04ms) by JSON::Schema::Modern::BEGIN@35 at line 94 of JSON/Schema/Modern/Document.pm # once (8µs+1.03ms) by JSON::Schema::Modern::BEGIN@34 at line 39 of JSON/Schema/Modern/Result.pm # once (3µs+979µs) by OpenAPI::Modern::BEGIN@26 at line 91 of JSON/Schema/Modern.pm # once (6µs+913µs) by JSON::Schema::Modern::BEGIN@35 at line 48 of JSON/Schema/Modern/Document.pm # once (6µs+816µs) by OpenAPI::Modern::BEGIN@26 at line 72 of JSON/Schema/Modern.pm # once (8µs+685µs) by JSON::Schema::Modern::BEGIN@34 at line 71 of JSON/Schema/Modern/Result.pm # once (5µs+626µs) by OpenAPI::Modern::BEGIN@26 at line 93 of JSON/Schema/Modern.pm # once (5µs+589µs) by OpenAPI::Modern::BEGIN@26 at line 59 of JSON/Schema/Modern.pm # once (10µs+573µs) by OpenAPI::Modern::BEGIN@26 at line 103 of JSON/Schema/Modern.pm # once (5µs+471µs) by OpenAPI::Modern::BEGIN@26 at line 78 of JSON/Schema/Modern.pm # once (5µs+417µs) by JSON::Schema::Modern::BEGIN@35 at line 29 of JSON/Schema/Modern/Document.pm # once (4µs+416µs) by OpenAPI::Modern::BEGIN@26 at line 98 of JSON/Schema/Modern.pm
my $newsub = sub {
3136247µs7294.0ms $has->(process_has(@_));
# spent 40.3ms making 16 calls to JSON::Schema::Modern::has, avg 2.52ms/call # spent 22.7ms making 8 calls to JSON::Schema::Modern::Document::has, avg 2.84ms/call # spent 11.5ms making 36 calls to MooX::HandlesVia::process_has, avg 319µs/call # spent 9.76ms making 6 calls to JSON::Schema::Modern::Result::has, avg 1.63ms/call # spent 9.71ms making 6 calls to Moo::has, avg 1.62ms/call
32512µs };
33
34515µs5105µs if (Moo::Role->is_role($target)) {
# spent 105µs making 5 calls to Moo::Role::is_role, avg 21µs/call
35 Moo::Role::_install_tracked($target, "has", $newsub);
36 }
37 else {
38511µs5143µs Moo::_install_tracked($target, "has", $newsub);
# spent 143µs making 5 calls to Moo::_Utils::_install_tracked, avg 29µs/call
39 }
40 }
41}
42
43
# spent 11.5ms (615µs+10.9) within MooX::HandlesVia::process_has which was called 36 times, avg 319µs/call: # 36 times (615µs+10.9ms) by MooX::HandlesVia::has at line 31, avg 319µs/call
sub process_has {
443687µs my ($name, %opts) = @_;
453619µs my $handles = $opts{handles};
4636196µs return ($name, %opts) if not $handles or ref $handles ne 'HASH';
47
481318µs if (my $via = delete $opts{handles_via}) {
49129µs $via = ref $via eq 'ARRAY' ? $via->[0] : $via;
50
51 # try to load the reserved mapping, if it exists, else the full name
521213µs $via = $RESERVED{$via} || $via;
531232µs1210.8ms require_module($via);
# spent 10.8ms making 12 calls to Module::Runtime::require_module, avg 900µs/call
54
55 # clone handles for HandlesMoose support
561222µs my %handles_clone = %$handles;
57
581251µs while (my ($target, $delegation) = each %$handles) {
59 # if passed an array, handle the curry
6036167µs3671µs if (ref $delegation eq 'ARRAY') {
# spent 71µs making 36 calls to UNIVERSAL::can, avg 2µs/call
61 my ($method, @curry) = @$delegation;
62 if ($via->can($method)) {
63 $handles->{$target} = ['${\\'.$via.'->can("'.$method.'")}', @curry];
64 }
65 }
66 elsif (ref $delegation eq '') {
67 if ($via->can($delegation)) {
68 $handles->{$target} = '${\\'.$via.'->can("'.$delegation.'")}';
69 }
70 }
71 }
72
73 # install our support for moose upgrading of class/role
74 # we deleted the handles_via key above, but install it as a native trait
75125µs my $inflator = $opts{moosify};
76 $opts{moosify} = sub {
77 my ($spec) = @_;
78
79 $spec->{handles} = \%handles_clone;
80 $spec->{traits} = [$REVERSED{$via} || $via];
81
82 # pass through if needed
83 $inflator->($spec) if ref($inflator) eq 'CODE';
841235µs };
85 }
86
871368µs ($name, %opts);
88}
89
9017µs1;
91
92=pod
93
94=encoding UTF-8
95
96=head1 NAME
97
98MooX::HandlesVia - NativeTrait-like behavior for Moo.
99
100=head1 VERSION
101
102version 0.001009
103
104=head1 SYNOPSIS
105
106 {
107 package Hashy;
108 use Moo;
109 use MooX::HandlesVia;
110
111 has hash => (
112 is => 'rw',
113 handles_via => 'Hash',
114 handles => {
115 get_val => 'get',
116 set_val => 'set',
117 all_keys => 'keys'
118 }
119 );
120 }
121
122 my $h = Hashy->new(hash => { a => 1, b => 2});
123
124 $h->get_val('b'); # 2
125
126 $h->set_val('a', 'BAR'); # sets a to BAR
127
128 my @keys = $h->all_keys; # returns a, b
129
130=head1 DESCRIPTION
131
132MooX::HandlesVia is an extension of Moo's 'handles' attribute functionality. It
133provides a means of proxying functionality from an external class to the given
134atttribute. This is most commonly used as a way to emulate 'Native Trait'
135behavior that has become commonplace in Moose code, for which there was no Moo
136alternative.
137
138=head1 SHORTCOMINGS
139
140Due to current Moo implementation details there are some deficiencies in how
141MooX::HandlesVia in comparison to what you would expect from Moose native
142traits.
143
144=over 4
145
146=item * methods delegated via the Moo 'handles' interface are passed the
147attribue value directly. and there is no way to access the parent class. This
148means if an attribute is updated any triggers or type coercions B<WILL NOT>
149fire.
150
151=item * Moo attribute method delegations are passed the attribute value. This
152is fine for references (objects, arrays, hashrefs..) it means simple scalar
153types are B<READ ONLY>. This unfortunately means Number, String, Counter, Bool
154cannot modify the attributes value, rendering them largely useless.
155
156=back
157
158If these are issues for you, consider L<Sub::HandlesVia>, which uses a
159different architecture, respecting triggers and coercions, and allowing
160read-write access to non-reference values. It should be possible to use
161Sub::HandlesVia as a drop-in replacement for MooX::HandlesVia.
162
163=head1 PROVIDED INTERFACE/FUNCTIONS
164
165=over 4
166
167=item B<process_has(@_)>
168
169MooX::HandlesVia preprocesses arguments passed to has() attribute declarations
170via the process_has function. In a given Moo class, If 'handles_via' is set to
171a ClassName string, and 'handles' is set with a hashref mapping of desired moo
172class methods that should map to ClassName methods, process_has() will create
173the appropriate binding to create the mapping IF ClassName provides that named
174method.
175
176 has options => (
177 is => 'rw',
178 handles_via => 'Array',
179 handles => {
180 mixup => 'shuffle',
181 unique_options => 'uniq',
182 all_options => 'elements'
183 }
184 );
185
186=back
187
188The following handles_via keywords are reserved as shorthand for mapping to
189L<Data::Perl>:
190
191=over 4
192
193=item * B<Hash> maps to L<Data::Perl::Collection::Hash::MooseLike>
194
195=item * B<Array> maps to L<Data::Perl::Collection::Array::MooseLike>
196
197=item * B<String> maps to L<Data::Perl::String::MooseLike>
198
199=item * B<Number> maps to L<Data::Perl::Number::MooseLike>
200
201=item * B<Bool> maps to L<Data::Perl::Bool::MooseLike>
202
203=item * B<Code> maps to L<Data::Perl::Code>
204
205=back
206
207=head1 SEE ALSO
208
209=over 4
210
211=item * L<Moo>
212
213=item * L<MooX::late>
214
215=item * L<Sub::HandlesVia>
216
217=back
218
219=head1 ORIGINAL AUTHOR
220
221Matthew Phillips <mattp@cpan.org>
222
223=head1 AUTHOR
224
225Toby Inkster <tobyink@cpan.org>
226
227=head1 COPYRIGHT AND LICENSE
228
229This software is copyright (c) 2020 by Matthew Phillips <mattp@cpan.org>.
230
231This is free software; you can redistribute it and/or modify it under
232the same terms as the Perl 5 programming language system itself.
233
234=cut
235
236__END__