File Coverage

blib/lib/Dancer2/Core/Role/Hookable.pm
Criterion Covered Total %
statement 54 55 98.1
branch 17 20 85.0
condition 2 3 66.6
subroutine 12 12 100.0
pod 0 5 0.0
total 85 95 89.4


line stmt bran cond sub pod time code
1             # ABSTRACT: Role for hookable objects
2             $Dancer2::Core::Role::Hookable::VERSION = '0.400000';
3             use Moo::Role;
4 154     154   161890 use Dancer2::Core;
  154         344  
  154         829  
5 154     154   64516 use Dancer2::Core::Types;
  154         331  
  154         3866  
6 154     154   4568 use Carp 'croak';
  154         357  
  154         1216  
7 154     154   1235756 use Safe::Isa;
  154         384  
  154         8736  
8 154     154   14137  
  154         14085  
  154         128748  
9             requires 'supported_hooks', 'hook_aliases';
10              
11             # The hooks registry
12             has hooks => (
13             is => 'ro',
14             isa => HashRef,
15             builder => '_build_hooks',
16             lazy => 1,
17             );
18              
19              
20       870 0   # after a hookable object is built, we go over its postponed hooks and register
21             # them if any.
22             after BUILD => sub {
23             my ( $self, $args ) = @_;
24             $self->_add_postponed_hooks($args)
25             if defined $args->{postponed_hooks};
26             };
27              
28             my ( $self, $args ) = @_;
29             my $postponed_hooks = $args->{postponed_hooks};
30              
31 793     793   1922 # find the internal name of the hooks, from the caller name
32 793         1684 my $caller = ref($self);
33             my ( $dancer, $h_type, $h_name, @rest ) = map lc, split /::/, $caller;
34             $h_name = $rest[0] if $h_name eq 'role';
35 793         1753 if ( $h_type =~ /(template|logger|serializer|session)/ ) {
36 793         6423 $h_name = $h_type;
37 793 50       2969 $h_type = 'engine';
38 793 100       5267 }
39 596         1263  
40 596         1153 # keep only the hooks we want
41             $postponed_hooks = $postponed_hooks->{$h_type}{$h_name};
42             return unless defined $postponed_hooks;
43              
44 793         2144 foreach my $name ( keys %{$postponed_hooks} ) {
45 793 100       13917 my $hook = $postponed_hooks->{$name}{hook};
46             my $caller = $postponed_hooks->{$name}{caller};
47 5         12  
  5         23  
48 5         14 $self->has_hook($name)
49 5         17 or croak "$h_name $h_type does not support the hook `$name'. ("
50             . join( ", ", @{$caller} ) . ")";
51              
52             $self->add_hook($hook);
53 5 50       19 }
  0         0  
54             }
55 5         150  
56             # mst++ for the hint
57             my ($self) = @_;
58             my %hooks = map +( $_ => [] ), $self->supported_hooks;
59             return \%hooks;
60             }
61 362     362   4271  
62 362         1759 # This binds a coderef to an installed hook if not already
63 362         5750 # existing
64             my ( $self, $hook ) = @_;
65             my $name = $hook->name;
66             my $code = $hook->code;
67              
68             croak "Unsupported hook '$name'"
69 326     326 0 8691 unless $self->has_hook($name);
70 326         4860  
71 326         2539 push @{ $self->hooks->{$name} }, $code;
72             }
73 326 100       980  
74             # allows the caller to replace the current list of hooks at the given position
75             # this is useful if the object where this role is composed wants to compile the
76 325         3023 # hooks.
  325         4646  
77             my ( $self, $position, $hooks ) = @_;
78              
79             croak "Hook '$position' must be installed first"
80             unless $self->has_hook($position);
81              
82             $self->hooks->{$position} = $hooks;
83 1643     1643 0 4303 }
84              
85 1643 100       2722 # Boolean flag to tells if the hook is registered or not
86             my ( $self, $hook_name ) = @_;
87             return exists $self->hooks->{$hook_name};
88 1642         28638 }
89              
90             # Execute the hook at the given position
91             my $self = shift;
92             my $name = shift;
93 25990     25990 0 39358  
94 25990         347869 $name and !ref $name
95             or croak "execute_hook needs a hook name";
96              
97             $name = $self->hook_aliases->{$name}
98             if exists $self->hook_aliases->{$name};
99 22125     22125 0 29802  
100 22125         25385 croak "Hook '$name' does not exist"
101             if !$self->has_hook($name);
102 22125 100 66     63714  
103             $self->$_isa('Dancer2::Core::App') &&
104             $self->log( core => "Entering hook $name" );
105              
106 22124 100       41604 for my $hook ( @{ $self->hooks->{$name} } ) {
107             $hook->(@_);
108 22124 50       40767 }
109             }
110              
111 22124 100       159675 1;
112              
113              
114 22124         230284 =pod
  22124         287106  
115 630         5571  
116             =encoding UTF-8
117              
118             =head1 NAME
119              
120             Dancer2::Core::Role::Hookable - Role for hookable objects
121              
122             =head1 VERSION
123              
124             version 0.400000
125              
126             =head1 AUTHOR
127              
128             Dancer Core Developers
129              
130             =head1 COPYRIGHT AND LICENSE
131              
132             This software is copyright (c) 2022 by Alexis Sukrieh.
133              
134             This is free software; you can redistribute it and/or modify it under
135             the same terms as the Perl 5 programming language system itself.
136              
137             =cut