}
sub _next {
- my ($self) = @_;
+ my ($self, $am_peek) = @_;
# if our main stream is already gone then we can short-circuit
# straight out - there's no way for an alternate stream to be there
# it's gone - we're still effectively "in the match" but this is the
# point at which that fact is abstracted away from downstream consumers
+ my $_next = $am_peek ? 'peek' : 'next';
+
if (my $alt = $self->{_alt_stream}) {
- if (my ($evt) = $alt->next) {
+ if (my ($evt) = $alt->$_next) {
+ $self->{_peeked_from} = $alt if $am_peek;
return $evt;
}
# if there's no alternate stream currently, process the main stream
- while (my ($evt) = $self->{_stream}->next) {
+ while (my ($evt) = $self->{_stream}->$_next) {
+
+ $self->{_peeked_from} = $self->{_stream} if $am_peek;
# don't match this event? return it immediately
# the filter returned a stream - if it contains something return the
# first entry and stash it as the new alternate stream
- if (my ($new_evt) = $res->next) {
+ if (my ($new_evt) = $res->$_next) {
$self->{_alt_stream} = $res;
+ $self->{_peeked_from} = $res if $am_peek;
return $new_evt;
}
# - this will happens for e.g. with an in place close (<foo />) that's
# being removed. In that case, we fall off to loop back round and try
# the next event from our main stream
+ } continue {
+
+ # if we fell off the bottom (empty new alternate stream or filter ate
+ # the event) then we need to advance our internal stream one so that the
+ # top of the while loop gets the right thing; also, we need to clear the
+ # _peeked_from in case our source stream is exhausted (it'll be
+ # re-assigned if the while condition gets a new event)
+
+ if ($am_peek) {
+ $self->{_stream}->next;
+ delete $self->{_peeked_from};
+ }
}
# main stream exhausted so throw it away so we hit the short circuit
}
sub _next {
- return unless (my $self = shift)->{_source};
+ my ($self, $am_peek) = @_;
+ return unless $self->{_source};
# If we were aiming for a "true" perl-like map then we should
# elegantly handle the case where the map function returns 0 events
# and the case where it returns >1 - if you're reading this comment
# because you wanted it to do that, now would be the time to fix it :)
- if (my ($next) = $self->{_source}->next) {
+ if (my ($next) = $self->{_source}->${\($am_peek ? 'peek' : 'next')}) {
+ $self->{_peeked_from} = $next if $am_peek;
local $_ = $next;
return $self->{_mapper}->($next);
}
if (exists $self->{_peeked}) {
return ($self->{_peeked});
}
- if (my ($peeked) = $self->_next) {
+ if (my ($peeked) = $self->_next(1)) {
return ($self->{_peeked} = $peeked);
}
return;
# peeked entry so return that
if (exists $self->{_peeked}) {
+ if (my $peeked_from = delete $self->{_peeked_from}) {
+ $peeked_from->next;
+ }
return (delete $self->{_peeked});
}
$self->$code;
}
+sub to_html {
+ my ($self) = @_;
+ $self->_zconfig->producer->html_from_stream($self);
+}
+
1;
--- /dev/null
+use strictures 1;
+use Test::More;
+use HTML::Zoom;
+
+my $z = HTML::Zoom->from_html(q{<html>
+ <body>
+ <div class="outer">
+ <div class="inner"><span /></div>
+ </div>
+ </body>
+</html>});
+
+is(
+ $z->select('.outer')
+ ->collect_content({
+ filter => sub { $_->select('.inner')->replace_content('bar!') },
+ passthrough => 1
+ })
+ ->to_html,
+ q{<html>
+ <body>
+ <div class="outer">
+ <div class="inner">bar!</div>
+ </div>
+ </body>
+</html>},
+ "filter within collect works ok"
+);
+
+done_testing;