← 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:30 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Base.pm
StatementsExecuted 7755425 statements in 8.81s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1519183441.48s1.48sMojo::Base::::new Mojo::Base::new
9863142611848ms848msMojo::URL::::fragment Mojo::URL::fragment
59735941596ms596msMojo::URL::::scheme Mojo::URL::scheme
49210921502ms502msMojo::Path::::charset Mojo::Path::charset
51353241424ms424msMojo::URL::::host Mojo::URL::host
32780211414ms414msMojo::Parameters::::charset Mojo::Parameters::charset
37763621231ms231msMojo::URL::::port Mojo::URL::port
339631174.1ms74.1msMojo::URL::::base Mojo::URL::base
687182155.9ms55.9msMojo::URL::::userinfo Mojo::URL::userinfo
1114.07ms4.33msMojo::Base::::BEGIN@17 Mojo::Base::BEGIN@17
111384µs447µsMojo::Base::::BEGIN@5 Mojo::Base::BEGIN@5
12128310µs1.25msMojo::Base::::import Mojo::Base::import
511112µs242µsMojo::Base::::attr Mojo::Base::attr
111105µs136µsMojo::Base::::BEGIN@20 Mojo::Base::BEGIN@20
152134µs34µsMojo::Base::::CORE:match Mojo::Base::CORE:match (opcode)
11131µs35µsMojo::Base::::BEGIN@3 Mojo::Base::BEGIN@3
11120µs44µsMojo::Base::::BEGIN@133 Mojo::Base::BEGIN@133
11111µs62µsMojo::Path::::has Mojo::Path::has
1119µs18µsMojo::Base::::BEGIN@45 Mojo::Base::BEGIN@45
1118µs47µsMojo::Base::::BEGIN@4 Mojo::Base::BEGIN@4
1118µs99µsMojo::Base::::BEGIN@6 Mojo::Base::BEGIN@6
1118µs11µsMojo::Base::::BEGIN@7 Mojo::Base::BEGIN@7
1116µs40µsMojo::JSON::Pointer::::hasMojo::JSON::Pointer::has
1116µs57µsMojo::Parameters::::has Mojo::Parameters::has
2215µs111µsMojo::URL::::has Mojo::URL::has
1113µs3µsMojo::Base::::BEGIN@10 Mojo::Base::BEGIN@10
1112µs2µsMojo::Base::::BEGIN@11 Mojo::Base::BEGIN@11
0000s0sMojo::Base::::DESTROY Mojo::Base::DESTROY
0000s0sMojo::Base::::__ANON__[:113] Mojo::Base::__ANON__[:113]
0000s0sMojo::Base::::__ANON__[:136] Mojo::Base::__ANON__[:136]
0000s0sMojo::Base::::__ANON__[:43] Mojo::Base::__ANON__[:43]
0000s0sMojo::Base::::__ANON__[:66] Mojo::Base::__ANON__[:66]
0000s0sMojo::Base::::__ANON__[:73] Mojo::Base::__ANON__[:73]
0000s0sMojo::Base::::__ANON__[:81] Mojo::Base::__ANON__[:81]
0000s0sMojo::Base::::__ANON__[:88] Mojo::Base::__ANON__[:88]
0000s0sMojo::Base::::__ANON__[:91] Mojo::Base::__ANON__[:91]
0000s0sMojo::Base::::tap Mojo::Base::tap
0000s0sMojo::Base::::with_roles Mojo::Base::with_roles
0000s0sMojo::JSON::Pointer::::dataMojo::JSON::Pointer::data
0000s0sMojo::Util::_Guard::::has Mojo::Util::_Guard::has
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package Mojo::Base;
2
3238µs239µs
# spent 35µs (31+4) within Mojo::Base::BEGIN@3 which was called: # once (31µs+4µs) by Mojo::URL::BEGIN@2 at line 3
use strict;
# spent 35µs making 1 call to Mojo::Base::BEGIN@3 # spent 4µs making 1 call to strict::import
4223µs286µs
# spent 47µs (8+39) within Mojo::Base::BEGIN@4 which was called: # once (8µs+39µs) by Mojo::URL::BEGIN@2 at line 4
use warnings;
# spent 47µs making 1 call to Mojo::Base::BEGIN@4 # spent 39µs making 1 call to warnings::import
52240µs2450µs
# spent 447µs (384+63) within Mojo::Base::BEGIN@5 which was called: # once (384µs+63µs) by Mojo::URL::BEGIN@2 at line 5
use utf8;
# spent 447µs making 1 call to Mojo::Base::BEGIN@5 # spent 3µs making 1 call to utf8::import
6225µs2190µs
# spent 99µs (8+91) within Mojo::Base::BEGIN@6 which was called: # once (8µs+91µs) by Mojo::URL::BEGIN@2 at line 6
use feature ':5.16';
# spent 99µs making 1 call to Mojo::Base::BEGIN@6 # spent 91µs making 1 call to feature::import
7220µs214µs
# spent 11µs (8+3) within Mojo::Base::BEGIN@7 which was called: # once (8µs+3µs) by Mojo::URL::BEGIN@2 at line 7
use mro;
# spent 11µs making 1 call to Mojo::Base::BEGIN@7 # spent 3µs making 1 call to mro::import
8
9# No imports because we get subclassed, a lot!
10215µs13µs
# spent 3µs within Mojo::Base::BEGIN@10 which was called: # once (3µs+0s) by Mojo::URL::BEGIN@2 at line 10
use Carp ();
# spent 3µs making 1 call to Mojo::Base::BEGIN@10
11263µs12µs
# spent 2µs within Mojo::Base::BEGIN@11 which was called: # once (2µs+0s) by Mojo::URL::BEGIN@2 at line 11
use Scalar::Util ();
# spent 2µs making 1 call to Mojo::Base::BEGIN@11
12
13# Defer to runtime so Mojo::Util can use "-strict"
141527µsrequire Mojo::Util;
15
16# Role support requires Role::Tiny 2.000001+
175644µs34.39ms
# spent 4.33ms (4.07+255µs) within Mojo::Base::BEGIN@17 which was called: # once (4.07ms+255µs) by Mojo::URL::BEGIN@2 at line 17
use constant ROLES => !!(eval { require Role::Tiny; Role::Tiny->VERSION('2.000001'); 1 });
# spent 4.33ms making 1 call to Mojo::Base::BEGIN@17 # spent 57µs making 1 call to constant::import # spent 9µs making 1 call to UNIVERSAL::VERSION
18
19# async/await support requires Future::AsyncAwait 0.52+
20
# spent 136µs (105+31) within Mojo::Base::BEGIN@20 which was called: # once (105µs+31µs) by Mojo::URL::BEGIN@2 at line 22
use constant ASYNC => $ENV{MOJO_NO_ASYNC}
21 ? 0
223411µs2167µs : !!(eval { require Future::AsyncAwait; Future::AsyncAwait->VERSION('0.52'); 1 });
# spent 136µs making 1 call to Mojo::Base::BEGIN@20 # spent 31µs making 1 call to constant::import
23
24# Protect subclasses using AUTOLOAD
25sub DESTROY { }
26
27
# spent 242µs (112+130) within Mojo::Base::attr which was called 5 times, avg 48µs/call: # 5 times (112µs+130µs) by Mojo::JSON::Pointer::has or Mojo::Parameters::has or Mojo::Path::has or Mojo::URL::has at line 136, avg 48µs/call
sub attr {
2856µs my ($self, $attrs, $value, %kv) = @_;
2953µs return unless (my $class = ref $self || $self) && $attrs;
30
3152µs Carp::croak 'Default has to be a code reference or constant value' if ref $value && ref $value ne 'CODE';
3254µs Carp::croak 'Unsupported attribute option' if grep { $_ ne 'weak' } keys %kv;
33
34 # Weaken
3554µs if ($kv{weak}) {
36 state %weak_names;
37 unless ($weak_names{$class}) {
38 my $names = $weak_names{$class} = [];
39 my $sub = sub {
40 my $self = shift->next::method(@_);
41 ref $self->{$_} and Scalar::Util::weaken $self->{$_} for @$names;
42 return $self;
43 };
44 Mojo::Util::monkey_patch(my $base = $class . '::_Base', 'new', $sub);
4521.19ms227µs
# spent 18µs (9+9) within Mojo::Base::BEGIN@45 which was called: # once (9µs+9µs) by Mojo::URL::BEGIN@2 at line 45
no strict 'refs';
# spent 18µs making 1 call to Mojo::Base::BEGIN@45 # spent 9µs making 1 call to strict::unimport
46 unshift @{"${class}::ISA"}, $base;
47 }
48 push @{$weak_names{$class}}, ref $attrs eq 'ARRAY' ? @$attrs : $attrs;
49 }
50
51522µs for my $attr (@{ref $attrs eq 'ARRAY' ? $attrs : [$attrs]}) {
52950µs924µs Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/;
# spent 24µs making 9 calls to Mojo::Base::CORE:match, avg 3µs/call
53
54 # Very performance-sensitive code with lots of micro-optimizations
5594µs my $sub;
5696µs if ($kv{weak}) {
57 if (ref $value) {
58 $sub = sub {
59 return
60 exists $_[0]{$attr}
61 ? $_[0]{$attr}
62 : (ref($_[0]{$attr} = $value->($_[0])) && Scalar::Util::weaken($_[0]{$attr}), $_[0]{$attr})
63 if @_ == 1;
64 ref($_[0]{$attr} = $_[1]) and Scalar::Util::weaken($_[0]{$attr});
65 $_[0];
66 };
67 }
68 else {
69 $sub = sub {
70 return $_[0]{$attr} if @_ == 1;
71 ref($_[0]{$attr} = $_[1]) and Scalar::Util::weaken($_[0]{$attr});
72 $_[0];
73 };
74 }
75 }
76 elsif (ref $value) {
77
# spent 74.1ms within Mojo::URL::base which was called 33963 times, avg 2µs/call: # 33963 times (74.1ms+0s) by Mojo::URL::to_abs at line 128 of Mojo/URL.pm, avg 2µs/call
$sub = sub {
783396315.4ms return exists $_[0]{$attr} ? $_[0]{$attr} : ($_[0]{$attr} = $value->($_[0])) if @_ == 1;
793396328.7ms $_[0]{$attr} = $_[1];
803396352.1ms $_[0];
8112µs };
82 }
83 elsif (defined $value) {
84
# spent 502ms within Mojo::Path::charset which was called 492109 times, avg 1µs/call: # 366247 times (340ms+0s) by Mojo::Path::to_string at line 84 of Mojo/Path.pm, avg 929ns/call # 125862 times (162ms+0s) by Mojo::Path::_parse at line 106 of Mojo/Path.pm, avg 1µs/call # spent 414ms within Mojo::Parameters::charset which was called 327802 times, avg 1µs/call: # 327802 times (414ms+0s) by Mojo::Parameters::to_string at line 150 of Mojo/Parameters.pm, avg 1µs/call
$sub = sub {
858199111.60s return exists $_[0]{$attr} ? $_[0]{$attr} : ($_[0]{$attr} = $value) if @_ == 1;
86 $_[0]{$attr} = $_[1];
87 $_[0];
88211µs };
89 }
90 else {
9137950894.35s
# spent 848ms within Mojo::URL::fragment which was called 986314 times, avg 859ns/call: # 311941 times (231ms+0s) by Mojo::URL::_string at line 181 of Mojo/URL.pm, avg 740ns/call # 126625 times (126ms+0s) by JSON::Schema::Modern::Utilities::canonical_uri at line 193 of JSON/Schema/Modern/Utilities.pm, avg 998ns/call # 126625 times (121ms+0s) by JSON::Schema::Modern::Utilities::canonical_uri at line 195 of JSON/Schema/Modern/Utilities.pm, avg 953ns/call # 89213 times (58.1ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 861 of JSON/Schema/Modern.pm, avg 651ns/call # 71790 times (45.9ms+0s) by JSON::Schema::Modern::Utilities::A at line 252 of JSON/Schema/Modern/Utilities.pm, avg 639ns/call # 64986 times (42.0ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 866 of JSON/Schema/Modern.pm, avg 646ns/call # 57141 times (64.5ms+0s) by Mojo::URL::parse at line 60 of Mojo/URL.pm, avg 1µs/call # 46881 times (40.8ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 849 of JSON/Schema/Modern.pm, avg 870ns/call # 39123 times (68.8ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 865 of JSON/Schema/Modern.pm, avg 2µs/call # 39123 times (40.0ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 852 of JSON/Schema/Modern.pm, avg 1µs/call # 5172 times (4.14ms+0s) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 237 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 801ns/call # 4217 times (2.65ms+0s) by JSON::Schema::Modern::Utilities::E at line 218 of JSON/Schema/Modern/Utilities.pm, avg 629ns/call # 2586 times (2.46ms+0s) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 243 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 952ns/call # 758 times (514µs+0s) by JSON::Schema::Modern::traverse at line 258 of JSON/Schema/Modern.pm, avg 678ns/call # 36 times (35µs+0s) by JSON::Schema::Modern::Document::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern/Document.pm:135] at line 131 of JSON/Schema/Modern/Document.pm, avg 972ns/call # 18 times (16µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:672] at line 663 of JSON/Schema/Modern.pm, avg 889ns/call # 15 times (19µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor at line 171 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 1µs/call # 14 times (12µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id at line 62 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 857ns/call # 14 times (11µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id at line 66 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 786ns/call # 10 times (11µs+0s) by JSON::Schema::Modern::Document::_set_canonical_uri at line 39 of (eval 264)[Sub/Quote.pm:3], avg 1µs/call # 9 times (15µs+0s) by JSON::Schema::Modern::add_schema at line 143 of JSON/Schema/Modern.pm, avg 2µs/call # 8 times (15µs+0s) by JSON::Schema::Modern::Document::canonical_uri at line 44 of (eval 263)[Sub/Quote.pm:3], avg 2µs/call # 6 times (11µs+0s) by JSON::Schema::Modern::Document::new at line 74 of (eval 424)[Sub/Quote.pm:3], avg 2µs/call # once (2µs+0s) by JSON::Schema::Modern::Document::OpenAPI::new at line 77 of (eval 417)[Sub/Quote.pm:3] # once (2µs+0s) by JSON::Schema::Modern::Document::OpenAPI::traverse at line 115 of JSON/Schema/Modern/Document/OpenAPI.pm # once (2µs+0s) by Type::Tiny::__ANON__[(eval 421)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Sub/Quote.pm:3]:16] at line 16 of (eval 421)[Sub/Quote.pm:3] # spent 424ms within Mojo::URL::host which was called 513532 times, avg 827ns/call: # 311941 times (230ms+0s) by Mojo::URL::ihost at line 41 of Mojo/URL.pm, avg 736ns/call # 99702 times (103ms+0s) by Mojo::URL::host_port at line 26 of Mojo/URL.pm, avg 1µs/call # 67926 times (69.9ms+0s) by Mojo::URL::to_abs at line 132 of Mojo/URL.pm, avg 1µs/call # 33963 times (22.1ms+0s) by Mojo::URL::to_abs at line 131 of Mojo/URL.pm, avg 652ns/call # spent 231ms within Mojo::URL::port which was called 377636 times, avg 613ns/call: # 309710 times (178ms+0s) by Mojo::URL::host_port at line 30 of Mojo/URL.pm, avg 574ns/call # 67926 times (53.7ms+0s) by Mojo::URL::to_abs at line 132 of Mojo/URL.pm, avg 791ns/call # spent 55.9ms within Mojo::URL::userinfo which was called 68718 times, avg 814ns/call: # 67926 times (55.4ms+0s) by Mojo::URL::to_abs at line 132 of Mojo/URL.pm, avg 815ns/call # 792 times (562µs+0s) by Mojo::URL::_string at line 171 of Mojo/URL.pm, avg 710ns/call # spent 596ms within Mojo::URL::scheme which was called 597359 times, avg 997ns/call: # 311941 times (270ms+0s) by Mojo::URL::protocol at line 96 of Mojo/URL.pm, avg 864ns/call # 117790 times (109ms+0s) by Mojo::URL::is_abs at line 48 of Mojo/URL.pm, avg 924ns/call # 99702 times (149ms+0s) by Mojo::URL::parse at line 57 of Mojo/URL.pm, avg 1µs/call # 67926 times (68.0ms+0s) by Mojo::URL::to_abs at line 128 of Mojo/URL.pm, avg 1µs/call
$sub = sub { return $_[0]{$attr} if @_ == 1; $_[0]{$attr} = $_[1]; $_[0] };
92 }
93914µs9106µs Mojo::Util::monkey_patch($class, $attr, $sub);
# spent 106µs making 9 calls to Mojo::Util::monkey_patch, avg 12µs/call
94 }
95}
96
97
# spent 1.25ms (310µs+944µs) within Mojo::Base::import which was called 12 times, avg 104µs/call: # once (45µs+211µs) by Mojo::Parameters::BEGIN@2 at line 2 of Mojo/Parameters.pm # once (63µs+180µs) by Mojo::URL::BEGIN@2 at line 2 of Mojo/URL.pm # once (50µs+173µs) by Mojo::Util::BEGIN@2 at line 2 of Mojo/Util.pm # once (40µs+155µs) by Mojo::JSON::Pointer::BEGIN@2 at line 2 of Mojo/JSON/Pointer.pm # once (53µs+113µs) by Mojo::Util::_Guard::BEGIN@538 at line 538 of Mojo/Util.pm # once (31µs+112µs) by Mojo::Path::BEGIN@2 at line 2 of Mojo/Path.pm # once (8µs+0s) by JSON::Schema::Modern::Document::BEGIN@17 at line 17 of JSON/Schema/Modern/Document.pm # once (6µs+0s) by JSON::Schema::Modern::BEGIN@35 at line 35 of JSON/Schema/Modern.pm # once (4µs+0s) by JSON::Schema::Modern::BEGIN@23 at line 23 of JSON/Schema/Modern.pm # once (4µs+0s) by OpenAPI::Modern::BEGIN@28 at line 28 of OpenAPI/Modern.pm # once (4µs+0s) by Mojo::URL::BEGIN@5 at line 5 of Mojo/URL.pm # once (2µs+0s) by Mojo::URL::BEGIN@6 at line 6 of Mojo/URL.pm
sub import {
981237µs my ($class, $caller) = (shift, caller);
991239µs return unless my @flags = @_;
100
101 # Mojo modules are strict!
1026139µs18316µs $_->import for qw(strict warnings utf8);
# spent 250µs making 6 calls to warnings::import, avg 42µs/call # spent 56µs making 6 calls to strict::import, avg 9µs/call # spent 10µs making 6 calls to utf8::import, avg 2µs/call
103617µs6526µs feature->import(':5.16');
# spent 526µs making 6 calls to feature::import, avg 88µs/call
104
105634µs while (my $flag = shift @flags) {
106
107 # Base
1081135µs610µs if ($flag eq '-base') { push @flags, $class }
# spent 10µs making 6 calls to Mojo::Base::CORE:match, avg 2µs/call
109
110 # Role
111 elsif ($flag eq '-role') {
112 Carp::croak 'Role::Tiny 2.000001+ is required for roles' unless ROLES;
113 Mojo::Util::monkey_patch($caller, 'has', sub { attr($caller, @_) });
114 eval "package $caller; use Role::Tiny; 1" or die $@;
115 }
116
117 # async/await
118 elsif ($flag eq '-async_await') {
119 Carp::croak 'Future::AsyncAwait 0.52+ is required for async/await' unless ASYNC;
120 require Mojo::Promise;
121 Future::AsyncAwait->import_into($caller, future_class => 'Mojo::Promise');
122 }
123
124 # Signatures (Perl 5.20+)
125 elsif ($flag eq '-signatures') {
126 Carp::croak 'Subroutine signatures require Perl 5.20+' if $] < 5.020;
127 require experimental;
128 experimental->import($_) for qw(signatures postderef);
129 }
130
131 # Module
132 elsif ($flag !~ /^-/) {
13321.13ms268µs
# spent 44µs (20+24) within Mojo::Base::BEGIN@133 which was called: # once (20µs+24µs) by Mojo::URL::BEGIN@2 at line 133
no strict 'refs';
# spent 44µs making 1 call to Mojo::Base::BEGIN@133 # spent 24µs making 1 call to strict::unimport
134538µs513µs require(Mojo::Util::class_to_path($flag)) unless $flag->can('new');
# spent 13µs making 5 calls to UNIVERSAL::can, avg 3µs/call
135531µs push @{"${caller}::ISA"}, $flag;
1361049µs10321µs
# spent 111µs (5+106) within Mojo::URL::has which was called 2 times, avg 56µs/call: # once (0s+68µs) by JSON::Schema::Modern::BEGIN@23 at line 10 of Mojo/URL.pm # once (5µs+38µs) by JSON::Schema::Modern::BEGIN@23 at line 9 of Mojo/URL.pm # spent 62µs (11+51) within Mojo::Path::has which was called: # once (11µs+51µs) by Mojo::URL::BEGIN@6 at line 7 of Mojo/Path.pm # spent 57µs (6+51) within Mojo::Parameters::has which was called: # once (6µs+51µs) by Mojo::URL::BEGIN@5 at line 7 of Mojo/Parameters.pm # spent 40µs (6+34) within Mojo::JSON::Pointer::has which was called: # once (6µs+34µs) by Moo::_Utils::_require at line 4 of Mojo/JSON/Pointer.pm
Mojo::Util::monkey_patch($caller, 'has', sub { attr($caller, @_) });
# spent 242µs making 5 calls to Mojo::Base::attr, avg 48µs/call # spent 79µs making 5 calls to Mojo::Util::monkey_patch, avg 16µs/call
137 }
138
139 elsif ($flag ne '-strict') { Carp::croak "Unsupported flag: $flag" }
140 }
141}
142
143
# spent 1.48s within Mojo::Base::new which was called 1519183 times, avg 974ns/call: # 613160 times (513ms+0s) by Mojo::Path::new at line 53 of Mojo/Path.pm, avg 837ns/call # 524236 times (632ms+0s) by Mojo::URL::new at line 50 of Mojo/URL.pm, avg 1µs/call # 381772 times (335ms+0s) by Mojo::Parameters::new at line 63 of Mojo/Parameters.pm, avg 877ns/call # 15 times (45µs+0s) by Mojo::JSON::Pointer::new at line 9 of Mojo/JSON/Pointer.pm, avg 3µs/call
sub new {
1441519183207ms my $class = shift;
14515191832.55s bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
146}
147
148sub tap {
149 my ($self, $cb) = (shift, shift);
150 $_->$cb(@_) for $self;
151 return $self;
152}
153
154sub with_roles {
155 Carp::croak 'Role::Tiny 2.000001+ is required for roles' unless ROLES;
156 my ($self, @roles) = @_;
157 return $self unless @roles;
158
159 return Role::Tiny->create_class_with_roles($self, map { /^\+(.+)$/ ? "${self}::Role::$1" : $_ } @roles)
160 unless my $class = Scalar::Util::blessed $self;
161
162 return Role::Tiny->apply_roles_to_object($self, map { /^\+(.+)$/ ? "${class}::Role::$1" : $_ } @roles);
163}
164
16514µs1;
166
167=encoding utf8
168
169=head1 NAME
170
171Mojo::Base - Minimal base class for Mojo projects
172
173=head1 SYNOPSIS
174
175 package Cat;
176 use Mojo::Base -base;
177
178 has name => 'Nyan';
179 has ['age', 'weight'] => 4;
180
181 package Tiger;
182 use Mojo::Base 'Cat';
183
184 has friend => sub { Cat->new };
185 has stripes => 42;
186
187 package main;
188 use Mojo::Base -strict;
189
190 my $mew = Cat->new(name => 'Longcat');
191 say $mew->age;
192 say $mew->age(3)->weight(5)->age;
193
194 my $rawr = Tiger->new(stripes => 38, weight => 250);
195 say $rawr->tap(sub { $_->friend->name('Tacgnol') })->weight;
196
197=head1 DESCRIPTION
198
199L<Mojo::Base> is a simple base class for L<Mojo> projects with fluent interfaces.
200
201 # Automatically enables "strict", "warnings", "utf8" and Perl 5.16 features
202 use Mojo::Base -strict;
203 use Mojo::Base -base;
204 use Mojo::Base 'SomeBaseClass';
205 use Mojo::Base -role;
206
207All four forms save a lot of typing. Note that role support depends on L<Role::Tiny> (2.000001+).
208
209 # use Mojo::Base -strict;
210 use strict;
211 use warnings;
212 use utf8;
213 use feature ':5.16';
214 use mro;
215
216 # use Mojo::Base -base;
217 use strict;
218 use warnings;
219 use utf8;
220 use feature ':5.16';
221 use mro;
222 push @ISA, 'Mojo::Base';
223 sub has { Mojo::Base::attr(__PACKAGE__, @_) }
224
225 # use Mojo::Base 'SomeBaseClass';
226 use strict;
227 use warnings;
228 use utf8;
229 use feature ':5.16';
230 use mro;
231 require SomeBaseClass;
232 push @ISA, 'SomeBaseClass';
233 sub has { Mojo::Base::attr(__PACKAGE__, @_) }
234
235 # use Mojo::Base -role;
236 use strict;
237 use warnings;
238 use utf8;
239 use feature ':5.16';
240 use mro;
241 use Role::Tiny;
242 sub has { Mojo::Base::attr(__PACKAGE__, @_) }
243
244On Perl 5.20+ you can also use the C<-signatures> flag with all four forms and enable support for L<subroutine
245signatures|perlsub/"Signatures">.
246
247 # Also enable signatures
248 use Mojo::Base -strict, -signatures;
249 use Mojo::Base -base, -signatures;
250 use Mojo::Base 'SomeBaseClass', -signatures;
251 use Mojo::Base -role, -signatures;
252
253If you have L<Future::AsyncAwait> 0.52+ installed you can also use the C<-async_await> flag to activate the C<async>
254and C<await> keywords to deal much more efficiently with promises. Note that this feature is B<EXPERIMENTAL> and might
255change without warning!
256
257 # Also enable async/await
258 use Mojo::Base -strict, -async_await;
259 use Mojo::Base -base, -signatures, -async_await;
260
261This will also disable experimental warnings on versions of Perl where this feature was still experimental.
262
263=head1 FLUENT INTERFACES
264
265Fluent interfaces are a way to design object-oriented APIs around method chaining to create domain-specific languages,
266with the goal of making the readability of the source code close to written prose.
267
268 package Duck;
269 use Mojo::Base -base, -signatures;
270
271 has 'name';
272
273 sub quack ($self) {
274 my $name = $self->name;
275 say "$name: Quack!"
276 }
277
278L<Mojo::Base> will help you with this by having all attribute accessors created with L</"has"> (or L</"attr">) return
279their invocant (C<$self>) whenever they are used to assign a new attribute value.
280
281 Duck->new->name('Donald')->quack;
282
283In this case the C<name> attribute accessor is called on the object created by C<Duck-E<gt>new>. It assigns a new
284attribute value and then returns the C<Duck> object, so the C<quack> method can be called on it afterwards. These
285method chains can continue until one of the methods called does not return the C<Duck> object.
286
287=head1 FUNCTIONS
288
289L<Mojo::Base> implements the following functions, which can be imported with the C<-base> flag or by setting a base
290class.
291
292=head2 has
293
294 has 'name';
295 has ['name1', 'name2', 'name3'];
296 has name => 'foo';
297 has name => sub {...};
298 has ['name1', 'name2', 'name3'] => 'foo';
299 has ['name1', 'name2', 'name3'] => sub {...};
300 has name => sub {...}, weak => 1;
301 has name => undef, weak => 1;
302 has ['name1', 'name2', 'name3'] => sub {...}, weak => 1;
303
304Create attributes for hash-based objects, just like the L</"attr"> method.
305
306=head1 METHODS
307
308L<Mojo::Base> implements the following methods.
309
310=head2 attr
311
312 $object->attr('name');
313 SubClass->attr('name');
314 SubClass->attr(['name1', 'name2', 'name3']);
315 SubClass->attr(name => 'foo');
316 SubClass->attr(name => sub {...});
317 SubClass->attr(['name1', 'name2', 'name3'] => 'foo');
318 SubClass->attr(['name1', 'name2', 'name3'] => sub {...});
319 SubClass->attr(name => sub {...}, weak => 1);
320 SubClass->attr(name => undef, weak => 1);
321 SubClass->attr(['name1', 'name2', 'name3'] => sub {...}, weak => 1);
322
323Create attribute accessors for hash-based objects, an array reference can be used to create more than one at a time.
324Pass an optional second argument to set a default value, it should be a constant or a callback. The callback will be
325executed at accessor read time if there's no set value, and gets passed the current instance of the object as first
326argument. Accessors can be chained, that means they return their invocant when they are called with an argument.
327
328These options are currently available:
329
330=over 2
331
332=item weak
333
334 weak => $bool
335
336Weaken attribute reference to avoid L<circular references|perlref/"Circular-References"> and memory leaks.
337
338=back
339
340=head2 new
341
342 my $object = SubClass->new;
343 my $object = SubClass->new(name => 'value');
344 my $object = SubClass->new({name => 'value'});
345
346This base class provides a basic constructor for hash-based objects. You can pass it either a hash or a hash reference
347with attribute values.
348
349=head2 tap
350
351 $object = $object->tap(sub {...});
352 $object = $object->tap('some_method');
353 $object = $object->tap('some_method', @args);
354
355Tap into a method chain to perform operations on an object within the chain (also known as a K combinator or Kestrel).
356The object will be the first argument passed to the callback, and is also available as C<$_>. The callback's return
357value will be ignored; instead, the object (the callback's first argument) will be the return value. In this way,
358arbitrary code can be used within (i.e., spliced or tapped into) a chained set of object method calls.
359
360 # Longer version
361 $object = $object->tap(sub { $_->some_method(@args) });
362
363 # Inject side effects into a method chain
364 $object->foo('A')->tap(sub { say $_->foo })->foo('B');
365
366=head2 with_roles
367
368 my $new_class = SubClass->with_roles('SubClass::Role::One');
369 my $new_class = SubClass->with_roles('+One', '+Two');
370 $object = $object->with_roles('+One', '+Two');
371
372Create a new class with one or more L<Role::Tiny> roles. If called on a class returns the new class, or if called on an
373object reblesses the object into the new class. For roles following the naming scheme C<MyClass::Role::RoleName> you
374can use the shorthand C<+RoleName>. Note that role support depends on L<Role::Tiny> (2.000001+).
375
376 # Create a new class with the role "SubClass::Role::Foo" and instantiate it
377 my $new_class = SubClass->with_roles('+Foo');
378 my $object = $new_class->new;
379
380=head1 SEE ALSO
381
382L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
383
384=cut
 
# spent 34µs within Mojo::Base::CORE:match which was called 15 times, avg 2µs/call: # 9 times (24µs+0s) by Mojo::Base::attr at line 52, avg 3µs/call # 6 times (10µs+0s) by Mojo::Base::import at line 108, avg 2µs/call
sub Mojo::Base::CORE:match; # opcode