在地图上使用find {},而不是对每个地图元素进行评估

时间:2018-10-05 21:15:25

标签: groovy

我创建了一些混合方法。下面的代码和示例:

URL.metaClass.withCreds = { u, p ->
    delegate.openConnection().tap {
        setRequestProperty('Authorization', "Basic ${(u + ':' + p).bytes.encodeBase64()}")
    }
}

URLConnection.metaClass.fetchJson = {
    delegate.setRequestProperty('Accept', 'application/json')
    delegate.connect()
    def code = delegate.responseCode
    def result = new JsonSlurper().parse(code >= 400 ? delegate.errorStream : delegate.inputStream as InputStream)
    [
            ok  : code in (200..299),
            body: result,
            code: code
    ]

}

用法示例:

new URL("$baseUrl/projects/$name").withCreds(u, p).fetchJson().find {
        it.ok
    }?.tap{
        it.repos = getRepos(it.key).collectEntries { [(it.slug): it] }
    }
}

当我不使用 find()时,按预期,我的对象是包含这三个元素的地图。当我使用find it是具有键ok和值true的Map.Entry

会产生此错误:

groovy.lang.MissingPropertyException: No such property: ok for class: java.util.LinkedHashMap$Entry
Possible solutions: key

当我写这篇文章时,我想到将地图视为可迭代地图,因此查看了我随后验证的每个条目。如何在整个地图上find?我想要it.ok,因为如果确实如此,我需要将其继续前进

1 个答案:

答案 0 :(得分:1)

Groovy SDK中没有这样的方法。 Map.find()在您调用方法所依据的地图的条目集上运行。根据您所定义的期望,我猜测您正在寻找一个函数,该函数使用给定的谓词测试map并在匹配谓词时返回该map。您可以通过Map.metaClass添加一个执行此操作的函数(因为您已经向URLURLConnection类添加了方法)。考虑以下示例:

Map.metaClass.continueIf = { Closure<Boolean> predicate ->
    predicate(delegate) ? delegate : null
}

def map = [
        ok  : true,
        body: '{"message": "ok"}',
        code: 200
]

map.continueIf { it.ok }?.tap {
    it.repos = "something"
}

println map

在此示例中,我们引入了一种新方法Map.continueIf(predicate),该方法测试map是否与给定谓词匹配,否则返回null。运行上面的示例将产生以下输出:

[ok:true, body:{"message": "ok"}, code:200, repos:something]

如果不满足谓词,则map不会被修改。

或者,对于更严格的设计,您可以使fetchJson()方法返回具有相应的onSuccess()onError()方法的对象,以便您可以更清楚地表示添加repos当您获得成功的响应时,或者选择创建错误响应时,否则。

希望对您有帮助。