Search code examples
groovykotlinspockarrow-kt

How can I use Arrow-kt's Some() in Groovy code?


I'm trying to test my Kotlin code, which has Arrow-kt types, using Spock in Groovy. However, I'm not able to use Arrow-kt's additions such as Some. For example, I have a test as follows:

    @Unroll
    def "add returns #expected for queryRecord #queryRecord"() {
        given:
        def ip = "ip"
        def rule = "rule"

        when:
        def result = unit.add(ip, rule)

        then:
        1 * dynamoDBMapperMock.load(ActionRecord.class, ip) >> queryRecord

        result == expected

        where:
        queryRecord        | expected
        new ActionRecord() | None.INSTANCE
        null               | Some(new ActionInternal("ip"))
    }

While the first data row succeeds with no problems, the second one fails with the following error:

groovy.lang.MissingMethodException: No signature of method: package.name.EventSpec.Some() is applicable for argument types: (package.name.ActionInternal) values: [ActionInternal(dropletIp=null)] Possible solutions: Mock(), Spy(), Stub(), dump(), Mock(groovy.lang.Closure), Mock(java.lang.Class)

I've tried .some() as well, but not to avail. Apparently Groovy can't access Kotlin extensions, but Some is simply a data class[1], so I'm not sure why I cannot use it in Groovy.


Solution

  • Yes, you can use Arrow Datatypes in Groovy, the result is not as idiomatic as in Kotlin because the library heavily depends on extension functions and functions in the companion object

    Example

    import arrow.core.Option
    import static arrow.core.OptionKt.getOrElse
    
    static main(args){
        println 'What is your name?'
        def name = Option.@Companion.fromNullable(System.in.newReader().readLine())
            .filterNot { it.isEmpty() }
            .map { it.toUpperCase() }
    
        println("Welcome ${getOrElse(name) { 'Anonymous' }}")
    }
    

    Output

    'Welcome JOHN' (or 'Welcome Anonymous' if the provided name is null or empty) 
    

    As you can see, to be able to use getOrElse extension function, we need to import it as a static method

    Hint

    Do not use Some directly unless you are absolutely sure the value is not null, otherwise, you should rely on Option.fromNullable to safely lift the value to the Option context (i.e create Some or None depending if the value is null or not)