2 use warnings FATAL => 'all';
5 use HTML::Zoom::Parser::BuiltIn;
6 use HTML::Zoom::Producer::BuiltIn;
7 use HTML::Zoom::SelectorParser;
8 use HTML::Zoom::FilterBuilder;
9 use HTML::Zoom::FilterStream;
14 <span class="hilight name">Bob</span>
15 <span class="career">Builder</span>
21 sub src_stream { HTML::Zoom::Parser::BuiltIn->new->html_to_stream($tmpl); }
23 sub html_sink { HTML::Zoom::Producer::BuiltIn->new->html_from_stream($_[0]) }
25 my $fb = HTML::Zoom::FilterBuilder->new;
27 my $sp = HTML::Zoom::SelectorParser->new;
30 my ($stream, $sel, $cb) = @_;
31 return HTML::Zoom::FilterStream->new({
33 match => $sp->parse_selector($sel),
34 filter => do { local $_ = $fb; $cb->($fb) }
51 ($expect = $tmpl) =~ s/class="main"/class="foo"/;
54 run_for { $_->set_attribute({ name => 'class', value => 'foo' }) },
56 'set attribute on existing attribute'
59 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
62 run_for { $_->set_attribute({ name => 'foo', value => 'bar' }) },
64 'set attribute on non existing attribute'
67 ($expect = $tmpl) =~ s/class="main"/class="main foo"/;
70 run_for { $_->add_to_attribute({ name => 'class', value => 'foo' }) },
72 'add attribute on existing attribute'
75 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
78 run_for { $_->add_to_attribute({ name => 'foo', value => 'bar' }) },
80 'add attribute on non existing attribute'
83 ($expect = $tmpl) =~ s/ class="main"//;
86 run_for { $_->remove_attribute({ name => 'class' }) },
88 'remove attribute on existing attribute'
92 run_for { $_->remove_attribute({ name => 'foo' }) },
94 'remove attribute on non existing attribute'
97 ($expect = $tmpl) =~ s/(?=<div)/O HAI/;
99 my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
102 run_for { $_->add_before($ohai) },
104 'add_before event ok'
107 eval { run_for { $_->add_before('O HAI') } },
109 'add_before string ok'
112 ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
115 run_for { $_->add_after($ohai) },
120 eval { run_for { $_->add_after('O HAI') } },
122 'add_after string ok'
125 ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
128 run_for { $_->prepend_content($ohai) },
133 ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
136 (run_for { $_->prepend_content($ohai) } 'hr'),
138 'prepend_content ok with in place close'
147 run_for { $_->replace($ohai) },
152 run_for { $_->replace('O HAI') },
160 run_for { $_->collect({ into => \@ev }) },
165 'collect removes without passthrough'
169 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
171 <span class="hilight name">Bob</span>
172 <span class="career">Builder</span>
175 'collect collected right events'
181 run_for { $_->collect({ into => \@ev, content => 1 }) },
183 <div class="main"></div>
186 'collect w/content removes correctly'
190 HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
192 <span class="hilight name">Bob</span>
193 <span class="career">Builder</span>
196 'collect w/content collects correctly'
200 run_for { $_->replace($ohai, { content => 1 }) },
202 <div class="main">O HAI</div>
208 ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
211 run_for { $_->append_content($ohai) },
216 my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } };
224 filter($_ => '.name' => $r_content->('mst'))
225 => '.career' => $r_content->('Chainsaw Wielder')
229 filter($_ => '.name' => $r_content->('mdk'))
230 => '.career' => $r_content->('Adminion')
237 <span class="hilight name">mst</span>
238 <span class="career">Chainsaw Wielder</span>
240 </div><div class="main">
241 <span class="hilight name">mdk</span>
242 <span class="career">Adminion</span>
256 filter($_ => '.name' => $r_content->('mst'))
257 => '.career' => $r_content->('Chainsaw Wielder')
261 filter($_ => '.name' => $r_content->('mdk'))
262 => '.career' => $r_content->('Adminion')
269 <span class="hilight name">mst</span>
270 <span class="career">Chainsaw Wielder</span>
273 <span class="hilight name">mdk</span>
274 <span class="career">Adminion</span>
288 HTML::Zoom::ArrayStream->new({ array => [
290 filter($_ => '.name' => $r_content->('mst'))
291 => '.career' => $r_content->('Chainsaw Wielder')),
292 HTML::Zoom::ArrayStream->new({ array => \@between })
297 filter($_ => '.name' => $r_content->('mdk'))
298 => '.career' => $r_content->('Adminion')
302 filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) }
309 <span class="hilight name">mst</span>
310 <span class="career">Chainsaw Wielder</span>
312 <span class="hilight name">mdk</span>
313 <span class="career">Adminion</span>
318 'repeat_content with filter ok'
328 filter($_ => '.name' => $r_content->('mst'))
329 => '.career' => $r_content->('Chainsaw Wielder')
333 filter($_ => '.name' => $r_content->('mdk'))
334 => '.career' => $r_content->('Adminion')
337 { repeat_between => 'hr' }
342 <span class="hilight name">mst</span>
343 <span class="career">Chainsaw Wielder</span>
345 <span class="hilight name">mdk</span>
346 <span class="career">Adminion</span>
351 'repeat_content using repeat_between ok'