File Coverage

blib/lib/Dancer2/Core/Role/DSL.pm
Criterion Covered Total %
statement 52 56 92.8
branch 11 16 68.7
condition n/a
subroutine 15 15 100.0
pod 0 3 0.0
total 78 90 86.6


line stmt bran cond sub pod time code
1             package Dancer2::Core::Role::DSL;
2             # ABSTRACT: Role for DSL
3             $Dancer2::Core::Role::DSL::VERSION = '1.0.0';
4 138     138   90050 use Moo::Role;
  138         401  
  138         1089  
5 138     138   66021 use Dancer2::Core::Types;
  138         528  
  138         1096  
6 138     138   1814789 use Carp 'croak';
  138         398  
  138         7777  
7 138     138   1008 use Scalar::Util qw();
  138         424  
  138         51245  
8              
9             with 'Dancer2::Core::Role::Hookable';
10              
11             has app => ( is => 'ro', required => 1 );
12              
13             has keywords => (
14             is => 'rw',
15             isa => HashRef,
16             lazy => 1,
17             builder => '_build_dsl_keywords',
18             );
19              
20             sub _build_dsl_keywords {
21 211     211   2158 my ($self) = @_;
22 211 50       1705 $self->can('dsl_keywords')
23             ? $self->dsl_keywords
24             : {};
25             }
26              
27             sub register {
28 2     2 0 41 my ( $self, $keyword, $is_global ) = @_;
29 2         40 my $keywords = $self->keywords;
30 2         62 my $pkg = ref($self);
31 2         5 $pkg =~ s/__WITH__.+$//;
32              
33 2 50       16 if ( exists $keywords->{$keyword} ) {
34 0         0 my $reg_pkg = $keywords->{$keyword}{'pkg'};
35 0         0 $reg_pkg =~ s/__WITH__.+$//;
36 0 0       0 $reg_pkg eq $pkg and return;
37              
38 0         0 croak "[$pkg] Keyword $keyword already registered by $reg_pkg";
39             }
40              
41 2         20 $keywords->{$keyword} = { is_global => $is_global, pkg => $pkg };
42             }
43              
44 29     29 0 79 sub dsl { $_[0] }
45              
46             # exports new symbol to caller
47             sub export_symbols_to {
48 211     211 0 752 my ( $self, $caller, $args ) = @_;
49 211         795 my $exports = $self->_construct_export_map($args);
50              
51             ## no critic
52 211         581 foreach my $export ( keys %{$exports} ) {
  211         2853  
53 138     138   1339 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  138         419  
  138         60459  
54 17095         21320 my $existing = *{"${caller}::${export}"}{CODE};
  17095         53252  
55              
56 17095 100       31034 next if defined $existing;
57              
58 16673         21491 *{"${caller}::${export}"} = $exports->{$export};
  16673         35662  
59             }
60             ## use critic
61              
62 211         1338 return keys %{$exports};
  211         20349942  
63             }
64              
65             # private
66              
67             sub _compile_keyword {
68 17095     17095   28023 my ( $self, $keyword, $opts ) = @_;
69              
70             my $code = $opts->{is_global}
71 854     854   378515 ? sub { $self->$keyword(@_) }
        836      
72             : sub {
73 472 50   472   73836 croak "Function '$keyword' must be called from a route handler"
74             unless defined $Dancer2::Core::Route::REQUEST;
75              
76 472         2211 $self->$keyword(@_)
77 17095 100       68689 };
78              
79 17095         33089 return $self->_apply_prototype($code, $opts);
80             }
81              
82             sub _apply_prototype {
83 17095     17095   25786 my ($self, $code, $opts) = @_;
84              
85             # set prototype if one is defined for the keyword. undef => no prototype
86 17095         20285 my $prototype;
87 17095 100       29141 exists $opts->{'prototype'} and $prototype = $opts->{'prototype'};
88 17095         59244 return Scalar::Util::set_prototype( \&$code, $prototype );
89             }
90              
91             sub _construct_export_map {
92 211     211   502 my ( $self, $args ) = @_;
93 211         3718 my $keywords = $self->keywords;
94 211         6053 my %map;
95 211         2964 foreach my $keyword ( keys %$keywords ) {
96             # check if the keyword were excluded from importation
97 17100 100       38249 $args->{ '!' . $keyword } and next;
98 17095         29679 $map{$keyword} = $self->_compile_keyword( $keyword, $keywords->{$keyword} );
99             }
100 211         1635 return \%map;
101             }
102              
103             1;
104              
105             __END__
106              
107             =pod
108              
109             =encoding UTF-8
110              
111             =head1 NAME
112              
113             Dancer2::Core::Role::DSL - Role for DSL
114              
115             =head1 VERSION
116              
117             version 1.0.0
118              
119             =head1 AUTHOR
120              
121             Dancer Core Developers
122              
123             =head1 COPYRIGHT AND LICENSE
124              
125             This software is copyright (c) 2023 by Alexis Sukrieh.
126              
127             This is free software; you can redistribute it and/or modify it under
128             the same terms as the Perl 5 programming language system itself.
129              
130             =cut