Ruby é uma linguagem consistente, orientada à objeto e dinâmica, ou seja, você receberá um feedback a cada comando. Nesse artigo será mostrado seus conceitos, como fazer e utilizar suas classes e métodos.


Guia do artigo:

Ao baixar seu pacote, um interpretador interativo chamado irb é instalado. Utilizando este no prompt de comando (cmd ou Terminal) você poderá executar os códigos. Para iniciar uma sessão abra seu prompt e digite:


        $ irb
        irb(main):001:0>
        

Agora você está dentro do Ruby.

Caso você ainda não tenha nenhum conhecimento da linguagem, aconselho que primeiro veja uma introdução sobre o Framework Ruby on Rails e caso já tenha um certo conhecimento e gostaria de se aprofundar ainda mais, sugiro que faça esse curso online de Ruby on Rails.

Sintaxe da linguagem

Variáveis

Variáveis são usadas para guardar valores enquanto há um processamento de dados. Em Ruby, como já deve ter sido notado, não é necessário definir tipos, apenas é necessário que a variável tenha um nome e um valor atribuído, depois disso o trabalho será do interpretador.

São quatro tipos de variáveis:

  • Variáveis Locais: Apenas existem no método ou bloco de código que foram atribuídos. Os valores são atribuídos enquanto o programa roda. A escrita dessas variáveis é sempre com letra minúscula.
    Exemplo: meu_nome
  • Variáveis Instanciadas:Começam com @. São as únicas variáveis que dão uma instância à classe.
    Exemplo: @usuario
  • Variáveis da Classe: Começam com @@. Existem no escopo da classe, então todas as instâncias de uma classe específica têm um valor para a variável da classe.
    Exemplo: @@usuarios
  • Variáveis constantes: São aquelas que não mudam durante a execução do programa. Em Ruby, elas podem ser realocadas, mas será recebido um aviso do interpretador. Além disso, são escritas em letra maiúscula.
    Exemplo: IP_SERVER

Operadores

Para fazer operações com valores é necessário uma série de sinais, como os mostrados a seguir:

  • Aritmético:*, /, %, +, **
  • Atribuição: []=, =
  • Comparação: <=, >=, <, >
  • Lógico:&, ^, |
  • E, OU:||, &&

Na documentação do Ruby você consegue maior conhecimento da aplicação desses conceitos, senão, o artigo ficaria muito extenso. Mas veremos exemplos a seguir da utilização de alguns deles.

Tipos de dados Ruby

Um tipo de dado é uma limitação colocada no interpretador, por exemplo, números e textos são dois tipos diferentes. Como em outras linguagens, no Ruby existe essa distinção.

String

Esse será uma sequência de caracteres representados por uma palavra ou alguma forma de texto. No Ruby, qualquer dado entre apóstrofo ou aspas será do tipo string.

Para testar, como o irb já está na sua tela de comando, digite:


        2.0.0-p451 :001> ‘Ruby é uma linguagem diferente’
        

O irb irá responder:

 => “Ruby é uma linguagem diferente”

A principal diferença entre usar delimitações do string com apóstrofo (‘’) ou aspas (“”) é que apóstrofos são sujeitos à alterações ou erros como, por exemplo:

2.0.0-p451 :002> ‘King’s Boulevard’
        2.0.0-p451 :003’> ' SyntaxError: (irb):12: syntax error, unexpected tIDENTIFIER, expecting end-of-input
        'Kings's boulevard'
        ^

O que aconteceu é que o interpretador não soube onde era o término do código e continuou sem dar o feedback, mesmo com o símbolo do apóstrofo do lado do número, até que a frase fosse terminada.

Outro exemplo:

 2.0.0-p451 :004> ‘Agora é #{Time.now}’
        => ‘Agora é \#{Time.now}’

No string acima foi utilizado o construtor #{}, que serve para substituições de varáveis. Essa técnica é conhecida como interpolation. Como a substituição foi feita com ‘’, a resposta foi inesperada. Se as aspas tivessem sido usadas, o retorno seria algo do gênero:

=> “Agora é 2014-09-10 18:28:09 -0300”

Quando você utiliza a hastag (#) com as chaves, o Ruby entende que deve-se avaliar o que está ali dentro. Porém, quando você usa o apóstrofo,a substituição não é checada.

Existem vários métodos para fazer uma manipulação string como, por exemplo, aumentara letra ou deixar apenas a primeira letra em maiúscula. Para isso, digite no seu prompt:

2.0.0-p451 :005>”Brasília-Brasil”.upcase
        => “BRASÍLIA-BRASIL”
        2.0.0-p 451 :006> “RUBY ON RAILS”.capitalize
        => "Ruby on rails"

Esses são alguns dos vários exemplos e se você quiser, pode testar com outros métodos, como downcase e .length.

Números

Em Ruby, os números possuem algumas classes para os representarem como: Fixnum, Bignum e Float.

O Fixnume Bignum fazem parte dos números inteiros e o Floatos números reais, ou seja, fracionários. Como em outras linguagens, você pode fazer contas aritméticas como faria na calculadora no Terminal. Por exemplo:

 2.0.0-p451 :001 > 1+2
        => 3

Ao utilizar inteiros, se dividí-los, o resultado mostrado será um do mesmo tipo. Para obter um resultado decimal é preciso indicar tal fato. Por exemplo:

2.0.0-p451 :002 > 3/5
        => 0

        2.0.0-p451 :003 > 3.0/5
        => 0.6

Symbol

Os símbolos não são muito comuns nas linguagens de programação. Porém, são extremamente úteis. Eles são um tipo de dado que começam com dois pontos(:), como :nome. Estes são objetos usados para apontar alguma data que não é tradicionalmente um objeto String. A diferença é que um Symbol é imutável, enquanto que um String é mutável e pode ter problemas com resultados inesperados e desempenho reduzido. Vejamos um exemplo:


        2.0.0-p451 :001 > module One
        2.0.0-p451 :002?> class Fred
        2.0.0-p451 :003?> end
        2.0.0-p451 :004?> $f1 = :Fred
        2.0.0-p451 :005?> end
        => :Fred
        2.0.0-p451 :006 > module Two
        2.0.0-p451 :007?> Fred = 1
        2.0.0-p451 :008?> $f2 = :Fred
        2.0.0-p451 :009?> end
        => :Fred
        2.0.0-p451 :010 > $f1.object_id
        => 538668
        2.0.0-p451 :011 > $f2.object_id
        => 538668
        

Nesse trecho fica claro que, independentemente das mudanças, o valor do símbolo continua retornando o mesmo número.

Array

Arrays são parte de quase todas as linguagens de programação. Eles mantem a informação em ordem e são definidos com a utilização de colchetes [ ]. Os primeiros elementos sempre têm índice zero. Alguns exemplos a seguir deixarão mais claro como funcionam no Ruby.


        (1) 2.0.0-p451 :012 > array_cidades = ["Rio de Janeiro", "Salvador", "São Paulo"]
        =>["Rio de Janeiro", "Salvador", "São Paulo"]

        (2) 2.0.0-p451 :013 > array_cidades[0]
        => "Rio de Janeiro"

        (3) 2.0.0-p451 :014 > array_cidades[2] = "Cuiabá"
        => "Cuiabá"

        (4) 2.0.0-p451 :015 > array_cidades << "Brasília"
        => ["Rio de Janeiro", "Salvador", "Cuiabá", "Brasília"]

        (5) 2.0.0-p451 :016 > array_cidades + ["Fortaleza"]
        => ["Rio de Janeiro", "Salvador", "Cuiabá", "Brasília", "Fortaleza"] 

No primeiro exemplo foi definido o array das cidades com três elementos. No segundo a cidade com índice 0 foi referência para a resposta do irb: “Rio de Janeiro”. No terceiro exemplo substitui-se o objeto de índice 2, “São Paulo”, por “Cuiabá”. No quarto exemplo temos o operador conhecido como shovel, que adiciona um novo objeto à lista, assim como o último exemplo, que utiliza uma forma diferente para colocar um novo item no array.

Hash

Um Hash oferece uma forma diferente de representar uma coleção em relação ao array, pois ele utiliza uma chave (key). Em Ruby, frequentemente utiliza-se um símbolo como chave. Na verdade, qualquer objeto pode ter a função de uma key. A forma de escrever um Hash em Ruby é hash = {key: “value”}. Para ficar mais claro, seguem alguns exemplos:


        (1) 2.0.0-p451 :008 > meu_hash = {nome: "João", idade: 12, estado: "GO"}
        => {:nome=>"João", :idade=>12, :estado=>"GO"}

        (2) 2.0.0-p451 :009 > meu_hash[:nome]
        => "João"

        (3) 2.0.0-p451 :013 > meu_hash.first
        => [:nome, "João"]

        (4) 2.0.0-p451 :014 > meu_hash.keys
        => [:nome, :idade, :estado]

        (5) 2.0.0-p451 :015 > meu_hash[:cidade] = "Florianópolis"
        => "Florianópolis"

        (6)2.0.0-p451 :016 > meu_hash[:estado] = "SC"
        => "SC"

        2.0.0-p451 :019 > meu_hash[:estado]
        => "SC" 

No exemplo número 1 o hash foi criado. No segundo exemplo a key ‘nome’ é colocada para descobrir seu valor (value). No exemplo 3, o primeiro da lista é mostrado. No quarto exemplo é mostrado apenas os símbolos pedidos. No exemplo número 5 cria-se um novo objeto e no exemplo 6 substitui-se um valor existente por um novo na chave (key) de ‘:estado’.

NOTA:

Para versões de Ruby abaixo de 1.9, a representação de um hash será: exemplo = {:key=> “value”}.

Lógica

O Ruby possui todas as estruturas lógicas mais comuns, como while e if, mas enquanto os programadores de Java, C e Perl se perdem nas chaves, a estrutura aqui é muito mais simples.

Vejamos a seguir alguns exemplos de Estruturas de Controle:


        2.0.0-p451 :020 > count = gets.to_i
        3
        => 3
        2.0.0-p451 :021 > if count == 3
        2.0.0-p451 :022?> puts "Voce acertou!"
        2.0.0-p451 :023?> else
        2.0.0-p451 :024 > puts "Digite novamente"
        2.0.0-p451 :025?> end
        => Voce acertou! 

Na primeira linha, uma variável é criada e é transformada em inteiro (to_i) para receber um valor pedido pelo comando gets. Após isso, uma estrutura if e else é definida e o usuário recebe o valor que a lógica promove. O else if também existe no Ruby, porém, é escrito elsif e não utiliza o end no final.

Outra forma é o unless e é utilizado para fazer uma exceção com um apenas um if, como mostra o exemplo a seguir:


        2.0.0-p451 :050 > a = 5
        2.0.0-p451 :058 > unless a > 5
        2.0.0-p451 :059?> puts "Não é maior que 5"
        2.0.0-p451 :060?> end
        Não é maior que 5
        => nil 

A estrutura while também é terminada com end e tem formato comum de outras linguagens:

while condição

lógica

end

Um exemplo feito no terminal é:


        2.0.0-p451 :041 > a = 5
        => 5
        2.0.0-p451 :042 > b = 10
        => 10
        2.0.0-p451 :043 > while a < b
        2.0.0-p451 :044?> puts "a é #{a}"
        2.0.0-p451 :045?> a += 1
        2.0.0-p451 :046?> end
        a é 5
        a é 6
        a é 7
        a é 8
        a é 9
        => nil 

Nesse código foram definidas duas variáveis para descobrir os números que serão mostrados enquanto ‘b’ for maior que ‘a’.

Blocos e Iterações

O fragmento de código entre chaves ou a palavra do...end determinará a quantidade de vezes que o objeto ou variável será lido pelo interpretador e repetido no programa. Em Ruby, o for utilizado em muitas linguagens também existe, porém o mais comum é o each.

O times é uma forma de entender o funcionamento do each, apesar de não utilizado frequentemente por precisar de uma quantidade específica. Para melhor compreensão, seguem os exemplos:


        3.times { puts "Olá!" }
        Olá!
        Olá!
        Olá!
        => 3 

É fácil de perceber que a palavra entre as chaves sobre o comando puts será mostrado três vezes e pulando linhas. Caso tivesse sido utilizado p ou print, a palavra seria mostrada na mesma linha, como é demonstrado a seguir:


        2.0.0-p451 :062 > 3.times { print "Oi! "}
        Oi! Oi! Oi! => 3 

O bloco each tem a mesma lógica para ler toda a coleção, porém, seu formato pode ser de duas maneiras:

(1) exemplos.each {|exemplo| puts exemplo}

(2) exemplos.each do |exemplo|

puts exemplo

end

Alguns exemplos abaixo podem deixar mais claro o funcionamento da estrutura:


        (1)
        2.0.0-p451 :063 > numeros = [1, 2, 3]
        2.0.0-p451 :065 > numeros.each {|numero| puts numero}
        1
        2
        3
        => [1, 2, 3]

        (2)
        2.0.0-p451 :063 > numeros = [1, 2, 3]
        2.0.0-p451 :066 > numeros.each do |numero|
        2.0.0-p451 :067 > puts numero
        2.0.0-p451 :068?> end
        1
        2
        3
        => [1, 2, 3]
        (3)
        2.0.0-p451 :063 > numeros = [1, 2, 3]
        2.0.0-p451 :072 > numeros.each_with_index do |numero, index|
        2.0.0-p451 :073 > puts "Valor: #{numero}, Índice: #{index}"
        2.0.0-p451 :074?> end
        Valor: 1, Índice: 0
        Valor: 2, Índice: 1
        Valor: 3, Índice: 2
        => [1, 2, 3] 

O primeiro e segundo exemplos seguem a estrutura já mostrada. Porém, no terceiro exemplo é utilizado each_with_index que irá fazer uma leitura no array e estabelecerá o número do índice, representado porindex.

Classes, Métodos e Objetos

Após demonstrar uma parte inicial da linguagem, é preciso introduzir a parte mais importante dela: a orientação a objetos (OO).

Orientação a objetos é dividida, basicamente, em: classes, métodos e objetos, onde a classe é a essência - a representação de um conjunto de objetos, enquanto o método é a ação e o objeto é uma referência a um local da memória que possui um valor. Esses conceitos serão aprofundados a seguir para um maior entendimento desse funcionamento no Ruby.

Métodos

São ações programáveis que você pode definir para facilitar o desenvolvimento do seu projeto. A estruturados métodos na linguagem Ruby é:


        def nomedométodo(parâmetros)
        código
        end 

Um outro exemplo:


        def saudacao(nome)
        "Oi, #{nome}!"
        end
        puts saudacao("Paula") 

Os métodos podem ser muito mais complexos, incluir criação de variáveis e condições. Mas, por agora, o bom é o entendimento da estrutura,do funcionamento e sua importância para as, futuramente introduzidas, classes.

Objetos

O objeto é a instância de uma classe. A instância representa o objeto concretizado a partir de uma classe inicializada e alocada na memória do computador.A classe é apenas uma matriz, que especifica objetos, mas que não pode ser utilizada diretamente.

Basicamente, objetos são formas fáceis de separar seu código e os dados que este contém. Eles podem ser mudados, deletados, criados, movidos e outros. Na programação OO, utiliza-se objetos para chamar métodos ou passá-los para outros métodos. Isso ficará mais claro com os com explicações a seguir:


        2.0.0-p451 :001 > time = [[10, "Atacante", "Pedro"], [8, "Meio de Campo", "Henrique"], [3, "Zagueiro",
        "David"]]

        => [[10, "Atacante", "Pedro"], [8, "Meio de Campo", "Henrique"], [3, "Zagueiro", "David"]]
        

Esse é um array multidimensional, ou seja, simplesmente contém dentro mais de um array como elemento. O exemplo acima é sobre um time de futebol onde [número da camisa, função, nome] são componentes. Essa forma de representação agora funciona, mas é fácil de confundir, especialmente se continuarmos a adicionar novos times.

O estilo de código mostrado é processual e não orientado à objeto. Os dados mantidos na coleção são muitos e feitos com tipos simples. Para melhorar o código é necessário a organização, fazer um padrão para o objeto, conhecido como classe.

Classe

Uma classe é uma entidade, ou seja, abstrai um conjunto de características similares. Através de métodos, nela definidos, será possível fazer os comportamentos de seus objetos.

Em Ruby, sem saber, já trabalhamos com classes, como Array e String. Afinal, tudo nessa linguagem tem orientação a objetos. Agora, criaremos uma classe, conforme a Listagem 1, em um editor de texto, como exemplo para os conceitos ficarem mais claros.

NOTA:

Sempre salve um arquivo na linguagem Ruby com .rb no final.

Listagem 1. Jogador.rb

        class Jogador
        attr_acessor :primeiro_nome, :ultimo_nome, :numero

        def initialize (prim_nome, ult_nome, numero)
        @primeiro_nome = prim_nome
        @ultimo_nome = ult_nome
        @numero = numero
        end

        def nome_completo
        “#{ultimo_nome.capitalize}, #{primeiro_nome.capitalize}”
        end

        def posição
        while @numero == 0 || @numero < 0
        puts “Coloque novamente um número possível: “
        @numero = gets.to_i
        end
        if @numero < 6 && @numero <0
        return “Zaga”
        elsif @numero >= 6 && @numero <=10
        return “Meio Campo”
        else
        return “Ataque”
        end
        end
        end
        jogador = jogador .new(gets.chomp, gets.chomp, gets.to_i)
        p “#{jogador.nome_completo} – Função no(a): #{jogador.posicao}”

Para checar se o código está funcionando, entre no terminal ou CMD, na pasta onde está o arquivo e digite: ruby nomedoarquivo.rb. Após, basta colocar os dados na sequência do programa.

No código acima foi criado uma classe jogador de futebol na qual cada um tem primeiro nome, último nome e número da camisa. O initialize é o construtor, ou seja, através do formato dele criaremos o objeto e os valores recebidos nos parâmetros serão iguais aos campos da classe. O método ‘nome’ coloca o ‘ultimo_nome’ na frente na hora de imprimir e os dois campos com letra inicial maiúscula, através do capitalize.

No método ‘posicao’ foi criado uma lógica para a numeração das camisas. As regras são: o jogador com camisa de 1 até 5 terá sua função na zaga do time; os com camisa número 6 à 10 estarão no meio de campo; os com números maiores serão os atacantes; e no time não é possível ter uma camisa com numeração igual ou menor que 0, sendo assim, enquanto esse valor for colocado, o código rodará novamente pedindo um número possível.

Quando a classe termina, um objeto é criado com a palavra new, responsável por chamar um construtor de uma classe e é salvo na variável ‘jogador’. O método gets foi usado para o usuário digitar os valores do initialize no terminal ou cmd. A diferença é que no primeiro e último nome os valores recebidos serão strings (e como são atribuídos em nova linha, precisam do chomp para não ter um \n no final da palavra (aparece sempre que aperta-se Enter)) e no número, obviamente, um int (to_i).

No início da classe foi utilizado o attr_accessor para definir os campos. Ele é responsável por ler e escrever uma variável instanciada, ou seja, através dele é possível que o interpretador Ruby consiga permitir uma atribuição de valor e ler esse valor. Se, por exemplo, ele não tivesse sido usado para criar a instância ‘primeiro_nome’, seria necessário o seguinte código:


        class Jogador
        attr_accessor :ultimo_nome, :numero
        def primeiro_nome=(value)
        @primeiro_nome = value
        end
        def primeiro_nome
        @primeiro_nome
        end
        ...
        end

No primeiro método, a variável instanciada pode receber um valor e no segundo é possível ler esse valor. Existem o attr_reader e o attr_writer, que unidos, são o attr_accessor que, como o nome já diz, fará o acesso à instância.

Fazendo uma Classe

Para entender melhor uma linguagem de programação, é necessário praticá-la. Baseando-se no exemplo do jogador de futebol, será criada uma classe Time, conforme o código da Listagem 2. Afinal, os números das camisas seriam repetidos e utilizando apenas a classe Jogador assume-se que está se referindo apenas à um time, ou então, teria mais jogadores do que o comum.

O que é preciso fazer?

  • Chamar a classe jogador;
  • Estabelecer um nome para cada time;
  • Ter uma lista dos jogadores de cada time;
  • Poder adicionar mais jogadores à lista;
  • Mostrar todos os jogadores de cada time.
Listagem 2. Time.rb

        require_relative ‘Jogador’

        class Time
        attr_accessor :nome_time, :jogadores

        def initialize(nome_time)
        @nome_time = nome_time
        @jogadores = [ ]
        end

        def adiciona_jogador(primeiro_nome, ultimo_nome,numero)
        jogador = Jogador.new(primeiro_nome,ultimo_nome,numero)
        @jogadores << jogador
        end

        def print_time
        puts “#{nome_time.capitalize}”
        @jogadores.each do |jogador|
        puts “#{jogador.numero} – “{jogador.nome_completo} (#{jogador.posicao}
        end
        end
        end
        time = Time.new(gets.chomp)
        time.adiciona_jogador(“John”,“Smith”, 10)
        time.adiciona_jogador(“Henrique”,“Carvalho”,5)
        time.print_time

        time2 = Time.new(gets.chomp)
        time2.adiciona_jogador(“Alberto”, “Silva”,6)
        time2.adiciona_jogador(“Vicente”, “Souza”,1)
        time2.print_time

Com o require_relative foi chamado a classe jogador de outro arquivo para a classe Time. Para não precisar escrever um novo jogador antes de rodar o programa Time (porque o interpretador irá rodar primeiro a classe Jogador), comente tudo que está além da classe no outro arquivo.

No método initialize, o construtor recebe o nome do time e cria um array para receber os jogadores. O método seguinte adiciona novos jogadores e eles são alocados pela shovel no array . No último método, o nome do time é printado e depois todos os seus jogadores são mostrados através do each. Quando a classe acaba, o objeto é criado e os valores atribuídos. Mostra-se tudo, ao chamar o método ‘print_time’.

Para entender melhor o exemplo criado nesse artigo, na opção código-fonte, no topo do post, você pode baixar o código-fonte completo.