Está en la página 1de 4

Ruby: Orientação a objetos em detalhes

Olá pessoal!

Este é meu primeiro artigo no Imasters e pretendo publicar uma série sobre a linguagem Ruby.
De fato a linguagem ganhou bastante destaque no cenário mundial graças ao framework Ruby on Rails, e
por este mesmo motivo percebo que a grande maioria dos desenvolvedores iniciam o aprendizado sobre
Rails e Ruby ao mesmo tempo.

Com isso, alguns pontos importantes da linguagem são "aprendidos" de forma secundária sem termos um
entendimento mais aprofundado sobre como as coisas realmente funcionam.

Por este motivo vou iniciar esta série falando sobre Orientação a Objetos em Ruby.
Meu objetivo não é abordar o paradigma de Orientação a Objetos em si, mas sim, abordar algumas
particularidades da linguagem.

Neste contexto, uma das frases mais famosas é: "Em Ruby tudo é objeto".
Mas o que isso realmente significa?
Significa que até mesmo uma classe é um objeto. Neste caso uma classe é um objeto da classe Class.

O principal para entendermos esta afirmação, está relacionado com o fato de que Ruby é uma linguagem
interpretada e as definições de nossos programas são literalmente executadas.
Logo, quando definimos uma classe, estamos na verdade criando uma instância da classe Class.
E com isso, para entendermos de forma mais clara o funcionamento do modelo de objetos em Ruby é
necessário pensarmos em função dos objetos, e não das classes.

Um exemplo: podemos definir uma simples classe em Ruby da seguinte forma:

class Person
end

p = Person.new

Quando este código for interpretado, um objeto do tipo Class será criado e associado com uma constante
global que no caso é "Person".
Vejam que o simples fato de escrevermos class Person end já estaremos criando um objeto.

Quando fazemos Person.new estamos criando um objeto Person e o método new do objeto Class é
executado por padrão.
Uma outra frase famosa: "Ruby é uma linguagem 100% orientada a objetos"

Isso quer dizer que diferentemente da maioria das linguagens, não temos construções como
number = Math.abs(number), onde um método separado é chamado. Este é um código Java onde o static
method abs da classe Math é chamado para poder calcular o valor absoluto do número passado como
parâmetro.

Em Ruby a responsabilidade de determinar o valor absoluto de um número pertence aos próprios números.
Logo podemos ter algo como: number = number.abs

Neste caso podemos dizer que estamos enviando a mensagem "abs" para o objeto number

Uma nova frase famosa: "Em Ruby as classes são abertas"

Isso significa que ao contrário da maioria das outras linguagens de programação, podemos "injetar" códigos
para modificar qualquer classe.
Pelo dinamismo da linguagem, isso acontece em tempo de execução e esta é uma das funcionalidades que
mais torna a linguagem poderosa.

Não só podemos injetar códigos, mas também modificar comportamentos.


Vamos a um exemplo prático. Iremos definir uma classe com apenas um método e logo abaixo iremos
acrescentar um novo.

class Animal
def speak
puts "speaking..."
end
end

class Animal
def walk
puts "walking..."
end
end

No segundo trecho é como se nós estivéssemos "abrindo" a classe Animal e injetando um novo método.
Poderíamos também fazer o mesmo procedimento da seguinte forma:

class Animal
def speak
puts "Speaking"
end
end

def walk
puts "Walking"
end

Animal.send(:public, :walk)

No caso acima, o método send foi responsável por injetar o método(publico) walk na classe Animal.
Uma dúvida que talvez possa surgir: O que o método walk está fazendo “perdido” no exemplo acima?
Na realidade ele não está “perdido”. Ele já está dentro de um objeto chamado main que no caso é uma
instância da classe Object.

Continuando os exemplos de "classes abertas", em um dos exemplos acima foi citado que em uma
instrução do tipo Person.new o método new do objeto Class é executado por padrão.
Se Class é um objeto da classe Class, podemos "abrí-la" e também alterar seu respectivo funcionamento.
Vejam um exemplo:

class Class
alias oldNew new
def new(*args)
print "Creating a new ", self.name, "\n"
oldNew(*args)
end
end

class Name
end

n = Name.new #Creating a new Name

Neste trecho de código, primeiramente "abrimos" a classe Class e criamos um alias (apelido) para o método
new. Agora ele se chama oldNew. Tecnicamente falando, o método de classe alias cria um novo método e
o aponta para a implementação do método antigo.

Em seguida definimos o "nosso" método new e inserimos um simples print, indicando que estamos criando
um novo objeto.
Por último realizamos a chamada do "verdadeiro" método new passando os mesmos argumentos, para que
ele possa alocar espaço para o objeto.
Com isso é como se estivéssemos "sobrescrevendo" o método new.

Quando a instrução n = Name.new for executada, deveremos ver a mensagem "creating a new Name"
sendo exibida.

Relembrando que tudo é objeto:

Para finalizar vamos verificar uma simples atribuição do tipo:

number = 7 + 3

Algumas pessoas se assustam ao saber que neste caso o = (igual) na verdade é um método.
Neste exemplo da atribuição acontece o seguinte:

1) O +(mais) é um método do objeto 7 e este é uma instância da classe Fixnum.


2) 3 também é uma instância da classe Fixnum e é passada como parâmetro para o método +(mais)
3) O resultado ( que é uma instância da classe Fixnum) é atribuído para o objeto "number".

Vamos a um outro exemplo mais detalhado.


Vejamos esta instrução:

Person.name = "My new name!"


Aparentemente estamos acessando o atributo "name" da classe Person e atribuindo um novo valor.
Correto?
Não. A classe Person possui este método(name=) que permite atualizar o valor.
Ruby irá interpretar a chamada da seguinte forma:

Person.nome=("My new name!")

Percebam que na verdade o método se chama name= e este recebe como parâmetro uma String como o
novo nome.
Logo, em Ruby não é possível acessar diretamente os atributos de uma classe.

Em meu próximo artigo irei abordar outras peculiaridades da linguagem para que em breve possamos falar
de um assunto bastante discutido na comunidade Ruby: Metaprogramação!

Até a próxima!