Filename | /Users/ether/.perlbrew/libs/36.0@std/lib/perl5/MooX/HandlesVia.pm |
Statements | Executed 338 statements in 1.37ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
36 | 1 | 1 | 492µs | 10.5ms | process_has | MooX::HandlesVia::
36 | 31 | 5 | 203µs | 72.6ms | has | MooX::HandlesVia::
5 | 5 | 5 | 64µs | 272µs | import | MooX::HandlesVia::
1 | 1 | 1 | 24µs | 26µs | BEGIN@4 | MooX::HandlesVia::
1 | 1 | 1 | 18µs | 22µs | BEGIN@25 | MooX::HandlesVia::
1 | 1 | 1 | 6µs | 19µs | BEGIN@9 | MooX::HandlesVia::
1 | 1 | 1 | 4µs | 13µs | BEGIN@26 | MooX::HandlesVia::
1 | 1 | 1 | 4µs | 38µs | BEGIN@5 | MooX::HandlesVia::
1 | 1 | 1 | 2µs | 2µs | BEGIN@8 | MooX::HandlesVia::
1 | 1 | 1 | 1µs | 1µs | BEGIN@7 | MooX::HandlesVia::
0 | 0 | 0 | 0s | 0s | __ANON__[:32] | MooX::HandlesVia::
0 | 0 | 0 | 0s | 0s | __ANON__[:84] | MooX::HandlesVia::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package MooX::HandlesVia; | ||||
2 | # ABSTRACT: NativeTrait-like behavior for Moo. | ||||
3 | 1 | 1µs | $MooX::HandlesVia::VERSION = '0.001009'; | ||
4 | 2 | 37µs | 2 | 28µs | # spent 26µs (24+2) within MooX::HandlesVia::BEGIN@4 which was called:
# once (24µs+2µs) by JSON::Schema::Modern::BEGIN@30 at line 4 # spent 26µs making 1 call to MooX::HandlesVia::BEGIN@4
# spent 2µs making 1 call to strict::import |
5 | 2 | 15µs | 2 | 72µs | # spent 38µs (4+34) within MooX::HandlesVia::BEGIN@5 which was called:
# once (4µs+34µs) by JSON::Schema::Modern::BEGIN@30 at line 5 # spent 38µs making 1 call to MooX::HandlesVia::BEGIN@5
# spent 34µs making 1 call to warnings::import |
6 | |||||
7 | 2 | 22µs | 1 | 1µ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 # spent 1µs making 1 call to MooX::HandlesVia::BEGIN@7 |
8 | 2 | 14µs | 1 | 2µs | # spent 2µs within MooX::HandlesVia::BEGIN@8 which was called:
# once (2µs+0s) by JSON::Schema::Modern::BEGIN@30 at line 8 # spent 2µs making 1 call to MooX::HandlesVia::BEGIN@8 |
9 | 2 | 61µs | 2 | 32µs | # spent 19µs (6+13) within MooX::HandlesVia::BEGIN@9 which was called:
# once (6µs+13µs) by JSON::Schema::Modern::BEGIN@30 at line 9 # spent 19µs making 1 call to MooX::HandlesVia::BEGIN@9
# spent 13µs making 1 call to Module::Runtime::import |
10 | |||||
11 | # reserved hardcoded mappings for classname shortcuts. | ||||
12 | 1 | 3µs | my %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 | ); | ||||
20 | 1 | 4µs | my %REVERSED = reverse %RESERVED; | ||
21 | |||||
22 | # spent 272µs (64+208) within MooX::HandlesVia::import which was called 5 times, avg 54µs/call:
# once (13µs+67µs) by JSON::Schema::Modern::BEGIN@30 at line 30 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (15µs+42µs) by JSON::Schema::Modern::Document::OpenAPI::BEGIN@24 at line 24 of JSON/Schema/Modern/Document/OpenAPI.pm
# once (16µs+37µs) by OpenAPI::Modern::BEGIN@29 at line 29 of OpenAPI/Modern.pm
# once (12µs+30µs) by JSON::Schema::Modern::Document::BEGIN@23 at line 23 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (8µs+32µs) by JSON::Schema::Modern::Result::BEGIN@19 at line 19 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm | ||||
23 | 5 | 4µs | my ($class) = @_; | ||
24 | |||||
25 | 2 | 32µs | 2 | 26µs | # spent 22µs (18+4) within MooX::HandlesVia::BEGIN@25 which was called:
# once (18µs+4µs) by JSON::Schema::Modern::BEGIN@30 at line 25 # spent 22µs making 1 call to MooX::HandlesVia::BEGIN@25
# spent 4µs making 1 call to strict::unimport |
26 | 2 | 319µs | 2 | 22µs | # spent 13µs (4+9) within MooX::HandlesVia::BEGIN@26 which was called:
# once (4µs+9µs) by JSON::Schema::Modern::BEGIN@30 at line 26 # spent 13µs making 1 call to MooX::HandlesVia::BEGIN@26
# spent 9µs making 1 call to warnings::unimport |
27 | |||||
28 | 5 | 3µs | my $target = caller; | ||
29 | 5 | 39µs | 5 | 8µs | if (my $has = $target->can('has')) { # spent 8µs making 5 calls to UNIVERSAL::can, avg 2µs/call |
30 | # spent 72.6ms (203µs+72.4) within MooX::HandlesVia::has which was called 36 times, avg 2.02ms/call:
# 4 times (33µs+5.78ms) by JSON::Schema::Modern::Document::OpenAPI::has at line 6 of (eval 384)[Class/Method/Modifiers.pm:148], avg 1.45ms/call
# 2 times (14µs+9.68ms) by JSON::Schema::Modern::BEGIN@34 at line 67 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm, avg 4.85ms/call
# 2 times (10µs+2.46ms) by OpenAPI::Modern::has at line 6 of (eval 399)[Class/Method/Modifiers.pm:148], avg 1.23ms/call
# once (6µs+9.87ms) by JSON::Schema::Modern::BEGIN@35 at line 79 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (7µs+8.88ms) by OpenAPI::Modern::BEGIN@26 at line 122 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (8µs+7.28ms) by OpenAPI::Modern::BEGIN@26 at line 650 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (10µs+3.22ms) by OpenAPI::Modern::BEGIN@26 at line 752 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (8µs+3.02ms) by OpenAPI::Modern::BEGIN@26 at line 936 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (7µs+2.98ms) by OpenAPI::Modern::BEGIN@26 at line 710 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (5µs+2.68ms) by JSON::Schema::Modern::BEGIN@35 at line 91 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (3µs+2.10ms) by JSON::Schema::Modern::BEGIN@35 at line 111 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (6µs+1.87ms) by JSON::Schema::Modern::BEGIN@35 at line 40 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (8µs+1.79ms) by OpenAPI::Modern::BEGIN@26 at line 968 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (8µs+1.06ms) by OpenAPI::Modern::BEGIN@26 at line 910 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (6µs+907µs) by JSON::Schema::Modern::BEGIN@35 at line 46 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (8µs+887µs) by OpenAPI::Modern::BEGIN@26 at line 57 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (4µs+886µs) by JSON::Schema::Modern::BEGIN@35 at line 48 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (7µs+844µs) by JSON::Schema::Modern::BEGIN@34 at line 39 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm
# once (2µs+785µs) by JSON::Schema::Modern::BEGIN@34 at line 48 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm
# once (4µs+701µs) by JSON::Schema::Modern::BEGIN@35 at line 94 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (5µs+648µs) by JSON::Schema::Modern::BEGIN@34 at line 72 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm
# once (2µs+615µs) by OpenAPI::Modern::BEGIN@26 at line 70 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (3µs+578µs) by OpenAPI::Modern::BEGIN@26 at line 91 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (6µs+506µs) by JSON::Schema::Modern::BEGIN@35 at line 29 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm
# once (3µs+362µs) by OpenAPI::Modern::BEGIN@26 at line 72 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (4µs+359µs) by OpenAPI::Modern::BEGIN@26 at line 93 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (3µs+355µs) by JSON::Schema::Modern::BEGIN@34 at line 78 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm
# once (4µs+337µs) by OpenAPI::Modern::BEGIN@26 at line 98 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (2µs+330µs) by OpenAPI::Modern::BEGIN@26 at line 103 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (4µs+320µs) by OpenAPI::Modern::BEGIN@26 at line 59 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
# once (3µs+279µs) by OpenAPI::Modern::BEGIN@26 at line 78 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm | ||||
31 | 36 | 188µs | 72 | 72.4ms | $has->(process_has(@_)); # spent 31.8ms making 16 calls to JSON::Schema::Modern::has, avg 1.99ms/call
# spent 16.0ms making 8 calls to JSON::Schema::Modern::Document::has, avg 2.00ms/call
# spent 10.5ms making 36 calls to MooX::HandlesVia::process_has, avg 292µs/call
# spent 8.17ms making 6 calls to Moo::has, avg 1.36ms/call
# spent 5.84ms making 6 calls to JSON::Schema::Modern::Result::has, avg 974µs/call |
32 | 5 | 9µs | }; | ||
33 | |||||
34 | 5 | 11µs | 5 | 85µs | if (Moo::Role->is_role($target)) { # spent 85µs making 5 calls to Moo::Role::is_role, avg 17µs/call |
35 | Moo::Role::_install_tracked($target, "has", $newsub); | ||||
36 | } | ||||
37 | else { | ||||
38 | 5 | 9µs | 5 | 115µs | Moo::_install_tracked($target, "has", $newsub); # spent 115µs making 5 calls to Moo::_Utils::_install_tracked, avg 23µs/call |
39 | } | ||||
40 | } | ||||
41 | } | ||||
42 | |||||
43 | # spent 10.5ms (492µs+10.0) within MooX::HandlesVia::process_has which was called 36 times, avg 292µs/call:
# 36 times (492µs+10.0ms) by MooX::HandlesVia::has at line 31, avg 292µs/call | ||||
44 | 36 | 105µs | my ($name, %opts) = @_; | ||
45 | 36 | 14µs | my $handles = $opts{handles}; | ||
46 | 36 | 84µs | return ($name, %opts) if not $handles or ref $handles ne 'HASH'; | ||
47 | |||||
48 | 13 | 13µs | if (my $via = delete $opts{handles_via}) { | ||
49 | 12 | 5µs | $via = ref $via eq 'ARRAY' ? $via->[0] : $via; | ||
50 | |||||
51 | # try to load the reserved mapping, if it exists, else the full name | ||||
52 | 12 | 10µs | $via = $RESERVED{$via} || $via; | ||
53 | 12 | 31µs | 12 | 9.95ms | require_module($via); # spent 9.95ms making 12 calls to Module::Runtime::require_module, avg 829µs/call |
54 | |||||
55 | # clone handles for HandlesMoose support | ||||
56 | 12 | 20µs | my %handles_clone = %$handles; | ||
57 | |||||
58 | 12 | 38µs | while (my ($target, $delegation) = each %$handles) { | ||
59 | # if passed an array, handle the curry | ||||
60 | 36 | 168µs | 36 | 78µs | if (ref $delegation eq 'ARRAY') { # spent 78µ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 | ||||
75 | 12 | 36µ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'; | ||||
84 | 12 | 30µs | }; | ||
85 | } | ||||
86 | |||||
87 | 13 | 45µs | ($name, %opts); | ||
88 | } | ||||
89 | |||||
90 | 1 | 4µs | 1; | ||
91 | |||||
92 | =pod | ||||
93 | |||||
94 | =encoding UTF-8 | ||||
95 | |||||
96 | =head1 NAME | ||||
97 | |||||
98 | MooX::HandlesVia - NativeTrait-like behavior for Moo. | ||||
99 | |||||
100 | =head1 VERSION | ||||
101 | |||||
102 | version 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 | |||||
132 | MooX::HandlesVia is an extension of Moo's 'handles' attribute functionality. It | ||||
133 | provides a means of proxying functionality from an external class to the given | ||||
134 | atttribute. This is most commonly used as a way to emulate 'Native Trait' | ||||
135 | behavior that has become commonplace in Moose code, for which there was no Moo | ||||
136 | alternative. | ||||
137 | |||||
138 | =head1 SHORTCOMINGS | ||||
139 | |||||
140 | Due to current Moo implementation details there are some deficiencies in how | ||||
141 | MooX::HandlesVia in comparison to what you would expect from Moose native | ||||
142 | traits. | ||||
143 | |||||
144 | =over 4 | ||||
145 | |||||
146 | =item * methods delegated via the Moo 'handles' interface are passed the | ||||
147 | attribue value directly. and there is no way to access the parent class. This | ||||
148 | means if an attribute is updated any triggers or type coercions B<WILL NOT> | ||||
149 | fire. | ||||
150 | |||||
151 | =item * Moo attribute method delegations are passed the attribute value. This | ||||
152 | is fine for references (objects, arrays, hashrefs..) it means simple scalar | ||||
153 | types are B<READ ONLY>. This unfortunately means Number, String, Counter, Bool | ||||
154 | cannot modify the attributes value, rendering them largely useless. | ||||
155 | |||||
156 | =back | ||||
157 | |||||
158 | If these are issues for you, consider L<Sub::HandlesVia>, which uses a | ||||
159 | different architecture, respecting triggers and coercions, and allowing | ||||
160 | read-write access to non-reference values. It should be possible to use | ||||
161 | Sub::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 | |||||
169 | MooX::HandlesVia preprocesses arguments passed to has() attribute declarations | ||||
170 | via the process_has function. In a given Moo class, If 'handles_via' is set to | ||||
171 | a ClassName string, and 'handles' is set with a hashref mapping of desired moo | ||||
172 | class methods that should map to ClassName methods, process_has() will create | ||||
173 | the appropriate binding to create the mapping IF ClassName provides that named | ||||
174 | method. | ||||
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 | |||||
188 | The following handles_via keywords are reserved as shorthand for mapping to | ||||
189 | L<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 | |||||
221 | Matthew Phillips <mattp@cpan.org> | ||||
222 | |||||
223 | =head1 AUTHOR | ||||
224 | |||||
225 | Toby Inkster <tobyink@cpan.org> | ||||
226 | |||||
227 | =head1 COPYRIGHT AND LICENSE | ||||
228 | |||||
229 | This software is copyright (c) 2020 by Matthew Phillips <mattp@cpan.org>. | ||||
230 | |||||
231 | This is free software; you can redistribute it and/or modify it under | ||||
232 | the same terms as the Perl 5 programming language system itself. | ||||
233 | |||||
234 | =cut | ||||
235 | |||||
236 | __END__ |