line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Catalyst::View::Seamstress; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
1763927
|
use strict; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
54
|
|
4
|
|
|
|
|
|
|
# [10:05:57] <@andyg> Catalyst::View is the correct base class |
5
|
2
|
|
|
2
|
|
10
|
use base qw/Catalyst::View/; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
777
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
515173
|
use Data::Dumper; |
|
2
|
|
|
|
|
9393
|
|
|
2
|
|
|
|
|
839
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '2.2_002'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Catalyst::View::Seamstress - HTML::Seamstress View Class for Catalyst |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# use the helper to create MyApp::View::Seamstress |
19
|
|
|
|
|
|
|
# where comp_root and skeleton are optional |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
myapp_create.pl view Seamstress Seamstress /path/to/html html::skeleton |
22
|
|
|
|
|
|
|
^-modulenm ^-helpernm ^-comp_root ^-skeleton |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# optionally edit the skeleton and meat_pack routines |
25
|
|
|
|
|
|
|
# in lib/MyApp/View/Seamstress.pm |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# create your seamstress template packaged with spkg.pl |
28
|
|
|
|
|
|
|
# see HTML::Seamstress.. This will give you a .pm file to go with your html, |
29
|
|
|
|
|
|
|
# so something like html::helloworld |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub message : Global { |
34
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# LOOM points to our template class made with spkg.pl or |
37
|
|
|
|
|
|
|
# manually: |
38
|
|
|
|
|
|
|
$c->stash->{LOOM} = 'html::hello_world'; |
39
|
|
|
|
|
|
|
$c->stash->{name} = 'Mister GreenJeans'; |
40
|
|
|
|
|
|
|
$c->stash->{date} = 'Today'; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# the DefaultEnd plugin would mean no need for this line |
43
|
|
|
|
|
|
|
$c->forward('MyApp::View::Seamstress'); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# and in your html::helloworld you can do something like: |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub process{ |
49
|
|
|
|
|
|
|
my( $tree, $c, $stash ) = @_; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$tree->look_down( id => 'name' )->replace_content( $stash->{name} |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head1 DESCRIPTION |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
This is the Catalyst view class for L<HTML::Seamstress|HTML::Seamstress>. |
58
|
|
|
|
|
|
|
Your application should define a view class which is a subclass of |
59
|
|
|
|
|
|
|
this module. The easiest way to achieve this is using the |
60
|
|
|
|
|
|
|
F<myapp_create.pl> script (where F<myapp> should be replaced with |
61
|
|
|
|
|
|
|
whatever your application is called). This script is created as part |
62
|
|
|
|
|
|
|
of the Catalyst setup. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
$ script/myapp_create.pl view Seamstress Seamstress |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
This creates a MyApp::View::Seamstress.pm module in the |
67
|
|
|
|
|
|
|
F<lib> directory (again, replacing C<MyApp> with the name of your |
68
|
|
|
|
|
|
|
application). |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Now you can modify your action handlers in the main application and/or |
72
|
|
|
|
|
|
|
controllers to forward to your view class. You might choose to do this |
73
|
|
|
|
|
|
|
in the end() method, for example, to automatically forward all actions |
74
|
|
|
|
|
|
|
to the Seamstress view class. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# In MyApp or MyApp::Controller::SomeController |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub end : Private { |
79
|
|
|
|
|
|
|
my( $self, $c ) = @_; |
80
|
|
|
|
|
|
|
$c->forward('MyApp::View::Seamstress'); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Or you might like to use |
84
|
|
|
|
|
|
|
L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd> |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
or even |
87
|
|
|
|
|
|
|
L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 CONFIGURATION |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
The helper app automatically puts the per-application |
93
|
|
|
|
|
|
|
configuration info in C<MyApp::View::Seamstress>. You configure the |
94
|
|
|
|
|
|
|
per-request information (e.g. C<< $c->stash->{LOOM} >> and |
95
|
|
|
|
|
|
|
variables for this template) in your controller. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
The two main options which control how View::Seamtress renders HTML are the |
98
|
|
|
|
|
|
|
LOOM (which is taken from the stash) and optionally the skeleton, which is |
99
|
|
|
|
|
|
|
stored in the app config. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
If you just configure a LOOM then you are most likely using the "plain meat" method described below. If you also configure a skeleton in your config as well then you're using the "meat and skeleton" method. See below for a more detailed discussion of this! |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=over |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=item * C<< $c->stash->{LOOM} >> |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
The Seamstress view plugin MUST have a LOOM |
108
|
|
|
|
|
|
|
to work on or it |
109
|
|
|
|
|
|
|
will balk with an error: |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub message : Global { |
112
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
113
|
|
|
|
|
|
|
$c->stash->{LOOM} = 'html::hello_world'; |
114
|
|
|
|
|
|
|
$c->stash->{name} = 'Billy Bob'; |
115
|
|
|
|
|
|
|
$c->stash->{date} = 'medjool sahara'; |
116
|
|
|
|
|
|
|
$c->forward('MyApp::View::Seamstress'); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=item * C<< MyApp::View::Seamstress->config->{skeleton} >> |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
By default this is not set and the HTML output is simply the result of |
123
|
|
|
|
|
|
|
taking C<< $c->stash->{LOOM} >>, calling C<new()> to create |
124
|
|
|
|
|
|
|
an HTML tree and then passing this to C<process()> so that it can rework |
125
|
|
|
|
|
|
|
the tree. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
However, if C<< MyApp::View::Seamstress->config->{skeleton} >> is |
128
|
|
|
|
|
|
|
set, then both its value and the values of |
129
|
|
|
|
|
|
|
C<< MyApp::View::Seamstress->config->{meat_pack} >> |
130
|
|
|
|
|
|
|
and C<< $stash->{LOOM}->fixup() >> |
131
|
|
|
|
|
|
|
come into effect |
132
|
|
|
|
|
|
|
as described in L<HTML::Seamstress/"The_meat-skeleton_paradigm">. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
Let's take that a little slower: C<< $stash->{LOOM}->fixup() >> |
135
|
|
|
|
|
|
|
means: given a Seamstress-style Perl class, whose name is |
136
|
|
|
|
|
|
|
C<< $stash->{LOOM} >>, call the method C<fixup()> in that |
137
|
|
|
|
|
|
|
class so that it can do a final fixup of the entire HTML that is about |
138
|
|
|
|
|
|
|
to be shipped back to the client. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=back |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
The output generated from the LOOM |
143
|
|
|
|
|
|
|
(and possibly its interaction with a skeleton) |
144
|
|
|
|
|
|
|
is stored in |
145
|
|
|
|
|
|
|
C<< $c->response->body >>. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head2 Other Config Options |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=over |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item config->{fixup} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Set this to a coderef to allow the view to change the tree after the main |
155
|
|
|
|
|
|
|
processing phase. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=item config->{use_xhtml} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
By default the view will generate html 4 style html by calling as_HTML on the |
160
|
|
|
|
|
|
|
tree object. If you set this to a true value it will generate XHTML style HTML |
161
|
|
|
|
|
|
|
by calling as_XML on the tree object. See L<HTML::Element> for details for |
162
|
|
|
|
|
|
|
these methods. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Also note that this won't apply proper HTML doctypes and what-have-you unless |
165
|
|
|
|
|
|
|
you have them in your original HTML. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item config->{meat_pack} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
This is the subref which is called to pack meat into the skeleton for the meat |
170
|
|
|
|
|
|
|
skeleton method. Tinker with this to have more creative LOOMS. See "Funny |
171
|
|
|
|
|
|
|
LOOMs" and the meat/skeleton discussions. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=back |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head2 Funny LOOMs |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
In the examples so far the LOOM has always been a class name. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
If instead LOOM is an object then we'll assume that is a useful HTML::Element style |
180
|
|
|
|
|
|
|
object and just use that instead of calling C<new> on the LOOM. In this case we'll also not ->delete it at the end of the request so you'll have to do that yourself! |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
If the LOOM is in fact an ARRAY reference filled with class names we'll send the meat_pack a hash of class names mapped to objects. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=cut |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# process() |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# C<< eval-requires >> the module specified in C<< $c->stash->{LOOM} >>. |
190
|
|
|
|
|
|
|
# Gets the |
191
|
|
|
|
|
|
|
# C<HTML::Tree> representation of the file via C<new> and then calls |
192
|
|
|
|
|
|
|
# C<< $self->process($c, $c->stash) >> to rewrite the tree. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub page2tree { |
195
|
4
|
|
|
4
|
0
|
12
|
my ($self, $c, $page_class, $process_method) = @_; |
196
|
|
|
|
|
|
|
|
197
|
4
|
50
|
|
|
|
21
|
$c->log->debug(qq/Rendering template "$page_class"/) if $c->debug; |
198
|
|
|
|
|
|
|
|
199
|
4
|
|
50
|
|
|
41
|
$process_method ||= 'process'; |
200
|
|
|
|
|
|
|
|
201
|
4
|
|
|
|
|
7
|
my $page_object; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# IF we've been passed a page class, build an object: |
204
|
4
|
50
|
|
|
|
13
|
if (not ref $page_class) { |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# pull in the page class: |
207
|
4
|
|
|
|
|
220
|
eval "require $page_class"; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# emit errors if there were problems with the page_class: |
210
|
4
|
50
|
|
|
|
58566
|
if ($@) { |
211
|
0
|
|
|
|
|
0
|
my $error = qq/Couldn't load $page_class -- "$@"/; |
212
|
0
|
|
|
|
|
0
|
$c->log->error($error); |
213
|
0
|
|
|
|
|
0
|
$c->error($error); |
214
|
0
|
|
|
|
|
0
|
return 0; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
4
|
|
|
|
|
20
|
$page_object = $page_class->new($c); # e.g html::hello_world->new |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
# IF we've been passed a page object, just use it: |
220
|
|
|
|
|
|
|
else { |
221
|
0
|
|
|
|
|
0
|
$page_object = $page_class; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Run the process hook: |
225
|
4
|
|
|
|
|
6360
|
my $tree; eval { $tree = $page_object->$process_method($c, $c->stash) } ; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
19
|
|
226
|
|
|
|
|
|
|
|
227
|
4
|
50
|
|
|
|
553
|
if ( my $error = $@ ) { |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
0
|
chomp $error; |
230
|
0
|
|
|
|
|
0
|
$error = qq/process() failed in "$page_class". Error: "$error"/; |
231
|
0
|
|
|
|
|
0
|
$c->log->error($error); |
232
|
0
|
|
|
|
|
0
|
$c->error($error); |
233
|
0
|
|
|
|
|
0
|
return undef; |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
} else { |
236
|
|
|
|
|
|
|
|
237
|
4
|
|
|
|
|
14
|
return $tree; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Main view process hook: |
244
|
|
|
|
|
|
|
sub process { |
245
|
2
|
|
|
2
|
1
|
110677
|
my ( $self, $c ) = @_; |
246
|
|
|
|
|
|
|
|
247
|
2
|
|
|
|
|
7
|
my $body_is_skeleton = 0; |
248
|
|
|
|
|
|
|
|
249
|
2
|
|
|
|
|
5
|
my ($skeleton, $meat, $body) ; |
250
|
|
|
|
|
|
|
|
251
|
2
|
|
|
|
|
8
|
my $loom = $c->stash->{LOOM}; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
# check we actually got a loom to work with: |
254
|
2
|
50
|
|
|
|
153
|
unless ($loom) { |
255
|
0
|
0
|
|
|
|
0
|
$c->log->debug('No LOOM specified for rendering') if $c->debug; |
256
|
0
|
|
|
|
|
0
|
return 0; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
2
|
50
|
|
|
|
43
|
unless ( $c->response->content_type ) { |
260
|
2
|
|
|
|
|
516
|
$c->response->content_type('text/html; charset=utf-8'); |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
2
|
50
|
|
|
|
322
|
if (ref($loom) eq 'ARRAY') { |
265
|
|
|
|
|
|
|
map { |
266
|
0
|
|
|
|
|
0
|
$meat->{$_} = $self->page2tree($c, $_); |
|
0
|
|
|
|
|
0
|
|
267
|
|
|
|
|
|
|
} @$loom; |
268
|
|
|
|
|
|
|
} else { |
269
|
2
|
|
|
|
|
13
|
$meat = $body = $self->page2tree($c, $loom); |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# |
273
|
|
|
|
|
|
|
# render and pack MyApp::View::Seamstress->config->{skeleton} |
274
|
|
|
|
|
|
|
# if defined |
275
|
|
|
|
|
|
|
# |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
278
|
2
|
50
|
|
|
|
13
|
if ($skeleton = $self->config->{skeleton}) { |
279
|
2
|
|
|
|
|
175
|
$skeleton = $self->page2tree($c, $skeleton); |
280
|
|
|
|
|
|
|
|
281
|
2
|
|
|
|
|
9
|
$self->config->{meat_pack}->( |
282
|
|
|
|
|
|
|
$self, $c, $c->stash, $meat, $skeleton |
283
|
|
|
|
|
|
|
); |
284
|
|
|
|
|
|
|
|
285
|
2
|
|
|
|
|
655
|
$body_is_skeleton = 1; |
286
|
2
|
|
|
|
|
5
|
$body = $skeleton ; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# give the main view config an opportunity to twiddle the tree a bit: |
290
|
2
|
50
|
|
|
|
8
|
if ( ref $self->config->{fixup} ) { |
291
|
2
|
|
|
|
|
138
|
$self->config->{fixup}->($body, $c); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# take the the body and make some REAL html out of it! |
296
|
2
|
|
|
|
|
124
|
my $response_body; |
297
|
2
|
50
|
|
|
|
10
|
if ( $c->config->{use_xhtml} ) { |
298
|
0
|
|
|
|
|
0
|
$response_body = $body->as_XML( undef, ' ' ); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
else { |
301
|
2
|
|
|
|
|
174
|
$response_body = $body->as_HTML(undef, ' ') |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# stuff the response_body in the response body! |
305
|
2
|
|
|
|
|
2218
|
$c->response->body( $response_body ); |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# we delete the body unless our loom ( or skeleton if we have one) is a reference |
309
|
|
|
|
|
|
|
# which we take as a sign that the user is doing something more elaborate caching or something.. |
310
|
2
|
50
|
33
|
|
|
92
|
unless( (! $body_is_skeleton && ref $loom) || ( $body_is_skeleton && ref $self->config->{skeleton} ) ) { |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
311
|
2
|
|
|
|
|
153
|
$body->delete; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
2
|
|
|
|
|
242
|
return 1; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
;1; |
318
|
|
|
|
|
|
|
__END__ |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head1 The meat-skeleton paradigm |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Generally Catalyst::View::Seamstress operates in one of 2 ways: a plain meat |
323
|
|
|
|
|
|
|
way or a meat-skeleton way. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Plain meat is simple: the View takes C<$c->stash->{LOOM} > and calls |
326
|
|
|
|
|
|
|
C<new()> and C<process()> on it and stores the result in C<$c->response->body>. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
Meat-skeleton is designed to facilitate the way that most web sites are |
329
|
|
|
|
|
|
|
typically designed: |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
HTML pages typically have meat and a skeleton. The meat varies from page |
332
|
|
|
|
|
|
|
to page while the skeleton is fairly (though not completely) |
333
|
|
|
|
|
|
|
static. For example, the skeleton of a webpage is usually a header, a |
334
|
|
|
|
|
|
|
footer, and a navbar. The meat is what shows up when you click on a |
335
|
|
|
|
|
|
|
link on the page somewhere. While the meat will change with each |
336
|
|
|
|
|
|
|
click, the skeleton is rather static. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Mason accomodates the meat-skeleton paradigm via |
340
|
|
|
|
|
|
|
an C<autohandler> and C<< $m->call_next() >>. Template |
341
|
|
|
|
|
|
|
accomodates it via its C<WRAPPER> directive. |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
And Seamstress? Well, here's what you _can_ do: |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=over |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=item 1 generate the meat, C<$meat> |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
This is typically what you see in the C<body> part of an HTML page |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=item 2 generate the skeleton, C<$skeleton> |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
This is typically the html, head, and maybe some body |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=item 3 put the meat in the skeleton |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=back |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
So, nothing about this is forced. This is just how I typically do |
360
|
|
|
|
|
|
|
things and that is why |
361
|
|
|
|
|
|
|
L<Catalyst::View::Seamstress|Catalyst::View::Seamstress> has support |
362
|
|
|
|
|
|
|
for this. |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=head1 Tips to View Writers |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=head2 The order of use base is VERY significant |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
When your helper module creates C<MyApp::View::Seamstress> it is B<very> |
369
|
|
|
|
|
|
|
important for the C<use base> to look this way: |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
use base qw(Catalyst::View::Seamstress HTML::Seamstress ); |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
and not this way: |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
use base qw(HTML::Seamstress Catalyst::View::Seamstress ); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
so that certain calls (probably new) get handled properly. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head2 Getting config information from MyApp and MyApp::View::* |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
assuming C<Catalyst::View::Seamstress::new()> starts off |
382
|
|
|
|
|
|
|
like this: |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub new { |
385
|
|
|
|
|
|
|
my $self = shift; |
386
|
|
|
|
|
|
|
my $c = shift; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
C<< $self->config >> contains things set in C<MyApp::View::*>. |
389
|
|
|
|
|
|
|
C<< $c->config >> contains things set in C<MyApp> |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
assuming C<Catalyst::View::Seamstress::process()> starts off |
392
|
|
|
|
|
|
|
similarly: |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub process { |
395
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
C<< $self->config >> contains things set in C<MyApp::View::*>. |
398
|
|
|
|
|
|
|
C<< $c->config >> contains things set in C<MyApp>. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
There is no automatic merging of the two sources of configuration: you |
401
|
|
|
|
|
|
|
have to do that yourself if you want to do it. |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head2 |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=head1 SEE ALSO |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
L<Catalyst>, |
410
|
|
|
|
|
|
|
L<Catalyst::View>, |
411
|
|
|
|
|
|
|
L<Catalyst::Helper::View::Seamstress>, |
412
|
|
|
|
|
|
|
L<HTML::Seamstress> |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=head2 A working sample app |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
The best way to see a fully working Seamstress-style Perl class is to |
417
|
|
|
|
|
|
|
pull down the working sample app from sourceforge. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
A working sample app, which does both simple and |
420
|
|
|
|
|
|
|
meat-skeleton rendering is available from github: |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
git clone git://github.com/draxil/catalyst--view--seamstress-sample-app.git |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 SUPPORT |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Email the author or ping him on C<#catalyst> on C<irc.perl.org> |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head1 AUTHORS |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Terrence Brannon <metaperl@gmail.com> |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
With some additional hacking by: |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
Joe Higton <draxil@cpan.org> |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head1 COPYRIGHT |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
This program is free software, you can redistribute it and/or modify it |
439
|
|
|
|
|
|
|
under the same terms as Perl itself. |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=cut |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
|