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({ name => 'class', value => 'foo' }) },
55 'set attribute on existing attribute'
58 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
61 run_for { $_->set_attribute({ name => 'foo', value => 'bar' }) },
63 'set attribute on non existing attribute'
66 ($expect = $tmpl) =~ s/class="main"/class="main foo"/;
69 run_for { $_->add_to_attribute({ name => 'class', value => 'foo' }) },
71 'add attribute on existing attribute'
74 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
77 run_for { $_->add_to_attribute({ name => 'foo', value => 'bar' }) },
79 'add attribute on non existing attribute'
82 ($expect = $tmpl) =~ s/ class="main"//;
85 run_for { $_->remove_attribute({ name => 'class' }) },
87 'remove attribute on existing attribute'
91 run_for { $_->remove_attribute({ name => 'foo' }) },
93 'remove attribute on non existing attribute'
96 ($expect = $tmpl) =~ s/(?=<div)/O HAI/;
98 my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
101 run_for { $_->add_before($ohai) },
106 ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
109 run_for { $_->add_after($ohai) },
114 ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
117 run_for { $_->prepend_content($ohai) },
122 ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
125 (run_for { $_->prepend_content($ohai) } 'hr'),
127 'prepend_content ok with in place close'
131 run_for { $_->replace($ohai) },
142 run_for { $_->collect({ into => \@ev }) },
147 'collect removes without passthrough'
151 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
153 <span class="hilight name">Bob</span>
154 <span class="career">Builder</span>
157 'collect collected right events'
163 run_for { $_->collect({ into => \@ev, content => 1 }) },
165 <div class="main"></div>
168 'collect w/content removes correctly'
172 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
174 <span class="hilight name">Bob</span>
175 <span class="career">Builder</span>
178 'collect w/content collects correctly'
182 run_for { $_->replace($ohai, { content => 1 }) },
184 <div class="main">O HAI</div>
190 ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
193 run_for { $_->append_content($ohai) },
198 my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } };
206 filter($_ => '.name' => $r_content->('mst'))
207 => '.career' => $r_content->('Chainsaw Wielder')
211 filter($_ => '.name' => $r_content->('mdk'))
212 => '.career' => $r_content->('Adminion')
219 <span class="hilight name">mst</span>
220 <span class="career">Chainsaw Wielder</span>
222 </div><div class="main">
223 <span class="hilight name">mdk</span>
224 <span class="career">Adminion</span>
238 filter($_ => '.name' => $r_content->('mst'))
239 => '.career' => $r_content->('Chainsaw Wielder')
243 filter($_ => '.name' => $r_content->('mdk'))
244 => '.career' => $r_content->('Adminion')
251 <span class="hilight name">mst</span>
252 <span class="career">Chainsaw Wielder</span>
255 <span class="hilight name">mdk</span>
256 <span class="career">Adminion</span>
270 HTML::Zoom::ArrayStream->new({ array => [
272 filter($_ => '.name' => $r_content->('mst'))
273 => '.career' => $r_content->('Chainsaw Wielder')),
274 HTML::Zoom::ArrayStream->new({ array => \@between })
279 filter($_ => '.name' => $r_content->('mdk'))
280 => '.career' => $r_content->('Adminion')
284 filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) }
291 <span class="hilight name">mst</span>
292 <span class="career">Chainsaw Wielder</span>
294 <span class="hilight name">mdk</span>
295 <span class="career">Adminion</span>
300 'repeat_content with filter ok'
310 filter($_ => '.name' => $r_content->('mst'))
311 => '.career' => $r_content->('Chainsaw Wielder')
315 filter($_ => '.name' => $r_content->('mdk'))
316 => '.career' => $r_content->('Adminion')
319 { repeat_between => 'hr' }
324 <span class="hilight name">mst</span>
325 <span class="career">Chainsaw Wielder</span>
327 <span class="hilight name">mdk</span>
328 <span class="career">Adminion</span>
333 'repeat_content using repeat_between ok'