← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 16:10:05 2022
Reported on Wed Dec 14 16:12:57 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/MooX/HandlesVia.pm
StatementsExecuted 338 statements in 1.94ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
3611693µs11.3msMooX::HandlesVia::::process_hasMooX::HandlesVia::process_has
36315404µs95.7msMooX::HandlesVia::::hasMooX::HandlesVia::has
55570µs299µsMooX::HandlesVia::::importMooX::HandlesVia::import
11127µs30µsMooX::HandlesVia::::BEGIN@4MooX::HandlesVia::BEGIN@4
1118µs35µsMooX::HandlesVia::::BEGIN@5MooX::HandlesVia::BEGIN@5
1117µs13µsMooX::HandlesVia::::BEGIN@25MooX::HandlesVia::BEGIN@25
1115µs19µsMooX::HandlesVia::::BEGIN@9MooX::HandlesVia::BEGIN@9
1112µs17µsMooX::HandlesVia::::BEGIN@26MooX::HandlesVia::BEGIN@26
1111µs1µsMooX::HandlesVia::::BEGIN@7MooX::HandlesVia::BEGIN@7
1111µs1µ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.
311µs$MooX::HandlesVia::VERSION = '0.001009';
4226µs233µs
# spent 30µs (27+3) within MooX::HandlesVia::BEGIN@4 which was called: # once (27µs+3µs) by JSON::Schema::Modern::BEGIN@30 at line 4
use strict;
# spent 30µs making 1 call to MooX::HandlesVia::BEGIN@4 # spent 3µs making 1 call to strict::import
5215µs262µs
# spent 35µs (8+27) within MooX::HandlesVia::BEGIN@5 which was called: # once (8µs+27µs) by JSON::Schema::Modern::BEGIN@30 at line 5
use warnings;
# spent 35µs making 1 call to MooX::HandlesVia::BEGIN@5 # spent 27µs making 1 call to warnings::import
6
728µs11µs
# spent 1µs within MooX::HandlesVia::BEGIN@7 which was called: # once (1µs+0s) by JSON::Schema::Modern::BEGIN@30 at line 7
use Moo ();
# spent 1µs making 1 call to MooX::HandlesVia::BEGIN@7
8213µs11µs
# spent 1µs within MooX::HandlesVia::BEGIN@8 which was called: # once (1µs+0s) by JSON::Schema::Modern::BEGIN@30 at line 8
use Moo::Role ();
# spent 1µs making 1 call to MooX::HandlesVia::BEGIN@8
9268µs233µs
# spent 19µs (5+14) within MooX::HandlesVia::BEGIN@9 which was called: # once (5µs+14µs) by JSON::Schema::Modern::BEGIN@30 at line 9
use Module::Runtime qw/require_module/;
# spent 19µs making 1 call to MooX::HandlesVia::BEGIN@9 # spent 14µs making 1 call to Module::Runtime::import
10
11# reserved hardcoded mappings for classname shortcuts.
1216µ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);
2013µsmy %REVERSED = reverse %RESERVED;
21
22
# spent 299µs (70+229) within MooX::HandlesVia::import which was called 5 times, avg 60µs/call: # once (21µs+60µs) by JSON::Schema::Modern::BEGIN@30 at line 30 of JSON/Schema/Modern.pm # once (17µs+58µs) by JSON::Schema::Modern::Document::OpenAPI::BEGIN@24 at line 24 of JSON/Schema/Modern/Document/OpenAPI.pm # once (11µs+40µs) by JSON::Schema::Modern::Result::BEGIN@19 at line 19 of JSON/Schema/Modern/Result.pm # once (14µs+34µs) by OpenAPI::Modern::BEGIN@29 at line 29 of OpenAPI/Modern.pm # once (7µs+37µs) by JSON::Schema::Modern::Document::BEGIN@23 at line 23 of JSON/Schema/Modern/Document.pm
sub import {
2353µs my ($class) = @_;
24
25223µs219µs
# spent 13µs (7+6) within MooX::HandlesVia::BEGIN@25 which was called: # once (7µs+6µs) by JSON::Schema::Modern::BEGIN@30 at line 25
no strict 'refs';
# spent 13µs making 1 call to MooX::HandlesVia::BEGIN@25 # spent 6µs making 1 call to strict::unimport
262560µs232µs
# spent 17µs (2+15) within MooX::HandlesVia::BEGIN@26 which was called: # once (2µs+15µs) by JSON::Schema::Modern::BEGIN@30 at line 26
no warnings 'redefine';
# spent 17µs making 1 call to MooX::HandlesVia::BEGIN@26 # spent 15µs making 1 call to warnings::unimport
27
2854µs my $target = caller;
29543µs58µs if (my $has = $target->can('has')) {
# spent 8µs making 5 calls to UNIVERSAL::can, avg 2µs/call
30
# spent 95.7ms (404µs+95.3) within MooX::HandlesVia::has which was called 36 times, avg 2.66ms/call: # 4 times (43µs+6.82ms) by JSON::Schema::Modern::Document::OpenAPI::has at line 6 of (eval 384)[Class/Method/Modifiers.pm:148], avg 1.72ms/call # 2 times (20µs+12.2ms) by JSON::Schema::Modern::BEGIN@34 at line 67 of JSON/Schema/Modern/Result.pm, avg 6.09ms/call # 2 times (12µs+2.99ms) by OpenAPI::Modern::has at line 6 of (eval 399)[Class/Method/Modifiers.pm:148], avg 1.50ms/call # once (10µs+12.3ms) by OpenAPI::Modern::BEGIN@26 at line 641 of JSON/Schema/Modern.pm # once (9µs+12.1ms) by JSON::Schema::Modern::BEGIN@35 at line 79 of JSON/Schema/Modern/Document.pm # once (8µs+8.48ms) by OpenAPI::Modern::BEGIN@26 at line 122 of JSON/Schema/Modern.pm # once (9µs+3.83ms) by OpenAPI::Modern::BEGIN@26 at line 927 of JSON/Schema/Modern.pm # once (7µs+3.81ms) by JSON::Schema::Modern::BEGIN@35 at line 91 of JSON/Schema/Modern/Document.pm # once (7µs+3.14ms) by JSON::Schema::Modern::BEGIN@35 at line 111 of JSON/Schema/Modern/Document.pm # once (25µs+3.03ms) by OpenAPI::Modern::BEGIN@26 at line 701 of JSON/Schema/Modern.pm # once (8µs+2.77ms) by OpenAPI::Modern::BEGIN@26 at line 959 of JSON/Schema/Modern.pm # once (8µs+2.71ms) by OpenAPI::Modern::BEGIN@26 at line 743 of JSON/Schema/Modern.pm # once (8µs+2.68ms) by JSON::Schema::Modern::BEGIN@35 at line 40 of JSON/Schema/Modern/Document.pm # once (11µs+1.82ms) by JSON::Schema::Modern::BEGIN@34 at line 48 of JSON/Schema/Modern/Result.pm # once (6µs+1.74ms) by JSON::Schema::Modern::BEGIN@35 at line 46 of JSON/Schema/Modern/Document.pm # once (9µs+1.57ms) by OpenAPI::Modern::BEGIN@26 at line 91 of JSON/Schema/Modern.pm # once (14µs+1.44ms) by JSON::Schema::Modern::BEGIN@34 at line 39 of JSON/Schema/Modern/Result.pm # once (8µs+1.33ms) by OpenAPI::Modern::BEGIN@26 at line 901 of JSON/Schema/Modern.pm # once (7µs+1.33ms) by OpenAPI::Modern::BEGIN@26 at line 57 of JSON/Schema/Modern.pm # once (7µs+1.32ms) by JSON::Schema::Modern::BEGIN@35 at line 48 of JSON/Schema/Modern/Document.pm # once (7µs+1.27ms) by JSON::Schema::Modern::BEGIN@34 at line 72 of JSON/Schema/Modern/Result.pm # once (61µs+1.13ms) by JSON::Schema::Modern::BEGIN@35 at line 94 of JSON/Schema/Modern/Document.pm # once (5µs+980µs) by OpenAPI::Modern::BEGIN@26 at line 70 of JSON/Schema/Modern.pm # once (7µs+655µs) by OpenAPI::Modern::BEGIN@26 at line 72 of JSON/Schema/Modern.pm # once (6µs+639µs) by OpenAPI::Modern::BEGIN@26 at line 93 of JSON/Schema/Modern.pm # once (5µs+622µs) by OpenAPI::Modern::BEGIN@26 at line 78 of JSON/Schema/Modern.pm # once (8µs+609µs) by OpenAPI::Modern::BEGIN@26 at line 98 of JSON/Schema/Modern.pm # once (4µs+582µs) by JSON::Schema::Modern::BEGIN@34 at line 78 of JSON/Schema/Modern/Result.pm # once (50µs+520µs) by OpenAPI::Modern::BEGIN@26 at line 59 of JSON/Schema/Modern.pm # once (6µs+509µs) by OpenAPI::Modern::BEGIN@26 at line 103 of JSON/Schema/Modern.pm # once (9µs+460µs) by JSON::Schema::Modern::BEGIN@35 at line 29 of JSON/Schema/Modern/Document.pm
my $newsub = sub {
3136321µs7295.3ms $has->(process_has(@_));
# spent 41.2ms making 16 calls to JSON::Schema::Modern::has, avg 2.58ms/call # spent 22.3ms making 8 calls to JSON::Schema::Modern::Document::has, avg 2.79ms/call # spent 11.3ms making 36 calls to MooX::HandlesVia::process_has, avg 313µs/call # spent 10.8ms making 6 calls to JSON::Schema::Modern::Result::has, avg 1.79ms/call # spent 9.73ms making 6 calls to Moo::has, avg 1.62ms/call
32511µs };
33
34514µs590µs if (Moo::Role->is_role($target)) {
# spent 90µs making 5 calls to Moo::Role::is_role, avg 18µs/call
35 Moo::Role::_install_tracked($target, "has", $newsub);
36 }
37 else {
3859µs5131µs Moo::_install_tracked($target, "has", $newsub);
# spent 131µs making 5 calls to Moo::_Utils::_install_tracked, avg 26µs/call
39 }
40 }
41}
42
43
# spent 11.3ms (693µs+10.6) within MooX::HandlesVia::process_has which was called 36 times, avg 313µs/call: # 36 times (693µs+10.6ms) by MooX::HandlesVia::has at line 31, avg 313µs/call
sub process_has {
4436102µs my ($name, %opts) = @_;
453626µs my $handles = $opts{handles};
4636175µs return ($name, %opts) if not $handles or ref $handles ne 'HASH';
47
481314µs if (my $via = delete $opts{handles_via}) {
49126µs $via = ref $via eq 'ARRAY' ? $via->[0] : $via;
50
51 # try to load the reserved mapping, if it exists, else the full name
521214µs $via = $RESERVED{$via} || $via;
531240µs1210.5ms require_module($via);
# spent 10.5ms making 12 calls to Module::Runtime::require_module, avg 872µs/call
54
55 # clone handles for HandlesMoose support
561241µs my %handles_clone = %$handles;
57
581235µs while (my ($target, $delegation) = each %$handles) {
59 # if passed an array, handle the curry
6036253µs36103µs if (ref $delegation eq 'ARRAY') {
# spent 103µs making 36 calls to UNIVERSAL::can, avg 3µ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';
841236µs };
85 }
86
871356µs ($name, %opts);
88}
89
9015µ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__