Arquivo para a tag ‘mop’
Maravilhas do Groovy: O método ‘collect’ das listas
Passei agora pela seguinte situação:
Possuía uma lista de objetos (pogos) com várias propriedades, e a partir desta lista, eu precisaria de uma nova lista com apenas os ids de cada um destes objetos, ao invés da clássica iteração para se resgatar os valores, acabei usando o método collect, que recebe uma closure, e para cada objeto da lista, aplica esta closure!
Para quem conhece, funciona da mesma maneira que o FileFilter do Java, que é usado para filtrar arquivos dentro de um diretório.
def listaPogos = ...
def listaIds = listaPogos.collect { pogo ->
pogo.id
}
Quer ver funcionando? Clique aqui para rodar o código no Groovy Web Console
Maravilhas do Groovy: A propriedade metaClass
Uma das facilidades que o groovy também traz, é a possibilidade de adicionar métodos em nossas classes em tempo de execução através da propriedade metaClass dos objetos.
Agora mesmo, eu precisava de um recurso para criar “slugs” (essas URLs amigáveis que o WordPress cria) de titulos de artigos. Tradicionalmente, o processo é criar aquelas classes **Utils.java com todos os métodos utilitários, mas com a metaprogramação, o mais usual passa a ser adicionar o métodos nas próprias classes que geram este comportamento.
No exemplo abaixo, eu adicionei o método slug() em runtime dentro da classe String e a partir de agora, qualquer objeto da classe java.lang.String possui o método slug(), com o comportamento descrito abaixo.
String.metaClass.slug { ->
def s = delegate.toLowerCase()
s = s.replaceAll(/[^a-z0-9\s-]/, "").replaceAll(/\s+/, " ").trim()
if (s.length() > 45)
s = s.substring(0, 45).trim()
s.replaceAll(/\s/, "-")
}
Em primeiro, definimos uma varíavel interna ’s’ com o valor da própria string que está sendo usada (através da propriedade delegate), após isso, aplicamos a primeira regex de caracteres especiais, outra para substituir os espaços em excesso e cortamos a string caso ela tenha mais que 45 caracteres. Por fim, substituímos os espaços por dashes.
Você pode rodar este script neste endereço, basta clicar em “Execute script”
Não tenha medo das closures
Você tem medo das closures? Já vi muita gente dizer que closures são perigosas e trazê-las a tona seria como acordar um monstro adormecido (o medonho GOTO – veja uma ótima definição neste link).
Não eu não concordo, closures só querem o seu bem, eis a razão.
Bom, uma closure nada mais é que um trecho de código! Mas o que difere este bloco de instruções chamado closure de um método? A grande diferença neste caso, é que as closures são um pouco mais flexíveis que os métodos, e por sua vez podem até ser passadas como parâmetro na chamada de outras funções, ou seja, podem ser atribuídas a uma variável.
Em java não temos closures nativas na linguagem, e uma das formas de tentar alcançar o objetivo é através do uso de classes anônimas, o que particularmente não me agrada muito, pela sujeira que fica no código.
Em um primeiro exemplo, mais simples, segue como definir uma closure, associá-la a uma variável e depois executá-la. (exemplo em groovy).
def c = {
println "Testando o uso de uma closure"
}
c.call()
Este é um exemplo simples, onde a frase acima será impressa no console.
Para incrementarmos um pouco, podemos fazer com que nossa closure receba um parâmetro para usá-lo dentro da execução, além de criar um método que faça o uso dela. O exemplo abaixo mostra isto.
//definição da closure para dizer oi
def ola = { nome ->
println "E ai ${nome}, tudo bom?"
}
//definição da closure para dizer tchau
def tchau = { nome ->
println "To indo ${nome}, ate a proxima!"
}
//criação do método que fará o uso da closure
void falar(Closure c, String paraQuem) {
c.call(paraQuem)
}
//invoke do método com as closures de parametro
//note que a closure é passada como se fosse uma variável qualquer
falar(ola, "Fulano")
falar(tchau, "Ciclano")
Mas uma das maiores vantagens que eu enxergo nas closures, é a possibilidade de definição delas em runtime. Isso mesmo, conforme você programa, pode criar uma nova closure e chamar uma função que precise dela! Vemos isso em ruby e groovy com frequência para métodos onde iteramos listas e mapas.
Por exemplo, as listas e arrays em groovy possuem um método each que recebe uma closure como parâmetro, esta closure define o que será feito com cada um dos items da lista/array em questão. O exemplo abaixo mostra a praticidade de se fazer a definição da closure inline, ou seja, sem criar uma variável para ela antes.
Em groovy
//groovy
def lista = ["Ferrari", "RBR", "STR", "Brawn", "Renault", "Williams"]
lista.each { equipe ->
println "A equipe ${equipe} correu na #F1 em 2009"
}
Em ruby
#ruby
lista = ["Ferrari", "RBR", "STR", "Brawn", "Renault", "Williams"]
lista.each { |equipe|
puts "A equipe #{equipe} correu na #F1 em 2009"
}
Em scala
//scala
val teams = List("Ferrari", "RBR", "STR", "Brawn", "Renault", "Williams")
teams foreach {
team => printf("A equipe %s correu na #F1 em 2009", team)
}
Dá pra perceber que a closure foi criada já no momento em que ela foi usada. Desta maneira, além de fácil, um código muito mais limpo e fácil de ser entendido.
Acredite, closures são suas amigas, e estão aqui pra te ajudar, então aproveite!
Ahh, e fica a dica de sempre: Ler a documentação:
Closures em Groovy (wiki) (groovydoc) (definição formal)
Closures (Proc) em Ruby (doc) (wiki)
Closures em Scala (wiki)