"Uma imagem vale mais que mil palavras"
Entre as linguagens de programação orientada a objetos, muito se discute se são puramente orientadas a objeto ou não, já que grande parte possui recursos que não se comportam como objetos.
Os tipos primitivos de Java são um exemplo desta contradição, já que não são objetos de verdade. Ruby é considerada uma linguagem puramente orientada a objetos, já que tudo em Ruby é um objeto (inclusive as classes, como veremos).
Ruby é uma linguagem puramente orientada a objetos, bastante influenciada pelo Smalltalk. Desta forma, tudo em Ruby é um objeto, até mesmo os tipos básicos que vimos até agora.
Uma maneira simples de visualizar isso é através da chamada de um método em qualquer um dos objetos:
"strings são objetos".upcase() :um_simbolo.object_id()
Até os números inteiros são objetos, da classe Fixnum:
10.class()
Uma das funcionalidades comuns a diversas linguagens orientadas a objeto está na capacidade de, dado um objeto, descobrir de que tipo ele é. No ruby, existe um método chamado class(), que retorna o tipo do objeto, enquanto object_id(), retorna o número da referência, ou identificador único do objeto dentro da memória heap.
Outro método comum a essas linguagens, é aquele que "transforma" um objeto em uma String, geralmente usado para log. O Ruby também disponibiliza esse método, através da chamada ao to_s().
Adicionalmente aos tipos básicos, podemos criar nossos próprios objetos, que já vem com esses métodos que todo objeto possui (class, object_id).
Para criar um objeto em Ruby, basta invocar o método new na classe que desejamos instanciar. O exemplo a seguir mostra como instanciar um objeto:
# criando um objeto objeto = Object.new()
Querendo aprender ainda mais sobre a linguagem Ruby e o framework Ruby on Rails? Esclarecer dúvidas dos exercícios? Ouvir explicações detalhadas com um instrutor?
A Caelum oferece o curso RR-71 presencial nas cidades de São Paulo, Rio de Janeiro e Brasília, além de turmas incompany.
Consulte as vantagens do curso Desenv. Ágil para Web com Ruby on Rails.
def é uma palavra chave do Ruby para a definição (criação) de métodos, que podem, claro, receber parâmetros:
def pessoa.vai(lugar) puts "indo para " + lugar end
Mas, e o retorno de um método? Como funciona? Para diminuir o excesso de código que as linguagens costumam introduzir (chamado de ruído sintático), o Ruby optou por retornar o resultado da execução da última instrução executada no método. O exemplo a seguir mostra um método que devolve uma String:
def pessoa.vai(lugar) "indo para " + lugar end
Para visualizar esse retorno funcionando, podemos acessar o método e imprimir o retorno do mesmo:
puts pessoa.vai("casa")
Podemos ainda refatorar o nosso método para usar interpolação:
def pessoa.vai(lugar) "indo para #{lugar}" end
Para receber vários argumentos em um método, basta separá-los por vírgula:
def pessoa.troca(roupa, lugar) "trocando de #{roupa} no #{lugar}" end
A invocação desses métodos é feita da maneira tradicional:
pessoa.troca('camiseta', 'banheiro')
Alguns podem até ter um valor padrão, fazendo com que sejam opcionais:
def pessoa.troca(roupa, lugar='banheiro') "trocando de #{roupa} no #{lugar}" end # invocação sem o parametro: pessoa.troca("camiseta") # invocação com o parametro: pessoa.troca("camiseta", "sala")
Métodos são uma das formas com que os objetos se comunicam. Vamos utilizar os conceitos vistos no capítulo anterior porém indo um pouco mais além na orientação a objetos agora.
Ao final de cada exercício você pode rodar o arquivo no terminal com o comandoruby restaurante_avancado.rb.
Vamos simular um método que atribui uma nota a um restaurante.
# declaração do método def qualifica(nota) puts "A nota do restaurante foi #{nota}" end # chamada do método qualifica(10)
Podemos ter parâmetros opcionais em ruby utilizando um valor padrão.
def qualifica(nota, msg="Obrigado") puts "A nota do restaurante foi #{nota}. #{msg}" end # chamadas com parâmetros opcionais qualifica(10) qualifica(1, "Comida ruim.")
Na orientação a objetos a chamada de um método é análoga ao envio de uma mensagem ao objeto. Cada objeto pode reagir de uma forma diferente à mesma mensagem, ao mesmo estímulo. Isso é o polimorfismo.
Seguindo a ideia de envio de mensagens, uma maneira alternativa de chamar um método é usar o método send(), que todo objeto em Ruby possui.
pessoa.send(:fala)
O método send recebe como argumento o nome do método a ser invocado, que pode ser um símbolo ou uma string. De acordo com a orientação a objetos é como se estivéssemos enviando a mensagem "fala" ao objeto pessoa.
Além da motivação teórica, você consegue enxergar um outro grande benefício dessa forma de invocar métodos, através do send()? Qual?
O GUJ é um dos principais fóruns brasileiros de computação e o maior em português sobre Java. A nova versão do GUJ é baseada em uma ferramenta de perguntas e respostas (QA) e tem uma comunidade muito forte. São mais de 150 mil usuários pra ajudar você a esclarecer suas dúvidas.
Faça sua pergunta.
Para não precisar adicionar sempre todos os métodos em todo objeto que criamos, Ruby possui classes, que atuam como fábricas (molde) de objetos. Classes possibilitam a criação de objetos já incluindo alguns métodos.
class Pessoa def fala puts "Sei Falar" end def troca(roupa, lugar="banheiro") "trocando de #{roupa} no #{lugar}" end end p = Pessoa.new # o objeto apontado por p já nasce com os métodos fala e troca.
Todo objeto em Ruby possui o método class, que retorna a classe que originou este objeto (note que os parênteses podem ser omitidos na chamada e declaração de métodos):
p.class # => Pessoa
O diferencial de classes em Ruby é que são abertas. Ou seja, qualquer classepode ser alterada a qualquer momento na aplicação. Basta "reabrir" a classe e fazer as mudanças:
class Pessoa def novo_metodo # ... end end
Caso a classe Pessoa já exista estamos apenas reabrindo sua definição paraadicionar mais código. Não será criada uma nova classe e nem haverá um erro dizendo que a classe já existe.
Nosso método qualifica não pertence a nenhuma classe atualmente. Crie a classeRestaurante e instancie o objeto.
class Restaurante def qualifica(nota, msg="Obrigado") puts "A nota do restaurante foi #{nota}. #{msg}" end end
Crie dois objetos, com chamadas diferentes.
restaurante_um = Restaurante.new restaurante_dois = Restaurante.new restaurante_um.qualifica(10) restaurante_dois.qualifica(1, "Ruim!")
Qualquer classe em Ruby pode ser reaberta e qualquer método redefinido. Inclusive classes e métodos da biblioteca padrão, como Object e Fixnum.
Podemos redefinir a soma de números reabrindo a classe Fixnum? Isto seria útil?
class Fixnum def +(outro) self - outro # fazendo a soma subtrair end end
Editoras tradicionais pouco ligam para ebooks e novas tecnologias. Não conhecem programação para revisar os livros tecnicamente a fundo. Não têm anos de experiência em didáticas com cursos.
Conheça a Casa do Código, uma editora diferente, com curadoria da Caelume obsessão por livros de qualidade a preços justos.
Casa do Código, ebook com preço de ebook.
Um método pode invocar outro método do próprio objeto. Para isto, basta usar a referência especial self, que aponta para o para o próprio objeto. É análogo aothis de outras linguagens como Java e C#.
Todo método em Ruby é chamado em algum objeto, ou seja, um método é sempre uma mensagem enviada a um objeto. Quando não especificado, o destino da mensagem é sempre self:
class Conta def transfere_para(destino, quantia) debita quantia # mesmo que self.debita(quantia) destino.deposita quantia end end
Vimos que todo método é sempre chamado em um objeto. Quando não especificamos o objeto em que o método está sendo chamado, Ruby sempre assume que seja em self.
Como tudo em Ruby é um objeto, todas as operações devem ser métodos. Em especial, puts não é uma operação, muito menos uma palavra reservada da linguagem.
puts "ola!"
Em qual objeto é chamado o método puts? Por que podemos chamar puts em qualquer lugar do programa? (dentro de classes, dentro de métodos, fora de tudo, ...)
Se podemos chamar puts em qualquer self, por que o código abaixo não funciona? (Teste!)
obj = "uma string" obj.puts "todos os objetos possuem o método puts?"
(opcional) Pesquise onde (em que classe ou algo parecido) está definido o método puts. Uma boa dica é usar a documentação oficial da biblioteca padrão:
Atributos, também conhecidos como variáveis de instância, em Ruby são sempre privados e começam com @. Não há como alterá-los de fora da classe; apenas os métodos de um objeto podem alterar os seus atributos (encapsulamento!).
class Pessoa def muda_nome(novo_nome) @nome = novo_nome end def diz_nome "meu nome é #{@nome}" end end p = Pessoa.new p.muda_nome "João" p.diz_nome # => "João"
Podemos fazer com que algum código seja executado na criação de um objeto. Para isso, todo objeto pode ter um método especial, chamado de initialize:
class Pessoa def initialize puts "Criando nova Pessoa" end end Pessoa.new # => "Criando nova Pessoa"
Os initializers são métodos privados (não podem ser chamados de fora da classe) e podem receber parâmetros. Veremos mais sobre métodos privados adiante.
class Pessoa def initialize(nome) @nome = nome end end joao = Pessoa.new("João")
Métodos acessores e modificadores são muito comuns e dão a ideia de propriedades. Existe uma convenção para a definição destes métodos, que a maioria dos desenvolvedores Ruby segue (assim como Java tem a convenção paragetters e setters):
class Pessoa def nome # acessor @nome end def nome=(novo_nome) @nome = novo_nome end end pessoa = Pessoa.new pessoa.nome=("José") puts pessoa.nome # => "José"
A Alura oferece dezenas de cursos online em sua plataforma exclusiva de ensino que favorece o aprendizado com aqualidade reconhecida da Caelum. Você pode escolher um curso nas áreas de Java, Ruby, Web, Mobile, .NET e outros, ou fazer a assinatura semestral que dá acesso a todos os cursos.
Conheça os cursos online da Caelum.
Desde o início, Matz teve como objetivo claro fazer com que Ruby fosse uma linguagem extremamente legível. Portanto, sempre que houver oportunidade de deixar determinado código mais legível, Ruby o fará.
Um exemplo importante é o modificador que acabamos de ver (nome=). Os parenteses na chamada de métodos são quase sempre opcionais, desde que não haja ambiguidades:
pessoa.nome= "José"
Para ficar bastante parecido com uma simples atribuição, bastaria colocar um espaço antes do '='. Priorizando a legibilidade, Ruby abre mão da rigidez sintática em alguns casos, como este:
pessoa.nome = "José"
Apesar de parecer, a linha acima não é uma simples atribuição, já que na verdade o método nome= está sendo chamado. Este recurso é conhecido comoSyntax Sugar, já que o Ruby aceita algumas exceções na sintaxe para que o código fique mais legível.
A mesma regra se aplica às operações aritméticas que havíamos visto. Os números em Ruby também são objetos! Experimente:
10.class # => Fixnum
Os operadores em Ruby são métodos comuns. Tudo em ruby é um objeto e todas as operações funcionam como envio de mensagens.
10.+(3)
Ruby tem Syntax Sugar para estes métodos operadores matemáticos. Para este conjunto especial de métodos, podemos omitir o ponto e trocar por um espaço. Como com qualquer outro método, os parenteses são opcionais.
Crie um initialize no Restaurante.
class Restaurante def initialize puts "criando um novo restaurante" end # não apague o método 'qualifica' end
Rode o exemplo e verifique a chamada ao initialize.
Cada restaurante da nossa aplicação precisa de um nome diferente. Vamos criar o atributo e suas propriedades de acesso.
class Restaurante def initialize(nome) puts "criando um novo restaurante: #{nome}" end # não apague o método 'qualifica' end # crie dois nomes diferentes restaurante_um = Restaurante.new("Fasano") restaurante_dois = Restaurante.new("Fogo de Chao")
Embora nossos objetos tenham agora recebido um nome, esse nome não foi guardado em nenhuma variável.
class Restaurante def initialize(nome) puts "criando um novo restaurante: #{nome}" @nome = nome end # altere o método qualifica def qualifica(nota, msg="Obrigado") puts "A nota do #{@nome} foi #{nota}. #{msg}" end end
Repare que a variável nome é uma variável de instância de Restaurante. Em ruby, o "@" definiu esse comportamento. Agora vamos fazer algo parecido com o atributo nota e suas propriedades de acesso.
class Restaurante def initialize(nome) puts "criando um novo restaurante: #{nome}" @nome = nome end # altere o método qualifica def qualifica(msg="Obrigado") puts "A nota do #{@nome} foi #{@nota}. #{msg}" end # propriedades def nota=(nota) @nota = nota end def nota @nota end end restaurante_um = Restaurante.new("Fasano") restaurante_dois = Restaurante.new("Fogo de Chao") restaurante_um.nota = 10 restaurante_dois.nota = 1 restaurante_um.qualifica restaurante_dois.qualifica("Comida ruim.")
Seria muito trabalhoso definir todas as propriedades de acesso a nossa variáveis. Refatore a classe Restaurante para utilizar o attr_accessor :nota Seu arquivo final deve ficar assim:
class Restaurante attr_accessor :nota def initialize(nome) puts "criando um novo restaurante: #{nome}" @nome = nome end def qualifica(msg="Obrigado") puts "A nota do #{@nome} foi #{@nota}. #{msg}" end end restaurante_um = Restaurante.new("Fasano") restaurante_dois = Restaurante.new("Fogo de Chao") restaurante_um.nota = 10 restaurante_dois.nota = 1 restaurante_um.qualifica restaurante_dois.qualifica("Comida ruim.")
Arrays em Ruby são instâncias da classe Array, não sendo simplesmente uma estrutura de dados, mas possuindo diversos métodos auxiliares que nos ajudam no dia-a-dia.
Um exemplo simples e encontrado em objetos de tipo Array em várias linguagens é o que permite a inclusão de elementos e size que nos retorna a quantidade de elementos lá dentro.
lista = Array.new lista << "RR-71" lista << "RR-75" lista << "FJ-91" puts lista.size # => 3
A tarefa mais comum ao interagir com array é a de resgatar os elementos e para isso usamos [] passando um índice como parametro:
puts lista[1] # => "RR-75" puts lista[0] # => "RR-71"
Muitas vezes já sabemos de antemão o que desejamos colocar dentro da nossa array e o Ruby fornece uma maneira literal de declará-la:
lista = [1, 2, "string", :simbolo, /$regex^/] puts lista[2] # => string
Um exemplo que demonstra uma aparição de arrays é a chamada ao métodomethods, que retorna uma array com os nomes de todos os métodos que o objeto sabe responder naquele instante. Esse método é definido na classe Object então todos os objetos o possuem:
cliente = "Petrobras" puts cliente.methods
Você chegou aqui porque a Caelum é referência nacional em cursos de Java, Ruby, Agile, Mobile, Web e .NET.
Faça curso com quem escreveu essa apostila.
Consulte as vantagens do curso Desenv. Ágil para Web com Ruby on Rails.
Em alguns instantes desejamos receber um número arbitrário de argumentos em um método, por exemplo a lista de produtos que estamos comprando em um serviço:
def compra(produto1, produto2, produto3, produtoN) end
Para receber um número qualquer de parâmetros usamos a sintaxe * do Ruby:
def compra(*produtos) # produtos é uma array puts produtos.size end
Note que nesse caso, em Ruby receber uma array ou um número indeterminado de argumentos resulta no mesmo código interno ao método pois a variável produtos funciona como uma array.
A mudança ocorre na sintaxe de chamada a esse método. Na versão mostrada acima, invocamos o método compra com diversos parâmetros:
compra("Notebook", "Pendrive", "Cafeteira")
Já no caso de definir o método recebendo uma array, somos obrigados a definir uma array no momento de invocá-lo:
def compra(produtos) # produtos é uma array puts produtos.size end compra( ["Notebook", "Pendrive", "Cafeteira"] )
O operador * é chamado de splat.
Mas nem sempre desejamos trabalhar com arrays cuja maneira de encontrar o que está lá dentro é através de um número. Por exemplo, ao ler um arquivo de configuração de um servidor desejamos saber qual a porta e se ele deve ativar o suporte ssh:
porta = 80 ssh = false nome = Caelum.com.br
Nesse caso não desejamos acessar uma array através de inteiros (Fixnum), mas sim o valor correspondente as chaves "porta", "ssh" e "nome".
Ruby também tem uma estrutura indexada por qualquer objeto, onde as chaves podem ser de qualquer tipo, o que permite atingir nosso objetivo. A classe Hash é quem dá suporte a essa funcionalidade, sendo análoga aos objetos HashMap,HashTable, arrays indexados por String e dicionários de outras linguagens.
config = Hash.new config["porta"] = 80 config["ssh"] = false config["nome"] = "Caelum.com.br" puts config.size # => 3 puts config["ssh"] # => false
Por serem únicos e imutáveis, símbolos são ótimos candidatos a serem chaves em Hashes, portanto poderíamos trabalhar com:
config = Hash.new config[:porta] = 80
Ao invocar um método com um número maior de parâmetros, o código fica pouco legível, já que Ruby não possui tipagem explícita, apesar de esta não ser a única causa.
Imagine que tenho uma conta bancária em minhas mãos e desejo invocar o método de transferência, que requer a conta destino, a data na qual o valor será transferido e o valor. Então tento invocar:
aluno = Conta.new escola = Conta.new # Time.now gera um objeto Time que representa "agora" aluno.transfere(escola, Time.now, 50.00)
No momento de executar o método descobrimos que a ordem dos parâmetros era incorreta, o valor deveria vir antes da data, de acordo com a definição do método:
class Conta def transfere(destino, valor, data) # executa a transferência end end
Mas só descobrimos esse erro ao ler a definição do método na classe original, e para contornar esse problema, existe um movimento que se tornou comum com a popularização do Rails 2, passando parâmetro através de hash:
aluno.transfere( {:destino => escola, :data => Time.now, :valor => 50.00} )
Note que o uso do Hash implicou em uma legibilidade maior apesar de uma proliferação de palavras:
def transfere(argumentos) destino = argumentos[:destino] data = argumentos[:data] valor = argumentos[:valor] # executa a transferência end
Isso acontece pois a semântica de cada parâmetro fica explícita para quem lê o código, sem precisar olhar a definição do método para lembrar o que eram cada um dos parâmetros.
Variações nos símbolos permitem melhorar ainda mais a legibilidade, por exemplo:
class Conta def transfere(valor, argumentos) destino = argumentos[:para] data = argumentos[:em] # executa a transferência end end aluno.transfere(50.00, {:para => escola, :em => Time.now})
Para quem utiliza Ruby 1.9, ao criar um Hash onde a chave é um símbolo, podemos utilizar uma outra sintaxe que por vezes se torna mais legível:
aluno.transfere(50.00, {para: escola, em: Time.now})
Além dos parênteses serem sempre opcionais, quando um Hash é o último parâmetro de um método, as chaves podem ser omitidas (Syntax Sugar).
aluno.transfere :destino => escola, :valor => 50.0, :data => Time.now
No seu diretório ruby crie mais um arquivo chamado listas.rb. Teste um array adicionando dois elementos.
nomes = [] nomes[0] = "Fasano" nomes << "Fogo de Chao" for nome in nomes puts nome end
Vamos juntar os conhecimentos de classes e métodos para criar uma franquia onde podemos adicionar uma lista de restaurantes. Para isso teremos que criar na inicialização um array de restaurantes.
class Franquia def initialize @restaurantes = [] end def adiciona(restaurante) @restaurantes << restaurante end def mostra for restaurante in @restaurantes puts restaurante.nome end end end class Restaurante attr_accessor :nome end restaurante_um = Restaurante.new restaurante_um.nome = "Fasano" restaurante_dois = Restaurante.new restaurante_dois.nome = "Fogo de Chao" franquia = Franquia.new franquia.adiciona restaurante_um franquia.adiciona restaurante_dois franquia.mostra
O método adiciona recebe apenas um restaurante. Podemos usar a syntax com * e refatorar o método para permitir múltiplos restaurantes como parâmetro.
# refatore o método adiciona def adiciona(*restaurantes) for restaurante in restaurantes @restaurantes << restaurante end end # adicione ambos de uma só vez franquia.adiciona restaurante_um, restaurante_dois
Hashes são muito úteis para passar valores identificados nos parâmetros. Na classe restaurante adicione o método fechar_conta e faça a chamada.
def fechar_conta(dados) puts "Conta fechado no valor de #{dados[:valor]} e com nota #{dados[:nota]}. Comentário: #{dados[:comentario]}" end restaurante_um.fechar_conta :valor => 50, :nota => 9, :comentario => 'Gostei!'
Conheça a Casa do Código, uma nova editora, com autores de destaque no mercado, foco em ebooks (PDF, epub, mobi), preçosimbatíveis e assuntos atuais.
Com a curadoria da Caelum e excelentes autores, é uma abordagem diferente para livros de tecnologia no Brasil. Conheça os títulos e a nova proposta, você vai gostar.
Casa do Código, livros para o programador.
Imagine o exemplo a seguir que soma o saldo das contas de um banco:
class Banco def initialize(contas) @contas = contas end def status saldo = 0 for conta in @contas saldo += conta end saldo end end banco = Banco.new([200, 300, 400]) banco.status
Esse processo é executado em diversos pontos da nossa aplicação e todos eles precisam exatamente desse comportamento.
Em um dia ensolarado, um ponto de nossa aplicação passa a necessitar da impressão dos saldos parciais, isso é que cada soma seja impressa. Como fazer isso sem alterar os outros tantos pontos de execução e sem duplicação de código?
O primeiro passo é perceber a necessidade que temos de inserir um código novo, desejamos incluir o seguinte código:
for conta in @contas saldo += conta puts saldo # essa linha é nova end
Então na chamada específica desse método, passemos esse código como "parâmetro":
banco.status do |saldo| puts saldo end
Isso não é um parâmetro, e sim um bloco de código, o código que desejamos executar. Note que esse bloco recebe um parâmetro chamado saldo e que esse parâmetro é o saldo parcial que desejamos imprimir. Para facilitar a leitura podemos renomeá-lo para saldo_parcial:
banco.status do |saldo_parcial| puts saldo_parcial end
Imagine que o bloco funciona exatamente como a definição de uma função em ruby: ele pode receber parâmetros e ser invocado. Falta invocá-lo no código do banco, para dar a chance de execução a cada chamada do laço:
class Banco # initialize... def status(&block) saldo = 0 for conta in @contas saldo += conta block.call(saldo) end saldo end end
Note que block é um objeto que ao ter o método call invocado, chamará o bloco que foi passado, concluindo nosso primeiro objetivo: dar a chance de quem se interessar no saldo parcial, fazer algo com ele.
Qualquer outro tipo de execução, como outros cálculos, que eu desejar fazer para cada saldo, posso fazê-lo passando blocos distintos.
Ainda faltou manter compatibilidade com aquelas chamadas que não possuem bloco. Para isso, basta verificarmos se foi passado algum bloco como parâmetro para nossa função, e somente nesse caso invocá-lo.
Isto é, se o bloco foi dado (block_given?), então invoque o bloco:
for conta in @contas saldo += conta if block_given? block.call(saldo) end end
Existe uma outra sintaxe que podemos utilizar para passar blocos que envolve o uso de chaves:
banco.status { |saldo_parcial| puts saldo_parcial }
Como vimos até aqui, o método que recebe um bloco pode decidir se deve ou não chamá-lo. Para chamar o bloco associado, existe uma outra abordagem com a palavra yield:
if block_given? yield(saldo) end
Nessa abordagem, não se faz necessário receber o argumento &block portanto o código do Banco seria:
class Banco # initialize... def status saldo = 0 for conta in @contas saldo += conta if block_given? yield(saldo) end end saldo end end
Entender quando usar blocos costuma parecer complicado no início, não se preocupe . Você pode enxergá-los como uma oportunidade do método delegar parte da responsabilidade a quem o chama, permitindo customizações em cada uma de suas chamadas (estratégias diferentes, ou callbacks).
A biblioteca padrão do Ruby faz alguns usos muito interessantes de blocos. Podemos analisar a forma de iterar em coleções, que é bastante influenciada por técnicas de programação funcional.
Dizer que estamos passando uma função (pedaço de código) como parâmetro a outra função é o mesmo que passar blocos na chamada de métodos.
Para iterar em uma Array possuímos o método each, que chama o bloco de código associado para cada um dos seus items, passando o item como parâmetro ao bloco:
lista = ["rails", "rake", "ruby", "rvm"] lista.each do |programa| puts programa end
A construção acima não parece trazer muitos ganhos se comparada a forma tradicional e imperativa de iterar em um array (for).
Imagine agora uma situação onde queremos colocar o nome de todos os funcionários em maiúsculo, isto é, aplicar uma função para todos os elementos de uma array, construindo uma array nova.
funcionarios = ["Guilherme", "Sergio", "David"] nomes_maiusculos = [] for nome in funcionarios nomes_maiusculos << nome.upcase end
Poderíamos usar o método each:
funcionarios = ["Guilherme", "Sergio", "David"] nomes_maiusculos = [] funcionarios.each do |nome| nomes_maiusculos << nome.upcase end
Mas as duas abordagens envolvem o conceito de dizer a linguagem que queremos adicionar um elemento a uma lista existente: o trabalho é imperativo.
Lembrando que o bloco, assim como uma função qualquer, possui retorno, seria muito mais compacto se pudéssemos exprimir o desejo de criar a array diretamente:
funcionarios = ["Guilherme", "Sergio", "David"] nomes_maiusculos = funcionarios.cria_uma_array
O código dessa função deve iterar por cada elemento, adicionando eles dentro da nossa array, *exatamente* como havíamos feito antes:
class Array def cria_uma_array array = [] self.each do |elemento| array << elemento.upcase end array end end
Mas podemos reclamar que o método upcase nem sempre vai funcionar: a cada chamada de cria_uma_array queremos executar um comportamento diferente. E essa é a dica para utilização de blocos: passe um bloco que customiza o comportamento do método cria_uma_array:
nomes_maiusculos = funcionarios.cria_uma_array do |nome| nome.upcase end
E faça o cria_uma_array invocar esse bloco:
class Array def cria_uma_array array = [] self.each do |elemento| array << yield(elemento) end end end
Esse método que criamos já existe e se chama map (ou collect), que coleta os retornos de tomas as chamadas do bloco associado:
funcionarios = ["Guilherme", "Sergio", "David"] nomes_maiusculos = funcionarios.map do |nome| nome.upcase end
Na programação imperativa tradicional precisamos de no mínimo mais duas linhas, para o array auxiliar e para adicionar os items maiúsculos no novo array.
Diversos outros métodos do módulo Enumerable seguem a mesma ideia: find,find_all, grep, sort, inject. Não deixe de consultar a documentação, que pode ajudar a criar código mais compacto.
Só tome cuidado pois código mais compacto nem sempre é mais legível e fácil de manter.
Refatore o método mostra de Franquia para iterar sobre os elementos usando blocos.
def mostra @restaurantes.each do |r| puts r.nome end end
Crie um método relatorio que envia a lista de restaurantes da franquia. Repare que esse método não sabe o que ocorrerá com cada item da lista. Ele disponibiliza os itens e é o bloco passado que define o que fazer com eles.
def relatorio @restaurantes.each do |r| yield r end end # chamada com blocos franquia.relatorio do |r| puts "Restaurante cadastrado: #{r.nome}" end
Analise e rode o código abaixo, olhe na documentação o método sort_by e teste o next.
caelum = [ {:ruby => 'rr-71', :java => 'fj-11'}, {:ruby => 'rr-75', :java => 'fj-21'} ] caelum.sort_by { |curso| curso[:ruby] }.each do |curso| puts "Curso de RoR na Caelum: #{ curso[:ruby] }" end caelum.sort_by { |curso| curso[:ruby] }.each do |curso| next if curso[:ruby] == 'rr-71' puts "Curso de RoR na Caelum: #{ curso[:ruby] }" end
Se você gosta de estudar essa apostila aberta da Caelum, certamente vai gostar dos novos cursos online que lançamos na plataforma Alura. Você estuda a qualquer momento com aqualidade Caelum.
Conheça a assinatura semestral.
Queremos imprimir o nome de todos os alunos de uma turma com o código a seguir:
fj91 = Turma.new("Guilherme", "Paulo", "Paniz") fj91.each do |nome| puts nome end
Crie a sua classe Turma que durante a invocação do método each, itera por todos os nomes passados em seu construtor.
Tente lembrar dos conceitos de blocos e programação funcional para resolver.
A biblioteca padrão do Ruby faz usos bastante interessante de módulos como mixins. Os principais exemplos são os módulos Enumerable e Comparable.
Uma e
Xo สล็อตออนไลน์ โปรสล็อต XO เกมออนไลน์ทำเงินยอดฮิตเกมสล็อต xopg.net คือเกมทำเงิน reeffutures2018 ผ่านทางออนไลน์อย่างหนึ่ง ที่เล่นง่าย และได้เงินไว แถมยังลงทุนด้วยเงินน้อย mavoixtavoie ทำเงินได้ตลอดเวลา ซึ่งหลายคนอาจได้เคยเห็นรีวิวเรื่องของ สล็อต xo สล็อตออนไลน์ ไว้มากมาย เทคนิคสล็อต ทั้งเรื่องการเล่นแล้วได้เงิน herbalpertpresents และเล่น สล็อต แล้วไม่ได้เงิน นั่นเองค่ะ ซึ่งการที่คุณจะเล่นได้เงินหรือไม่ได้เงินนั้น essentialsforasoul ส่วนหนึ่งก็เป็นในเรื่องของดวงเข้ามาเกี่ยวด้วย northbristol เพราะสล็อตเป็นเกมออนไลน์เสี่ยงโชค ทดลองเล่น xo เกมหนึ่งซึ่งจะมีสูตร หรือเทคนิคเข้ามาช่วย gclub เพื่อโกงดวงอยู่เสมอซึ่งในเว็บของเรา สมัคร xo ก็มีมาแนะนำไว้ให้เห็นกันมากมายหลายสูตร
Xo สล็อตออนไลน์ โปรสล็อต XO เกมออนไลน์ทำเงินยอดฮิตเกมสล็อต xopg.net คือเกมทำเงิน reeffutures2018 ผ่านทางออนไลน์อย่างหนึ่ง ที่เล่นง่าย และได้เงินไว แถมยังลงทุนด้วยเงินน้อย mavoixtavoie ทำเงินได้ตลอดเวลา ซึ่งหลายคนอาจได้เคยเห็นรีวิวเรื่องของ สล็อต xo สล็อตออนไลน์ ไว้มากมาย เทคนิคสล็อต ทั้งเรื่องการเล่นแล้วได้เงิน herbalpertpresents และเล่น สล็อต แล้วไม่ได้เงิน นั่นเองค่ะ ซึ่งการที่คุณจะเล่นได้เงินหรือไม่ได้เงินนั้น essentialsforasoul ส่วนหนึ่งก็เป็นในเรื่องของดวงเข้ามาเกี่ยวด้วย northbristol เพราะสล็อตเป็นเกมออนไลน์เสี่ยงโชค ทดลองเล่น xo เกมหนึ่งซึ่งจะมีสูตร หรือเทคนิคเข้ามาช่วย gclub เพื่อโกงดวงอยู่เสมอซึ่งในเว็บของเรา สมัคร xo ก็มีมาแนะนำไว้ให้เห็นกันมากมายหลายสูตร