Skip to content

Commit

Permalink
(#971) Paged iterable
Browse files Browse the repository at this point in the history
  • Loading branch information
llorllale committed Jan 22, 2019
1 parent 0a88360 commit d0b2b05
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 1 deletion.
55 changes: 55 additions & 0 deletions src/main/java/org/cactoos/iterable/IterableOf.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@

import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.cactoos.Func;
import org.cactoos.Scalar;
import org.cactoos.func.UncheckedFunc;
import org.cactoos.iterator.IteratorOf;
import org.cactoos.scalar.StickyScalar;
import org.cactoos.scalar.UncheckedScalar;

/**
Expand Down Expand Up @@ -65,6 +69,57 @@ public IterableOf(final Iterator<X> list) {
this(() -> list);
}

/**
* Paged iterable.
* <p>
* Elements will continue to be provided so long as {@code next} produces
* non-empty iterators.
* @param <I> Custom iterator
* @param first First bag of elements
* @param next Subsequent bags of elements
*/
@SuppressWarnings(
{
"PMD.CallSuperInConstructor",
"PMD.ConstructorOnlyInitializesOrCallOtherConstructors"
}
)
public <I extends Iterator<X>> IterableOf(
final Scalar<I> first, final Func<I, I> next
) {
// @checkstyle AnonInnerLengthCheck (30 lines)
this(
() -> new Iterator<X>() {
private UncheckedScalar<I> current = new UncheckedScalar<>(
new StickyScalar<>(first)
);
private final UncheckedFunc<I, I> subsequent =
new UncheckedFunc<>(next);

@Override
public boolean hasNext() {
if (!this.current.value().hasNext()) {
final I next = this.subsequent.apply(
this.current.value()
);
this.current = new UncheckedScalar<>(
new StickyScalar<>(() -> next)
);
}
return this.current.value().hasNext();
}

@Override
public X next() {
if (this.hasNext()) {
return this.current.value().next();
}
throw new NoSuchElementException();
}
}
);
}

/**
* Ctor.
* @param sclr The encapsulated iterator of x
Expand Down
74 changes: 73 additions & 1 deletion src/test/java/org/cactoos/iterable/IterableOfTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,24 @@
*/
package org.cactoos.iterable;

import java.util.Iterator;
import org.cactoos.iterator.IteratorOf;
import org.cactoos.list.ListOf;
import org.cactoos.scalar.LengthOf;
import org.cactoos.scalar.Ternary;
import org.cactoos.text.TextOf;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.hamcrest.collection.IsIterableContainingInOrder;
import org.hamcrest.collection.IsIterableWithSize;
import org.hamcrest.core.IsEqual;
import org.junit.Test;

/**
* Test case for {@link IterableOf}.
* @since 0.12
* @checkstyle JavadocMethodCheck (500 lines)
* @checkstyle ClassDataAbstractionCoupling (2 lines)
*/
public final class IterableOfTest {

Expand Down Expand Up @@ -73,5 +81,69 @@ public void convertsObjectsToIterable() {
);
}

}
// @todo #971:30min Implement equals() and hashCode() on IterableEnvelope.
// Then, refactor this test so that only
// `new IsEqual<>(new Joined<>(first, second, third))` is required as a
// matcher.
@Test
@SuppressWarnings({"unchecked", "PMD.AvoidDuplicateLiterals"})
public void containAllPagedContentInOrder() throws Exception {
final Iterable<String> first = new IterableOf<>("one", "two");
final Iterable<String> second = new IterableOf<>("three", "four");
final Iterable<String> third = new IterableOf<>("five");
final Iterable<Iterable<String>> service = new IterableOf<>(
first, second, third
);
final Iterator<Iterable<String>> pages = service.iterator();
MatcherAssert.assertThat(
"Must have all page values",
new IterableOf<>(
() -> pages.next().iterator(),
page -> new Ternary<>(
() -> pages.hasNext(),
() -> pages.next().iterator(),
() -> new IteratorOf<String>()
).value()
),
new IsIterableContainingInOrder<>(
new ListOf<>(
new IsEqual<>("one"),
new IsEqual<>("two"),
new IsEqual<>("three"),
new IsEqual<>("four"),
new IsEqual<>("five")
)
)
);
}

@Test
@SuppressWarnings("unchecked")
public void reportTotalPagedLength() throws Exception {
final Iterable<String> first = new IterableOf<>("A", "five");
final Iterable<String> second = new IterableOf<>("word", "long");
final Iterable<String> third = new IterableOf<>("sentence");
final Iterable<Iterable<String>> service = new IterableOf<>(
first, second, third
);
final Iterator<Iterable<String>> pages = service.iterator();
MatcherAssert.assertThat(
"Length must be equal to total number of elements",
new IterableOf<>(
() -> pages.next().iterator(),
page -> new Ternary<>(
() -> pages.hasNext(),
() -> pages.next().iterator(),
() -> new IteratorOf<String>()
).value()
),
new IsIterableWithSize<>(
new IsEqual<>(
new LengthOf(
new Joined<>(first, second, third)
).intValue()
)
)
);
}
}

0 comments on commit d0b2b05

Please sign in to comment.