← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 15:57:08 2022
Reported on Wed Dec 14 16:00:32 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/MooX/HandlesVia.pm
StatementsExecuted 338 statements in 1.78ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
3611562µs9.58msMooX::HandlesVia::::process_hasMooX::HandlesVia::process_has
36315354µs97.7msMooX::HandlesVia::::hasMooX::HandlesVia::has
55584µs473µsMooX::HandlesVia::::importMooX::HandlesVia::import
11137µs42µsMooX::HandlesVia::::BEGIN@4MooX::HandlesVia::BEGIN@4
1119µs27µsMooX::HandlesVia::::BEGIN@9MooX::HandlesVia::BEGIN@9
1118µs16µsMooX::HandlesVia::::BEGIN@25MooX::HandlesVia::BEGIN@25
1117µs50µsMooX::HandlesVia::::BEGIN@5MooX::HandlesVia::BEGIN@5
1116µs22µsMooX::HandlesVia::::BEGIN@26MooX::HandlesVia::BEGIN@26
1115µs5µsMooX::HandlesVia::::BEGIN@8MooX::HandlesVia::BEGIN@8
1113µs3µsMooX::HandlesVia::::BEGIN@7MooX::HandlesVia::BEGIN@7
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';
4239µs247µs
# spent 42µs (37+5) within MooX::HandlesVia::BEGIN@4 which was called: # once (37µs+5µs) by JSON::Schema::Modern::BEGIN@30 at line 4
use strict;
# spent 42µs making 1 call to MooX::HandlesVia::BEGIN@4 # spent 5µs making 1 call to strict::import
5226µs293µs
# spent 50µs (7+43) within MooX::HandlesVia::BEGIN@5 which was called: # once (7µs+43µs) by JSON::Schema::Modern::BEGIN@30 at line 5
use warnings;
# spent 50µs making 1 call to MooX::HandlesVia::BEGIN@5 # spent 43µs making 1 call to warnings::import
6
7261µ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
8228µs15µs
# spent 5µs within MooX::HandlesVia::BEGIN@8 which was called: # once (5µs+0s) by JSON::Schema::Modern::BEGIN@30 at line 8
use Moo::Role ();
# spent 5µs making 1 call to MooX::HandlesVia::BEGIN@8
9277µs245µs
# spent 27µs (9+18) within MooX::HandlesVia::BEGIN@9 which was called: # once (9µs+18µs) by JSON::Schema::Modern::BEGIN@30 at line 9
use Module::Runtime qw/require_module/;
# spent 27µs making 1 call to MooX::HandlesVia::BEGIN@9 # spent 18µs making 1 call to Module::Runtime::import
10
11# reserved hardcoded mappings for classname shortcuts.
1214µ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 473µs (84+389) within MooX::HandlesVia::import which was called 5 times, avg 95µs/call: # once (20µs+137µs) by JSON::Schema::Modern::Result::BEGIN@19 at line 19 of JSON/Schema/Modern/Result.pm # once (20µs+80µs) by JSON::Schema::Modern::Document::OpenAPI::BEGIN@24 at line 24 of JSON/Schema/Modern/Document/OpenAPI.pm # once (15µs+76µs) by JSON::Schema::Modern::Document::BEGIN@23 at line 23 of JSON/Schema/Modern/Document.pm # once (16µs+58µs) by JSON::Schema::Modern::BEGIN@30 at line 30 of JSON/Schema/Modern.pm # once (13µs+38µs) by OpenAPI::Modern::BEGIN@29 at line 29 of OpenAPI/Modern.pm
sub import {
2352µs my ($class) = @_;
24
25234µs224µs
# spent 16µs (8+8) within MooX::HandlesVia::BEGIN@25 which was called: # once (8µs+8µs) by JSON::Schema::Modern::BEGIN@30 at line 25
no strict 'refs';
# spent 16µs making 1 call to MooX::HandlesVia::BEGIN@25 # spent 8µs making 1 call to strict::unimport
262401µs238µs
# spent 22µs (6+16) within MooX::HandlesVia::BEGIN@26 which was called: # once (6µs+16µs) by JSON::Schema::Modern::BEGIN@30 at line 26
no warnings 'redefine';
# spent 22µs making 1 call to MooX::HandlesVia::BEGIN@26 # spent 16µs making 1 call to warnings::unimport
27
2854µs my $target = caller;
29564µs511µs if (my $has = $target->can('has')) {
# spent 11µs making 5 calls to UNIVERSAL::can, avg 2µs/call
30
# spent 97.7ms (354µs+97.3) within MooX::HandlesVia::has which was called 36 times, avg 2.71ms/call: # 4 times (27µs+6.52ms) by JSON::Schema::Modern::Document::OpenAPI::has at line 6 of (eval 380)[Class/Method/Modifiers.pm:148], avg 1.64ms/call # 2 times (73µs+9.45ms) by JSON::Schema::Modern::BEGIN@34 at line 60 of JSON/Schema/Modern/Result.pm, avg 4.76ms/call # 2 times (48µs+5.18ms) by OpenAPI::Modern::has at line 6 of (eval 395)[Class/Method/Modifiers.pm:148], avg 2.62ms/call # once (10µs+15.1ms) by OpenAPI::Modern::BEGIN@26 at line 122 of JSON/Schema/Modern.pm # once (9µs+10.1ms) by JSON::Schema::Modern::BEGIN@35 at line 79 of JSON/Schema/Modern/Document.pm # once (5µs+8.72ms) by OpenAPI::Modern::BEGIN@26 at line 637 of JSON/Schema/Modern.pm # once (8µs+4.57ms) by OpenAPI::Modern::BEGIN@26 at line 739 of JSON/Schema/Modern.pm # once (11µs+4.12ms) by OpenAPI::Modern::BEGIN@26 at line 697 of JSON/Schema/Modern.pm # once (13µs+4.01ms) by JSON::Schema::Modern::BEGIN@35 at line 40 of JSON/Schema/Modern/Document.pm # once (8µs+4.01ms) by OpenAPI::Modern::BEGIN@26 at line 923 of JSON/Schema/Modern.pm # once (6µs+3.35ms) by JSON::Schema::Modern::BEGIN@35 at line 91 of JSON/Schema/Modern/Document.pm # once (7µs+2.55ms) by JSON::Schema::Modern::BEGIN@35 at line 111 of JSON/Schema/Modern/Document.pm # once (9µs+2.26ms) by JSON::Schema::Modern::BEGIN@35 at line 48 of JSON/Schema/Modern/Document.pm # once (11µs+1.95ms) by OpenAPI::Modern::BEGIN@26 at line 897 of JSON/Schema/Modern.pm # once (9µs+1.79ms) by JSON::Schema::Modern::BEGIN@35 at line 46 of JSON/Schema/Modern/Document.pm # once (7µs+1.62ms) by OpenAPI::Modern::BEGIN@26 at line 956 of JSON/Schema/Modern.pm # once (11µs+1.62ms) by JSON::Schema::Modern::BEGIN@34 at line 48 of JSON/Schema/Modern/Result.pm # once (7µs+1.55ms) by JSON::Schema::Modern::BEGIN@34 at line 65 of JSON/Schema/Modern/Result.pm # once (8µs+1.35ms) by OpenAPI::Modern::BEGIN@26 at line 57 of JSON/Schema/Modern.pm # once (10µs+1.24ms) by JSON::Schema::Modern::BEGIN@34 at line 39 of JSON/Schema/Modern/Result.pm # once (7µs+783µs) by JSON::Schema::Modern::BEGIN@35 at line 29 of JSON/Schema/Modern/Document.pm # once (6µs+740µs) by JSON::Schema::Modern::BEGIN@35 at line 94 of JSON/Schema/Modern/Document.pm # once (2µs+731µs) by OpenAPI::Modern::BEGIN@26 at line 70 of JSON/Schema/Modern.pm # once (4µs+698µs) by OpenAPI::Modern::BEGIN@26 at line 91 of JSON/Schema/Modern.pm # once (10µs+673µs) by OpenAPI::Modern::BEGIN@26 at line 72 of JSON/Schema/Modern.pm # once (7µs+650µs) by OpenAPI::Modern::BEGIN@26 at line 78 of JSON/Schema/Modern.pm # once (6µs+575µs) by JSON::Schema::Modern::BEGIN@34 at line 71 of JSON/Schema/Modern/Result.pm # once (7µs+449µs) by OpenAPI::Modern::BEGIN@26 at line 59 of JSON/Schema/Modern.pm # once (2µs+313µs) by OpenAPI::Modern::BEGIN@26 at line 93 of JSON/Schema/Modern.pm # once (3µs+300µs) by OpenAPI::Modern::BEGIN@26 at line 103 of JSON/Schema/Modern.pm # once (3µs+294µs) by OpenAPI::Modern::BEGIN@26 at line 98 of JSON/Schema/Modern.pm
my $newsub = sub {
3136335µs7297.3ms $has->(process_has(@_));
# spent 45.1ms making 16 calls to JSON::Schema::Modern::has, avg 2.82ms/call # spent 22.2ms making 8 calls to JSON::Schema::Modern::Document::has, avg 2.78ms/call # spent 11.6ms making 6 calls to Moo::has, avg 1.93ms/call # spent 9.58ms making 36 calls to MooX::HandlesVia::process_has, avg 266µs/call # spent 8.84ms making 6 calls to JSON::Schema::Modern::Result::has, avg 1.47ms/call
32510µs };
33
34516µs5113µs if (Moo::Role->is_role($target)) {
# spent 113µs making 5 calls to Moo::Role::is_role, avg 23µs/call
35 Moo::Role::_install_tracked($target, "has", $newsub);
36 }
37 else {
38513µs5265µs Moo::_install_tracked($target, "has", $newsub);
# spent 265µs making 5 calls to Moo::_Utils::_install_tracked, avg 53µs/call
39 }
40 }
41}
42
43
# spent 9.58ms (562µs+9.02) within MooX::HandlesVia::process_has which was called 36 times, avg 266µs/call: # 36 times (562µs+9.02ms) by MooX::HandlesVia::has at line 31, avg 266µs/call
sub process_has {
4436107µs my ($name, %opts) = @_;
453625µs my $handles = $opts{handles};
4636108µs return ($name, %opts) if not $handles or ref $handles ne 'HASH';
47
481312µs if (my $via = delete $opts{handles_via}) {
49125µs $via = ref $via eq 'ARRAY' ? $via->[0] : $via;
50
51 # try to load the reserved mapping, if it exists, else the full name
521223µs $via = $RESERVED{$via} || $via;
531236µs128.94ms require_module($via);
# spent 8.94ms making 12 calls to Module::Runtime::require_module, avg 745µs/call
54
55 # clone handles for HandlesMoose support
561228µs my %handles_clone = %$handles;
57
581234µs while (my ($target, $delegation) = each %$handles) {
59 # if passed an array, handle the curry
6036185µs3677µs if (ref $delegation eq 'ARRAY') {
# spent 77µ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
75127µ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';
841241µs };
85 }
86
871348µs ($name, %opts);
88}
89
9016µ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__