Saltar para o conteúdo

Mixins em Ruby

Fonte: Wikiversidade
Foi solicitada a renomeação desta para " Ruby: Módulos, Namespace e Mixins". Você pode contribuir com sua opinião na discussão dela própria, ou contactar um administrador em Wikiversidade:Pedidos a administradores.




Origens e Influências

Logo

A linguagem Ruby surgiu a partir de discussões de Yukihiro Matsumoto (Japão, 1965), também conhecido como Matz, que desejava uma linguagem de scripts verdadeiramente orientada a objetos que fosse sintaticamente simples, portável e que tivesse outras características que pudessem aumentar a produtividade de quem a usasse.

Ele alegava conhecer Perl, mas não gostava dela porque ele achava que não parecia ser uma linguagem séria e também conhecia Python, mas ela não era exatamente orientada a objetos.

Ele queria uma linguagem com a qual fosse divertido programar e não um pesadelo. Essa linguagem deveria ser primordialmente compreensível por humanos e em segundo lugar por máquinas.

Como Matz não encontrou a linguagem ideal, ele resolveu criar uma. Ele passou vários meses escrevendo um interpretador e em 1995 divulgou seu trabalho em newsgroups no Japão. Para definir a linguagem ele buscou inspiração nas melhores estruturas e conceitos de Smalltalk, Perl, Ada, Eiffel e LISP.

Outras versões saíram em 1996 e 1997, mas só em 1998 foi lançada uma versão verdadeiramente estável, a 1.2. Nesse ano também ele começa a divulgar sua linguagem fora do Japão ao criar uma lista de discussão sobre Ruby em inglês.

Em 1999 Matz e Keiju Ishitsuka publicam o primeiro livro em japonês sobre Ruby, cujo título traduzido para o inglês era: “The Object-Oriented Scripting Language Ruby” . Um livro em inglês foi publicado no ano seguinte: “Programming Ruby” . Nessa época a linguagem já era mais popular do que Python no Japão e começava a se espalhar pelo mundo.

Yukihiro Matsumoto em março de 2007.

Em 2005, com o framework Ruby on Rails, um ambiente de desenvolvimento rápido de aplicações que permitia uma grande produtividade por parte dos programadores, Ruby fica realmente popular. Esse ambiente é muito usado na comunidade de criadores de aplicações Web. Ele foi criado por David H. Hansson (Dinamarca, 1979) em Ruby, e graças a ele, Ruby tornou-se uma das linguagens mais usadas hoje no mundo, estando em 11º lugar na tabela Tiobe em fevereiro de 2016.

Ruby foi projetada para seguir o princípio conhecido como POLA, “Principle Of Least Astonishment”, o que significa que as estruturas da linguagem não devem surpreender os programadores. Em muitas linguagens de programação encontramos essas surpresas, como estruturas que funcionam de forma inesperada.

Eventualmente Matz foi criticado por pessoas que diziam ter programado sempre com outras linguagens e que ficavam surpresas com alguns comportamentos de Ruby, mas ele esclarecia que o princípio só se aplica a quem já é programador Ruby; quem vem de outras culturas de programação certamente vai achar algumas coisas estranhas. Ele observa que outras linguagens, como C++, por exemplo, continuavam surpreendendo mesmo quem já as programava a muitos anos e era isso o que ele queria evitar que Ruby fizesse.

Ruby está posicionada entre no top 10 da maioria dos índices que medem o crescimento da popularidade de linguagens de programação pelo mundo todo (tais como o índice TIOBE). O Ruby também é totalmente livre. Não somente livre de custos, mas também livre para utilizar, copiar, modificar e distribuir.

Linha do Tempo







Principais marcos da origem da linguagem Ruby e de seu framework principal Ruby on Rails.

Classificação da Linguagem

Ruby é uma linguagem de programação de alto nível, interpretada, multiparadigma, com gerenciamento de memória automático e dinamicamente, implicitamente e fortemente tipada.


Interpretada

Os interpretadores se diferenciam por serem de uma ou de múltiplas passadas. Isso implica diferenças na ordem do código e no desempenho da linguagem, pois o interpretador de passada única lê serialmente o código. Sendo assim, todas referências utilizadas já devem ter sido lidas e criadas pelo interpretador. Ruby, na maioria de usas implementações, faz uso do interpretador de passada única.

Multiparadima

Dar liberdade ao desenvolvedor escolher o paradigma que queira, suporte a programação orientada a objetos, imperativa e funcional. A maior influência na orientação de objetos de Ruby é SmallTalk, a pioneira nesse paradigma, onde não existe tipos de dados que não são objetos. Por exemplo, não existem inteiros, booleandos e caracteres, ao invés disso são objetos inteiros, objetos booleanos e objetos caracteres.


Tipagem Dinâmica

Quer dizer que, a cada interação, o tipo é verificado. Isso fica claro no seguinte exemplo:

x = 100 
(1..4).each{ x = x * 100;  puts "#{ x.class} #{x}"}

Que gera o resultado:

Fixnum 10000
Fixnum 1000000
Fixnum 100000000
Fixnum 10000000000


Implicitamente Tipada

Continuando no mesmo exemplo, quando fizemos x = 100 não precisamos declarar o tipo de x. Ou seja, não foi necessário fazer algo como: Fixnum x = 100. Isso acontece pelo fato do Ruby detectar o tipo de cada variável em tempo de execução.


Fortemente Tipada

Todas as variáveis devem ter um tipo. Ou seja: fazer parte de uma classe no caso do Ruby - e que cada tipo segue a risca seu contrato. Por exemplo:

a = 100
b = "Ruby on Rails"
a + b
 
TypeError: String can't be coerced into Fixnum
    from (irb):54:in `+'
    from (irb):54

Como é possível notar, em Ruby não podemos somar um String com Fixnum pois essa operação não está no contrato da classe String e Fixnum.

Módulos

Descrição da Funcionalidade

Um módulo nada mais é do que uma coleção de métodos e constantes. Ou seja, em um módulo podemos definir quantos métodos e constantes desejarmos, e depois poderemos incluir esse módulo em outros módulos e até mesmo em várias classes, realizando, o compartilhamento de código.

É quase inevitável que ao primeiro contato com módulos não repararmos a sua certa similaridade com classes, pois ambos os recursos nos permitem agrupar uma coleção de métodos, constantes, compartilhar código e outras definições de classes e módulos.

No entanto, existem diferenças consideráveis entre eles, como por exemplo: o fato de que não se pode criar objetos a partir de um módulo. Outro ponto importante, é que módulos não utilizam herança e sim a prática da injeção de módulos, que nos permitir compartilhar mais de um módulo, realizando assim, algo semelhante a herança múltipla (não suportada pela linguagem).

Os módulos disponibilizam dois grandes privilégios: NameSpace e Mixins.

Exemplos

Exemplo Didático

Exemplo Realístico

Exemplo em outra linguagem

Namespace

Descrição da Funcionalidade

NameSpace resumidamente é uma forma de organizar código que nos permite criar um contexto local as suas propriedades. Sendo utilizado principalmente para evitar colisões de diferentes recursos que possuem o mesmo nome.

Como assim? Normalmente quando o nosso projeto ganha “corpo” e deixa de ser pequeno, passamos a dividi-lo em vários arquivos. No entanto, com a necessidade de se criar código (classes, métodos, constantes etc) poderemos alterar configurações do corelib ruby ou até mesmo de propriedades criadas anteriormente por nós. Como por exemplo: digamos que queríamos criar uma classe chamada de String, no entanto, essa classe já foi definida no corelib. Portanto, ao definirmos propriedades a nossa classe ‘recém criada’, estaríamos na verdade modificando a classe já existente no corelib da linguagem.

Exemplos

Exemplo Didático

1. Criar um módulo: Na seção introdutória desse post falei sobre o recurso de NameSpace oferecido por módulos, onde cheguei a citar um exemplo envolvendo a class String do corelib. Naquela ocasião, prometi demostrar como utilizar o NameSpace para evitar o problema então citado.

Portando, iremos entender um pouco mais sobre o conceito de NameSpace aplicado na prática. Vamos começar criando dentro do nosso arquivo modules(.rb) um outro módulo chamado de Duplicate. Nesse módulo definiremos uma class chamada de String, que por sua vez terá um método predicativo chamado de plural?.

Figura 1 - Definição do módulo Duplicate.

Após a criação do módulo Duplicate, foi feita a definição da class String e do seu método plural?. Esse método recebe uma string como argumento e ele retornará true caso o último elemento da string seja igual ao caractere ‘s’, e caso isso não aconteça, ele retornará false que é a última instrução do método. Atenção, esse método não possui muitas validações, pois a intenção é apenas demostrar o recurso de NameSpace.


2. Aplicar Namescapes: O próximo passo será no arquivo main(.rb) instanciar um objeto do tipo da nossa class recém criada, e a partir dele chamar o método plural?.

Figura 2 - Criação da Main.

Antes de tudo, lembre-se que classes também são constantes em ruby e por isso, precisamos utilizar o operador constant look para acessar aquelas que forem definidas dentro de módulos. Esse é o caso da nossa classe String.

3. Executar:

Figura 3 - Execução da Main.

Observe que conseguimos utilizar o método plural? através do objeto copy_string, que é do tipo da class String definida no módulo Duplicate. Já ao tentarmos acessar o mesmo método através de um objeto do tipo String (class do corelib), recebemos um erro. Comprovando que criamos uma nova class chamada de String ao invés de termos alterado a class de mesmo nome definida no corelib, isso é claro, com NameSpace relacionado ao módulo Duplicate.

Exemplo Realístico

Exemplo em outra linguagem

Mixins

Descrição da Funcionalidade

Os Mixins possibilitam utilizar o compartilhamento código. Onde podemos distribui métodos comuns entre várias classes, objetos e módulos.

Exemplos

Exemplo Didático

1. Criar um módulo: A criação de um módulo é bastante similar a de uma classe, no entanto, em oposição de se utilizar a palavra reservada class, o programador deverá utilizar a palavra module. Também é importante destacar que a nomenclatura de módulos segue o mesmo padrão de classes, onde definimos que a letra inicial de cada palavra deverá ser escrita em maiúscula (camel case). O arquivo será chamado de modules.rb.

Figura 1 - Definição do Módulo Converter.

O módulo recém criado possui 04 métodos de conversão, são eles: real_to_dolar, real_to_euro, dolar_to_real e euro_to_real. No intuito de demonstrar a utilização de constantes foi feita a declaração de DOLAR e EURO, para armazenarem de maneira estática a cotação das respectivas moedas.

2. Aplicar o Mixin: O próximo passo é a criação de uma classe que irá utilizar os recursos definidos no módulo Converter. O nome dessa classe será Cambio e a mesma terá dois métodos denominados de menu e selected_action, que por sua vez terão as responsabilidade de dispor as opções disponíveis de conversão de moeda, solicitar uma resposta (opção selecionada) ao usuário e de acordo com essa resposta, invocar um dos métodos de conversão. O arquivo será chamado de cambio.rb.

Figura 2 - Criação da Classe Cambio

Analisando o código acima, é possível perceber que a primeira iniciativa (através do require_relative) foi carregar o arquivo module.rb para o próprio arquivo cambio.rb. Isso foi necessário já que na linha de Nº 04 é pedido para incluir o módulo Converter na classe Cambio, no entanto, o módulo era um desconhecido para o arquivo cambio(.rb). Portanto, a partir da linha de Nº 01 o arquivo cambio(.rb) passou a ‘conhecer’ o arquivo modules(.rb) e assim as suas propriedades puderam ser referenciadas.

Portanto, o módulo Converter foi injetado em nossa classe Cambio através do comando include. Com isso, a classe Cambio ganhou acesso aos métodos do módulo Converter. Dessa forma, qualquer instância de Cambio poderá usufruir desses recursos injetados. Esse processo é chamado de mixin.

Então logo após o comando include, foi definido método menu. Esse método irá exibir o menu de opções e receber a opção de conversão selecionada pelo usuário, retornando-a no final. Depois, foi a vez do método selected_action. Ele primeiramente irá invocar o método menu e de acordo com o retorno obtido, irá chamar um dos métodos de conversão implementados pelo módulo Converter.


3. Executar: É necessário criar um arquivo e dentro dele instanciar um objeto com base na classe Cambio. O arquivo será chamado de main(.rb).

Figura 3 - Criação da Main

Perceba que após a criação do objeto novo_cambio com base na classe Cambio, fizemos esse objeto chamar o método selected_action (que invoca o método menu internamente).

Figura 4 - Execução da Main

Na figura acima pudemos observar o funcionamento do nosso programa, no qual utilizamos os métodos do módulo Converter de dentro da classe Cambio através do seu método selected_action. Resumindo, o objeto instanciado novo_cambio acessou os recursos do nosso módulo de forma ‘indireta’, através do método selected_action que se encarregou de acionar os mecanismos do módulo.

Isso só foi possível porque incluímos tal módulo em nossa classe, fazendo com que os métodos definidos no módulo pudessem ser compartilhados com a classe.

Agora o próximo passo será fazer um objeto instanciado da classe Cambio acessar diretamente os métodos definidos no módulo Converter. Para fazer isso é muito simples, basta solicitar os recursos do módulo a partir do objeto criado (instanciado).

Figura 5 - Acessando os recurso do módulo Converter diretamente do objeto recém criado.

Exemplo Realístico

Exemplo em outra linguagem

Referências

https://www.lume.ufrgs.br/bitstream/handle/10183/31036/000782127.pdf


_________________________________________________________________________________________________________________________

Trabalho para a matéria Estrutura de Linguagens do curso de Ciência da Computação da Universidade do Estado do Rio de Janeiro com o tema de Mixins da linguagem de programação Ruby.

Desenvolvido pelos alunos Raquel Vieira Braga da Silva e Gustavo Moss de Oliveira Demetrio Ferreira.