Um hashe é como um array, só que ele permite nomes literais nos índices, por exemplo:
pessoa = {nome: "Fulano", idade: 25, sexo: "M"}
# Podemos adicionar valores posteriormente assim:
pessoa[:fuma] = false
# Iteração com loop:
pessoa.each do |k, v|
puts "Chave: #{k} - Valor: #{v}."
end
Hashes vazios podem ser declarados assim:
h1 = {}
h2 = Hash.new
Para exibir os índices literalmente, use os dois pontos, assim:
conta = {tipo: "CC", saldo: 1500.99, ativo: true}
puts "Tipo de conta: #{conta[:tipo]}"
puts "Saldo da conta: R$#{'%.2f' % conta[:saldo]}"
puts "Conta ativa: #{conta[:ativo]}"
PS: Podemos declarar os hashes assim também:
carro = {"marca" => "Volkswagen", "modelo" => "Fusca", "cor" => "Vermelho", "ano" => 1994, "potencia" => 1.6}
carro.each_pair do |k, v|
puts "#{k} é #{v}"
end
Basicamente, um procedimento é um método que não retorna nada, como este:
def saudacao()
puts "Olá, usuário! Bom dia!"
end
# Invocação do método, pode ser com ou sem parênteses:
saudacao
Com um parâmetro:
def saudacao(nome)
puts "Olá, #{nome}! Bom dia!"
end
# Invocação do método, pode ser com ou sem parênteses:
saudacao "Fulano"
Com isso podemos criar métodos para códigos grandes, por exemplo:
def datas
dataAtual = Time.now
dia = dataAtual.strftime("%d/%m/%Y")
ds = dataAtual.strftime("%w").to_i
semana = ["Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado"]
hora = dataAtual.strftime("%H:%M:%S")
puts "Hoje é #{dia}, #{semana[ds]}, e a hora atual é #{hora}."
end
datas
Mas em alguns casos, como as funções que retornam valores, devemos usar os parênteses, por exemplo:
def multi(n1, n2)
return n1 * n2
end
puts multi(10, 5)
Temos também as Lambdas, usadas da seguinte forma:
mens = lambda {puts "Mensagem com Lambda!"}
mens.call # Invocação de lambdas exige o call
soma = lambda {|n1, n2| n1 + n2} # Com parâmetros e retorno (ele dispensa o "return")
puts soma.call(10, 5)
PS: Podemos salvar as funções em outro arquivo, e chamar eles por um include, dessa forma:
require "./funcoes.rb"
Vamos considerar esse código para calcular uma divisão:
print "Digite o numerador: "
n1 = gets.to_i
print "Digite o denominador: "
n2 = gets.to_i
res = n1 / n2
puts "A divisão entre #{n1} e #{n2} é igual à #{res}."
Se tentarmos dividir qualquer número por zero, ele dará erro e lançará a exceção "ZeroDivisorError".
Para tratarmos esse erro, usamos o bloco begin rescue (equivalente ao try catch/except) assim:
begin # Equivalente ao try, é obrigatório
rescue # Equivalente ao catch/except, pelo menos um é obrigatório
else # É opcional
ensure # Equivalente ao finally, é opcional
end
No caso, colocamos o código suscetível a erro dentro do begin (equivalente ao try), ele executará ele todo ou parará quando encontrar um erro, e passará a executar o que está dentro do rescue (equivalente ao catch/except). O else (opcional) executa caso não exista erro. O ensure (equivalente ao finally) executará com erro ou não.
O código acima ficaria assim:
begin
print "Digite o numerador: "
n1 = gets.to_i
print "Digite o denominador: "
n2 = gets.to_i
res = n1 / n2
puts "A divisão entre #{n1} e #{n2} é igual à #{res}."
rescue
puts "O código deu erro."
else
puts "O código foi executado corretamente."
ensure
puts "Conclusão do código."
end
Ou jogando o exception numa variável, assim:
begin
print "Digite o numerador: "
n1 = gets.to_i
print "Digite o denominador: "
n2 = gets.to_i
res = n1 / n2
puts "A divisão entre #{n1} e #{n2} é igual à #{res}."
rescue Exception => ex
puts "ERRO: #{ex}."
end
No geral, o Exception pega qualquer erro, já que todas as exceções herdam dele. No entanto, podemos ter vários blocos rescue, como podemos ver:
def divisao(n1, n2)
return n1 / n2
end
begin
puts divisao(10, "a")
rescue TypeError => ex
puts "ERRO: Tipos Incompatíveis."
rescue ZeroDivisionError => ex
puts "ERRO: Divisão por zero."
end
Podemos lançar também nossas próprias exceções, utilizando o raise
, assim:
def contador(num)
if num <= 0 then
raise "O número deverá ser maior que zero"
end
cont = 0
while cont <= num do
puts cont
cont += 1
end
end
begin
contador(0) # Tente trocar por uma string
rescue Exception => ex
puts "ERRO: #{ex}."
end
Para escrever arquivos em Ruby, podemos fazer assim:
print "Digite algo para inserir no arquivo: "
entr = gets.strip
File.write("arquivo.txt", "#{entr}\n")
Só que, caso o arquivo já exista, ele sobrescreverá o que está escrito. para ele não sobrescrever, faça assim:
print "Digite algo para inserir no arquivo: "
entr = gets.strip
File.write("arquivo.txt", "#{entr}\n", mode: "a")
Para ler também é simples:
arq = File.readlines("arquivo.txt")
puts arq