| Filename | /Users/ether/.perlbrew/libs/36.0@std/lib/perl5/MooX/HandlesVia.pm |
| Statements | Executed 338 statements in 1.78ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 36 | 1 | 1 | 562µs | 9.58ms | MooX::HandlesVia::process_has |
| 36 | 31 | 5 | 354µs | 97.7ms | MooX::HandlesVia::has |
| 5 | 5 | 5 | 84µs | 473µs | MooX::HandlesVia::import |
| 1 | 1 | 1 | 37µs | 42µs | MooX::HandlesVia::BEGIN@4 |
| 1 | 1 | 1 | 9µs | 27µs | MooX::HandlesVia::BEGIN@9 |
| 1 | 1 | 1 | 8µs | 16µs | MooX::HandlesVia::BEGIN@25 |
| 1 | 1 | 1 | 7µs | 50µs | MooX::HandlesVia::BEGIN@5 |
| 1 | 1 | 1 | 6µs | 22µs | MooX::HandlesVia::BEGIN@26 |
| 1 | 1 | 1 | 5µs | 5µs | MooX::HandlesVia::BEGIN@8 |
| 1 | 1 | 1 | 3µs | 3µs | MooX::HandlesVia::BEGIN@7 |
| 0 | 0 | 0 | 0s | 0s | MooX::HandlesVia::__ANON__[:32] |
| 0 | 0 | 0 | 0s | 0s | MooX::HandlesVia::__ANON__[:84] |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package MooX::HandlesVia; | ||||
| 2 | # ABSTRACT: NativeTrait-like behavior for Moo. | ||||
| 3 | 1 | 0s | $MooX::HandlesVia::VERSION = '0.001009'; | ||
| 4 | 2 | 39µs | 2 | 47µ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 # spent 42µs making 1 call to MooX::HandlesVia::BEGIN@4
# spent 5µs making 1 call to strict::import |
| 5 | 2 | 26µs | 2 | 93µ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 # spent 50µs making 1 call to MooX::HandlesVia::BEGIN@5
# spent 43µs making 1 call to warnings::import |
| 6 | |||||
| 7 | 2 | 61µs | 1 | 3µ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 # spent 3µs making 1 call to MooX::HandlesVia::BEGIN@7 |
| 8 | 2 | 28µs | 1 | 5µ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 # spent 5µs making 1 call to MooX::HandlesVia::BEGIN@8 |
| 9 | 2 | 77µs | 2 | 45µ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 # 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. | ||||
| 12 | 1 | 4µ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 | 3µs | my %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 | ||||
| 23 | 5 | 2µs | my ($class) = @_; | ||
| 24 | |||||
| 25 | 2 | 34µs | 2 | 24µ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 # spent 16µs making 1 call to MooX::HandlesVia::BEGIN@25
# spent 8µs making 1 call to strict::unimport |
| 26 | 2 | 401µs | 2 | 38µ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 # spent 22µs making 1 call to MooX::HandlesVia::BEGIN@26
# spent 16µs making 1 call to warnings::unimport |
| 27 | |||||
| 28 | 5 | 4µs | my $target = caller; | ||
| 29 | 5 | 64µs | 5 | 11µ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 | ||||
| 31 | 36 | 335µs | 72 | 97.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 |
| 32 | 5 | 10µs | }; | ||
| 33 | |||||
| 34 | 5 | 16µs | 5 | 113µ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 { | ||||
| 38 | 5 | 13µs | 5 | 265µ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 | ||||
| 44 | 36 | 107µs | my ($name, %opts) = @_; | ||
| 45 | 36 | 25µs | my $handles = $opts{handles}; | ||
| 46 | 36 | 108µs | return ($name, %opts) if not $handles or ref $handles ne 'HASH'; | ||
| 47 | |||||
| 48 | 13 | 12µ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 | 23µs | $via = $RESERVED{$via} || $via; | ||
| 53 | 12 | 36µs | 12 | 8.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 | ||||
| 56 | 12 | 28µs | my %handles_clone = %$handles; | ||
| 57 | |||||
| 58 | 12 | 34µs | while (my ($target, $delegation) = each %$handles) { | ||
| 59 | # if passed an array, handle the curry | ||||
| 60 | 36 | 185µs | 36 | 77µ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 | ||||
| 75 | 12 | 7µ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 | 41µs | }; | ||
| 85 | } | ||||
| 86 | |||||
| 87 | 13 | 48µs | ($name, %opts); | ||
| 88 | } | ||||
| 89 | |||||
| 90 | 1 | 6µ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__ |