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;
12 <div name="cow" class="main">
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/name="cow" class="main"/name="bar" class="foo"/;
61 run_for { $_->set_attribute({ 'class' => 'foo', 'name' => 'bar'}) },
63 'set attributes using hashref form'
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="bar"/;
85 run_for { $_->add_to_attribute( 'foo' => 'bar' ) },
87 'add attribute on non existing attribute'
90 ($expect = $tmpl) =~ s/ class="main"//;
93 run_for { $_->remove_attribute({ name => 'class' }) },
95 'remove attribute on existing attribute'
99 run_for { $_->remove_attribute({ name => 'foo' }) },
101 'remove attribute on non existing attribute'
104 ($expect = $tmpl) =~ s/ class="main"//;
108 $_->transform_attribute({
112 return if $a eq 'main';
118 'transform_attribute deletes the attr if code returns undef',
121 ($expect = $tmpl) =~ s/ class="main"/ class="moan"/;
125 $_->transform_attribute({
128 ( my $b = shift ) =~ s/main/moan/;
134 'transform_attribute transforms something',
137 ($expect = $tmpl) =~ s/ class="main"/ class="main" noggin="zonk"/;
141 $_->transform_attribute({
143 code => sub { 'zonk' },
147 'transform_attribute adds attribute if not there before',
152 $_->transform_attribute({
158 'transform_attribute on nonexistent att does not add it if code returns undef',
162 ($expect = $tmpl) =~ s/(?=<div)/O HAI/;
164 my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
167 run_for { $_->add_before($ohai) },
172 ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
175 run_for { $_->add_after($ohai) },
180 ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
183 run_for { $_->prepend_content($ohai) },
188 ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
191 (run_for { $_->prepend_content($ohai) } 'hr'),
193 'prepend_content ok with in place close'
197 run_for { $_->replace($ohai) },
208 run_for { $_->collect({ into => \@ev }) },
213 'collect removes without passthrough'
217 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
218 '<div name="cow" class="main">
219 <span class="hilight name">Bob</span>
220 <span class="career">Builder</span>
223 'collect collected right events'
229 run_for { $_->collect({ into => \@ev, content => 1 }) },
231 <div name="cow" class="main"></div>
234 'collect w/content removes correctly'
238 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
240 <span class="hilight name">Bob</span>
241 <span class="career">Builder</span>
244 'collect w/content collects correctly'
248 run_for { $_->replace($ohai, { content => 1 }) },
250 <div name="cow" class="main">O HAI</div>
256 ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
259 run_for { $_->append_content($ohai) },
264 my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } };
272 filter($_ => '.name' => $r_content->('mst'))
273 => '.career' => $r_content->('Chainsaw Wielder')
277 filter($_ => '.name' => $r_content->('mdk'))
278 => '.career' => $r_content->('Adminion')
284 <div name="cow" class="main">
285 <span class="hilight name">mst</span>
286 <span class="career">Chainsaw Wielder</span>
288 </div><div name="cow" class="main">
289 <span class="hilight name">mdk</span>
290 <span class="career">Adminion</span>
304 filter($_ => '.name' => $r_content->('mst'))
305 => '.career' => $r_content->('Chainsaw Wielder')
309 filter($_ => '.name' => $r_content->('mdk'))
310 => '.career' => $r_content->('Adminion')
316 <div name="cow" class="main">
317 <span class="hilight name">mst</span>
318 <span class="career">Chainsaw Wielder</span>
321 <span class="hilight name">mdk</span>
322 <span class="career">Adminion</span>
336 HTML::Zoom::ArrayStream->new({ array => [
338 filter($_ => '.name' => $r_content->('mst'))
339 => '.career' => $r_content->('Chainsaw Wielder')),
340 HTML::Zoom::ArrayStream->new({ array => \@between })
345 filter($_ => '.name' => $r_content->('mdk'))
346 => '.career' => $r_content->('Adminion')
350 filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) }
356 <div name="cow" class="main">
357 <span class="hilight name">mst</span>
358 <span class="career">Chainsaw Wielder</span>
360 <span class="hilight name">mdk</span>
361 <span class="career">Adminion</span>
366 'repeat_content with filter ok'
376 filter($_ => '.name' => $r_content->('mst'))
377 => '.career' => $r_content->('Chainsaw Wielder')
381 filter($_ => '.name' => $r_content->('mdk'))
382 => '.career' => $r_content->('Adminion')
385 { repeat_between => 'hr' }
389 <div name="cow" class="main">
390 <span class="hilight name">mst</span>
391 <span class="career">Chainsaw Wielder</span>
393 <span class="hilight name">mdk</span>
394 <span class="career">Adminion</span>
399 'repeat_content using repeat_between ok'