4 use warnings FATAL => 'all';
6 use HTML::Zoom::ZConfig;
7 use HTML::Zoom::MatchWithoutFilter;
8 use HTML::Zoom::ReadFH;
11 my ($class, $args) = @_;
13 $new->{zconfig} = HTML::Zoom::ZConfig->new($args->{zconfig}||{});
17 sub zconfig { shift->_self_or_new->{zconfig} }
20 ref($_[0]) ? $_[0] : $_[0]->new
24 bless({ %{$_[0]}, %{$_[1]} }, ref($_[0]));
28 my $self = shift->_self_or_new;
30 initial_events => $self->zconfig->parser->html_to_events($_[0])
35 my $self = shift->_self_or_new;
37 $self->from_html(do { local (@ARGV, $/) = ($filename); <> });
42 die "No events to build from - forgot to call from_html?"
43 unless $self->{initial_events};
44 my $sutils = $self->zconfig->stream_utils;
45 my $stream = $sutils->stream_from_array(@{$self->{initial_events}});
46 foreach my $filter_spec (@{$self->{filters}||[]}) {
47 $stream = $sutils->wrap_with_filter($stream, @{$filter_spec});
53 HTML::Zoom::ReadFH->from_zoom(shift);
58 $self->zconfig->stream_utils->stream_to_array($self->to_stream);
63 my ($self, $code) = @_;
70 $self->zconfig->producer->html_from_stream($self->to_stream);
75 ref($self)->new($self)->from_html($self->to_html);
79 my ($self, $selector, $filter) = @_;
80 my $match = $self->parse_selector($selector);
82 filters => [ @{$self->{filters}||[]}, [ $match, $filter ] ]
87 my ($self, $selector) = @_;
88 my $match = $self->parse_selector($selector);
89 return HTML::Zoom::MatchWithoutFilter->construct(
90 $self, $match, $self->zconfig->filter_builder,
94 # There's a bug waiting to happen here: if you do something like
96 # $zoom->select('.foo')
97 # ->remove_attribute({ class => 'foo' })
99 # ->well_anything_really
101 # the second action won't execute because it doesn't match anymore.
102 # Ideally instead we'd merge the match subs but that's more complex to
103 # implement so I'm deferring it for the moment.
107 die "Can't call ->then without a previous filter"
108 unless $self->{filters};
109 $self->select($self->{filters}->[-1][0]);
113 my ($self, $selector) = @_;
114 return $selector if ref($selector); # already a match sub
115 $self->zconfig->selector_parser->parse_selector($selector);
122 HTML::Zoom - selector based streaming template engine
128 my $template = <<HTML;
131 <title>Hello people</title>
134 <h1 id="greeting">Placeholder</h1>
137 <p>Name: <span class="name">Bob</span></p>
138 <p>Age: <span class="age">23</span></p>
140 <hr class="between" />
146 my $output = HTML::Zoom
147 ->from_html($template)
148 ->select('title, #greeting')->replace_content('Hello world & dog!')
149 ->select('#list')->repeat_content(
152 $_->select('.name')->replace_content('Matt')
153 ->select('.age')->replace_content('26')
156 $_->select('.name')->replace_content('Mark')
157 ->select('.age')->replace_content('0x29')
160 $_->select('.name')->replace_content('Epitaph')
161 ->select('.age')->replace_content('<redacted>')
164 { repeat_between => '.between' }
178 <title>Hello world & dog!</title>
181 <h1 id="greeting">Hello world & dog!</h1>
184 <p>Name: <span class="name">Matt</span></p>
185 <p>Age: <span class="age">26</span></p>
187 <hr class="between" />
189 <p>Name: <span class="name">Mark</span></p>
190 <p>Age: <span class="age">0x29</span></p>
192 <hr class="between" />
194 <p>Name: <span class="name">Epitaph</span></p>
195 <p>Age: <span class="age"><redacted></span></p>
205 is($output, $expect, 'Synopsis code works ok');
209 =head1 SOMETHING ELSE