Search

Dark theme | Light theme

March 26, 2015

Groovy Goodness: New Methods to Sort and Remove Duplicates From Collection

In Groovy we can use the sort and unique methods to sort a collection or remove duplicates from a collection. These methods alter the collection on which they are invoked. This is a side effect we might want to avoid. Therefore the sort and unique methods where changed and we could pass a boolean argument to indicate if the original collection should be changed or that we must have a new collection as the result of the methods, leaving the original collection untouched. Since Groovy 2.4 we have two new methods which by default return a new collection: toSorted and toUnique.

In the following sample we see the new methods in action:

@groovy.transform.Sortable
@groovy.transform.ToString
class User {
    String username, email
}

def mrhaki1 = new User(username: 'mrhaki', email: 'mrhaki@localhost')
def mrhaki2 = new User(username: 'mrhaki', email: 'user@localhost')
def hubert1 = new User(username: 'hubert', email: 'user@localhost')
def hubert2 = new User(username: 'hubert', email: 'hubert@localhost')


// We make the list immutable,
// so we check the toSorted and toUnique methods
// do not alter it.
def users = [mrhaki1, mrhaki2, hubert1, hubert2].asImmutable()


// toSorted 
def sortedUsers = users.toSorted()

// @Sortable adds a compareTo method 
// to User class to sort first by username
// and then email.
assert sortedUsers == [hubert2, hubert1, mrhaki1, mrhaki2]

// Original list is unchanged.
assert users == [mrhaki1, mrhaki2, hubert1, hubert2]

// Use toSorted with closure.
def sortedByEmail = users.toSorted { a, b -> a.email <=> b.email }
assert sortedByEmail == [hubert2, mrhaki1, mrhaki2, hubert1]

// Or use toSorted with Comparator.
// @Sortable added static comparatorByProperty
// methods.
def sortedByEmailComparator = users.toSorted(User.comparatorByEmail())
assert sortedByEmailComparator == [hubert2, mrhaki1, mrhaki2, hubert1]


// toUnique with Comparator.
def uniqueUsers = users.toUnique(User.comparatorByUsername())
assert uniqueUsers == [mrhaki1, hubert1]
assert users == [mrhaki1, mrhaki2, hubert1, hubert2]

// toUnique with Closure.
def uniqueByEmail = users.toUnique { a, b -> a.email <=> b.email }
assert uniqueByEmail == [mrhaki1, mrhaki2, hubert2]

Written with Groovy 2.4.3.

March 23, 2015

Groovy Goodness: Combine Elements Iterable with Index

Since Groovy 2.4.0 we can get the indices from the elements in a collection with the indices method. In addition to this method we can also use the withIndex to combine an Iterable with the indices directly. The output is a List of tuples where the first item is the value of the Iterable and the second the index value. We can pass an optional argument to the withIndex which is the starting point for the index values.
Another alternative is the indexed method. The indexed method returns a Map, where the key of the entry is the index value and the entry value is the Iterable value.

In the following example we use the withIndex method. The sample of the alphabet is the same as in the blog post about indices, but rewritten with the withIndex method:

def list = [3, 20, 10, 2, 1]
assert list.withIndex() == [[3, 0], [20, 1], [10, 2], [2, 3], [1, 4]]


def alphabet = 'a'..'z'

// Combine letters in alphabet
// with position and start at 1.
def alphabetIndices = alphabet.withIndex(1)

// alphabetIndices = [['a', 1], ['b', 2], ...]
assert alphabetIndices[0..2] == [['a', 1], ['b', 2], ['c', 3]]

// Find position of each letter
// from 'groovy' in alphabet.
def positionInAlphabet = 'groovy'.inject([]) { result, value ->
    result << alphabetIndices.find { it[0] == value }[1]
    result
}

assert positionInAlphabet == [7, 18, 15, 15, 22, 25]

In the next example we use the indexed method:

def list = [3, 20, 10, 2, 1]
assert list.indexed() == [0: 3, 1: 20, 2: 10, 3: 2, 4: 1]


def alphabet = 'a'..'z'

// Combine letters in alphabet
// with position and start at 1.
def alphabetIndices = alphabet.indexed(1)

// alphabetIndices = [1: 'a', 2: 'b', ...]
assert alphabetIndices.findAll { key, value -> key < 4} == [1: 'a', 2: 'b', 3: 'c']

// Find position of each letter
// from 'groovy' in alphabet.
def positionInAlphabet = 'groovy'.inject([]) { result, value ->
    result << alphabetIndices.find { it.value == value }.key
    result
}

assert positionInAlphabet == [7, 18, 15, 15, 22, 25]

Written with Groovy 2.4.1.

Groovy Goodness: Swapping Elements in a List

Groovy already has so many extra methods for working with lists. If we have to need to swap two elements in a List we can use the swap method. We provide the two index values of the elements we want to swap and Groovy swaps the elements.

In the following sample we have a simple list and swap all elements by invoking the swap method two times:

def saying = ['Groovy', 'is', 'great']

def yodaSays = saying.swap(2, 1).swap(0, 1)

assert yodaSays.join(' ') == 'great Groovy is'

Written with Groovy 2.4.1.

March 19, 2015

Groovy Goodness: Use Constructor as Method Pointer

In Java 8 we can create a constructor reference. We must use the syntax Class::new and we get a constructor reference. This syntax is not supported in Groovy, but we can use the method pointer or reference syntax .& to turn a method into a closure. We can even turn a constructor into a closure and use it everywhere where closures are allowed.

In the following sample code we have a User class with some properties. Via the User.metaClass we can get a reference to the method invokeConstructor and turn it into a method closure:

@groovy.transform.Immutable
class User {
    String name
    int age
}


// Initial list with user defined
// using a map or Object array.
def userList = [
    // User defined as map, keys
    // are properties of User class.
    [name: 'mrhaki', age: 41], 
    
    // Object array with name and
    // age properties for User class.
    ['john', 30] as Object[]
]

// Create constructor reference.
// Result is a closure we can use in our code.
def createUser = User.metaClass.&invokeConstructor

// Invoke the collect method with our
// constructor reference. At the end
// all elements of the userList 
// are converted to new User objects.
def users = userList.collect(createUser)


assert users.name == ['mrhaki', 'john']
assert users.age == [41, 30]

Code written with Groovy 2.4.1.

March 4, 2015

Gradle Goodness: Define System Properties in gradle.properties File

To define system properties for our Gradle build we can use the command line option --system-prop or -D. But we can also add the values for system properties in the gradle.properties file of our project. This file contains project properties we want to externalized, but if we prefix the property name with systemProp. the property is turned into a system property. For a multi-module build only system properties defined in the gradle.properties file in the root of the project structure are used, others are ignored.

In the following build script we have the task showSystemProperty. Inside the task we assert the value of the system property sample and the project property sample:

// Simple task to show 
// some properties.
task showSystemProperty << {

    // System property 'sample' is set 
    // in gradle.properties file.
    assert System.properties.sample == 'Gradle is gr8'

    // Regular project property set
    // in gradle.properties file.
    assert project.sample == 'Gradle is great'

}

We can run the following command line command to make sure the assertions are true: $ gradle --system-prop "sample=Gradle is gr8" --project-prop "sample=Gradle is great" showSystemProperty.

Or we could create the following gradle.properties file in our project directory:

systemProp.sample = Gradle is gr8
sample = Gradle is great

Now we can run $ gradle showSystemProperty and the assertions are true.

Written with Gradle 2.3.

Awesome Asciidoctor: Use Inline Extension DSL with Gradle

One of the great features of Asciidoctor is the support for extensions. If we want to have some special feature we want to use, but is not supported by Asciidoctor, we can add our own extension. On the Java platform we can write those extensions in for example Java and Groovy. When we use Gradle as the build tool with the Asciidoctor plugin we can write the code for the extension in our Gradle build file with the Groovy extension DSL.

Suppose we want to write a new inline macro that will transform the following markup issue:PRJ-100[] into a link that points to the web page for issue PRJ-100. First we create our Asciidoctor source document:

= Sample

This is an issue issue:PRJ-100[].

Now we write the following Gradle build file. First we include the Gradle Asciidoctor plugin. Then we can use the extensions configuration method to add our code for the inline macro. If we would write another type of extension we could still use the same place to add it, but then we don't use inlinemacro.

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
    }
}

// Apply the Asciidoctor Gradle plugin.
apply plugin: 'org.asciidoctor.convert'


asciidoctor {

    // Here we can add the code for extensions we write.
    extensions {

        // Implementation for inline macro to replace
        // issue:<issue-id>[] with a link to the issue. 
        inlinemacro (name: "issue") {
            parent, target, attributes ->
 
            options = [
                "type": ":link", 
                "target": "http://issue-server/browse/${target}".toString()
            ]
      
            // Create the link to the issue.      
            createInline(parent, "anchor", target, attributes, options).render()
        }
 
    }    
}

Let's transform our sample Asciidoctor markup to HTML. We see the following result:

The link that is generated is http://issue-server/browse/PRJ-100.

Written with Gradle 2.3 and Asciidoctor 1.5.2.

March 2, 2015

Awesome Asciidoctor: Creating a Checklist

Creating a list with Asciidoctor markup is easy. To create an unordered we need to start a line with an asterisk (*) or hypen (-). We can add some extra markup to create a checked list. If we add two square brackets ([]) to the list item we have a checklist. To have an unchecked item we use a space, for a checked item we can use a lowercase x (x) or an asterisk (*).

In the next example we define a shopping cart list with Asciidoctor markup:

== Checklist

.Shopping cart
* [x] Milk  // Checked with x
* [ ] Sugar  // Unchecked
* [*] Chocolate  // Checked with *

When we create the HTML file we get the following output:

If we use font-based icons with the document attribute :icons: font the checkboxes are rendered using fonts:

The checkboxes are now simply output in the HTML file. We can add an options attribute to our list to make the checkboxes interactive:

== Checklist

// Make interactive checklist.
[options="interactive"] 
.Shopping cart
* [x] Milk  
* [ ] Sugar  
* [*] Chocolate 

If we transform this markup to HTML we see the following in our web browser:

Written with Asciidoctor 1.5.2.