add transform_attribute, which runs a coderef on the value of an attribute, and can...
[catagits/HTML-Zoom.git] / t / actions.t
CommitLineData
1cf03540 1use strictures 1;
456a815d 2use Test::More;
3
4use HTML::Zoom::Parser::BuiltIn;
5use HTML::Zoom::Producer::BuiltIn;
6use HTML::Zoom::SelectorParser;
7use HTML::Zoom::FilterBuilder;
8use HTML::Zoom::FilterStream;
9
10my $tmpl = <<END;
11<body>
12 <div class="main">
13 <span class="hilight name">Bob</span>
14 <span class="career">Builder</span>
15 <hr />
16 </div>
17</body>
18END
19
d80786d0 20sub src_stream { HTML::Zoom::Parser::BuiltIn->new->html_to_stream($tmpl); }
456a815d 21
d80786d0 22sub html_sink { HTML::Zoom::Producer::BuiltIn->new->html_from_stream($_[0]) }
456a815d 23
24my $fb = HTML::Zoom::FilterBuilder->new;
25
26my $sp = HTML::Zoom::SelectorParser->new;
27
28sub filter {
29 my ($stream, $sel, $cb) = @_;
30 return HTML::Zoom::FilterStream->new({
31 stream => $stream,
32 match => $sp->parse_selector($sel),
33 filter => do { local $_ = $fb; $cb->($fb) }
34 });
35}
36
37sub run_for (&;$) {
38 my $cb = shift;
39 (html_sink
40 (filter
41 src_stream,
42 (shift or '.main'),
43 $cb
44 )
45 )
46}
47
8f962884 48my ($expect, @ev);
49
50($expect = $tmpl) =~ s/class="main"/class="foo"/;
51
52is(
53 run_for { $_->set_attribute({ name => 'class', value => 'foo' }) },
54 $expect,
55 'set attribute on existing attribute'
56);
57
58($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
59
60is(
61 run_for { $_->set_attribute({ name => 'foo', value => 'bar' }) },
62 $expect,
63 'set attribute on non existing attribute'
64);
65
66($expect = $tmpl) =~ s/class="main"/class="main foo"/;
67
68is(
2daa653a 69 run_for { $_->add_to_attribute({ name => 'class', value => 'foo' }) },
8f962884 70 $expect,
71 'add attribute on existing attribute'
72);
73
74($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
75
76is(
2daa653a 77 run_for { $_->add_to_attribute({ name => 'foo', value => 'bar' }) },
8f962884 78 $expect,
79 'add attribute on non existing attribute'
80);
81
82($expect = $tmpl) =~ s/ class="main"//;
83
84is(
85 run_for { $_->remove_attribute({ name => 'class' }) },
86 $expect,
87 'remove attribute on existing attribute'
88);
89
90is(
91 run_for { $_->remove_attribute({ name => 'foo' }) },
92 $tmpl,
93 'remove attribute on non existing attribute'
94);
95
5cac799e 96($expect = $tmpl) =~ s/ class="main"//;
97
98is(
99 run_for {
100 $_->transform_attribute({
101 name => 'class',
102 code => sub {
103 my $a = shift;
104 return if $a eq 'main';
105 return $a;
106 },
107 })
108 },
109 $expect,
110 'transform_attribute deletes the attr if code returns undef',
111 );
112
113($expect = $tmpl) =~ s/ class="main"/ class="moan"/;
114
115is(
116 run_for {
117 $_->transform_attribute({
118 name => 'class',
119 code => sub {
120 ( my $b = shift ) =~ s/main/moan/;
121 $b
122 },
123 })
124 },
125 $expect,
126 'transform_attribute transforms something',
127 );
128
129($expect = $tmpl) =~ s/ class="main"/ class="main" noggin="zonk"/;
130
131is(
132 run_for {
133 $_->transform_attribute({
134 name => 'noggin',
135 code => sub { 'zonk' },
136 })
137 },
138 $expect,
139 'transform_attribute adds attribute if not there before',
140 );
141
142is(
143 run_for {
144 $_->transform_attribute({
145 name => 'noggin',
146 code => sub { },
147 })
148 },
149 $tmpl,
150 'transform_attribute on nonexistent att does not add it if code returns undef',
151 );
152
153
8f962884 154($expect = $tmpl) =~ s/(?=<div)/O HAI/;
456a815d 155
156my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
157
158is(
159 run_for { $_->add_before($ohai) },
160 $expect,
161 'add_before ok'
162);
163
164($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
165
166is(
167 run_for { $_->add_after($ohai) },
168 $expect,
169 'add_after ok'
170);
171
172($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
173
174is(
865bb5d2 175 run_for { $_->prepend_content($ohai) },
456a815d 176 $expect,
865bb5d2 177 'prepend_content ok'
456a815d 178);
179
180($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
181
182is(
865bb5d2 183 (run_for { $_->prepend_content($ohai) } 'hr'),
456a815d 184 $expect,
865bb5d2 185 'prepend_content ok with in place close'
456a815d 186);
187
188is(
189 run_for { $_->replace($ohai) },
190'<body>
191 O HAI
192</body>
193',
194 'replace ok'
195);
196
8f962884 197@ev = ();
c86c0ce2 198
199is(
200 run_for { $_->collect({ into => \@ev }) },
201 '<body>
202
203</body>
204',
205 'collect removes without passthrough'
206);
207
208is(
209 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
210 '<div class="main">
211 <span class="hilight name">Bob</span>
212 <span class="career">Builder</span>
213 <hr />
214 </div>',
215 'collect collected right events'
216);
41153e87 217
8f962884 218@ev = ();
41153e87 219
220is(
865bb5d2 221 run_for { $_->collect({ into => \@ev, content => 1 }) },
8f962884 222 '<body>
223 <div class="main"></div>
224</body>
225',
865bb5d2 226 'collect w/content removes correctly'
41153e87 227);
228
229is(
8f962884 230 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
231 '
232 <span class="hilight name">Bob</span>
233 <span class="career">Builder</span>
234 <hr />
235 ',
865bb5d2 236 'collect w/content collects correctly'
41153e87 237);
238
11cc25dd 239is(
865bb5d2 240 run_for { $_->replace($ohai, { content => 1 }) },
11cc25dd 241 '<body>
242 <div class="main">O HAI</div>
243</body>
244',
865bb5d2 245 'replace w/content'
11cc25dd 246);
247
a25b8d4d 248($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
249
250is(
865bb5d2 251 run_for { $_->append_content($ohai) },
a25b8d4d 252 $expect,
865bb5d2 253 'append content ok'
a25b8d4d 254);
255
865bb5d2 256my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } };
3cdbc13f 257
258is(
259 run_for {
260 $_->repeat(
261 [
262 sub {
263 filter
865bb5d2 264 filter($_ => '.name' => $r_content->('mst'))
265 => '.career' => $r_content->('Chainsaw Wielder')
3cdbc13f 266 },
267 sub {
268 filter
865bb5d2 269 filter($_ => '.name' => $r_content->('mdk'))
270 => '.career' => $r_content->('Adminion')
3cdbc13f 271 },
272 ]
273 )
274 },
275 q{<body>
276 <div class="main">
277 <span class="hilight name">mst</span>
278 <span class="career">Chainsaw Wielder</span>
279 <hr />
280 </div><div class="main">
281 <span class="hilight name">mdk</span>
282 <span class="career">Adminion</span>
283 <hr />
284 </div>
285</body>
286},
287 'repeat ok'
288);
289
865bb5d2 290is(
291 run_for {
292 $_->repeat_content(
293 [
294 sub {
295 filter
296 filter($_ => '.name' => $r_content->('mst'))
297 => '.career' => $r_content->('Chainsaw Wielder')
298 },
299 sub {
300 filter
301 filter($_ => '.name' => $r_content->('mdk'))
302 => '.career' => $r_content->('Adminion')
303 },
304 ]
305 )
306 },
307 q{<body>
308 <div class="main">
309 <span class="hilight name">mst</span>
310 <span class="career">Chainsaw Wielder</span>
311 <hr />
312
313 <span class="hilight name">mdk</span>
314 <span class="career">Adminion</span>
315 <hr />
316 </div>
317</body>
318},
319 'repeat_content ok'
320);
3cdbc13f 321
dae33531 322is(
323 run_for {
324 my @between;
325 $_->repeat_content(
326 [
327 sub {
b5a48c47 328 HTML::Zoom::ArrayStream->new({ array => [
dae33531 329 (filter
330 filter($_ => '.name' => $r_content->('mst'))
331 => '.career' => $r_content->('Chainsaw Wielder')),
b5a48c47 332 HTML::Zoom::ArrayStream->new({ array => \@between })
333 ] })->flatten
dae33531 334 },
335 sub {
336 filter
337 filter($_ => '.name' => $r_content->('mdk'))
338 => '.career' => $r_content->('Adminion')
339 },
340 ],
341 { filter => sub {
342 filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) }
343 }
344 }
345 )
346 },
347 q{<body>
348 <div class="main">
349 <span class="hilight name">mst</span>
350 <span class="career">Chainsaw Wielder</span>
351 <hr />
352 <span class="hilight name">mdk</span>
353 <span class="career">Adminion</span>
354
355 </div>
356</body>
357},
358 'repeat_content with filter ok'
359);
360
f8ed299b 361is(
362 run_for {
363 my @between;
364 $_->repeat_content(
365 [
366 sub {
367 filter
368 filter($_ => '.name' => $r_content->('mst'))
369 => '.career' => $r_content->('Chainsaw Wielder')
370 },
371 sub {
372 filter
373 filter($_ => '.name' => $r_content->('mdk'))
374 => '.career' => $r_content->('Adminion')
375 },
376 ],
377 { repeat_between => 'hr' }
378 )
379 },
380 q{<body>
381 <div class="main">
382 <span class="hilight name">mst</span>
383 <span class="career">Chainsaw Wielder</span>
384 <hr />
385 <span class="hilight name">mdk</span>
386 <span class="career">Adminion</span>
387
388 </div>
389</body>
390},
391 'repeat_content using repeat_between ok'
392);
393
456a815d 394done_testing;