File Coverage

blib/lib/HTML/MasonX/Free/Compiler.pm
Criterion Covered Total %
statement 67 75 89.3
branch 18 34 52.9
condition 15 18 83.3
subroutine 11 11 100.0
pod 4 4 100.0
total 115 142 80.9


line stmt bran cond sub pod time code
1 4     4   760420 use strict;
  4         169  
  4         141  
2 4     4   28 use warnings;
  4         9  
  4         326  
3             package HTML::MasonX::Free::Compiler 0.007;
4              
5             # ABSTRACT: an HTML::Mason compiler that can reject more input
6 4     4   25 use parent 'HTML::Mason::Compiler::ToObject';
  4         9  
  4         86  
7              
8             #pod =head1 OVERVIEW
9             #pod
10             #pod This is an alternate compiler for HTML::Mason. It's meant to fill in for the
11             #pod default, L<HTML::Mason::Compiler::ToObject>. (Don't trust things telling you
12             #pod that the default is HTML::Mason::Compiler. If you're using Mason, you're
13             #pod almost certainly have ToObject doing the work.)
14             #pod
15             #pod By default, it I<should> behave just like the normal compiler, but more options
16             #pod can be provided to make it stricter.
17             #pod
18             #pod Right now, there's just one extra option, but there will be more.
19             #pod
20             #pod =attr allow_stray_content
21             #pod
22             #pod If false, any text outside of a block (like a method or doc block), other than
23             #pod blank lines, will be fatal. Similar, any Perl lines other than comments will
24             #pod be fatal.
25             #pod
26             #pod =attr default_method_to_call
27             #pod
28             #pod If set, this is the name of a method that will be dropped in place whenever the
29             #pod user is trying to call a component without a method. For example, if you set
30             #pod it to "main" then this:
31             #pod
32             #pod <& /foo/bar &>
33             #pod
34             #pod ...will be treated like this:
35             #pod
36             #pod <& /foo/bar:main &>
37             #pod
38             #pod To keep this consistent with the top-level called performed by the mason
39             #pod interpreter, you should probably also use L<HTML::MasonX::Free::Component> as
40             #pod your component class.
41             #pod
42             #pod =cut
43              
44 4     4   118860 use namespace::autoclean;
  4         47331  
  4         16  
45              
46 4     4   293 use HTML::Mason::Exceptions(abbr => [qw(param_error)]);
  4         8  
  4         30  
47              
48 4     4   285 use Params::Validate qw(:all);
  4         10  
  4         948  
49             Params::Validate::validation_options(on_fail => sub {param_error join '', @_});
50              
51             BEGIN {
52 4     4   80 __PACKAGE__->valid_params(
53             allow_stray_content => {
54             parse => 'boolean',
55             type => SCALAR,
56             default => 1,
57             descr => "Whether to allow content outside blocks, or die",
58             },
59             default_method_to_call => {
60             parse => 'string',
61             type => SCALAR,
62             optional => 1,
63             descr => "A method to always call instead of calling a comp directly",
64             },
65             );
66             }
67              
68             sub text {
69 45     45 1 25357 my ($self, %arg) = @_;
70 45 100 100     204 if (
      100        
71             $self->{current_compile}{in_main}
72             and ! $self->{allow_stray_content}
73             and $arg{text} =~ /\S/
74             ) {
75 1         5 $self->lexer->throw_syntax_error(
76             "text outside of block: <<'END_TEXT'\n$arg{text}END_TEXT"
77             );
78             }
79 44         182 $self->SUPER::text(%arg);
80             }
81              
82             sub perl_line {
83 4     4 1 8488 my ($self, %arg) = @_;
84              
85 4 100 66     43 if (
      100        
86             $self->{current_compile}{in_main}
87             and ! $self->{allow_stray_content}
88             and $arg{line} !~ /\A\s*#/
89             ) {
90 1         6 $self->lexer->throw_syntax_error(
91             "perl outside of block: $arg{line}\n"
92             );
93             }
94 3         29 $self->SUPER::perl_line(%arg);
95             }
96              
97             # BEGIN DIRECT THEFT FROM HTML-Mason 1.50
98             sub component_call
99             {
100 11     11 1 2075 my $self = shift;
101 11         29 my %p = @_;
102              
103 11         61 my ($prespace, $call, $postspace) = ($p{call} =~ /(\s*)(.*)(\s*)/s);
104 11 50       45 if ( $call =~ m,^[\w/.],)
105             {
106 11         26 my $comma = index($call, ',');
107 11 50       28 $comma = length $call if $comma == -1;
108 11         58 (my $comp = substr($call, 0, $comma)) =~ s/\s+$//;
109 11 100 66     72 if (defined $self->{default_method_to_call} and $comp !~ /:/) { ##
110 2         10 $comp = "$comp:$self->{default_method_to_call}"; ##
111             } ##
112 11         35 $call = "'$comp'" . substr($call, $comma);
113             }
114 11         28 my $code = "\$m->comp( $prespace $call $postspace \n); ";
115 11 50       50 eval { $self->postprocess_perl->(\$code) } if $self->postprocess_perl;
  0         0  
116 11 50       57 compiler_error $@ if $@;
117              
118 11         37 $self->_add_body_code($code);
119              
120 11         394 $self->{current_compile}{last_body_code_type} = 'component_call';
121             }
122              
123             sub component_content_call_end
124             {
125 2     2 1 216 my $self = shift;
126 2         4 my $c = $self->{current_compile};
127 2         6 my %p = @_;
128              
129             $self->lexer->throw_syntax_error("Found component with content ending tag but no beginning tag")
130 2 50       4 unless @{ $c->{comp_with_content_stack} };
  2         8  
131              
132 2         4 my $call = pop @{ $c->{comp_with_content_stack} };
  2         5  
133 2         5 my $call_end = $p{call_end};
134 2         5 for ($call_end) { s/^\s+//; s/\s+$//; }
  2         5  
  2         4  
135              
136 2         5 my $comp = undef;
137 2 50       10 if ( $call =~ m,^[\w/.],)
138             {
139 2         7 my $comma = index($call, ',');
140 2 50       8 $comma = length $call if $comma == -1;
141 2         7 ($comp = substr($call, 0, $comma)) =~ s/\s+$//;
142 2 100 66     15 if (defined $self->{default_method_to_call} and $comp !~ /:/) { ##
143 1         3 $comp = "$comp:$self->{default_method_to_call}"; ##
144             } ##
145 2         9 $call = "'$comp'" . substr($call, $comma);
146             }
147 2 50       9 if ($call_end) {
148 0 0       0 if ($call_end !~ m,^[\w/.],) {
149 0         0 $self->lexer->throw_syntax_error("Cannot use an expression inside component with content ending tag; use a bare component name or </&> instead");
150             }
151 0 0       0 if (!defined($comp)) {
152 0         0 $self->lexer->throw_syntax_error("Cannot match an expression as a component name; use </&> instead");
153             }
154 0 0       0 if ($call_end ne $comp) {
155 0         0 $self->lexer->throw_syntax_error("Component name in ending tag ($call_end) does not match component name in beginning tag ($comp)");
156             }
157             }
158              
159 2         6 my $code = "} }, $call\n );\n";
160              
161 2 50       7 eval { $self->postprocess_perl->(\$code) } if $self->postprocess_perl;
  0         0  
162 2 50       13 compiler_error $@ if $@;
163              
164 2         6 $self->_add_body_code($code);
165              
166 2         69 $c->{last_body_code_type} = 'component_content_call_end';
167             }
168             # END DIRECT THEFT FROM HTML-Mason 1.50
169              
170             1;
171              
172             __END__
173              
174             =pod
175              
176             =encoding UTF-8
177              
178             =head1 NAME
179              
180             HTML::MasonX::Free::Compiler - an HTML::Mason compiler that can reject more input
181              
182             =head1 VERSION
183              
184             version 0.007
185              
186             =head1 OVERVIEW
187              
188             This is an alternate compiler for HTML::Mason. It's meant to fill in for the
189             default, L<HTML::Mason::Compiler::ToObject>. (Don't trust things telling you
190             that the default is HTML::Mason::Compiler. If you're using Mason, you're
191             almost certainly have ToObject doing the work.)
192              
193             By default, it I<should> behave just like the normal compiler, but more options
194             can be provided to make it stricter.
195              
196             Right now, there's just one extra option, but there will be more.
197              
198             =head1 PERL VERSION
199              
200             This library should run on perls released even a long time ago. It should work
201             on any version of perl released in the last five years.
202              
203             Although it may work on older versions of perl, no guarantee is made that the
204             minimum required version will not be increased. The version may be increased
205             for any reason, and there is no promise that patches will be accepted to lower
206             the minimum required perl.
207              
208             =head1 ATTRIBUTES
209              
210             =head2 allow_stray_content
211              
212             If false, any text outside of a block (like a method or doc block), other than
213             blank lines, will be fatal. Similar, any Perl lines other than comments will
214             be fatal.
215              
216             =head2 default_method_to_call
217              
218             If set, this is the name of a method that will be dropped in place whenever the
219             user is trying to call a component without a method. For example, if you set
220             it to "main" then this:
221              
222             <& /foo/bar &>
223              
224             ...will be treated like this:
225              
226             <& /foo/bar:main &>
227              
228             To keep this consistent with the top-level called performed by the mason
229             interpreter, you should probably also use L<HTML::MasonX::Free::Component> as
230             your component class.
231              
232             =head1 AUTHOR
233              
234             Ricardo Signes <cpan@semiotic.systems>
235              
236             =head1 COPYRIGHT AND LICENSE
237              
238             This software is copyright (c) 2022 by Ricardo Signes.
239              
240             This is free software; you can redistribute it and/or modify it under
241             the same terms as the Perl 5 programming language system itself.
242              
243             =cut