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   447475 use strict;
  4         6  
  4         99  
2 4     4   12 use warnings;
  4         8  
  4         174  
3             package HTML::MasonX::Free::Compiler;
4             $HTML::MasonX::Free::Compiler::VERSION = '0.006';
5             # ABSTRACT: an HTML::Mason compiler that can reject more input
6 4     4   13 use parent 'HTML::Mason::Compiler::ToObject';
  4         5  
  4         30  
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   57919 use namespace::autoclean;
  4         32250  
  4         12  
45              
46 4     4   192 use HTML::Mason::Exceptions(abbr => [qw(param_error)]);
  4         7  
  4         25  
47              
48 4     4   163 use Params::Validate qw(:all);
  4         7  
  4         754  
49             Params::Validate::validation_options(on_fail => sub {param_error join '', @_});
50              
51             BEGIN {
52 4     4   61 __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 13788 my ($self, %arg) = @_;
70 45 100 100     174 if (
      100        
71             $self->{current_compile}{in_main}
72             and ! $self->{allow_stray_content}
73             and $arg{text} =~ /\S/
74             ) {
75 1         3 $self->lexer->throw_syntax_error(
76             "text outside of block: <<'END_TEXT'\n$arg{text}END_TEXT"
77             );
78             }
79 44         123 $self->SUPER::text(%arg);
80             }
81              
82             sub perl_line {
83 4     4 1 3507 my ($self, %arg) = @_;
84              
85 4 100 66     40 if (
      100        
86             $self->{current_compile}{in_main}
87             and ! $self->{allow_stray_content}
88             and $arg{line} !~ /\A\s*#/
89             ) {
90 1         3 $self->lexer->throw_syntax_error(
91             "perl outside of block: $arg{line}\n"
92             );
93             }
94 3         21 $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 1210 my $self = shift;
101 11         19 my %p = @_;
102              
103 11         35 my ($prespace, $call, $postspace) = ($p{call} =~ /(\s*)(.*)(\s*)/s);
104 11 50       52 if ( $call =~ m,^[\w/.],)
105             {
106 11         18 my $comma = index($call, ',');
107 11 50       17 $comma = length $call if $comma == -1;
108 11         41 (my $comp = substr($call, 0, $comma)) =~ s/\s+$//;
109 11 100 66     55 if (defined $self->{default_method_to_call} and $comp !~ /:/) { ##
110 2         5 $comp = "$comp:$self->{default_method_to_call}"; ##
111             } ##
112 11         21 $call = "'$comp'" . substr($call, $comma);
113             }
114 11         19 my $code = "\$m->comp( $prespace $call $postspace \n); ";
115 11 50       29 eval { $self->postprocess_perl->(\$code) } if $self->postprocess_perl;
  0         0  
116 11 50       41 compiler_error $@ if $@;
117              
118 11         19 $self->_add_body_code($code);
119              
120 11         235 $self->{current_compile}{last_body_code_type} = 'component_call';
121             }
122              
123             sub component_content_call_end
124             {
125 2     2 1 123 my $self = shift;
126 2         2 my $c = $self->{current_compile};
127 2         4 my %p = @_;
128              
129             $self->lexer->throw_syntax_error("Found component with content ending tag but no beginning tag")
130 2 50       3 unless @{ $c->{comp_with_content_stack} };
  2         5  
131              
132 2         3 my $call = pop @{ $c->{comp_with_content_stack} };
  2         4  
133 2         2 my $call_end = $p{call_end};
134 2         3 for ($call_end) { s/^\s+//; s/\s+$//; }
  2         3  
  2         3  
135              
136 2         2 my $comp = undef;
137 2 50       6 if ( $call =~ m,^[\w/.],)
138             {
139 2         3 my $comma = index($call, ',');
140 2 50       5 $comma = length $call if $comma == -1;
141 2         5 ($comp = substr($call, 0, $comma)) =~ s/\s+$//;
142 2 100 66     11 if (defined $self->{default_method_to_call} and $comp !~ /:/) { ##
143 1         4 $comp = "$comp:$self->{default_method_to_call}"; ##
144             } ##
145 2         4 $call = "'$comp'" . substr($call, $comma);
146             }
147 2 50       3 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         5 my $code = "} }, $call\n );\n";
160              
161 2 50       3 eval { $self->postprocess_perl->(\$code) } if $self->postprocess_perl;
  0         0  
162 2 50       10 compiler_error $@ if $@;
163              
164 2         5 $self->_add_body_code($code);
165              
166 2         40 $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.006
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 ATTRIBUTES
199              
200             =head2 allow_stray_content
201              
202             If false, any text outside of a block (like a method or doc block), other than
203             blank lines, will be fatal. Similar, any Perl lines other than comments will
204             be fatal.
205              
206             =head2 default_method_to_call
207              
208             If set, this is the name of a method that will be dropped in place whenever the
209             user is trying to call a component without a method. For example, if you set
210             it to "main" then this:
211              
212             <& /foo/bar &>
213              
214             ...will be treated like this:
215              
216             <& /foo/bar:main &>
217              
218             To keep this consistent with the top-level called performed by the mason
219             interpreter, you should probably also use L<HTML::MasonX::Free::Component> as
220             your component class.
221              
222             =head1 AUTHOR
223              
224             Ricardo Signes <rjbs@cpan.org>
225              
226             =head1 COPYRIGHT AND LICENSE
227              
228             This software is copyright (c) 2016 by Ricardo Signes.
229              
230             This is free software; you can redistribute it and/or modify it under
231             the same terms as the Perl 5 programming language system itself.
232              
233             =cut