Filename | /Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Base.pm |
Statements | Executed 6750365 statements in 7.68s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1303813 | 4 | 4 | 1.35s | 1.35s | new | Mojo::Base::
842734 | 25 | 11 | 783ms | 783ms | fragment | Mojo::URL::
453779 | 4 | 1 | 481ms | 481ms | scheme | Mojo::URL::
420319 | 2 | 1 | 466ms | 466ms | charset | Mojo::Path::
441742 | 4 | 1 | 370ms | 370ms | host | Mojo::URL::
256012 | 1 | 1 | 350ms | 350ms | charset | Mojo::Parameters::
305846 | 2 | 1 | 192ms | 192ms | port | Mojo::URL::
33963 | 1 | 1 | 85.9ms | 85.9ms | base | Mojo::URL::
68718 | 2 | 1 | 53.3ms | 53.3ms | userinfo | Mojo::URL::
1 | 1 | 1 | 4.39ms | 4.72ms | BEGIN@17 | Mojo::Base::
1 | 1 | 1 | 370µs | 439µs | BEGIN@5 | Mojo::Base::
12 | 12 | 8 | 308µs | 1.11ms | import | Mojo::Base::
5 | 1 | 1 | 131µs | 254µs | attr | Mojo::Base::
1 | 1 | 1 | 109µs | 144µs | BEGIN@20 | Mojo::Base::
15 | 2 | 1 | 37µs | 37µs | CORE:match (opcode) | Mojo::Base::
1 | 1 | 1 | 28µs | 33µs | BEGIN@3 | Mojo::Base::
1 | 1 | 1 | 10µs | 18µs | BEGIN@133 | Mojo::Base::
1 | 1 | 1 | 8µs | 17µs | BEGIN@45 | Mojo::Base::
1 | 1 | 1 | 8µs | 10µs | BEGIN@7 | Mojo::Base::
2 | 2 | 1 | 8µs | 87µs | has | Mojo::URL::
1 | 1 | 1 | 7µs | 105µs | BEGIN@6 | Mojo::Base::
1 | 1 | 1 | 7µs | 67µs | has | Mojo::Path::
1 | 1 | 1 | 6µs | 61µs | has | Mojo::Parameters::
1 | 1 | 1 | 5µs | 48µs | BEGIN@4 | Mojo::Base::
1 | 1 | 1 | 5µs | 65µs | has | Mojo::JSON::Pointer::
1 | 1 | 1 | 3µs | 3µs | BEGIN@10 | Mojo::Base::
1 | 1 | 1 | 2µs | 2µs | BEGIN@11 | Mojo::Base::
0 | 0 | 0 | 0s | 0s | DESTROY | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:113] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:136] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:43] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:66] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:73] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:81] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:88] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | __ANON__[:91] | Mojo::Base::
0 | 0 | 0 | 0s | 0s | tap | Mojo::Base::
0 | 0 | 0 | 0s | 0s | with_roles | Mojo::Base::
0 | 0 | 0 | 0s | 0s | data | Mojo::JSON::Pointer::
0 | 0 | 0 | 0s | 0s | has | Mojo::Util::_Guard::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Mojo::Base; | ||||
2 | |||||
3 | 2 | 34µs | 2 | 38µs | # spent 33µs (28+5) within Mojo::Base::BEGIN@3 which was called:
# once (28µs+5µs) by Mojo::URL::BEGIN@2 at line 3 # spent 33µs making 1 call to Mojo::Base::BEGIN@3
# spent 5µs making 1 call to strict::import |
4 | 2 | 19µs | 2 | 91µs | # spent 48µs (5+43) within Mojo::Base::BEGIN@4 which was called:
# once (5µs+43µs) by Mojo::URL::BEGIN@2 at line 4 # spent 48µs making 1 call to Mojo::Base::BEGIN@4
# spent 43µs making 1 call to warnings::import |
5 | 2 | 233µs | 2 | 442µs | # spent 439µs (370+69) within Mojo::Base::BEGIN@5 which was called:
# once (370µs+69µs) by Mojo::URL::BEGIN@2 at line 5 # spent 439µs making 1 call to Mojo::Base::BEGIN@5
# spent 3µs making 1 call to utf8::import |
6 | 2 | 23µs | 2 | 203µs | # spent 105µs (7+98) within Mojo::Base::BEGIN@6 which was called:
# once (7µs+98µs) by Mojo::URL::BEGIN@2 at line 6 # spent 105µs making 1 call to Mojo::Base::BEGIN@6
# spent 98µs making 1 call to feature::import |
7 | 2 | 25µs | 2 | 12µs | # spent 10µs (8+2) within Mojo::Base::BEGIN@7 which was called:
# once (8µs+2µs) by Mojo::URL::BEGIN@2 at line 7 # spent 10µs making 1 call to Mojo::Base::BEGIN@7
# spent 2µs making 1 call to mro::import |
8 | |||||
9 | # No imports because we get subclassed, a lot! | ||||
10 | 2 | 16µs | 1 | 3µs | # spent 3µs within Mojo::Base::BEGIN@10 which was called:
# once (3µs+0s) by Mojo::URL::BEGIN@2 at line 10 # spent 3µs making 1 call to Mojo::Base::BEGIN@10 |
11 | 2 | 63µs | 1 | 2µs | # spent 2µs within Mojo::Base::BEGIN@11 which was called:
# once (2µs+0s) by Mojo::URL::BEGIN@2 at line 11 # spent 2µs making 1 call to Mojo::Base::BEGIN@11 |
12 | |||||
13 | # Defer to runtime so Mojo::Util can use "-strict" | ||||
14 | 1 | 551µs | require Mojo::Util; | ||
15 | |||||
16 | # Role support requires Role::Tiny 2.000001+ | ||||
17 | 5 | 526µs | 3 | 4.79ms | # spent 4.72ms (4.39+339µs) within Mojo::Base::BEGIN@17 which was called:
# once (4.39ms+339µs) by Mojo::URL::BEGIN@2 at line 17 # spent 4.72ms making 1 call to Mojo::Base::BEGIN@17
# spent 59µs making 1 call to constant::import
# spent 10µs making 1 call to UNIVERSAL::VERSION |
18 | |||||
19 | # async/await support requires Future::AsyncAwait 0.52+ | ||||
20 | # spent 144µs (109+35) within Mojo::Base::BEGIN@20 which was called:
# once (109µs+35µs) by Mojo::URL::BEGIN@2 at line 22 | ||||
21 | ? 0 | ||||
22 | 3 | 332µs | 2 | 179µs | : !!(eval { require Future::AsyncAwait; Future::AsyncAwait->VERSION('0.52'); 1 }); # spent 144µs making 1 call to Mojo::Base::BEGIN@20
# spent 35µs making 1 call to constant::import |
23 | |||||
24 | # Protect subclasses using AUTOLOAD | ||||
25 | sub DESTROY { } | ||||
26 | |||||
27 | # spent 254µs (131+123) within Mojo::Base::attr which was called 5 times, avg 51µs/call:
# 5 times (131µs+123µs) by Mojo::JSON::Pointer::has or Mojo::Parameters::has or Mojo::Path::has or Mojo::URL::has at line 136, avg 51µs/call | ||||
28 | 5 | 7µs | my ($self, $attrs, $value, %kv) = @_; | ||
29 | 5 | 3µs | return unless (my $class = ref $self || $self) && $attrs; | ||
30 | |||||
31 | 5 | 3µs | Carp::croak 'Default has to be a code reference or constant value' if ref $value && ref $value ne 'CODE'; | ||
32 | 5 | 4µs | Carp::croak 'Unsupported attribute option' if grep { $_ ne 'weak' } keys %kv; | ||
33 | |||||
34 | # Weaken | ||||
35 | 5 | 3µ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); | ||||
45 | 2 | 856µs | 2 | 26µs | # spent 17µs (8+9) within Mojo::Base::BEGIN@45 which was called:
# once (8µs+9µs) by Mojo::URL::BEGIN@2 at line 45 # spent 17µ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 | |||||
51 | 5 | 23µs | for my $attr (@{ref $attrs eq 'ARRAY' ? $attrs : [$attrs]}) { | ||
52 | 9 | 51µs | 9 | 31µs | Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/; # spent 31µs making 9 calls to Mojo::Base::CORE:match, avg 3µs/call |
53 | |||||
54 | # Very performance-sensitive code with lots of micro-optimizations | ||||
55 | 9 | 1µs | my $sub; | ||
56 | 9 | 9µ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 85.9ms within Mojo::URL::base which was called 33963 times, avg 3µs/call:
# 33963 times (85.9ms+0s) by Mojo::URL::to_abs at line 128 of Mojo/URL.pm, avg 3µs/call | ||||
78 | 33963 | 15.7ms | return exists $_[0]{$attr} ? $_[0]{$attr} : ($_[0]{$attr} = $value->($_[0])) if @_ == 1; | ||
79 | 33963 | 35.1ms | $_[0]{$attr} = $_[1]; | ||
80 | 33963 | 60.5ms | $_[0]; | ||
81 | 1 | 2µs | }; | ||
82 | } | ||||
83 | elsif (defined $value) { | ||||
84 | # spent 350ms within Mojo::Parameters::charset which was called 256012 times, avg 1µs/call:
# 256012 times (350ms+0s) by Mojo::Parameters::to_string at line 150 of Mojo/Parameters.pm, avg 1µs/call
# spent 466ms within Mojo::Path::charset which was called 420319 times, avg 1µs/call:
# 294457 times (298ms+0s) by Mojo::Path::to_string at line 84 of Mojo/Path.pm, avg 1µs/call
# 125862 times (168ms+0s) by Mojo::Path::_parse at line 106 of Mojo/Path.pm, avg 1µs/call | ||||
85 | 676331 | 1.38s | return exists $_[0]{$attr} ? $_[0]{$attr} : ($_[0]{$attr} = $value) if @_ == 1; | ||
86 | $_[0]{$attr} = $_[1]; | ||||
87 | $_[0]; | ||||
88 | 2 | 7µs | }; | ||
89 | } | ||||
90 | else { | ||||
91 | 3364349 | 3.72s | # spent 192ms within Mojo::URL::port which was called 305846 times, avg 627ns/call:
# 237920 times (140ms+0s) by Mojo::URL::host_port at line 30 of Mojo/URL.pm, avg 588ns/call
# 67926 times (52.0ms+0s) by Mojo::URL::to_abs at line 132 of Mojo/URL.pm, avg 765ns/call
# spent 783ms within Mojo::URL::fragment which was called 842734 times, avg 929ns/call:
# 240151 times (211ms+0s) by Mojo::URL::_string at line 181 of Mojo/URL.pm, avg 878ns/call
# 126625 times (123ms+0s) by JSON::Schema::Modern::Utilities::canonical_uri at line 193 of JSON/Schema/Modern/Utilities.pm, avg 970ns/call
# 126625 times (118ms+0s) by JSON::Schema::Modern::Utilities::canonical_uri at line 195 of JSON/Schema/Modern/Utilities.pm, avg 929ns/call
# 89213 times (59.7ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 865 of JSON/Schema/Modern.pm, avg 669ns/call
# 64986 times (41.7ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 870 of JSON/Schema/Modern.pm, avg 641ns/call
# 57141 times (65.5ms+0s) by Mojo::URL::parse at line 60 of Mojo/URL.pm, avg 1µs/call
# 46881 times (39.6ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 853 of JSON/Schema/Modern.pm, avg 845ns/call
# 39123 times (74.0ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 869 of JSON/Schema/Modern.pm, avg 2µs/call
# 39123 times (40.9ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 856 of JSON/Schema/Modern.pm, avg 1µs/call
# 5172 times (4.22ms+0s) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 237 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 816ns/call
# 4217 times (2.84ms+0s) by JSON::Schema::Modern::Utilities::E at line 218 of JSON/Schema/Modern/Utilities.pm, avg 675ns/call
# 2586 times (2.49ms+0s) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 243 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 962ns/call
# 758 times (420µs+0s) by JSON::Schema::Modern::traverse at line 259 of JSON/Schema/Modern.pm, avg 554ns/call
# 36 times (19µ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 528ns/call
# 18 times (19µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:676] at line 667 of JSON/Schema/Modern.pm, avg 1µs/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 (10µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id at line 66 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 714ns/call
# 14 times (9µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id at line 62 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 643ns/call
# 10 times (7µs+0s) by JSON::Schema::Modern::Document::_set_canonical_uri at line 39 of (eval 268)[Sub/Quote.pm:3], avg 700ns/call
# 9 times (10µs+0s) by JSON::Schema::Modern::add_schema at line 143 of JSON/Schema/Modern.pm, avg 1µs/call
# 8 times (40µs+0s) by JSON::Schema::Modern::Document::canonical_uri at line 44 of (eval 267)[Sub/Quote.pm:3], avg 5µs/call
# 6 times (4µs+0s) by JSON::Schema::Modern::Document::new at line 74 of (eval 428)[Sub/Quote.pm:3], avg 667ns/call
# once (2µs+0s) by JSON::Schema::Modern::Document::OpenAPI::new at line 77 of (eval 421)[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 (1µs+0s) by Type::Tiny::__ANON__[(eval 425)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Sub/Quote.pm:3]:16] at line 16 of (eval 425)[Sub/Quote.pm:3]
# spent 481ms within Mojo::URL::scheme which was called 453779 times, avg 1µs/call:
# 240151 times (228ms+0s) by Mojo::URL::protocol at line 96 of Mojo/URL.pm, avg 950ns/call
# 99702 times (152ms+0s) by Mojo::URL::parse at line 57 of Mojo/URL.pm, avg 2µs/call
# 67926 times (63.3ms+0s) by Mojo::URL::to_abs at line 128 of Mojo/URL.pm, avg 932ns/call
# 46000 times (37.6ms+0s) by Mojo::URL::is_abs at line 48 of Mojo/URL.pm, avg 818ns/call
# spent 53.3ms within Mojo::URL::userinfo which was called 68718 times, avg 775ns/call:
# 67926 times (52.8ms+0s) by Mojo::URL::to_abs at line 132 of Mojo/URL.pm, avg 777ns/call
# 792 times (500µs+0s) by Mojo::URL::_string at line 171 of Mojo/URL.pm, avg 631ns/call
# spent 370ms within Mojo::URL::host which was called 441742 times, avg 838ns/call:
# 240151 times (182ms+0s) by Mojo::URL::ihost at line 41 of Mojo/URL.pm, avg 759ns/call
# 99702 times (99.7ms+0s) by Mojo::URL::host_port at line 26 of Mojo/URL.pm, avg 1000ns/call
# 67926 times (67.6ms+0s) by Mojo::URL::to_abs at line 132 of Mojo/URL.pm, avg 996ns/call
# 33963 times (20.5ms+0s) by Mojo::URL::to_abs at line 131 of Mojo/URL.pm, avg 603ns/call | ||
92 | } | ||||
93 | 9 | 8µs | 9 | 92µs | Mojo::Util::monkey_patch($class, $attr, $sub); # spent 92µs making 9 calls to Mojo::Util::monkey_patch, avg 10µs/call |
94 | } | ||||
95 | } | ||||
96 | |||||
97 | # spent 1.11ms (308µs+801µs) within Mojo::Base::import which was called 12 times, avg 92µs/call:
# once (80µs+152µs) by Mojo::URL::BEGIN@2 at line 2 of Mojo/URL.pm
# once (54µs+134µs) by Mojo::Util::_Guard::BEGIN@538 at line 538 of Mojo/Util.pm
# once (40µs+134µs) by Mojo::Parameters::BEGIN@2 at line 2 of Mojo/Parameters.pm
# once (35µs+136µs) by Mojo::Util::BEGIN@2 at line 2 of Mojo/Util.pm
# once (36µs+132µs) by Mojo::Path::BEGIN@2 at line 2 of Mojo/Path.pm
# once (43µs+113µs) by Mojo::JSON::Pointer::BEGIN@2 at line 2 of Mojo/JSON/Pointer.pm
# once (5µs+0s) by JSON::Schema::Modern::Document::BEGIN@17 at line 17 of JSON/Schema/Modern/Document.pm
# once (4µs+0s) by Mojo::URL::BEGIN@5 at line 5 of Mojo/URL.pm
# once (4µs+0s) by JSON::Schema::Modern::BEGIN@35 at line 35 of JSON/Schema/Modern.pm
# once (3µs+0s) by Mojo::URL::BEGIN@6 at line 6 of Mojo/URL.pm
# once (2µs+0s) by JSON::Schema::Modern::BEGIN@23 at line 23 of JSON/Schema/Modern.pm
# once (2µs+0s) by OpenAPI::Modern::BEGIN@28 at line 28 of OpenAPI/Modern.pm | ||||
98 | 12 | 27µs | my ($class, $caller) = (shift, caller); | ||
99 | 12 | 59µs | return unless my @flags = @_; | ||
100 | |||||
101 | # Mojo modules are strict! | ||||
102 | 6 | 88µs | 18 | 247µs | $_->import for qw(strict warnings utf8); # spent 221µs making 6 calls to warnings::import, avg 37µs/call
# spent 16µs making 6 calls to strict::import, avg 3µs/call
# spent 10µs making 6 calls to utf8::import, avg 2µs/call |
103 | 6 | 18µs | 6 | 466µs | feature->import(':5.16'); # spent 466µs making 6 calls to feature::import, avg 78µs/call |
104 | |||||
105 | 6 | 34µs | while (my $flag = shift @flags) { | ||
106 | |||||
107 | # Base | ||||
108 | 11 | 31µs | 6 | 6µs | if ($flag eq '-base') { push @flags, $class } # spent 6µs making 6 calls to Mojo::Base::CORE:match, avg 1µ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 !~ /^-/) { | ||||
133 | 2 | 855µs | 2 | 26µs | # spent 18µs (10+8) within Mojo::Base::BEGIN@133 which was called:
# once (10µs+8µs) by Mojo::URL::BEGIN@2 at line 133 # spent 18µs making 1 call to Mojo::Base::BEGIN@133
# spent 8µs making 1 call to strict::unimport |
134 | 5 | 36µs | 5 | 12µs | require(Mojo::Util::class_to_path($flag)) unless $flag->can('new'); # spent 12µs making 5 calls to UNIVERSAL::can, avg 2µs/call |
135 | 5 | 30µs | push @{"${caller}::ISA"}, $flag; | ||
136 | 10 | 43µs | 10 | 324µs | # spent 87µs (8+79) within Mojo::URL::has which was called 2 times, avg 44µs/call:
# once (7µs+37µs) by JSON::Schema::Modern::BEGIN@23 at line 9 of Mojo/URL.pm
# once (1µs+42µs) by JSON::Schema::Modern::BEGIN@23 at line 10 of Mojo/URL.pm
# spent 61µs (6+55) within Mojo::Parameters::has which was called:
# once (6µs+55µs) by Mojo::URL::BEGIN@5 at line 7 of Mojo/Parameters.pm
# spent 65µs (5+60) within Mojo::JSON::Pointer::has which was called:
# once (5µs+60µs) by Moo::_Utils::_require at line 4 of Mojo/JSON/Pointer.pm
# spent 67µs (7+60) within Mojo::Path::has which was called:
# once (7µs+60µs) by Mojo::URL::BEGIN@6 at line 7 of Mojo/Path.pm # spent 254µs making 5 calls to Mojo::Base::attr, avg 51µs/call
# spent 70µs making 5 calls to Mojo::Util::monkey_patch, avg 14µs/call |
137 | } | ||||
138 | |||||
139 | elsif ($flag ne '-strict') { Carp::croak "Unsupported flag: $flag" } | ||||
140 | } | ||||
141 | } | ||||
142 | |||||
143 | # spent 1.35s within Mojo::Base::new which was called 1303813 times, avg 1µs/call:
# 541370 times (510ms+0s) by Mojo::Path::new at line 53 of Mojo/Path.pm, avg 941ns/call
# 452446 times (546ms+0s) by Mojo::URL::new at line 50 of Mojo/URL.pm, avg 1µs/call
# 309982 times (300ms+0s) by Mojo::Parameters::new at line 63 of Mojo/Parameters.pm, avg 967ns/call
# 15 times (29µs+0s) by Mojo::JSON::Pointer::new at line 9 of Mojo/JSON/Pointer.pm, avg 2µs/call | ||||
144 | 1303813 | 207ms | my $class = shift; | ||
145 | 1303813 | 2.26s | bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class; | ||
146 | } | ||||
147 | |||||
148 | sub tap { | ||||
149 | my ($self, $cb) = (shift, shift); | ||||
150 | $_->$cb(@_) for $self; | ||||
151 | return $self; | ||||
152 | } | ||||
153 | |||||
154 | sub 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 | |||||
165 | 1 | 4µs | 1; | ||
166 | |||||
167 | =encoding utf8 | ||||
168 | |||||
169 | =head1 NAME | ||||
170 | |||||
171 | Mojo::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 | |||||
199 | L<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 | |||||
207 | All 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 | |||||
244 | On Perl 5.20+ you can also use the C<-signatures> flag with all four forms and enable support for L<subroutine | ||||
245 | signatures|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 | |||||
253 | If you have L<Future::AsyncAwait> 0.52+ installed you can also use the C<-async_await> flag to activate the C<async> | ||||
254 | and C<await> keywords to deal much more efficiently with promises. Note that this feature is B<EXPERIMENTAL> and might | ||||
255 | change without warning! | ||||
256 | |||||
257 | # Also enable async/await | ||||
258 | use Mojo::Base -strict, -async_await; | ||||
259 | use Mojo::Base -base, -signatures, -async_await; | ||||
260 | |||||
261 | This will also disable experimental warnings on versions of Perl where this feature was still experimental. | ||||
262 | |||||
263 | =head1 FLUENT INTERFACES | ||||
264 | |||||
265 | Fluent interfaces are a way to design object-oriented APIs around method chaining to create domain-specific languages, | ||||
266 | with 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 | |||||
278 | L<Mojo::Base> will help you with this by having all attribute accessors created with L</"has"> (or L</"attr">) return | ||||
279 | their invocant (C<$self>) whenever they are used to assign a new attribute value. | ||||
280 | |||||
281 | Duck->new->name('Donald')->quack; | ||||
282 | |||||
283 | In this case the C<name> attribute accessor is called on the object created by C<Duck-E<gt>new>. It assigns a new | ||||
284 | attribute value and then returns the C<Duck> object, so the C<quack> method can be called on it afterwards. These | ||||
285 | method chains can continue until one of the methods called does not return the C<Duck> object. | ||||
286 | |||||
287 | =head1 FUNCTIONS | ||||
288 | |||||
289 | L<Mojo::Base> implements the following functions, which can be imported with the C<-base> flag or by setting a base | ||||
290 | class. | ||||
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 | |||||
304 | Create attributes for hash-based objects, just like the L</"attr"> method. | ||||
305 | |||||
306 | =head1 METHODS | ||||
307 | |||||
308 | L<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 | |||||
323 | Create attribute accessors for hash-based objects, an array reference can be used to create more than one at a time. | ||||
324 | Pass an optional second argument to set a default value, it should be a constant or a callback. The callback will be | ||||
325 | executed at accessor read time if there's no set value, and gets passed the current instance of the object as first | ||||
326 | argument. Accessors can be chained, that means they return their invocant when they are called with an argument. | ||||
327 | |||||
328 | These options are currently available: | ||||
329 | |||||
330 | =over 2 | ||||
331 | |||||
332 | =item weak | ||||
333 | |||||
334 | weak => $bool | ||||
335 | |||||
336 | Weaken 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 | |||||
346 | This base class provides a basic constructor for hash-based objects. You can pass it either a hash or a hash reference | ||||
347 | with 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 | |||||
355 | Tap into a method chain to perform operations on an object within the chain (also known as a K combinator or Kestrel). | ||||
356 | The object will be the first argument passed to the callback, and is also available as C<$_>. The callback's return | ||||
357 | value will be ignored; instead, the object (the callback's first argument) will be the return value. In this way, | ||||
358 | arbitrary 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 | |||||
372 | Create 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 | ||||
373 | object reblesses the object into the new class. For roles following the naming scheme C<MyClass::Role::RoleName> you | ||||
374 | can 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 | |||||
382 | L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>. | ||||
383 | |||||
384 | =cut | ||||
sub Mojo::Base::CORE:match; # opcode |