Skip Menu |

This queue is for tickets about the HOP-Stream CPAN distribution.

Report information
The Basics
Id: 33258
Status: resolved
Priority: 0/
Queue: HOP-Stream

People
Owner: Nobody in particular
Requestors: pauloscustodio [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.01
Fixed in: (no value)



Subject: Streams of array refs do not work properly
Hello Ovid, HOP-Sream is great, but it fails on the last stream element when the stream is composed of array refs, because tail [a,b] is b, even if [a,b] is the last stream element, and not a node. The attached solution blesses nodes into package, and checks if an element is a node in head, tail and list_to_stream. The change to list_to_stream allows the call $stream = list_to_stream( 1 .. 10 ) to work, which is more intuitive than the originaly recommended $stream = list_to_stream( 1 .. 9, node(10, undef) ); I have also added an append function to return a stream to concatenate the input streams, and added test cases to verify the introduced changes. Please feel free to comment on these changes and maybe incorporate in them the next HOP::Stream version. Best Regards, Paulo Custodio P.S. Perl: This is perl, v5.8.8 built for MSWin32-x86-multi-thread (with 50 registered patches, see perl -V for more detail) Copyright 1987-2006, Larry Wall Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com Built Jan 23 2007 15:57:46 OS: Microsoft Windows XP SP2
Subject: HOP-Stream-patch-0.01-0.01a.txt
diff -rc HOP-Stream-0.01/lib/HOP/Stream.pm HOP-Stream-0.01a/lib/HOP/Stream.pm *** HOP-Stream-0.01/lib/HOP/Stream.pm Thu Oct 27 19:12:19 2005 --- HOP-Stream-0.01a/lib/HOP/Stream.pm Sun Sep 23 11:06:56 2007 *************** *** 12,17 **** --- 12,18 ---- insert iterator_to_stream list_to_stream + append merge node promise *************** *** 30,40 **** =head1 VERSION ! Version 0.01 =cut ! our $VERSION = '0.01'; =head1 SYNOPSIS --- 31,41 ---- =head1 VERSION ! Version 0.01a =cut ! our $VERSION = '0.01a'; =head1 SYNOPSIS *************** *** 75,80 **** --- 76,83 ---- =item * list_to_stream + =item * append + =item * merge =item * node *************** *** 108,114 **** sub node { my ( $h, $t ) = @_; ! [ $h, $t ]; } ############################################################################## --- 111,117 ---- sub node { my ( $h, $t ) = @_; ! bless [ $h, $t ], __PACKAGE__; } ############################################################################## *************** *** 124,129 **** --- 127,133 ---- sub head { my ($s) = @_; + return undef unless is_node($s); $s->[0]; } *************** *** 139,144 **** --- 143,150 ---- sub tail { my ($s) = @_; + return undef unless is_node($s); + if ( is_promise( $s->[1] ) ) { $s->[1] = $s->[1]->(); } *************** *** 147,152 **** --- 153,175 ---- ############################################################################## + =head2 is_node + + if ( is_node($tail) ) { + ... + } + + Returns true if the tail of a node is a node. Generally this function is + used internally. + + =cut + + sub is_node { + UNIVERSAL::isa( $_[0], __PACKAGE__ ); + } + + ############################################################################## + =head2 is_promise if ( is_promise($tail) ) { *************** *** 284,289 **** --- 307,334 ---- ############################################################################## + =head2 append + + my $merged_stream = append( $stream1, $stream2 ); + + This function takes a list of streams and attaches them together head-to-tail + into a new stream. + + =cut + + sub append { + my ( @streams ) = @_; + + while ( @streams ) { + my $h = drop($streams[0]); + return node( $h, promise { append( @streams ) } ) if defined($h); + shift @streams; + } + return undef; + } + + ############################################################################## + =head2 list_to_stream my $stream = list_to_stream(@list); *************** *** 300,305 **** --- 345,352 ---- sub list_to_stream { my $node = pop; + $node = node($node) unless is_node($node); + while (@_) { my $item = pop; $node = node( $item, $node ); diff -rc HOP-Stream-0.01/t/10-streams.t HOP-Stream-0.01a/t/10-streams.t *** HOP-Stream-0.01/t/10-streams.t Thu Oct 27 19:12:19 2005 --- HOP-Stream-0.01a/t/10-streams.t Sun Sep 23 11:05:41 2007 *************** *** 2,9 **** use warnings; use strict; ! #use Test::More tests => 21; ! use Test::More 'no_plan'; use lib 'lib/', '../lib/'; --- 2,9 ---- use warnings; use strict; ! use Test::More tests => 61; ! #use Test::More 'no_plan'; use lib 'lib/', '../lib/'; *************** *** 19,24 **** --- 19,25 ---- insert iterator_to_stream list_to_stream + append merge node promise *************** *** 110,115 **** --- 111,131 ---- is_deeply \@numbers, [ 2, 4, 6, 8, 10 ], '... which should return the numbers we expect'; + # append + + my $stream1 = upto(4, 7); + my $stream2 = upto(12, 15); + my $stream3 = upto(25, 28); + ok $stream = append($stream1, $stream2, $stream3), + "append() should return a stream"; + + @numbers = (); + while ( defined( my $num = drop($stream) ) ) { + push @numbers, $num; + } + is_deeply \@numbers, [ 4..7, 12..15, 25..28 ], + '... and the stream should return all of the numbers'; + # merge sub scale { *************** *** 168,173 **** --- 184,199 ---- } is_deeply \@numbers, [ 1 .. 10 ], '... and create the numbers one to ten'; + # list_to_stream, final node computed internally + + ok $list = list_to_stream( 1 .. 10 ), + 'list_to_stream() should return a stream'; + @numbers = (); + while ( defined( my $num = drop($list) ) ) { + push @numbers, $num; + } + is_deeply \@numbers, [ 1 .. 10 ], '... and create the numbers one to ten'; + # insert my @list = qw/seventeen three one/; # sorted by descending length *************** *** 176,178 **** --- 202,246 ---- is_deeply \@list, [qw/seventeen three four one/], 'insert() should be able to insert items according to our sort criteria'; + # + # streams of array refs do not work properly, because tail [a,b] is b, even if [a,b] is + # the last stream element, and not a node + # Solution: bless nodes, check is_node in head, tail, list_to_stream + # + $stream = list_to_stream( [A => 1], [B => 2] ); + is_deeply $stream, + bless([ [A => 1], + bless([ [B => 2], + undef ], + 'HOP::Stream')], + 'HOP::Stream'), "stream of array refs"; + is_deeply head($stream), [A => 1], "... head is array ref"; + is_deeply tail($stream), + bless([ [B => 2], + undef ], + 'HOP::Stream'), "... tail is stream"; + + drop($stream); + is_deeply $stream, + bless([ [B => 2], + undef ], + 'HOP::Stream'), "stream of array refs, dropped 1"; + is_deeply head($stream), [B => 2], "... head is array ref"; + is_deeply tail($stream), undef, "... tail is stream"; + + drop($stream); + is_deeply $stream, undef, "stream of array refs, dropped 2"; + is_deeply head($stream), undef, "... head is undef"; + is_deeply tail($stream), undef, "... tail is undef"; + + drop($stream); + is_deeply $stream, undef, "stream of array refs, dropped 3"; + is_deeply head($stream), undef, "... head is undef"; + is_deeply tail($stream), undef, "... tail is undef"; + + # + # use a non-stream as stream + # + $stream = [1, [2, [3]]]; + is head($stream), undef, "no head of non-stream"; + is tail($stream), undef, "no head of non-stream";
On Thu Feb 14 10:06:21 2008, pauloscustodio@gmail.com wrote: Show quoted text
> Hello Ovid, > > HOP-Sream is great, but it fails on the last stream element when the > stream is composed of array refs, because tail [a,b] is b, even if [a,b] > is the last stream element, and not a node.
Patch accepted and applied. Thanks Paulo! Cheers, Ovid