/** * Copyright (c) 2012 BMW Car IT and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.jnario.jnario.documentation; import com.google.common.collect.Iterables; import java.util.Collections; import java.util.List; import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Functions.Function1; import org.eclipse.xtext.xbase.lib.Functions.Function2; import org.eclipse.xtext.xbase.lib.IterableExtensions; import org.eclipse.xtext.xbase.lib.ListExtensions; import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; import org.jnario.jnario.documentation._20FactsAboutXtendSpec; import org.jnario.lib.Assert; import org.jnario.lib.JnarioCollectionLiterals; import org.jnario.lib.Should; import org.jnario.runner.ExampleGroupRunner; import org.jnario.runner.Named; import org.jnario.runner.Order; import org.junit.Test; import org.junit.runner.RunWith; /** * A great thing about Xtend is that it enables a more functional programming style, * with its native support for anonymous functions, the so called lambda expressions, * and its rich library of extension methods. */ @Named("Functional Programming FTW") @RunWith(ExampleGroupRunner.class) @SuppressWarnings("all") public class _20FactsAboutXtendFunctionalProgrammingFTWSpec extends _20FactsAboutXtendSpec { /** * Xtend provides a rich set of extension methods for collections. Accessing elements * in lists. */ @Test @Named("Simple access to list elements") @Order(1) public void _simpleAccessToListElements() throws Exception { final List<String> colors = JnarioCollectionLiterals.<String>list("red", "blue", "green"); String _head = IterableExtensions.<String>head(colors); boolean _doubleArrow = Should.<String>operator_doubleArrow(_head, "red"); Assert.assertTrue("\nExpected colors.head => \"red\" but" + "\n colors.head is " + new org.hamcrest.StringDescription().appendValue(_head).toString() + "\n colors is " + new org.hamcrest.StringDescription().appendValue(colors).toString() + "\n", _doubleArrow); Iterable<String> _tail = IterableExtensions.<String>tail(colors); boolean _doubleArrow_1 = this.<String>operator_doubleArrow(_tail, Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("blue", "green"))); Assert.assertTrue("\nExpected colors.tail => #[\"blue\", \"green\"] but" + "\n colors.tail is " + new org.hamcrest.StringDescription().appendValue(_tail).toString() + "\n colors is " + new org.hamcrest.StringDescription().appendValue(colors).toString() + "\n #[\"blue\", \"green\"] is " + new org.hamcrest.StringDescription().appendValue(Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("blue", "green"))).toString() + "\n", _doubleArrow_1); String _last = IterableExtensions.<String>last(colors); boolean _doubleArrow_2 = Should.<String>operator_doubleArrow(_last, "green"); Assert.assertTrue("\nExpected colors.last => \"green\" but" + "\n colors.last is " + new org.hamcrest.StringDescription().appendValue(_last).toString() + "\n colors is " + new org.hamcrest.StringDescription().appendValue(colors).toString() + "\n", _doubleArrow_2); boolean _isEmpty = colors.isEmpty(); Assert.assertTrue("\nExpected colors.empty => false but" + "\n colors.empty is " + new org.hamcrest.StringDescription().appendValue(Boolean.valueOf(_isEmpty)).toString() + "\n colors is " + new org.hamcrest.StringDescription().appendValue(colors).toString() + "\n", Should.<Boolean>operator_doubleArrow(Boolean.valueOf(_isEmpty), false)); } /** * Here is another useful fact about Xtend, you can concatenate collections * using the `+` operator. */ @Test @Named("\\\'+\\\' concatenates collections") @Order(2) public void _concatenatesCollections() throws Exception { List<Integer> _list = JnarioCollectionLiterals.<Integer>list(Integer.valueOf(1), Integer.valueOf(2)); List<Integer> _list_1 = JnarioCollectionLiterals.<Integer>list(Integer.valueOf(3), Integer.valueOf(4)); Iterable<Integer> _plus = Iterables.<Integer>concat(_list, _list_1); Assert.assertTrue("\nExpected list(1, 2) + list(3, 4) => #[1, 2, 3, 4] but" + "\n list(1, 2) + list(3, 4) is " + new org.hamcrest.StringDescription().appendValue(_plus).toString() + "\n list(1, 2) is " + new org.hamcrest.StringDescription().appendValue(_list).toString() + "\n list(3, 4) is " + new org.hamcrest.StringDescription().appendValue(_list_1).toString() + "\n #[1, 2, 3, 4] is " + new org.hamcrest.StringDescription().appendValue(Collections.<Integer>unmodifiableList(CollectionLiterals.<Integer>newArrayList(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4)))).toString() + "\n", this.<Integer>operator_doubleArrow(_plus, Collections.<Integer>unmodifiableList(CollectionLiterals.<Integer>newArrayList(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4))))); } /** * Xtend has great support for lambda expressions. You can * declare an anonymous function by surrounding the lambda * expression by square brackets: * * <pre class="prettyprint lang-spec"> * var lambda = [String s | s.length] * </pre> * * The parameter type can be omitted if the type can be coerced from * the expression on the left-hand side: * * <pre class="prettyprint lang-spec"> * var (String)=>int lambda = [s | s.length] * </pre> * * Single parameter functions don't need a parameter declaration and the * parameter can be accessed via the implicit variable 'it': * * <pre class="prettyprint lang-spec"> * var (String)=>int lambda = [it.length] * </pre> * * ...and we can even completely remove the 'it' variable: */ @Test @Named("Concise Lambda Expressions") @Order(3) public void _conciseLambdaExpressions() throws Exception { final Function1<String, Integer> _function = new Function1<String, Integer>() { public Integer apply(final String it) { return Integer.valueOf(it.length()); } }; Function1<? super String, ? extends Integer> lambda = _function; Integer _apply = lambda.apply("hello"); Assert.assertTrue("\nExpected lambda.apply(\"hello\") => 5 but" + "\n lambda.apply(\"hello\") is " + new org.hamcrest.StringDescription().appendValue(_apply).toString() + "\n lambda is " + new org.hamcrest.StringDescription().appendValue(lambda).toString() + "\n", Should.<Integer>operator_doubleArrow(_apply, Integer.valueOf(5))); } /** * Lambda expressions are especially useful when working with * collections. For example, when performing the same assertion on each element * in a collection, the implicit `forEach` extension method is a lot more readable than * a loop: */ @Test @Named("Better loops") @Order(4) public void _betterLoops() throws Exception { List<Integer> _list = JnarioCollectionLiterals.<Integer>list(Integer.valueOf(11), Integer.valueOf(17), Integer.valueOf(19)); final Procedure1<Integer> _function = new Procedure1<Integer>() { public void apply(final Integer it) { Assert.assertTrue("\nExpected it > 10 but" + "\n it is " + new org.hamcrest.StringDescription().appendValue((it).intValue()).toString() + "\n", ((it).intValue() > 10)); } }; IterableExtensions.<Integer>forEach(_list, _function); } /** * The `filter` extension method is really helpful when you are only interested * in a subset of a collection. You can filter by type: */ @Test @Named("Filter iterables by type") @Order(5) public void _filterIterablesByType() throws Exception { List<Object> _list = JnarioCollectionLiterals.<Object>list("a string", Integer.valueOf(42), Boolean.valueOf(true)); Iterable<String> _filter = Iterables.<String>filter(_list, String.class); Assert.assertTrue("\nExpected list(\"a string\", 42, true).filter(typeof(String)) => #[\"a string\"] but" + "\n list(\"a string\", 42, true).filter(typeof(String)) is " + new org.hamcrest.StringDescription().appendValue(_filter).toString() + "\n list(\"a string\", 42, true) is " + new org.hamcrest.StringDescription().appendValue(_list).toString() + "\n #[\"a string\"] is " + new org.hamcrest.StringDescription().appendValue(Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("a string"))).toString() + "\n", this.<String>operator_doubleArrow(_filter, Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("a string")))); } /** * In this case we provide a lambda expressions that returns true for the * elements we are interested in: */ @Test @Named("... or via a custom predicate") @Order(6) public void _orViaACustomPredicate() throws Exception { List<String> _list = JnarioCollectionLiterals.<String>list("red", "blue", "green"); final Function1<String, Boolean> _function = new Function1<String, Boolean>() { public Boolean apply(final String it) { return Boolean.valueOf(it.startsWith("b")); } }; Iterable<String> _filter = IterableExtensions.<String>filter(_list, _function); List<String> _list_1 = JnarioCollectionLiterals.<String>list("blue"); Assert.assertTrue("\nExpected list(\"red\", \"blue\", \"green\").filter[startsWith(\"b\")] => list(\"blue\") but" + "\n list(\"red\", \"blue\", \"green\").filter[startsWith(\"b\")] is " + new org.hamcrest.StringDescription().appendValue(_filter).toString() + "\n list(\"red\", \"blue\", \"green\") is " + new org.hamcrest.StringDescription().appendValue(_list).toString() + "\n list(\"blue\") is " + new org.hamcrest.StringDescription().appendValue(_list_1).toString() + "\n", this.<String>operator_doubleArrow(_filter, _list_1)); } /** * This examples demonstrates how you can realize complex operations by * reusing existing functions with lambda expressions. Here we are counting * all characters in a list of Strings using the `map` and `reduce` extension methods. */ @Test @Named("Map/Reduce made easy") @Order(7) public void _mapReduceMadeEasy() throws Exception { final List<String> strings = JnarioCollectionLiterals.<String>list("red", "blue", "green"); final Function1<String, Integer> _function = new Function1<String, Integer>() { public Integer apply(final String s) { return Integer.valueOf(s.length()); } }; List<Integer> _map = ListExtensions.<String, Integer>map(strings, _function); final Function2<Integer, Integer, Integer> _function_1 = new Function2<Integer, Integer, Integer>() { public Integer apply(final Integer sum, final Integer size) { return Integer.valueOf(((sum).intValue() + (size).intValue())); } }; final Integer charCount = IterableExtensions.<Integer>reduce(_map, _function_1); Assert.assertTrue("\nExpected charCount => 12 but" + "\n charCount is " + new org.hamcrest.StringDescription().appendValue(charCount).toString() + "\n", Should.<Integer>operator_doubleArrow(charCount, Integer.valueOf(12))); } }