dwim selects and bugfixes, new transform_attribute method and handled trailing '...
[catagits/HTML-Zoom.git] / lib / HTML / Zoom / StreamUtils.pm
1 package HTML::Zoom::StreamUtils;
2
3 use strictures 1;
4 use base qw(HTML::Zoom::SubObject);
5 use Scalar::Util ();
6
7 use HTML::Zoom::CodeStream;
8 use HTML::Zoom::FilterStream;
9 use HTML::Zoom::ArrayStream;
10
11 sub stream_from_code {
12   my ($self, $code) = @_;
13   HTML::Zoom::CodeStream->new({
14     code => $code,
15     zconfig => $self->_zconfig,
16   })
17 }
18
19 sub stream_from_array {
20   my $self = shift;
21   my @array = @_;
22   HTML::Zoom::ArrayStream->new({
23     array => \@array,
24     zconfig => $self->_zconfig,
25   })
26 }
27
28 sub stream_concat {
29   shift->stream_from_array(@_)->flatten;
30 }
31
32 sub stream_from_proto {
33   my ($self, $proto) = @_;
34   my $ref = ref $proto;
35   if (not $ref) {
36     return $self->stream_from_array({
37       type => 'TEXT',
38       raw => $self->_zconfig->parser->html_escape($proto)
39     });
40   } elsif ($ref eq 'ARRAY') {
41     return $self->stream_from_array(@$proto);
42   } elsif ($ref eq 'CODE') {
43     return $proto->();
44   } elsif ($ref eq 'SCALAR') {
45     return $self->_zconfig->parser->html_to_stream($$proto);
46   } elsif (Scalar::Util::blessed($proto) && $proto->can('to_stream')) {
47     my $stream = $proto->to_stream;
48     return $self->stream_from_code(sub { $stream->next });
49   }
50   die "Don't know how to turn $proto (ref $ref) into a stream";
51 }
52
53 sub wrap_with_filter {
54   my ($self, $stream, $match, $filter) = @_;
55   HTML::Zoom::FilterStream->new({
56     stream => $stream,
57     match => $match,
58     filter => $filter,
59     zconfig => $self->_zconfig,
60   })
61 }
62
63 sub stream_to_array {
64   my $stream = $_[1];
65   my @array;
66   while (my ($evt) = $stream->next) { push @array, $evt }
67   return @array;
68 }
69
70 sub flatten_stream_of_streams {
71   my ($self, $source_stream) = @_;
72   my $cur_stream;
73   HTML::Zoom::CodeStream->new({
74     code => sub {
75       return unless $source_stream;
76       my $next;
77       until (($next) = ($cur_stream ? $cur_stream->next : ())) {
78         unless (($cur_stream) = $source_stream->next) {
79           undef $source_stream; return;
80         }
81       }
82       return $next;
83     }
84   });
85 }
86
87 1;