v0.7.0-SNAPSHOT

Code can be found here on the development branch atm.

@GrabResolver( name='so', root='https://oss.sonatype.org/content/repositories/snapshots/' )
@Grab( 'com.bloidonia:groovy-stream:0.7.0-SNAPSHOT' )
import groovy.stream.*
def quantities = [ eggs:3, ham:2, bread:4 ]
def result = Stream.from( [ 'ham', 'bread', 'eggs' ] )
                   .flatMap { [ it ] * quantities[ it ] }          // so 'ham' will return [ 'ham', 'ham' ]
                   .filter { it != 'bread' }                       // get rid of bread
                   .join( ',' )                                    // Join into a string
assert Stream.from( 1..5 ).skip( 3 ).collect() == [ 4, 5 ]
// One stream of 3 elements, one of 4
def letters = Stream.from 'a'..'c'
def numbers = Stream.from 1..4
assert letters.zip( numbers ) { a, b -> "$a$b" }
              .collect() == [ 'a1', 'b2', 'c3' ]


// other way round, same result
letters = Stream.from 'a'..'c'
numbers = Stream.from 1..4
assert numbers.zip( letters ) { a, b -> "$a$b" }
              .collect() == [ '1a', '2b', '3c' ]
def letters = Stream.from 'a'..'c'
def numbers = Stream.from 1..4
assert letters.concat( numbers ).collect() == [ 'a', 'b', 'c', 1, 2, 3, 4 ]

v0.6.2

v0.6.1

v0.6

The groovy-stream has been almost entirely rewritten so it's hopefully easier to maintain and extend.

The main difference now is that you can have multiple filter and map steps and they are executed
in the same order they are added to the Stream. ie:

@Grab( 'com.bloidonia:groovy-stream:0.6' )
import groovy.stream.*

def result = Stream.from( 1..50 )
                                     .filter { it % 5 == 0 }            // just the multiples of 5
                                     .map    { 100 / it    }            // as a divisor of 100
                                     .filter { it == Math.round( it ) } // Just the integers
                                     .map    { "#$it" }                 // Convert to a String
                                     .collect()

assert result == ['#20', '#10', '#5', '#4', '#2']

Accordingly as there is no implicit order things are fired any more, the unfilteredIndex is updated
before any steps are executed, and the streamIndex variable is updated after all steps have fired.

We also have a new step flatMap, which returns a Collection, and these values are passed individually
through the following steps before a new value is fetched from the source, ie:

@Grab( 'com.bloidonia:groovy-stream:0.6' )
import groovy.stream.*

def result = Stream.from( [ 'ham', 'bread', 'eggs' ] )
                   .flatMap { [ it ] * quantities[ it ] }          // so 'ham' will return [ 'ham', 'ham' ]
                   .filter { it != 'bread' }                       // get rid of bread
                   .using( quantities:[ eggs:3, ham:2, bread:4 ] ) // Our quantities
                   .join( ',' )                                    // Join into a string

assert result == 'ham,ham,eggs,eggs,eggs'

Also, added a collate method to Streams (same params as the Groovy collate method on List). Allows you to do:

@Grab( 'com.bloidonia:groovy-stream:0.6' )
import groovy.stream.*

def result = Stream.from( 1..10 )
                                     .collate( 3 )
                                     .collect()
                                     
assert result == [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ]

v0.5.4

Stream now implements Iterable<T>

This lets you (once 0.5.4 hits maven) use streams as observables with RxJava, ie:

@Grab('com.bloidonia:groovy-stream:0.5.4')
import groovy.stream.*
@Grab('com.netflix.rxjava:rxjava-groovy:0.5.2')
import rx.*

def integers = Stream.from 1..50
Observable.toObservable( integers )
                    .skip( 10 )
                    .take( 5 )
                    .map { "Number $it" }
                    .subscribe { println "onNext => " + it }

Which should print:

onNext => Number 11
onNext => Number 12
onNext => Number 13
onNext => Number 14
onNext => Number 15

v0.5.3

Fixed a slight issue where calling next() on a Stream before calling hasNext() would cause a NullPointerException

Although calling next() before calling hasNext() feels a bit free and loose as programming goes, it was probably wrong ;-)

v0.5.2

The library now works with Java 6 (thanks to Andres Almiray for spotting this one)

v0.5.1

Fixed a bug whereby Streams couldn't iterate another Stream.

v0.5

The functions where and transform have been renamed to filter and map respectively.

It's better to use existing, known function names for existing functionality rather than inventing your own terms.

v0.4

You can now use arrays as a source for groovy-streams. Previously, running:

int[] arr = [ 1,2,3 ]
Stream s = Stream.from arr
s.each { println it }

Would be an infinite loop, returning [1,2,3] every time.

This will now behave as expected.

v0.3

groovy-stream can now be used as a Module Extension with Groovy 2.0

This means you can do:

Stream s = [1,2,3].toStream()

Just by including the built jar on your classpath. It works with @Grab too:

@GrabResolver( name='bloidonia', root='https://raw.github.com/timyates/bloidonia-repo/master' )
@Grab('com.bloidonia:groovy-stream:0.3')
import groovy.stream.Stream 

def s = (1..4).toStream()
assert [1,2,3,4] == s.collect()

See groovy.stream.StreamExtension for the decorated classes.

Currently (as of Groovy 2.0RC4) there are issues with using @Grab -- (see GROOVY-5543 but this should work fine where the jar is added to the classpath by hand.

v0.2

When Streaming over a Map, it is now passed as a parameter to the where block so you can deal with shadowed variables, ie:

def x = 10

def bad = Stream.from x:1..3, y:1..3 where { x == y }
assert bad.collect() == [] // as 'x' in the where block == 10

def good = Stream.from x:1..3, y:1..3 where { it.x == it.y }
assert good.collect() == [ [x:1,y:1],[x:2,y:2],[x:3,y:3] ]

v0.1

Initial release.