10
Micro-Tutorial de Ruby - Parte I
by AkitaOnRails on Nov.10.2008 at 12:41am
Depois de fazer várias palestras nas últimas semanas, uma coisa que notei é que a maioria das pessoas que está iniciando no Ruby, ou só ouviu falar de Rails, fica muito surpreso ao ver algumas das características da linguagem.
Este artigo é destinado aos iniciantes ou a quem começou a se interessar recentemente por Ruby e Rails. Antes de mais nada, quem já sabe um pouco de Ruby e quer alguma documentação sobre Rails, recomendo muito o novo site Rails Guides, um esforço que se iniciou com o Pratik Naik e deu grandes frutos. Este site é um trabalho em constante evolução mas já concentra toneladas de guias sobre as principais funcionalidades do Rails. O Cassio, da DRC, também tem um PDF (e um screencast) disponível em seu site, que é uma atualização do material criado pelo Ronaldo Ferraz.
Meu objetivo nesta série de artigos é demonstrar algumas das características de Ruby que a tornam diferente de outras linguagens, principalmente as estáticas como Java ou C#.
Disclaimer: antes de mais nada, vale avisar que usarei alguns trechos de código Java apenas como referência para quem vem de linguagens tradicionais. Não considere isso uma comparação direta (pois os códigos estão propositadamente não otimizados ou simplificados por motivos didáticos).
O que tem de diferente no Ruby?
Todos os códigos Ruby mostrados neste artigo podem ser testados no ambiente IRB (Interpreted Ruby). Com o Ruby já instalado em sua máquina, digite o comando ‘irb’ e você estará dentro do ambiente dinâmico do interpretador Ruby. Qualquer código Ruby será executado na hora, o que deve facilitar seus testes. Na realidade eu recomendo que à medida que leiam o artigo, digitem os códigos em Ruby no IRB e vejam vocês mesmos os resultados. Será bem mais educativo desta forma.
Para começar, vejam este código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Pessoa def initialize(nome) @nome = nome end def nome @nome end def nome=(valor) @nome = valor end end fabio = Pessoa.new("Fabio") puts fabio.nome |
Antes de mais nada, algumas explicações: o que outras linguagens chamam de funções ou métodos, em Ruby são definidas com ‘def … end’. Todo bloco de código termina com ‘end’.
Para colocar um método todo na mesma linha você poderia separar cada linha com “;” (ponto-e-vírgula):
def nome; @nome; end |
Para que um método retorne um valor, não é necessário usar a palavra ‘return’ como estamos acostumados. O resultado da última expressão de um método sempre é devolvida no retorno. Por exemplo, o método ‘nome’ acima tem apenas ‘@nome’, que é o equivalente a fazer ‘return @nome’. Use ‘return’ apenas se quiser sair do fluxo do método antes de chegar à linha final. Finalmente, variáveis de instância (algo como ‘this.nome’) são denotados com o prefixo ‘@’.
Para instanciar uma classe, basta chamar o método ‘new’ dela. Os parâmetros passados a esse método são repassados como argumentos ao método padrão ‘initialize’. E ‘puts’ é apenas algo parecido com ‘System.out.println()’. Parênteses são opcionais, só os use para eliminar ambigüidades na hora de chamar um método com parâmetros.
À primeira vista, o código acima não é diferente de algo semelhante em Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Pessoa {
String nome;
public Pessoa(String nome) {
this.nome = nome;
}
public String getNome() {
return this.nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
Pessoa fabio = new Pessoa("Fabio");
System.out.println(fabio.getNome());
|
Nem mesmo em número de linhas de código temos algum ganho. Olhando apenas dessa forma, para um iniciante, ficaria a pergunta: Onde está a diferença? Apenas por não ter chaves?
Bom, vejamos um outro exemplo – da mesma classe Ruby:
1 2 3 4 5 6 7 8 9 |
require 'ostruct' class Pessoa < OpenStruct; end fabio = Pessoa.new :nome => "Fabio" puts fabio.nome fabio.email = 'akitaonrails@mac.com' puts fabio.email |
Bom, agora estamos começando a conversar! No caso acima eu confesso, trapaceei um pouco. Fiz a classe ‘Pessoa’ herdar a partir de uma classe padrão do Ruby, a ‘OpenStruct’. Ela permite que os objetos instanciados a partir dessa classe tenham qualquer atributo que for necessário em tempo de execução! Vou voltar neste ponto mais tarde, por enquanto apenas ignore a magia negra e continue.
Ruby suporta herança simples de classes, assim como em Java ou C#. O caracter ‘<’ é o equivalente a ‘extends’ em Java.
Vamos a mais alguns exemplos simples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
>> 1 + 2 => 3 >> numero = 5 => 5 >> numero * 3 => 15 >> contador = 1 => 1 >> while contador < numero >> puts contador >> contador += 1 >> end 1 2 3 4 >> def hello >> "Hello World" >> end >> puts hello Hello World |
Obs: quando você está no IRB, “>>” é o “prompt de comando” e “=>” é o resultado do comando que você acabou de executar. Não confunda com o código Ruby propriamente dito.
Na primeira parte algumas operações simples. Em seguida um loop tradicional, com contador. Depois um pequeno método chamado “hello” e sendo executado. Acredito que, independente da linguagem de onde você veio, o que mostrei até agora é bastante familiar. Novamente, fica a pergunta: “onde está a diferença?”
Quase tudo é Objeto
Ruby foi muito influenciado por Smalltalk, a verdadeira linguagem que inspirou quase todas as outras mais modernas de orientação-a-objetos. Não quero aqui começar nenhuma discussão sobre o que é ser OOP ou não pois argumentos desse tipo são irrelevantes aqui.
O que muitos costumam reclamar em linguagens tradicionais é o seguinte:
1 2 3 4 5 6 |
class Teste {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
|
Muita coisa para fazer um simples “Hello World”. Agora vejamos o Hello World em Ruby:
1 2 |
puts "Hello World"
|
“Oras, mas Ruby não é OOP?? Cadê a classe!!?” Vamos entender o exemplo. Considerando que ainda estamos dentro do ambiente IRB, faça o seguinte:
1 2 3 4 5 6 7 8 9 |
>> puts "Hello World" Hello World => nil >> self => main >> self.class => Object |
Em Ruby, “self” é mais ou menos parecido com a função do “this” em Java ou outras linguagens. Mas como podem ver, nós já estamos dentro de um objeto, de uma instância de Object. Nunca estamos num ambiente estático ou não-objeto. Criar um método no IRB significa adicionar esse método ao objeto ‘main’ que, por sua vez é uma instância da classe Object.
Mas não é apenas isso, veja o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 |
>> 1.class => Fixnum >> true.class => TrueClass >> false.class => FalseClass >> nil.class => NilClass |
Um número, um booleano (verdadeiro, falso) e até nulo (o "nil") são objetos. Todos eles respondem a métodos, em especial o método “class” que indica de que classe esse objeto é instância. Note que até o nulo é uma instância da classe chamada “NilClass”.
Classes Abertas
Uma coisa que não tem o que se fazer em muitas linguagens estáticas como Java é mudar de idéia. Toda a idéia de se ter interfaces e classes fechadas força o programador a decidir da primeira vez e ter que sobreviver às conseqüências de sua decisão, o que normalmente força ter que tomar a decisão certa logo no começo e incentiva o temido Big Design Up Front.
Quando precisamos de mais funcionalidades nesses casos, precisamos improvisar. Por exemplo:
1 2 3 4 5 6 7 8 9 |
class StringUtils {
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
}
String nome = "Fabio Akita";
StringUtils.isEmpty(nome);
|
O método “isEmpty()”, disponível na classe StringUtils do pacote Commons do Jakarta, avalia se o string que ele recebeu como argumento é nulo ou vazio. Na classe original “java.lang.String” não existia o método “isEmpty()”. Isso não é um erro, apenas na época em que essa classe foi criada, não parecia óbvio a ninguém que um método assim poderia ser útil. Mas agora, a classe String é fechada e não pode ser reimplementada. Também não adianta criar uma classe MyString que herda de String porque todas instâncias de String não terão as novas funcionalidades do MyString.
Portanto a solução-gambiarra significa criar uma classe separada “StringUtils”, com vários métodos estáticos, como o “isEmpty()”, o que efetivamente significa programação procedural e não-orientada a objetos. StringUtils é apenas uma estrutura com um punhado de métodos estáticos.
Em Ruby, podemos o mesmo problema resolver desta forma:
1 2 3 4 5 6 7 8 9 |
class String def empty? self.nil? || self.size == 0 end end nome = "Fabio Akita" nome.empty? |
Nesse caso específico nem precisaríamos fazer isso porque o método “empty?” já existe na String de Ruby, mas está aí apenas para ilustrar o problema.
Temos algumas coisas interessantes aqui. Primeiro, o nome do método pode parecer estranho por causa da interrogação no final. Mas não se assustem, em Ruby isso é um caracter válido num nome de método e não tem nenhum efeito colateral, é apenas um caracter a mais que expressa a intenção do método, no caso, de fazer uma pergunta ao objeto.
Mas o mais importante: hoje estamos decidindo que a classe String deveria ter mais métodos do que ele já tem. Felizmente, graças às características da linguagem, não estamos presos a uma classe fechada: podemos reabrí-la, reimplementá-la como quisermos e, automaticamente, toda instância de String (novas e inclusive as que já existiam), passam a responder à nova implementação.
Vejamos outro exemplo de orientação a objetos mesclado com “eye candy”.
1 2 3 |
>> 1 + 2 => 3 |
Vamos lembrar do básico: números, em Ruby, são objetos, mais especificamente instâncias da classe Fixnum. Agora vejamos outra maneira de escrever a mesma coisa em Ruby, sem “eye candy”:
1 2 3 |
>> 1.+(2) => 3 |
Espero que isso esteja claro: quando somamos dois números, na realidade estamos chamando o método especial “+” do objeto “1” e passando como argumento o objeto “2”. E isso vale para todos os operadores matemáticos que conhecemos como “-”, “/”. Mas o que acontece quando tentamos somar dois objetos incompatíveis?
1 2 3 4 5 6 7 8 9 10 |
>> 1 + "2" TypeError: String can't be coerced into Fixnum from (irb):35:in `+' from (irb):35 >> 1.+("s") TypeError: String can't be coerced into Fixnum from (irb):36:in `+' from (irb):36 |
Escrevi as duas maneiras novamente: passar um String como parâmetro ao método “+” de um Fixnum devolve uma exceção “TypeError” indicando que a operação é inválida. Mas digamos que, apenas por motivos didáticos, eu realmente queira que o Ruby reaja como Javascript ou Perl e que “1” seja convertido em String e depois concatenado ao parâmetro “2”, resultando em “12”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
>> class Fixnum >> alias :soma_velha :+ ?> def +(valor) >> return self.to_s + valor if valor.is_a? String >> soma_velha(valor) >> end >> end => nil >> 1 + 2 => 3 >> 1 + "2" => "12" |
Várias coisas acontecendo aqui. Vejamos os principais pontos: primeiro, estamos reabrindo a classe Fixnum, ou seja, todas as instâncias dessa classe serão afetadas automaticamente pelo que faremos a seguir.
Depois, mais uma novidade: o método ‘alias’. Esse é um método de classe que cria um novo apontamento a um método que já existe. Pense em algo assim: você tem ‘a = foo’ e depois ‘b = a’. Agora, tanto ‘a’ quanto ‘b’ apontam para o mesmo objeto ‘foo’.
Outra coisa: quando uma classe é criada, reaberta ou ‘executada’ os métodos chamados dentro dela são executados. Ou seja, o comando ‘alias’, por exemplo, serve para reapontar um método com outro nome. No exemplo, já existia o método chamado “+” e com “alias” criamos um segundo método chamado “soma_velha” que aponta para a mesma implementação do método original. Ou seja, neste ponto as três chamadas a seguir se equivalem:
1 2 3 4 5 6 7 8 9 |
>> 5 + 10 => 15 >> 5.+(10) => 15 >> 5.soma_velha(10) => 15 |
Mas fizemos mais: depois de criar o novo apontamento “soma_velha” reimplementamos o método antigo “+”. A idéia é: se o parâmetro for um String, quero transformar o objeto Fixnum num String e depois concatenamos os dois. Veja como usamos o ‘return’ para retornar imediatamente caso este seja o caso. Senão, se o argumento passado não for um String, passamos para o método ‘soma_velha’ fazer a soma do jeito antigo.
Note também que usamos o ‘if’ de uma forma um pouco diferente: no fim da expressão:
1 2 |
return self.to_s + valor if valor.is_a? String |
‘is_a?’ é um método que está sem os parênteses (lembram-se? são opcionais) e serve para verificar o tipo do objeto ‘valor’. Literalmente podemos ler assim: “retorne self.to_s concatenado com ‘valor’ se for do tipo String.” Se você entende inglês verá que a expressão é praticamente uma frase.
E é isso que acontece agora quando tentamos somar um número com um string: ele retorna a concatenação de dois Strings. Note também que esse comportamento passa a valer para todos os objetos numéricos (instâncias de Fixnum).
Esse conceito de reabrir uma classe e implementar uma nova funcionalidade ficou conhecido com o nome de monkey patching. É um recurso muito poderoso e, como tudo que é poderoso ele pode ser tanto uma grande vantagem como um grande risco se usado da maneira errada. Espera-se, claro, que o programador não abuse disso.
O framework Ruby on Rails faz muito uso desse recurso. Um dos pacotes que compõe o Rails chama-se Active Support e uma de suas utilidades é justamente reabrir diversas classes padrão do Ruby para incorporar mais funcionalidades. Por exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# carrega o pacote activesupport >> require 'rubygems' >> require 'activesupport' => true # horário atual >> Time.now => Wed Oct 29 23:36:24 -0200 2008 # fazendo cálculos com datas >> Time.now - 23.days => Mon Oct 06 23:36:28 -0300 2008 >> 2.weeks.ago => Wed Oct 15 23:36:32 -0200 2008 # fazendo cálculos com unidades de medida >> (1.gigabyte - 512.megabytes) / 1.kilobyte => 524288 # transformando objetos em XML >> { :html => { :body => { :p => "teste" } } }.to_xml => "<?xml version="1.0" encoding="UTF-8"?>\n <hash>\n <html>\n <body>\n <p>teste</p>\n </body>\n </html>\n </hash>\n" |
Como podem ver, podemos incrementar muito as funcionalidades de tudo que já existe. O Ruby on Rails começa exatamente assim: primeiro incorporando muitas coisas novas ao próprio Ruby e depois construindo sobre ela. Muitos são casos onde simplesmente depender de criar novas sub-classes não adiantaria muita coisa. Outro exemplo: em Java, se quisermos comparar o conteúdo de dois Strings, não devemos fazer isso:
1 2 3 4 5 6 7 8 9 |
String a = "foo";
String b = "bla";
if (a == b) {
System.out.println("encontrado!");
}
if (a > b) {
System.out.println("a maior do que b");
}
|
O correto seria assim:
1 2 3 4 5 6 7 |
if (a.equals(b)) {
System.out.println("encontrado!");
}
if (a.compareTo(b) > 0) {
System.out.println("a maior do que b");
}
|
Já, em Ruby, fazemos assim:
1 2 3 4 5 |
a = "foo" b = "bla" puts "encontrado!" if a == b puts "a maior do que b" if a > b |
Exatamente como imaginaríamos que deveria ser. Isso porque “==” e “>” são ‘operadores’ mas são também nomes de métodos, como explicamos acima. Então fica fácil implementar o comportamento que precisamos da maneira mais clara e expressiva possível.
Módulos e Organização
No exemplo do Fixnum, reabrimos diretamente a classe para colocar novas funcionalidades. Mas podemos fazer diferente:
1 2 3 4 5 6 7 8 |
Fixnum.class_eval do alias :soma_velha :+ def +(valor) return self.to_s + valor if valor.is_a? String soma_velha(valor) end end |
Como a classe “Fixnum” é por si mesmo um objeto, podemos chamar métodos nela. Por exemplo, “new” é um método dessa instância de Class. O que fizemos acima é a mesma coisa que fizemos antes, mas esse código podemos colocar dentro um método, para ser executado somente quando quisermos. Ou seja, podemos alterar o comportamento de uma classe programaticamente. Mas podemos ser ainda mais seletivos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>> a = "teste" => "teste" >> a.instance_eval do ?> def hello >> "hello from teste" >> end >> end => nil >> a.hello => "hello from teste" >> "foo".hello NoMethodError: undefined method `hello' for "foo":String from (irb):17 from :0 |
Veja agora: criamos um String na variável “a”. Então modificamos essa instância acrescentando um método chamado “hello”, mas somente a essa instância. Quando chamamos “a.hello” ele responde como esperamos, mas quando pegamos uma nova instância de String e tentamos chamar o mesmo método, vemos que não existe. Ou seja, podemos modificar o comportamento de todos os objetos de uma classe, ou somente de um único objeto individual.
Agora vejamos um outro meio de injetar código em classes de maneiras mais organizadas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
module MeusPatches def say_hello "Hello World!" end def say_time Time.now end end class Fixnum include MeusPatches end class String extend MeusPatches end |
Módulos são como Classes que não podem ser instanciadas. No exemplo acima, organizamos dois métodos dentro de um módulo chamado “MeusPatches”. Em seguida reabrimos as classes “Fixnum” e “String”. No primeiro incluímos o módulo e no segundo extendemos o módulo. Para entender a diferença vamos usar isso:
1 2 3 4 5 6 7 8 9 10 |
>> 13.say_hello => "Hello World!" >> "".say_hello NoMethodError: undefined method `say_hello' for "":String from (irb):19 >> String.say_hello => "Hello World!" |
O objeto “13” (que é instância de Fixnum) responde ao método do módulo. A string vazia “" não responde. Eis a diferença entre "include” e “extend”: no segundo quem responde ao método do módulo é a própria classe. Na prática, pense que “include” serve para acrescentar métodos de instância e “extend” para acrescentar “métodos de classe” – esse não é o termo correto mas para a maioria dos casos serve.
No Ruby on Rails esse recurso é muito usado, principalmente para organizar códigos de classes muito longas. Por exemplo, o ActiveRecord tem centenas de funcionalidades. Colocar tudo numa única classe seria muito difícil de manter depois, por isso ele se organiza desta forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# ActiveRecord::Base.class_eval do extend ActiveRecord::QueryCache include ActiveRecord::Validations include ActiveRecord::Locking::Optimistic include ActiveRecord::Locking::Pessimistic include ActiveRecord::AttributeMethods include ActiveRecord::Dirty include ActiveRecord::Callbacks include ActiveRecord::Observing include ActiveRecord::Timestamp include ActiveRecord::Associations include ActiveRecord::NamedScope include ActiveRecord::AssociationPreload include ActiveRecord::Aggregations include ActiveRecord::Transactions include ActiveRecord::Reflection include ActiveRecord::Calculations include ActiveRecord::Serialization end |
Cada um dos includes acima tem um arquivo separado. Por exemplo ActiveRecord::QueryCache fica no arquivo “active_record/query_cache.rb”. É uma excelente maneira de organizar seus códigos. Mas existem alguns truques importantes de se conhecer. Uma delas é entender que módulos tem “eventos”. Ou seja, podemos instruir o módulo para executar alguma coisa toda vez que for incluso em alguma classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
module MeusPatches def self.included(base) base.send(:extend, ClassMethods) puts "Module MeusPaches incluso na classe #{base.name}" end def metodo_de_instancia "sou um metodo de instancia" end module ClassMethods def self.extended(base) puts "Module MeusPatches::ClassMethods extendido na classe #{base.name}" end def metodo_de_classe "sou um metodo de classe" end end end class Pessoa end ?> Pessoa.send(:include, MeusPatches) Module MeusPatches::ClassMethods extendido na classe Pessoa Module MeusPaches incluso na classe Pessoa => Pessoa >> ?> fabio = Pessoa.new => #<Pessoa:0x1789528> >> fabio.metodo_de_instancia => "sou um metodo de instancia" >> ?> Pessoa.metodo_de_classe => "sou um metodo de classe" |
Você vai entender o que significa “send” na próxima seção. Apenas entenda a seguinte idéia: criamos um módulo chamado “MeusPatches” e um sub-módulo dentro dele chamado “ClassMethods” (poderia ser outro nome, mas só para padronizar). Os métodos do módulo principal ficam disponíveis às instâncias dos objetos e os métodos do sub-módulo ficam disponíveis como métodos de classe. A sequência é assim:
- primeiro definimos o módulo MeusPatches e seu sub-módulo ClassMethods
- definimos a classe Pessoa, uma classe vazia
- incluímos o módulo MeusPatches à classe Pessoa
- o método self.included é ativado que, por sua vez, manda extender o sub-módulo ClassMethods na classe Pessoa (que é passado como o parâmetro "base")
- agora a classe Pessoa ganhou os métodos de instância e de classe
- criamos a instância “fabio” e chamamos o método “metodo_de_instancia”
- chamamos o método “metodo_de_classe” diretamente da classe Pessoa
Se fôssemos reescrever a classe Pessoa sem o recurso de módulos, ela ficaria assim:
1 2 3 4 5 6 7 8 9 10 |
class Pessoa def metodo_de_instancia "sou um metodo de instancia" end def self.metodo_de_classe "sou um metodo de classe" end end |
Criar um método a partir de “self” significa que o método está disponível apenas à classe e não às suas instâncias. Novamente, para ser mais fácil de comparar, pense em métodos estáticos de classe como em Java. Mas entenda que não é a mesma coisa: em Java ou C# as classes são estruturas estáticas, em Ruby a própria classe é um objeto (pois ela é instância da classe "Class"). Outra maneira de escrever a mesma coisa seria:
1 2 3 4 5 6 7 8 9 10 11 12 |
class Pessoa def metodo_de_instancia "sou um metodo de instancia" end class << self def metodo_de_classe "sou um metodo de classe" end end end |
A diferença é que em vez de escrever “def self.” o tempo todo, podemos simplesmente reabrir a metaclasse da classe Pessoa e escrever todos os métodos “localmente” ali dentro. Em ambos os casos a classe vai se comportar da seguinte forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
>> p = Pessoa.new => #<Pessoa:0x1775370> >> p.metodo_de_instancia => "sou um metodo de instancia" >> p.metodo_de_classe NoMethodError: undefined method `metodo_de_classe' for #<Pessoa:0x1775370> from (irb):94 >> Pessoa.metodo_de_instancia NoMethodError: undefined method `metodo_de_instancia' for Pessoa:Class from (irb):95 >> Pessoa.metodo_de_classe => "sou um metodo de classe" |
Não perca a Parte II deste artigo para entender o básico da linguagem Ruby. Espero que até aqui tenha ficado bastante claro que não devemos tentar codificar Ruby da mesma forma que codificamos em outras linguagens estáticas. Tirem proveito do dinamismo dessa linguagem, é assim que fazemos o “The Ruby Way”.
Continue lendo a Parte II






Cara!! Muito bom, a forma como foi abordado os temas deixam bem claros o Jeitão Ruby!!!! Só nao gostei do nome, poderia se chamar Mega-tutorial, (tá eu sei, iria sair de algo modesto para megalomaníaco) mas pelo menos, mais realístico. ;-)
Meus Parabéns, jovem!
Abraços
Akita, gostei muito do conteudo e da forma que foi colocado. Apenas gostaria de comentar uma coisa: quando li ’Tutorial", entrei com a expectativa de ver algo bastante introdutório, pra quem nunca tinha visto uma linha de Ruby na vida, mas depois que li fiquei pensando se uma pessoa assim não vai ficar completamente perdida com os tantos exemplos de metaprogramação logo de cara. Talvez o tutorial devesse se chamar “Tutorial de metaprogramação em Ruby” ou algo assim. Enfim, just my $0.02. Abraços e parabéns mais uma vez pela iniciativa.
@Pablo hehe, então a idéia de “Micro-Tutorial” é meio que uma redundância, mais para indicar “galera, isso é só o começo, micro, ainda tem muito mais” :-)
@Demetrius pois é, esse é meu dilema. Para quem ainda não tem experiência em linguagem nenhuma o ideal é o Aprenda a Programar. Mas tentei imaginar: “eu, já sabendo Java, PHP, C# ou coisa assim, o que ganho com Ruby?” Como sempre, meus artigos no blog são experimentais, por isso seus 2 cents valem muito. Ainda preciso entender o que precisa para refinar esse formato.
Akita disse: “eu, já sabendo Java, PHP, C# ou coisa assim, o que ganho com Ruby?”
De fato, o artigo impressiona, e está na medida para aqueles que já têm algum conhecimento e estão passando por aquele dilema: “pô, eu aqui atolado de trabalho, e essa galera desocupada inventando mais uma linguagem…” rsss.
É de longe o maior “empurrãozinho” que recebi para aos poucos desbravar esse novo mundo.
Parabéns!
Fala akita !
No exemplo 18 com activesupport eu precisei dar um require ‘rubygems’ antes do require ‘activesupport’ para carregar essa lib pelo Debian, senao ele nao encontrava ela
valeu Akita, muito bom o artigo
mas vc disse não querer entrar em uma discussão sobre ruby ser OOP ou não
apreciaria mais explicações sobre o pq “Quase tudo ser Objeto”??? e não “tudo em ruby é objeto”
valeu
Legal Fabio muito bom…. fiz dois post no meu blog sobre array em ruby…. gostaria de sua avaliação sobre eles quando tiver um tempo… eh algo simples.. mas..
abraço
Akita, parabéns seu tutorial está muito bom! Vai direto aos pontos chave…
Mas concordo com o que o Demetrius colocou no comentário dele. Também dando meus 2 cents de contribuição, talvez seja melhor você fazer uma “Parte zero” com uma introdução mais suave. Quem achar que não precisa, pode pular e ir direto para a parte 1. Senão existe o risco de espantar pessoas com experiência em programação, mas que necessitam sentir um chão firme e equivalente ao conhecimento atual delas antes de partir para vôos mais ousados. Sabemos que existe muita coisa interessante no Ruby mesmo nas partes mais convencionais, o que poderia ser explorado em uma parte zero.
Mas com parte zero ou sem achei fantástico! Exatamente o que gostaria de ter lido tempos atrás.
Ótima a iniciativa de publicar algo nesta linha. Conheço muita gente que ainda tem preconceito com a linguagem ruby por achá-la limitada. A partir de agora vou mandá-los ler estes mini tutoriais antes de falarem qualquer bobagem. :D
>>Você vai entender o que significa “send” na próxima seção
Você explicou na próxima seção o que significa send, mas não explicou o motivo de utilizar base.send(:extend, ClassMethods) em vez de base.extend ClassMethods.
Seria mais educativo explicar a sutil diferença com relação a métodos privados, conforme:
http://joshstaiger.org/archives/2006/12/the_ruby_send_h.html
Vai aí minha sugestão para uma pequena inclusão em seu ótimo tutorial.
Um abraço,
Rodrigo.
Eu acho (posso estar errado) que a intenção de Akita foi fazer um tutorial mostrando as vantagens de Ruby em relação a linguagens estáticas e, principalmente, tradicionais. Por isso penso que não faz sentido ser muito didático, e ter algo introdutório.
Entretanto, acho que o título engana sim. Muita gente iniciante e que não sabe Ruby lê esse blog, e pode ter ficado desapontado, hehe.
Concluindo, achei muito bom, me ajuda a responder a galera de Java e .NET que vive me perguntando “porque Ruby é melhor?”.
Excelente tutorial, Fábio. Fica cada dia mais evidente que Ruby e Rails oferecem muito poder para nós desenvolvedores! heheh
[]’s
Acho que já entendi porque a dúvida quanto ao “Micro Tutorial”. Se vocês lerem as introduções das Partes I, II e III na realidade aquilo era um único artigo com vários links para outros materiais como o “Aprenda a Programar” que é justamente o mais básico. Mas quando decidi dividir em 3 partes, eu também dividi a introdução e essa informação ficou na Parte II.
@Rosenfeld tem razão, boa dica. Vou ver como encaixo isso.
Muito, muito bom o conteúdo dos tutorias. Muito claro e com ótimos exemplos! Continue assim!!!
Congratulations!!!
Quando tudo estava parecendo nebuloso pra mim, consegui entender a diferença entre método de classe e de instância.
Trabalho atualmente com PHP e não simpatizo muito com Java. Está muito interessante estudar Ruby e entender realmente uma linguagem OO.
Parabéns pelo tuto.
Akita, gostei bastante do artigo. Realmente não é muito básico, e acho que nem deveria ser. Mesmo já sabendo um pouco sobre Ruby deu pra aprender alguma coisa nova.
Este tutorial me deu uma visão mais ampla da linguagem Rails é simplesmente diferente de todos os tutoriais e mini tutoriais da internet . Parabéns e continue com esta série que com certeza deve se tornar um novo livro.
Opa! Muito bacana o tutorial. Achei bastante completo para um “micro-tutorial”.
Akita, me surgiu uma dúvida, talvez idiota.
Usar ostruct é ruim? É lento? Porque é “trapaça”?
Pergunto porque é um puta quebra galho. Não precisa ficar setando geters e seters. Mas aí surgiu a dúvida a respeito de performance.
Valeu, abraços!
Akita, eu queria saber das utilidades de ruby, e nao de rails como muitos difundem… eu queria fazer um projeto em ruby para mostrar para todas as pessoas que é bem mais gratificante do que em outras linguagens. Se puder me passar algum projeto feito em ruby com o codigo fonte (fora o rails claro) :) por favor me avise no meiu aleberver-aromba-gmaiu
como faço para deixar o prompt do ruby colorido no windows ?