Repository: yegor256/cactoos
Pull request #39 (2017-05-26 20:20:45)

IterableAsList
`IterableAsList` to make a list from iterable.

0crat: @g4s8 I'm not managing this repo, remove the [webhook](https://github.com/yegor256/cactoos/settings/hooks) or contact me in [Slack](http://www.zerocracy.com) //cc @yegor256
yegor256: @g4s8 good idea, but see my comment above
yegor256: @g4s8 also, I would put that `Repeat` into a different PR
codecov-io: # [Codecov](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@5c229df`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `94.44%`.

[![Impacted file tree graph](https://codecov.io/gh/yegor256/cactoos/pull/39/graphs/tree.svg?width=650&height=150&src=pr&token=ZFRrcTBGZT)](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master      #39   +/-   ##
=========================================
  Coverage          ?   75.54%           
  Complexity        ?       96           
=========================================
  Files             ?       39           
  Lines             ?      323           
  Branches          ?       18           
=========================================
  Hits              ?      244           
  Misses            ?       71           
  Partials          ?        8
```


| [Impacted Files](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=tree) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [src/main/java/org/cactoos/list/IterableAsList.java](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=tree#diff-c3JjL21haW4vamF2YS9vcmcvY2FjdG9vcy9saXN0L0l0ZXJhYmxlQXNMaXN0LmphdmE=) | `94.44% <94.44%> (ø)` | `7 <7> (?)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=footer). Last update [5c229df...ad3bfd0](https://codecov.io/gh/yegor256/cactoos/pull/39?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.travis.yml b/.travis.yml
index 37963f66..1f8e9d15 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,7 @@ cache:
 script:
   - set -e
   - mvn clean install -Pqulice --errors --batch-mode
+  - mvn clean
 env:
   global:
     - MAVEN_OPTS="-Xmx256m"
@@ -13,4 +14,4 @@ env:
 jdk:
   - oraclejdk8
 after_success:
-  - "bash <(curl -s https://codecov.io/bash)"
+    - "bash <(curl -s https://codecov.io/bash)"
diff --git a/README.md b/README.md
index 836c6f48..7ffd4da4 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 [![Build Status](https://travis-ci.org/yegor256/cactoos.svg?branch=master)](https://travis-ci.org/yegor256/cactoos)
 [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/org.cactoos/cactoos/badge.svg?color=blue&prefix=v)](http://www.javadoc.io/doc/org.cactoos/cactoos)
 [![PDD status](http://www.0pdd.com/svg?name=yegor256/cactoos)](http://www.0pdd.com/p?name=yegor256/cactoos)
-[![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/cactoos.svg)](https://codecov.io/github/yegor256/cactoos?branch=master)
+[![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/cactoos.svg?style=flat-square)](https://codecov.io/github/yegor256/cactoos?branch=master)
 [![Maven Central](https://img.shields.io/maven-central/v/org.cactoos/cactoos.svg)](https://maven-badges.herokuapp.com/maven-central/org.cactoos/cactoos)
 [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/cactoos/blob/master/LICENSE.txt)
 
diff --git a/src/main/java/org/cactoos/list/IterableAsList.java b/src/main/java/org/cactoos/list/IterableAsList.java
new file mode 100644
index 00000000..7e0d850c
--- /dev/null
+++ b/src/main/java/org/cactoos/list/IterableAsList.java
@@ -0,0 +1,108 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Yegor Bugayenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.cactoos.list;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+import org.cactoos.text.FormattedText;
+
+/**
+ * Iterable as {@link List}.
+ *
+ * <p>There is no thread-safety guarantee.
+ *
+ * @author Kirill (g4s8.public@gmail.com)
+ * @version $Id$
+ * @param <T> List type
+ * @since 0.1
+ */
+public final class IterableAsList<T> extends AbstractList<T> {
+
+    /**
+     * Iterable source.
+     */
+    private final Iterable<T> source;
+
+    /**
+     * Cache for source.
+     */
+    private final List<T> cache;
+
+    /**
+     * Iterable length.
+     *
+     * @todo #39:30m Needs cached `LengthOfIterable` version
+     *  to improve `IterableAsList` performance. Now each call
+     *  to `size()` goes through all iterable to calculate the size.
+     */
+    private final LengthOfIterable length;
+
+    /**
+     * Ctor.
+     *
+     * @param iterable An {@link Iterable}
+     */
+    public IterableAsList(final Iterable<T> iterable) {
+        super();
+        this.source = iterable;
+        this.cache = new ArrayList<>(0);
+        this.length = new LengthOfIterable(iterable);
+    }
+
+    @Override
+    public T get(final int index) {
+        if (index < 0 || index >= this.size()) {
+            throw new IndexOutOfBoundsException(
+                new FormattedText(
+                    "index=%d, bounds=[%d; %d]",
+                    index,
+                    0,
+                    this.size()
+                ).asString()
+            );
+        }
+        return this.cachedItem(index);
+    }
+
+    @Override
+    public int size() {
+        return this.length.asValue();
+    }
+
+    /**
+     * Find item in cache by index.
+     *
+     * @param index Item index
+     * @return Cached item
+     */
+    private T cachedItem(final int index) {
+        if (this.cache.size() != this.size()) {
+            for (final T item : this.source) {
+                this.cache.add(item);
+            }
+        }
+        return this.cache.get(index);
+    }
+}


Test patch:
diff --git a/src/test/java/org/cactoos/list/IterableAsListTest.java b/src/test/java/org/cactoos/list/IterableAsListTest.java
new file mode 100644
index 00000000..d7bba757
--- /dev/null
+++ b/src/test/java/org/cactoos/list/IterableAsListTest.java
@@ -0,0 +1,109 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Yegor Bugayenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.cactoos.list;
+
+import java.util.Collections;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+/**
+ * Test case for {@link IterableAsList}.
+ *
+ * @author Kirill (g4s8.public@gmail.com)
+ * @version $Id$
+ * @since 0.1
+ */
+public final class IterableAsListTest {
+
+    /**
+     * Test element by index.
+     *
+     * @throws Exception if failed
+     */
+    @Test
+    public void elementAtIndexTest() throws Exception {
+        final int num = 345;
+        MatcherAssert.assertThat(
+            new IterableAsList<>(
+                // @checkstyle MagicNumber (2 lines)
+                new ArrayAsIterable<>(0, 1, 2, num, 3, 4)
+            ).get(3),
+            Matchers.equalTo(num)
+        );
+    }
+
+    /**
+     * Test size of list.
+     *
+     * @throws Exception if failed
+     */
+    @Test
+    public void sizeTest() throws Exception {
+        final int size = 42;
+        MatcherAssert.assertThat(
+            new IterableAsList<>(
+                Collections.nCopies(size, 0)
+            ),
+            Matchers.hasSize(size)
+        );
+    }
+
+    /**
+     * Test empty IterableAsList.
+     *
+     * @throws Exception if failed
+     */
+    @Test
+    public void emptyTest() throws Exception {
+        MatcherAssert.assertThat(
+            new IterableAsList<>(
+                Collections.emptyList()
+            ).size(),
+            Matchers.equalTo(0)
+        );
+    }
+
+    /**
+     * Test low bound of list.
+     *
+     * @throws Exception if failed
+     */
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void lowBoundTest() throws Exception {
+        // @checkstyle MagicNumber (1 line)
+        new IterableAsList<>(Collections.nCopies(10, 0)).get(-1);
+    }
+
+    /**
+     * Test high bound of list.
+     *
+     * @throws Exception if failed
+     */
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void highBoundTest() throws Exception {
+        // @checkstyle MagicNumber (1 line)
+        new IterableAsList<>(Collections.nCopies(10, 0)).get(11);
+    }
+}