Nascido no ano de 1993 mas somente apresentado ao público em 1995 pelo seu criador Yukihiro Matsumoto, conhecido em todo o mundo por Matz, o Ruby é uma linguagem orientada a objetos com tipagem forte e dinâmica.

O Ruby destaca-se pelas suas características de ser uma linguagem bastante expressiva, muito simples de ler e ser entendida e muito produtiva. Como o Ruby é uma linguagem interpretada é necessário a instalação de um interpretador na máquina antes de executar um programa. Atualmente a versão mais difundida é a YARV (Yet Another Ruby VM), que é baseada em uma máquina virtual com recursos mais avançados da versão 2.2 do Ruby.

Para aqueles que utilizam o Ubuntu basta utilizar o comando abaixo para instalar o interpertador do Ruby:

sudo apt-get install ruby2.2 ruby2.2-dev build-essential libssl-dev zlib1g-dev \ ruby-switch

Para os que utilizam Windows ou desejam baixar diretamente do site basta visitar o endereço http://ruby-lang.org. Antes de instalar o Ruby é interessante verificar se ele já não está instalado no sistema através do comando "ruby --version".

No entanto, o Ruby possui diversas outras implementações alternativas da linguagem, surgidas após uma maior popularização da linguagem. Algumas dessas implementações são baseadas em uma máquina virtual ao invés de serem um simples interpretador, essas implementações possuem compiladores completados que transformam o Ruby em uma linguagem intermediária que será posteriormente interpretada por uma máquina virtual, semelhante ao que acontece com o Java e permite uma velocidade muito maior na execução do código. Com a utilização dessas máquinas virtuais também tem-se um código portável para diferentes plataformas, além de otimização do código em tempo de execução utilizando até mesmo recursos já conhecidos como o JIT.

Entre essas implementações alternativas tem-se o JRuby, IronRuby, Rubinius, Ruby Enterprise Edition e outras implementações, sendo essas as mais conhecidas atualmente.

O JRuby surgiu como a primeira implementação alternativa do Ruby 1.8.6, e também é a principal implementação da linguagem Java para a JVM. Assim, o JRuby destaca-se por possuir interoperabilidade com código Java existente e tirar proveito das vantagens da JVM como o GC, JIT, Threads, etc. Para adquirir o JRuby basta acessar http://jruby.org que tem como mantenedores empresas fortes como IBM, Borland e ThoughtWorks.

O IronRuby é outra implementação alternativa do Ruby, porém mantida pela poderosa Microsoft, destacando-se por ser o primeiro projeto de código totalmente aberto da Microsoft. Para adquirir e obter mais informações sobre o IronRuby basta acessar http://ironruby.net.

O Rubinius é um dos projetos mais ativos da comunidade Ruby. Entre as suas características este projeto traz ideias de máquinas virtuais do SmallTalk e o seu código é quase totalmente escrito em Ruby.

O Ruby Enterprise Edition veio com o objetivo de modificar o interpretador Ruby para melhorar a performance de aplicações Rails e diminuir a quantidade de memória utilizada. Apesar de ainda ser utilizado o projeto chegou ao fim depois que os mantenedores conseguiram inserir essas modificações na implementação oficial do Ruby, lançada na versão 1.9, que teve como codinome YARV. A última versão do Ruby também corrigiu diversos problemas que existiam no REE.

No restante do artigo veremos como utilizar duas funcionalidades muito importantes da linguagem Ruby, são eles os arrays e os blocos. Os arrays possuem diversas novidades em relação as linguagens mais tradicionais, como possibilidades alternativas de processamento utilizando blocos, métodos que facilitam muito a vida dos desenvolvedores, entre outras características que serão estudadas. Também veremos como funcionam os blocos, uma novidade que surgiu com o Ruby e vem ganhando cada vez mais adeptos em outras linguagens. Os blocos ajudam nas iterações sobre arrays eliminando os loops, e permitem execuções alternativas para os métodos.

Arrays

Os arrays no Ruby possuem diversos métodos que fazem praticamente tudo que é necessário para os programadores. Além disso, o Ruby possui blocos que removeu a necessidade de loops no código. Os blocos seção vistos na próxima seção.

Um array é usado para armazenar uma coleção de objetos. A coleção pode possuir qualquer tamanho que seja necessário para inserir os elementos desejados.

Vamos exemplificar a manipulação de arrays utilizando o Irb do Ruby. Para isso basta ir até a pasta “bin” do Ruby e invocar o Irb conforme abaixo:

prompt> C:\WINDOWS\system32>cd c:\Ruby22
  prompt> C:\Ruby22>cd bin
  prompt> C:\Ruby22\bin>irb

Segue abaixo um exemplo de como criar um array no Ruby utilizando o Irb:

  irb(main):001:0> valores = [1.99, 25.00, 9.90]
  => [1.99, 25.0, 9.9]
  

Listagem 1. Criando um array no Ruby.

Não é necessário criar todo o array com todo conteúdo necessário de uma vez. O array pode ser manipulado mesmo após criá-lo.

Após armazenar os dados iniciais no array é possível manipulá-lo. Para recuperar os valores armazenados no array deve-se especificar qual valor está sendo requerido. Os itens no array não numerados da esquerda para direita, iniciando a partir do zero, sendo que este item é chamado de índice do array.

Assim, dado o array criado anteriormente tem-se que o valor "1.99" está posicionado no índice 0 do array, o valor "25.00" está posicionado no índice 1 e o valor "9.90" está posicionado no índice 2.

Para retornar um item basta especificar o índice do item dentro dos colchetes conforme o exemplo abaixo no Irb:

  irb(main):002:0> puts valores[0]
  1.99
  irb(main):003:0> puts valores[1]
  25.0
  irb(main):004:0> puts valores[2]
  9.9
  

Listagem 2. Retornando itens com base nos índices.

Também é possível atribuir novos valores aos itens do array conforme exemplo abaixo:

  irb(main):005:0> valores[0] = 0.99
  => 0.99
  irb(main):006:0> valores[1] = 1.99
  => 1.99
  irb(main):007:0> valores[2] = 2.99
  => 2.99
  

Listagem 3. Atribuindo valores aos itens do array.

Para inspecionar os valores do array pode-se utilizar o método "p" conforme abaixo:

  irb(main):008:0> p valores
  [0.99, 1.99, 2.99]
  

Listagem 4. Utilizando o atalho “p” para listar os valores do array.

Se for atribuído um valor que está fora dos limites do array, o array crescerá o suficiente para abrigar o novo valor, conforme mostra o exemplo abaixo:

  irb(main):010:0> valores[5] = 5.99
  => 5.99
  irb(main):011:0> p valores
  [0.99, 1.99, 2.99, nil, nil, 5.99]
  

Listagem 5. Atribuindo valores fora dos limites do array.

O array inicialmente possuía três itens (do índice 0 ao 2) e agora expandiu para comportar novos itens. Também pode-se observar que os índices que não receberam nenhum valor foram definidos com nil que representa a falta de valores.

No entanto, se o desenvolvedor tentar acessar um valor fora do limite do array também receberá um valor nil indicando a falta de valor, conforme o exemplo abaixo em que ao tentar acessar a posição 6 de um array que tem no máximo 5 valores definidos é retornado o valor nil:

  irb(main):012:0> puts valores[6]
  => nil
  

Listagem 6. Acessando valores fora dos limites do array.

Os arrays, assim como tudo no Ruby, também são objetos conforme mostra o exemplo abaixo:

  irb(main):013:0> puts valores.class
  Array
  

Listagem 7. Exibindo o tipo da classe da variável valores.

Dessa forma, como um array é um objeto pode-se concluir que existem diversos métodos bastante úteis disponíveis para serem utilizados com este objeto Array. Segue abaixo a utilização de alguns dos métodos disponíveis:

  irb(main):020:0> puts valores.first
  0.99
  

Listagem 8. Utilizando o método first para retornar o primeiro valor do array.

  irb(main):021:0> puts valores.last
  5.99
  

Listagem 9. Utilizando o método last para retornar o último valor do array.

  irb(main):022:0> puts valores.length
  6
  

Listagem 10. Utilizando o método length para retornar o tamanho total do array.

Um métodos bastante interessante é o "include?" que pesquisa por valores dentro do array. Segue um exemplo de pesquisa de um valor que não existe e um valor que existe no array:

  irb(main):023:0> puts valores.include?(25.00)
  false
  

Listagem 11. Pesquisando valores dentro do array retornando false, indicando que o valor não foi encontrado.

irb(main):024:0> puts valores.include?(1.99)
true

Listagem 12. Pesquisando valores dentro do array retornando true, indicando que o valor foi encontrado.

O método "find_index" por sua vez pesquisa o índice de um elemento no array:

  irb(main):025:0> puts valores.find_index(1.99)
  1
  

Listagem 13. Retornando o índice correspondente ao elemento pesquisado utilizando find_index.

Os métodos pop, push e shift permitem inserir e retirar elementos do array conforme abaixo:

  irb(main):026:0> puts valores.push(1.99)
  0.99
  1.99
  2.99
  5.99
  1.99
  irb(main):027:0> p valores
  [0.99, 1.99, 2.99, nil, nil, 5.99, 1.99]

Listagem 14. Utilizando o método push para inserir um elemento no topo de um array.

  irb(main):028:0> puts valores.pop(1.99)
  1.99
  irb(main):029:0> p valores
  [0.99, 1.99, 2.99, nil, nil, 5.99]

Listagem 15. Utilizando o método pop para retirar um elemento de um array.

  irb(main):030:0> puts valores.shift
  0.99
  irb(main):031:0> p valores
  [1.99, 2.99, nil, nil, 5.99]
  

Listagem 16. Utilizando o método shift para retirar elementos da base de um array.

O operador << permite adicionar elementos ao array conforme abaixo:

  irb(main):032:0> p valores
  [1.99, 2.99, nil, nil, 5.99]
  irb(main):033:0> valores << 5.10
  irb(main):034:0> p valores
  [1.99, 2.99, nil, nil, 5.99, 5.1]
  

Listagem 17. Utilizando o operador << para inserção de elementos no array.

Os arrays também possuem métodos que os convertem para String conforme exemplo abaixo:

  irb(main):035:0> puts ["d", "e", "v", "m", "e", "d", "i", "a"].join
  devmedia
  

Listagem 18. Utilizando o método join sem parâmetros para converter o array em String.

  irb(main):036:0> puts ["d", "e", "v", "m", "e", "d", "i", "a"].join("-")
  d-e-v-m-e-d-i-a
  

Listagem 19. Utilizando o método join com parâmetros para converter o array em String.

Se necessário converter uma String para array também é possível conforme os exemplos abaixo:

  irb(main):037:0> p "d-e-v-m-e-d-i-a".chars
  ["d", "-", "e", "-", "v", "-", "m", "-", "e", "-", "d", "-", "i", "-", "a"]
  

Listagem 20. Utilizando o “chars” para conversão de String em array.

irb(main):038:0> p "d-e-v-m-e-d-i-a".split("-")
["d", "e", "v", "m",
"e", "d", "i", "a"]

Listagem 21. Utilizando o “split” para conversão de String em array.

Quando se trabalha com arrays às vezes se faz necessário iterar sobre todos os elementos de um array.

No exemplo abaixo tem-se um array e imprimimos todos os elementos do array:

  valores = [3.99, 25.00, 8.99]
  indice = 0
  while indice < valores.length
           puts valores[indices]
           indices += 1
  end
  

Listagem 22. Imprimindo elementos de um array utilizado o loop while.

A execução do código acima retorna os valores abaixo:

  irb(main):015:0> prices = [3.99, 25.00, 8.99]
  => [3.99, 25.0, 8.99]
  irb(main):016:0> index = 0
  => 0
  irb(main):017:0> while index < prices.length
  irb(main):018:1> puts prices[index]
  irb(main):019:1> index += 1
  irb(main):020:1> end
  3.99
  25.0
  8.99
   

Listagem 23. Execução do código no Irb.

No código acima foi utilizado o "while" para processar todos os elementos do array, um de cada vez.

Segue mais um exemplo abaixo em que se usa um acumulador para retornar o valor total:

  def total(precos)
           qtde = 0
           index = 0
   
           while index < precos.length
                     qtde += precos[index]
                     index += 1
           end
   
           qtde
   
  end
   
  precos = [3.99, 25.00, 8.99]
  puts format("%.2f", total(precos))
  

Listagem 24. Iterando pelo array utilizando acumuladores.

Na próxima seção veremos o que são os blocos e para que eles são utilizados. Os blocos foram inicialmente introduzidos no Ruby e já são cogitados para serem inseridos em outras linguagens de programação nas suas próximas versões.

Blocos

Os blocos (blocks) no Ruby representam a mais nova funcionalidade adicionada a uma linguagem de programação atual. Um bloco é um pedaço de código que pode ser associado com uma chamada de método. Enquanto o método executa ele pode invocar o bloco uma ou mais vezes, assim o método e o bloco trabalham em conjunto para processar a informação.

Os métodos e os blocos trabalham juntos, por isso não é possível ter um bloco sem possuir um método que o aceite. O método abaixo é um exemplo de um método que aceita um bloco como parâmetro:

  def meu_metodo(&meu_bloco)
           puts "O bloco abaixo será invocado:"
           meu_bloco.call
           puts "Após executar o bloco, voltamos para a execução do método!"
  end
  

Listagem 25. Definindo um método que aceita blocos como parâmetro.

Pode-se verificar acima o & antes do parâmetro do método, assim o Ruby espera que um bloco seja passado na chamada do método. Dessa forma, a chamada do método receberá esse bloco, converterá o bloco em um objeto, e armazenará em um parâmetro. O método call utilizado dentro do método é quem será o responsável por chamar o bloco de código passado como parâmetro.

Agora é preciso criar o bloco que será passado como parâmetro para o método. Segue o exemplo abaixo de como criar um bloco:

  meu_metodo do
           puts "Estamos dentro do bloco!"
  end
  

Listagem 26. Definição de um bloco que será passado como parâmetro.

O bloco começa com a definição do nome de um método (meu_metodo), seguido pela palavra reservada "do" que é o início do bloco, após isso tem-se o corpo do método e o fim do bloco. A definição inicial com o nome do método mostra como o método e o bloco estão associados.

Com isso o bloco já será invocado pelo método, não será necessário mais nada para associá-los, tudo é feito de forma automática.

Segue abaixo a execução do método com o bloco associado no Irb:

  irb(main):012:0> def meu_metodo(&meu_bloco)
  irb(main):013:1> puts "O bloco abaixo sera invocado:"
  irb(main):014:1> meu_bloco.call
  irb(main):015:1> puts "Voltamos para a execucao do metodo"
  irb(main):016:1> end
  => :meu_metodo
  irb(main):017:0> meu_metodo do
  irb(main):018:1* puts "Estamos dentro do bloco!"
  irb(main):019:1> end
  O bloco abaixo sera invocado:
  Estamos dentro do bloco!
  Voltamos para a execucao do metodo
  

Listagem 27. Executando o código no Irb.

Também é possível passar diferentes blocos para um único método, basta definir outros blocos conforme abaixo:

  meu_metodo do
           puts "Executando o segundo bloco!"
  end
  

Listagem 28. Criando outro bloco que será passado como parâmetro para o método.

E após isso chamar o bloco quantas vezes quiser conforme abaixo:

  def meu_metodo(&meu_bloco)
           puts "O bloco abaixo será invocado:"
           meu_bloco.call
           puts "Após executar o bloco, o bloco poderá ser invocado novamente:"
           meu_bloco.call
  end
  

Listagem 29. Chamando diversas vezes o bloco definido anteriormente.

Para o exemplo acima teremos a seguinte execução do código no Irb:

  irb(main):024:0> def meu_metodo(&meu_bloco)
  irb(main):025:1> puts "O bloco abaixo ser invocado:"
  irb(main):026:1> meu_bloco.call
  irb(main):027:1> puts “Após executar o bloco, o bloco poder ser invocado novamente:”
  irb(main):028:1> meu_bloco.call
  irb(main):029:1> end
  => :meu_metodo
  irb(main):030:0> meu_metodo do
  irb(main):031:1* puts "Executando o bloco!"
  irb(main):032:1> end
  O bloco abaixo ser invocado:
  Executando o bloco!
  Após executar o bloco, o bloco poder ser invocado novamente:
  Executando o bloco!
  

Listagem 30. Executando diversas chamadas utilizando o Irb.

Lembrando que os blocos vêm depois da definição dos métodos e não antes.

Os blocos, assim como os métodos, também aceitam parâmetros conforme abaixo:

  def teste(&meu_bloco)
           meu_bloco.call("parametro 1 para o bloco", "parametro 2 para o bloco")
  end
   
  teste do |parametro1, parametro2|
           puts "Parâmetros recebidos pelo método:"
           puts parametro1, parametro2
  end
  

Listagem 31. Definindo parâmetros para os blocos.

Como tudo no Ruby as coisas podem ficar ainda mais fáceis e produtivas. Com isso foi introduzido no Ruby a palavra-chave yield que faz a mesma coisa que meu_bloco.call, porém com apenas uma palavra-chave, conforme exemplo abaixo:

  def teste(&meu_bloco)
           yield "parametro 1 para o bloco", "parametro 2 para o bloco")
  end
   
  teste do |parametro1, parametro2|
           puts "Parâmetros recebidos pelo método:"
           puts parametro1, parametro2
  end
  

Listagem 32. Utilizando yield para realizar as chamadas de blocos.

Outra facilidade introduzida pelos blocos é que ao invés de utilizarmos o “do” e “end” para delimitar o corpo do bloco é possível utilizar apenas “chaves” ({ e }) conforme abaixo:

  meu_metodo { puts "Executando o segundo bloco!" }
  

Listagem 33. Utilizando as chaves ao invés de do e end nos blocos.

As chaves também podem ser utilizadas nos blocos que aceitam parâmetros:

  teste { |parametro1, parametro2|
           puts "Parâmetros recebidos pelo método:"
           puts parametro1, parametro2
  }
  

Listagem 34. Utilizando chaves nos blocos que aceitam parâmetros.

Por fim, o método each também é bastante útil quando se quer trabalhar com arrays e blocos. Nesse caso, o each pode ser utilizado para passar os elementos do array como parâmetros para um bloco processá-los, o exemplo abaixo mostra como ele pode ser utilizado:

  ["a", "b", "c"].each { |param| puts param }
  

Listagem 35. Utilizando each para chamar blocos.

Bibliografia

[1] Jay McGavren. Head First Ruby (O’Reilly, 2015).

[2] Ruby Programming Language. Disponível em https://www.ruby-lang.org/.