A linguagem de programação Ruby foi lançada no Japão por Yukihiro Matsumoto em 1995. Ao idealizar a linguagem seu criador disse que ela é “simples na aparência, mas complexa no interior, semelhante ao corpo humano”. O Ruby foi inspirado nas linguagens Perl, Ada, Lisp Smalltalk, Eiffel. Em 2005 a linguagem deu um salto no conceito dos desenvolvedores, muito provavelmente por conta do surgimento do framework Rails, escrito em Ruby, por essa época. Esse framework chegou na verdade a ser mais famoso do que a própria linguagem e, por isso, existe uma confusão de conceitos a respeito da linguagem Ruby e do framework Rails. A linguagem é livre para cópias, modificações e distribuições. O índice TIOBE registrou o crescimento de popularidade da linguagem Ruby nos últimos anos, baseado em um algoritmo de pesquisas na WEB. Ela ocupa a décima posição atualmente.
Características da linguagem
O Ruby foi desenhado com as seguintes características:
- Orientado a objetos: tudo em Ruby é um objeto e não existem tipos primitivos. Isso significa que até uma variável que armazene um valor inteiro é um objeto;
- Herança simples: um dos pilares da orientação a objetos é a herança. Ruby suporta herança simples, ou seja, uma classe pode herdar estados e comportamentos apenas de uma única classe;
- Meta programação: é a capacidade de gerar código em tempo de execução. Isso permite “abrir” uma classe enquanto o código está sendo executado e adicionar um método, por exemplo.
- Tipagem dinâmica: ao declarar uma variável o seu tipo não é explicitado, ou seja, não é necessário escrever o tipo de determinada variável, pois a linguagem irá inferir o seu tipo. Mas isso não significa necessariamente dizer que a tipagem seja fraca;
- Interpretada: não é necessário compilar o código escrito, este é interpretado por uma máquina virtual.
Instalação
Uma grande parte dos ambientes Linux trazem o ruby instalado por padrão. Isso pode ser facilmente verificado digitando o comando ruby --version ou o seu atalho ruby -v no terminal ou console. Mas se o ruby não estiver disponível, ele pode ser instalado rapidamente sem dificuldades.
Linux
Nesses ambientes é comum o uso de gerenciadores de pacotes, por isso, para instalar o Ruby versão 2.0, que será usada no decorrer desse post, no Ubuntu ou Debian deve-se digitar o seguinte comando no terminal:
sudo apt-get install ruby2.0
Para os sistemas operacionais que utilizando o yum como gerenciador de pacotes, como o CentOS, Fedora, RHEL, entre outros, o comando é:
sudo yum install ruby2.0
Windows
No Windows, um ambiente de desenvolvimento pode ser rapidamente configurado utilizando a ferramenta RubyInstaller. Para isso baixe o arquivo Ruby 2.0.0.exe ou Ruby 2.0.0-p647(x64).exe dependendo da arquitetura do seu computador (vide seção Links). O processo de instalação é simples, pois o usuário poderá seguir a configuração padrão apresentada pelo instalador.
Demais sistemas operacionais
O ruby está disponível para várias outras distribuições de sistemas operacionais. Caso deseje instalar em outro sistema operacional diferente dos citados, a documentação pode orientá-lo nesse sentido. Veja o tutorial de instalação (em inglês) na página oficial da linguagem (vide seção Links), que apresenta os caminhos que devem ser seguidos para a instalação da linguagem em diversos sistemas como, OS X, Solaris, OpenIndiana entre outros.
Interactive Ruby Shell – IRB
O IRB é uma ferramenta para interpretar código Ruby com uma resposta imediata que é executada em um terminal ou console. Ela se encaixa na categoria de programas RELP (Read, Eval, Print, Loop), ou seja, ela aceita ou lê uma instrução (read), avalia ou interpreta esta (evalution), mostra ou imprime o resultado (print), e volta para o primeiro passo (loop). Quando o ruby é instalado essa ferramenta é também instalada. Para que possamos usá-la basta digitar o comando irb no se prompt de comando ou terminal: o resultado pode ser visto na Figura 1.
A linha irb(main):001:0> indica que o interpretador está ativo e esperando que uma instrução seja passada para que possa interpretá-la e apresentar o resultado. Alguns exemplos encontrados no artigo utilizarão essa ferramenta.
Comentários
Os comentários permitem inserir breves informações ou observações sobre o código, mas eles são ignorados pelo interpretador. Os comentários em Ruby são divididos em duas categorias: comentários de linha e os comentários de bloco.
Os comentários de linha podem ser escritos apenas adicionando um sinal de # (cerquilha) na linha desejada. O que vier após esse caractere não será encarado como uma instrução a ser executada, como mostra o exemplo a seguir:
# o método puts imprime algo na saída
puts “Hello World”
# declaração de uma variável com o valor 100
valor = 100
Já os comentários de bloco iniciam com o sinal de = (igual) seguido da palavra begin e são encerrados também com o sinal de = (igual) seguido pela instrução end, como mostra o exemplo a seguir:
=begin
o método puts
imprime algo na saída
=end
puts “Hello World”
=begin
declaração de uma
variável com o valor 100
=end
valor = 100
Existe uma restrição com relação a essa última categoria de comentário, pois as instruções =begin e =end devem ficar posicionadas na primeira coluna do arquivo, sem espaços ou quaisquer outros caracteres. Esse tipo de comentário não é usado com frequência pelos desenvolvedores, pois a própria documentação da linguagem usa apenas comentários de linha.
Tipos de dados
Não existem tipos primitivos na linguagem Ruby, e todos os tipos são objetos. A seguir estão alguns detalhes sobre os principais tipos.
Integer
A classe Integer representa valores numéricos inteiros. Essa é uma classe abstrata, e não é possível instanciar objetos com ela, tanto que nem existe um método new no seu código. Se tentarmos instanciar um objeto com essa classe o resultado será um erro, conforme mostrado na Listagem 1.
irb(main):001:0> valor = Integer.new
NoMethodError: undefined method `new' for Integer:Class
from (irb):3
from /usr/bin/irb:11:in `<main>
Essa classe serve apenas como modelo para as classes que herdam ou estendem dela. As suas subclasses compartilharão os mesmos atributos e comportamentos dela, e são elas que realmente são usadas para instanciar objetos.
Fixnum
Essa classe é uma das subclasses de Integer, ela representa números inteiros. Quando digitamos um número inteiro no irb, automaticamente é instanciado um objeto Fixnum, como vemos no exemplo da Listagem 2.
irb(main):001:0> salario = 1000
=> 1000
irb(main):002:0> salario.class
=> Fixnum
O exemplo cria uma variável contendo um objeto Fixnum que representa o valor 1000. Na segunda instrução apenas confirmamos o tipo do objeto chamando o método class. Essa classe possui um limite de valor que ela pode armazenar, mas isso depende da arquitetura do computador.
Bignum
A classe Bignum também é subclasse de Integer e ela armazena valores inteiros maiores que Finum. O limite dos valores armazenados depende nesse caso da memória disponível. Na Listagem 3 é apresentada a declaração e inicialização de uma variável Bignum.
irb(main):001:0> valor = 9999999999999999999
=> 9999999999999999999
irb(main):002:0> valor.class
=> Bignum
Se os valores designados a uma variável do tipo Fixnum ultrapassarem o limite que o tipo suporta, o Ruby automaticamente converterá a variável para o tipo Bignum, como apresentado na Listagem 4.
irb(main):001:0> valor = 9999
=> 9999
irb(main):002:0> valor.class
=> Fixnum
irb(main):003:0> valor = 999999999999999999999
=> 999999999999999999999
irb(main):004:0> valor.class
=> Bignum
O exemplo mostra que a variável valor foi designada inicialmente como sendo um Fixnum, mas quando esse valor ultrapassou o limite de armazenagem, o tipo foi alterado para Bignum, que suporta o tamanho do valor inserido na variável.
Float
A classe Float deriva seu comportamento da classe Numeric e é usada para representar valores de ponto flutuante, ou seja, números com valores fracionados, independentemente do tamanho desse número. Para separar a parte inteira da fracionário usa-se o ponto e não virgula, como mostra o exemplo da Listagem 5.
irb(main):001:0> altura = 1.78
=> 1.78
irb(main):002:0> altura.class
=> Float
Operações
Para instâncias de objetos dos tipos numéricos citados, estão disponíveis métodos para efetuar cálculos ou operações matemáticas. Diferentemente de outras linguagens onde os responsáveis por cálculos são dispositivos chamados de operadores aritméticos, em Ruby eles são, na verdade, métodos, podendo até mesmo terem o comportamento sobrescrito. Os mais comumente usados e conhecidos são + (soma), - (subtração), / (divisão), * (multiplicação) % (modulo ou resto de uma divisão) e exponenciação (**).
Nas Listagens 6 a 8 temos alguns exemplos das operações básicas com os métodos citados, lembrando que essas instruções devem ser executadas no irb e que o texto precedido de # (cerquilha) é apenas um comentário explicativo.
#declaração de uma variável para armazenar a primeira nota
irb(main):001:0> nota1 = 9
=> 9
#declaração de uma variável para armazenar a segunda nota
irb(main):002:0> nota2 = 7
=> 7
#declaração de uma variável para armazenar a soma da primeira e segunda nota
irb(main):003:0> resultado = nota1 + nota2
=> 16
#declaração de uma variável para armazenar a média das duas notas, resultado de uma divisão
irb(main):004:0> media = resultado / 2
=> 8
#impressão de uma mensagem contendo o resultado da média
irb(main):005:0> puts "sua nota média é: " + media.to_s
sua nota média é: 8
#imprimindo resultado da operação de exponenciação 10³
irb(main):001:0> puts "10³ é igual a: " + (10**3).to_s
10³ é igual a: 1000
#imprimindo o resto da divisão de 10 / 3
irb(main):005:0> puts "O resto da divisão de 10 / 3 é: " + (10%3).to_s
O resto da divisão de 10 / 3 é: 1
String
As String's armazenam cadeias ou conjuntos de caracteres, e são usadas constantemente para representar textos na aplicação. Nos exemplos apresentados utilizamos objetos String's para retornar uma mensagem para o usuário. Em Ruby, as String’s vêm em dois tipos: as delimitadas por aspas simples e as delimitadas por aspas duplas, como no exemplo a seguir:
irb(main):001:0> mensagem = 'Hello Wolrd'
irb(main):001:0> nova_mensagem = “Hello Wolrd”
O conteúdo das que são declaradas entre aspas simples é interpretado literalmente, já as delimitadas por aspas duplas podem conter expressões que inferem para outras coisas, como mostra o exemplo da Listagem 9.
irb(main):001:0> usuario = 'Tavares'
irb(main):002:0> mensagem = 'Bem vindo, #{usuario}'
irb(main):003:0> puts mensagem
Bem vindo, #{usuario}
Note que a expressão #{usuário} foi impressa, ao invés do nome do usuário. Para que isso funcione devemos usar um objeto String que esteja delimitado por aspas duplas, só então essa instrução será interpretada como desejado:
irb(main):001:0> usuario = “Tavares”
irb(main):002:0> mensagem = “Bem vindo, #{usuario}”
irb(main):003:0> puts mensagem
Bem vindo, Tavares
Outros métodos
Além dessas peculiaridades, existem muitos métodos interessantes que são bastante úteis. São eles:
- O método capitalize altera para caixa alta o primeiro caractere contido na String:
irb(main):001:0> mensagem = "ola, João da Silva" irb(main):002:0> puts mensagem.capitalize Ola, joão da silva
- O método Upcase altera para caixa alta todo o objeto String, enquanto que o método downcase altera todos os caracteres para caixa baixa:
irb(main):001:0> boas_vindas = "ola, joao da silva" irb(main):002:0> puts boas_vindas.upcase OLA, JOAO DA SILVA irb(main):003:0> despedida = "ATE MAIS, JOAO DA SILVA" irb(main):004:0> puts despedida.downcase ate mais, joao da silva
- O método lengh retorna a quantidade de caracteres em uma String:
irb(main):001:0> empresa = "DEVMEDIA" irb(main):002:0> puts empresa.length 8
- Já o método << adiciona uma String passada como parâmetro ao final da String que teve tal método invocado:
irb(main):001:0> saudacao = "Ola, Joao da Silva" irb(main):002:0> saudacao << " Souza" irb(main):003:0> puts saudacao Ola, Joao da Silva Souza
- O método eql? retorna true (verdadeiro) se o conteúdo dos dois objetos String's forem idênticos, e false (falso) caso contrário:
irb(main):001:0> linguagem1 = "ruby" => "ruby" irb(main):002:0> linguagem2 = "java" => "java" irb(main):003:0> linguagem2.eql?(linguagem1) => false irb(main):004:0> linguagem2 = "ruby" => "ruby" irb(main):005:0> linguagem2.eql?(linguagem1) => true
- O reverse retorna a String's passada como parâmetro com os caracteres invertidos:
irb(main):001:0> linguagem = "ruby" => "ruby" irb(main):002:0> puts linguagem.reverse ybur
- Por fim, os métodos to_i e to_f fazem um cast, ou convertem, o objeto String respectivamente em um objeto Integer e Float, como vemos no exemplo a seguir:
irb(main):001:0> valor_em_string = "100" => "100" irb(main):002:0> valor_em_inteiro = valor_em_string.to_i => 100 irb(main):003:0> valor_em_inteiro.class => Fixnum irb(main):004:0> valor_em_float = valor_em_string.to_f => 100.0 irb(main):005:0> valor_em_float.class => Float
Array
Um array é uma estrutura de dados para guardar uma coleção de objetos, que podem ser até de tipos diferentes. Cada elemento está associado a um índice que inicia em 0, e pode ser usado para recuperar o elemento.
Os elementos do array em Ruby são delimitados por colchetes e separados por (virgula). A sintaxe de declaração de um array segue o seguinte:
nome_da_variavel = [elemento1, elemento2, elemento3]
Alguns métodos comumente usados em array's são each, <<, sort, include?, [], []=.
O método each é usado para percorrer os elementos de um array, e para isso deve ser passado um bloco de código que determina o que será feito com cada elemento. A Listagem 10 mostra o uso do método each para iterar sob os elementos e o puts para mostrar cada elemento do array.
irb(main):001:0> linguagens = ["ruby", "python", "java", "c++", "c#"]
=> ["ruby", "python", "java", "c++", "c#"]
irb(main):002:0> linguagens.each do |elemento|
irb(main):003:1* puts elemento
irb(main):004:1> end
ruby
python
java
c++
c#
O método << adiciona um novo elemento em um array já existente, como vemos no exemplo da Listagem 11.
irb(main):001:0> linguagens = ["ruby", "python", "java", "c++", "c#"]
=> ["ruby", "python", "java", "c++", "c#"]
irb(main):002:0> linguagens << "php"
=> ["ruby", "python", "java", "c++", "c#", "php"]
Também é possível ordenar os elementos de um array por meio do método sort, como mostra a Listagem 12.
irb(main):001:0> linguagens = ["ruby", "python", "java", "c++", "c#"]
=> ["ruby", "python", "java", "c++", "c#"]
irb(main):002:0> linguagens.sort
=> ["c#", "c++", "java", "python", "ruby"]
O include? Verifica se o objeto passado por parâmetro está contido ou incluso no array: ele retorna true (verdadeiro) ou false (falso) para indicar isso, coo mostra o exemplo da Listagem 13.
irb(main):001:0> linguagens = ["ruby", "python", "java", "c++", "c#"]
=> ["ruby", "python", "java", "c++", "c#"]
irb(main):002:0> linguagens.include?("java")
=> true
irb(main):003:0> linguagens.include?("php")
=> false
O [] é bastante usado com o objetivo de recuperar o item de um array pelo seu índice ou posição. Lembrando que esse índice inicia com 0. Observe a Listagem 14.
irb(main):001:0> linguagens = ["ruby", "python", "java", "c++", "c#"]
=> ["ruby", "python", "java", "c++", "c#"]
irb(main):002:0> puts "item da posição 0: #{linguagens[0]}"
item da posição 0: ruby
irb(main):003:0> puts "item da posição 2: #{linguagens[0]}"
item da posição 2: Ruby
Já o []= pode ser usado para substituir o elemento da posição passada por parâmetro, como demonstrado a seguir:
irb(main):001:0> linguagens = ["ruby", "python", "java", "c++", "c#"]
irb(main):002:0> linguagens[1]= "php"
irb(main):003:0> linguagens
=> ["ruby", "php", "java", "c++", "c#"]
Hash
O hash é uma estrutura semelhante ao array, pois também armazena uma coleção de informações ou elementos. Mas diferentemente do array, os elementos do hash não estão associados a um índice e sim a um objeto qualquer que funciona como uma chave. Os seus elementos são delimitados por “{}” (chaves) e a sintaxe para a declaração de um hash é a seguinte:
nome_da_variavel = {objeto_chave1 => valor1, objeto_chave2 => valor2}
Existem alguns métodos mais usados para manipular as informações de um hash: new, []=, has_key?, has_value?, each.
O método new, disponibiliza um caminho de criação de hash's. Quando executado sem parâmetros inicializa um objeto hash vazio:
irb(main):001:0> notas = Hash.new
=> {}
Assim como em objetos array, o método []= é usado para adicionar elementos a um hash. O exemplo a seguir mostra como adicionar um item ao hash criado logo acima.
irb(main):002:0> notas["Algoritmos"]= 8
irb(main):003:0> notas["Matematica"]= 7
irb(main):004:0> puts notas
{"Algoritmos"=>8, "Matematica"=>7}
Os métodos has_key? e has_value? são usados, respectivamente, para buscar se o hash possui uma determinada chave e um valor, como mostra a Listagem 15.
irb(main):001:0> notas = {"Algoritmos"=>8, "Matematica"=>7}
irb(main):002:0> notas.has_key?("Algoritmos")
=> true
irb(main):003:0> notas.has_key?("POO")
=> false
irb(main):004:0> notas.has_value?(7)
=> true
O método each, assim como nos array's, percorre os elementos do hash, mas existe apenas uma pequena diferença no seu uso, já que o hash é formado por uma estrutura chave>valor. O exemplo da Listagem 16 mostra como usar esse método.
irb(main):001:0> notas = {"Algoritmos"=>8, "Matematica"=>7}
irb(main):002:0> notas.each do |disciplina, nota|
irb(main):003:1* puts "#{disciplina} - #{nota}"
irb(main):004:1> end
Algoritmos - 8
Matematica – 7
Além do método each, estão também disponíveis each_key e each_value que iteram apenas sobre as chaves e valores, respectivamente.
Symbol
Os objetos desse tipo se assemelham com Strging's, mas não são definidos entre aspas, eles são, na verdade, definidos com um sinal de dois pontos. Dois símbolos idênticos apontam para o mesmo endereço de memória, ou seja, são únicos, justamente por esse motivo os desenvolvedores constantemente os usam como chaves em objetos hash's. A seguir o código demostra como usar os símbolos como chaves:
irb(main):001:0> notas = {:algoritmos => 8, :matematica => 7}
Isso também pode ser feito da seguinte maneira, tem o mesmo efeito, mas de uma forma mais simples:
irb(main):001:0> notas = {algoritmos: 8, matematica: 7}
Range
Um Range (série) representa um intervalo de objetos. É possível instanciar um Range usando os operadores “..” , “...” ou o método new, como mostra a Listagem 17.
irb(main):001:0> um_a_dez = 1..10
=> 1..10
irb(main):002:0> um_a_nove = 1...10
=> 1...10
irb(main):003:0> um_a_cem = Range.new(1, 100)
=> 1..100
Existe uma diferença entre os dois primeiros operadores: o “..” no exemplo mostrado inclui no intervalo criado o número 10, enquanto que o “...” exclui esse algarismo.
Os Range's podem ser convertidos para array's com a chamada ao método to_a, como visto a seguir:
irb(main):001:0> um_a_dez = 1..10
=> 1..10
irb(main):002:0> lista = um_a_dez.to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):003:0> lista.class
=> Array