4 use HTML::Zoom::Parser::BuiltIn;
5 use HTML::Zoom::Producer::BuiltIn;
6 use HTML::Zoom::SelectorParser;
7 use HTML::Zoom::FilterBuilder;
8 use HTML::Zoom::FilterStream;
13 <span class="hilight name">Bob</span>
14 <span class="career">Builder</span>
20 sub src_stream { HTML::Zoom::Parser::BuiltIn->new->html_to_stream($tmpl); }
22 sub html_sink { HTML::Zoom::Producer::BuiltIn->new->html_from_stream($_[0]) }
24 my $fb = HTML::Zoom::FilterBuilder->new;
26 my $sp = HTML::Zoom::SelectorParser->new;
29 my ($stream, $sel, $cb) = @_;
30 return HTML::Zoom::FilterStream->new({
32 match => $sp->parse_selector($sel),
33 filter => do { local $_ = $fb; $cb->($fb) }
50 ($expect = $tmpl) =~ s/class="main"/class="foo"/;
53 run_for { $_->set_attribute( 'class' => 'foo' ) },
55 'set attribute on existing attribute'
58 ($expect = $tmpl) =~ s/class="main"/class="foo"/;
61 run_for { $_->set_attr({ name => 'class', value => 'foo' }) },
63 'set attribute on existing attribute (shorthand)'
66 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
69 run_for { $_->set_attribute( 'foo' => 'bar' ) },
71 'set attribute on non existing attribute'
74 ($expect = $tmpl) =~ s/class="main"/class="main foo"/;
77 run_for { $_->add_to_attribute( 'class' => 'foo' ) },
79 'add attribute on existing attribute'
82 ($expect = $tmpl) =~ s/class="main"/class="main foo"/;
85 run_for { $_->add_class('foo') },
87 'add attribute on existing attribute (shorthand)'
90 ($expect = $tmpl) =~ s/class="main"/class="main" id="foo"/;
93 run_for { $_->set_id('foo') },
98 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
101 run_for { $_->add_to_attribute( 'foo' => 'bar' ) },
103 'add attribute on non existing attribute'
106 ($expect = $tmpl) =~ s/ class="main"//;
109 run_for { $_->remove_attribute({ name => 'class' }) },
111 'remove attribute on existing attribute'
115 run_for { $_->remove_attribute({ name => 'foo' }) },
117 'remove attribute on non existing attribute'
120 ($expect = $tmpl) =~ s/class="main"/class=""/;
123 run_for { $_->remove_from_attribute({ class => 'main' }) },
125 'remove name from attribute'
129 run_for { $_->remove_from_attribute({ madeup => 'main' }) },
131 'remove name from non existing attribute (ignored)'
134 ($expect = $tmpl) =~ s/class="main"/class=""/;
137 run_for { $_->remove_class( 'main' ) },
142 ($expect = $tmpl) =~ s/ class="main"//;
146 $_->transform_attribute({
150 return if $a eq 'main';
156 'transform_attribute deletes the attr if code returns undef',
159 ($expect = $tmpl) =~ s/ class="main"/ class="moan"/;
163 $_->transform_attribute({
166 ( my $b = shift ) =~ s/main/moan/;
172 'transform_attribute transforms something',
175 ($expect = $tmpl) =~ s/ class="main"/ class="main" noggin="zonk"/;
179 $_->transform_attribute({
181 code => sub { 'zonk' },
185 'transform_attribute adds attribute if not there before',
190 $_->transform_attribute({
196 'transform_attribute on nonexistent att does not add it if code returns undef',
200 ($expect = $tmpl) =~ s/(?=<div)/O HAI/;
202 my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
205 run_for { $_->add_before($ohai) },
210 ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
213 run_for { $_->add_after($ohai) },
218 ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
221 run_for { $_->prepend_content($ohai) },
226 ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
229 (run_for { $_->prepend_content($ohai) } 'hr'),
231 'prepend_content ok with in place close'
235 run_for { $_->replace($ohai) },
246 run_for { $_->collect({ into => \@ev }) },
251 'collect removes without passthrough'
255 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
257 <span class="hilight name">Bob</span>
258 <span class="career">Builder</span>
261 'collect collected right events'
267 run_for { $_->collect({ into => \@ev, content => 1 }) },
269 <div class="main"></div>
272 'collect w/content removes correctly'
276 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
278 <span class="hilight name">Bob</span>
279 <span class="career">Builder</span>
282 'collect w/content collects correctly'
286 run_for { $_->replace($ohai, { content => 1 }) },
288 <div class="main">O HAI</div>
294 ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
297 run_for { $_->append_content($ohai) },
302 my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } };
310 filter($_ => '.name' => $r_content->('mst'))
311 => '.career' => $r_content->('Chainsaw Wielder')
315 filter($_ => '.name' => $r_content->('mdk'))
316 => '.career' => $r_content->('Adminion')
323 <span class="hilight name">mst</span>
324 <span class="career">Chainsaw Wielder</span>
326 </div><div class="main">
327 <span class="hilight name">mdk</span>
328 <span class="career">Adminion</span>
342 filter($_ => '.name' => $r_content->('mst'))
343 => '.career' => $r_content->('Chainsaw Wielder')
347 filter($_ => '.name' => $r_content->('mdk'))
348 => '.career' => $r_content->('Adminion')
355 <span class="hilight name">mst</span>
356 <span class="career">Chainsaw Wielder</span>
359 <span class="hilight name">mdk</span>
360 <span class="career">Adminion</span>
374 HTML::Zoom::ArrayStream->new({ array => [
376 filter($_ => '.name' => $r_content->('mst'))
377 => '.career' => $r_content->('Chainsaw Wielder')),
378 HTML::Zoom::ArrayStream->new({ array => \@between })
383 filter($_ => '.name' => $r_content->('mdk'))
384 => '.career' => $r_content->('Adminion')
388 filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) }
395 <span class="hilight name">mst</span>
396 <span class="career">Chainsaw Wielder</span>
398 <span class="hilight name">mdk</span>
399 <span class="career">Adminion</span>
404 'repeat_content with filter ok'
414 filter($_ => '.name' => $r_content->('mst'))
415 => '.career' => $r_content->('Chainsaw Wielder')
419 filter($_ => '.name' => $r_content->('mdk'))
420 => '.career' => $r_content->('Adminion')
423 { repeat_between => 'hr' }
428 <span class="hilight name">mst</span>
429 <span class="career">Chainsaw Wielder</span>
431 <span class="hilight name">mdk</span>
432 <span class="career">Adminion</span>
437 'repeat_content using repeat_between ok'