{tecnologia, conceitos, negócios, idéias, práticas, .NET, ruby, osx, ios e algo mais}
05/07/2010
Já falamos um pouco sobre métodos, "tipagem", arrays e hash no Ruby/IronRuby.Em .Net estamos acostumados a trabalhar com delegates.aspx) e lambdas. Isto nos permite passar trechos de códigos como parâmetros para métodos e então operar com estes trechos de código.Esse comportamento nos permite realizar abstrações interessantes e escrever códigos interessantes. Não vou entrar nos detalhes, há muita informação sobre isso no google.
delegate string Impressor(string algo);
Impressor impressorMaiusculo = delegate(String s){
return "Upper -> " + s.ToUpper();
}
;
Impressor impressorMinusculo = delegate(String s){
return "Lower -> " + s.ToLower();
}
;
Console.WriteLine(impressorMinusculo("VINICIUS"));
Console.WriteLine(impressorMaiusculo("vinicius"));
Poderíamos ainda ter um método que recebe um delegate:
void MetodoQueImprimeNoConsole(Impressor impressor, string imprimir){ Console.WriteLine(impressor(imprimir));
}
MetodoQueImprimeNoConsole( delegate(String s) {
string reversed = string.Empty;
s.Reverse().ToList().ForEach(c => reversed += c.ToString());
return reversed;
}
, "Vinicius");
MetodoQueImprimeNoConsole(s => s.ToUpper(), "vinicius");
Agora as coisas começam a ficar um pouco mais interessantes. O Ruby trabalha muito com blocks, Procs e lambdas. Os conceitos são bastante semelhantes e a diferença está nos detalhes.
Blocks nada mais são do que blocos de código. Sua sintaxe é bastante simples:
letras = ["a","b","c"]#para quem gosta de do endletras.each do |letra| puts letra.upcaseend#para quem gosta de bracketsletras.each {
letra| puts letra.upcase}
O que acontece no código acima é que o método each recebe um block como argumento, ou seja, para cada item dentro do array ele executará o bloco de código informado. No exemplo acima, apenas exibimos o item em upper case.O código é bastante simples de entender. O método each passará como parâmetro para nosso bloco cada item do array. E dentro do bloco o que fazemos é colocar este item (que chamei de letra) em caixa alta, chamando o método upcase.
Os blocks são bastante interessantes, e são uma das coisas que chamam por aí de "rubismo", que oferece um jeito "rubista" de resolver as coisas. Sintaxe simples, elegante, etc.No entanto, não conseguimos reaproveitar os blocks em vários lugares, precisamos reescrever o block toda vez. E aí que surge a Proc.Relacionando com C#, poderia dizer que a Proc é um objeto contendo um delegate. Uma referência para uma função a ser executada. Vejamos:
nomes = ["vinicius","janynne"]caixa_alta = Proc.new do |texto| texto.upcaseendnomes.each do |nome| puts caixa_alta.call nomeend
O código não ficou muito diferente do trabalho com block. Criamos uma Proc expecificando qual código ela executa. E no corpo do each fazemos a chamada do método call da nossa Proc.Agora vamos fazer diferente:
class Telefone attr_accessor :ddd,:numero def initialize(ddd,numero) @ddd = ddd @numero = numero endendclass Agenda @telefones def initialize @telefones = [] end def add_telefone(ddd, numero) @telefones.push Telefone.new ddd,numero end def listar(bloco) @telefones.each do |telefone| bloco.call telefone end endendseparado_por_virgula = Proc.new do |tel| puts tel.ddd + "," + tel.numeroendseparado_por_hifen = Proc.new do |tel| puts tel.ddd + "-" + tel.numeroendagenda = Agenda.newagenda.add_telefone '011','12345678'agenda.add_telefone '011','00001111'agenda.listar separado_por_hifenagenda.listar separado_por_virgula
Novidade nesse código podemos ver na linha 2 onde usamos o attr_accessor para criar getters e setters para nossas propriedades ddd e numero.Da linha 19 até a linha 24 defini um método listas que recebe um parametro, um bloco. A idéia é que passemos para ele um block, uma Proc, etc. Depois crio duas Procs uma que recebe um objeto Telefone e exibe ele separado por vírgula e outra que exibe separado por hifen. Então chamo o método listar da classe Agenda passando as Procs.Bem simples, como deve ser mesmo.Com as Procs podemos por exemplo passar mais de uma para um método:
def listar(bloco1,bloco2) @telefones.each do |telefone| bloco1.call telefone bloco2.call telefone endendagenda.listar(separado_por_hifen, separado_por_virgula)agenda.listar(separado_por_virgula, separado_por_hifen)
Interessante não é?Bem, vou deixar a parte de lambdas para um post futuro, para não tornar esse muito mais extenso, pois farei as comparações entre as diferenças entre lambdas e Procs.E mostrarei também como criar os eventos por exemplo de botões em uma aplicação Windows Forms e WPF com IronRuby.Espero que tenham gostado, e aguardo feedbacks, dúvidas, etc.
Abraços, Vinicius Quaiato.