đ Preparação: Para este conteĂșdo, o aluno deverĂĄ dispor de um computador com acesso Ă internet, um web browser com suporte a HTML 5 (Google Chrome, Mozilla Firefox, Microsoft Edge, Safari, Opera etc.), um editor de texto ou IDE (VSCode etc.) e o software Ruby, com a versĂŁo mais recente, instalado na sua mĂĄquina local.
O Ruby foi uma linguagem de programação criada em 1995 por Matz, no Japão. à uma linguagem de programação interpretada e multi-paradigma com foco em simplicidade. Possui uma popularidade em 2001 após o livro "Programming Ruby". à uma linguagem dinùmica, open source, com foco na simplicidade e na produtividade. Tem uma sintaxe elegante de leitura natural e fåcil escrita. Além disso, tudo no Ruby é tratado como objeto da mesma forma como é na linguagem JavaScript, diferente da linguagem Java e C# que possui classes, métodos e atributos.
class Hello
def initialize (nome):
@nome = nome.capitalize
end
def falar
puts "OlĂĄ #{@nome}"
end
end
# Criar um objeto
h = Hello.new("mundo")
# saĂda: "OlĂĄ, mundo!"
g.falar
Possui uma tipagem dinùmica e forte, se assemelhando a linguagem de programação Python.
puts "Hello World!" # mais comum
puts ("Hello World!")
p "Hello, World!"
print "Hello, World!"
printf "Hello, World!"
O gerenciamento de versĂŁo se refere ao processo de planejamento, desenvolvimento, agendamento, testes, implantação e controle de versĂ”es de software. Ele garante que as equipes de versĂŁo entreguem com eficiĂȘncia os aplicativos e os upgrades exigidos pelas empresas e preservem, ao mesmo tempo, a integridade do ambiente de produção existente. Vamos utiliza-lo no ambiente de desenvolvimento para gerenciar as versĂ”es do Ruby.
No mundo competitivo, dinĂąmico e fluĂdo dos negĂłcios e da TI, as versĂ”es prematuras sĂŁo a Ășltima coisa de que vocĂȘ precisa. A empresa moderna Ă© um ambiente verdadeiramente dinĂąmico, e nem todas essas alteraçÔes ocorrem no mesmo ritmo. As organizaçÔes de TI precisam de um jeito para orquestrar essa grande quantidade de alteraçÔes. Ă aĂ que as soluçÔes Release Control e Deployment Automation entram em cena. Elas ajudam a facilitar a transição para a entrega contĂnua, e trabalham com a transformação digital, uma versĂŁo de cada vez. Essa Ă© a nova normalidade da TI.
Existe alguns tipos de gerenciadores de versĂŁo indicados:
- RVM (Mais popular)
- rbenv
- asdf (Mais recomendĂĄvel)
Vou usar o asdf, vocĂȘ pode usar ele nos sistemas operacionais Linux ou no macOS, alĂ©m dos interpretadores de comando UNIX, como Bash, ZSH ou Fish.
asdf version
asdf plugin-add ruby
asdf install ruby 2.7.1
ruby -v
asdf list ruby
asdf local ruby 2.7.1
asdf list nodejs
SĂŁo bibliotecas de cĂłdigo escritas em Ruby compartilhadas entre a comunidade, entĂŁo basicamente o gem
Ă© um gerenciador de pacotes (package manager) imbutido na linguagem Ruby. VocĂȘ consegue fazer o download de uma biblioteca Ruby fazendo: gem install nomeDaBiblioteca
, um exemplo de gem Ă© o prĂłprio Rails. Existe um site em que vocĂȘ pode encontrar essas gems: https://rubygems.org/?locale=pt-BR
gem list
Traduzido do inglĂȘs-O Interactive Ruby Shell Ă© um REPL (Um loop read-eval-print ( REPL ), tambĂ©m chamado de toplevel interativo ou shell de linguagem , Ă© um ambiente de programação de computador interativo simples que recebe entradas de um Ășnico usuĂĄrio, as executa e retorna o resultado para o usuĂĄrio; um programa escrito em um ambiente REPL Ă© executado por partes. O termo geralmente se refere a interfaces de programação semelhantes ao ambiente interativo clĂĄssico de mĂĄquina Lisp . Exemplos comuns incluem shells de linha de comando e ambientes semelhantes para linguagens de programação , e a tĂ©cnica Ă© muito caracterĂstica de linguagens de script).
Esse REPL serve para programação na linguagem de script orientada a objetos Ruby. A abreviação irb é um portmanteau da palavra "interativo" e a extensão do nome de arquivo para arquivos Ruby, .rb
.
O programa é iniciado a partir de uma linha de comando ( CLI - Command Line Interface ) e permite a execução de comandos Ruby com resposta imediata, experimentando em tempo real. Possui histórico de comandos , recursos de edição de linha e controle de tarefas , e é capaz de se comunicar diretamente como um script de shell pela Internet e interagir com um servidor ativo. Foi desenvolvido por Keiju Ishitsuka .
(Input) Entrada:
irb
7.times { puts "Hello, World!" }
exit()
A saĂda serĂĄ o "Hello, World!" impresso 7 vezes em cada linha.
(Output) SaĂda:
Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!
(Input) Entrada:
nome = Isaac
nome
(Output) SaĂda:
Isaac
Linguagem de tipagem dinĂąmica que pode trocar a tipagem a qualquer momento. Como Ă© de costume e padrĂŁo, sempre o Ășltimo valor atribuĂdo Ă© o que conta!
(Input) Entrada:
nome = 7
nome
(Output) SaĂda:
7
Verificando objetos
(Input) Entrada:
nome.object_id
(Output) SaĂda:
21
(Input) Entrada:
nome.class
(Output) SaĂda:
Integer
(Input) Entrada:
nil.object_id
nil = valor nulo
(Output) SaĂda:
8
(Input) Entrada:
nil.class
(Output) SaĂda:
NilClass
(Input) Entrada:
NilClass.object_id
(Output) SaĂda:
40
(Input) Entrada:
NilClass.superclass
(Output) SaĂda:
Object
Definindo funçÔes:
(Input) Entrada:
def somar (x,y)
puts "Outra coisa..."
x+y
end
somar (1, 2)
(Output) SaĂda:
Outra coisa... 3
Atribuição de uma função
(Input) Entrada:
soma = somar (10, 5)
soma
(Output) SaĂda:
15
Array (Listas)
(Input) Entrada:
lista = ["Isaac", 7, "DevOps", true, nil, 7.77, "Ruby"]
lista
lista.class
lista.length
(Output) SaĂda:
["Isaac", 7, "DevOps", true, nil, 7.77, "Ruby"] Array 7
Executando o Ruby pelo interpretador no terminal
(Input) Entrada:
ruby main.rb
(Output) SaĂda:
Hello World
# comentĂĄrio de uma linha
SĂŁo tipos de dados tratados como escrita ou texto, podem ser definidas entre aspas duplas ("")
ou apóstrofos, também conhecida como aspas simples ('')
.
Exemplo:
nome = "Isaac"
nome = 'Isaac'
nome = %q(meu texto)
\n
\t
\"
nome = "Isaac"
mensagem = "Bem vindo #{nome}"
puts mensagem
mensagem = <<~TXT
Essa Ă© minha mensagem
TXT
CĂłdigo-fonte main.rb
:
nome = "Isaac"
mensagem = "Bem vindo #{nome}"
mensagemErrada = 'Bem vindo #{nome}'
soma = "O valor da soma de 1 + 2 = #{1 + 2}"
outraMensagem = "Bem vindo" + nome
puts nome
puts mensagem
puts mensagemErrada
puts soma
puts outraMensagem
#{}
não serve somente para strings, mas sim para interpolação de código. Os apóstrofos se inseridos em conjunto com o delimitador de manipulação de variåvel retornarão o mesmo código inserido.
(Input) Entrada:
ruby main.rb
(Output) SaĂda:
Isaac Bem vindo Isaac Bem vindo #{nome} O valor da soma de 1 + 2 = 3 Bem vindo Isaac
CĂłdigo-fonte mensagem.rb
:
nome = "Isaac"
mensagem = <<-MENSAGEM
OlĂĄ #{nome}
Bem vindo(a) ao meu programa!
Obrigado
MENSAGEM
puts mensagem
(Input) Entrada:
ruby mensagem.rb
(Output) SaĂda:
OlĂĄ Isaac Bem vindo(a) ao meu programa! Obrigado
CĂłdigo-fonte mensagem.rb
:
mensagem = %q(Bem vindo ao meu programa)
mensagemErrada = %q(Bem vindo ao meu programa #{nome})
puts mensagem
puts mensagemErrada
(Input) Entrada:
ruby mensagem.rb
(Output) SaĂda:
Bem vindo ao meu programa Bem vindo ao meu programa #{nome}
Caso queira interpolar com o delimitador de manipulação de variåvel
%q
, Ă© necessĂĄrio usar o%Q
.
CĂłdigo-fonte mensagem.rb
:
nome = "Isaac"
mensagem = %Q(Bem vindo ao meu programa #{nome})
puts mensagem
(Input) Entrada:
ruby mensagem.rb
(Output) SaĂda:
Bem vindo ao meu programa Isaac
CĂłdigo-fonte public-methods.rb
:
nome = "Isaac"
mensagem = %Q(Bem vindo ao meu programa #{nome})
puts mensagem.public_methods
puts mensagem
Esse comando, atributo
public_methods
, vai imprimir os mĂ©todos pĂșblicos do Ruby que possui nessa string para ser utilizado.
(Input) Entrada:
ruby public-methods.rb
(Output) SaĂda:
unicode_normalized? encode! unicode_normalize ascii_only? unicode_normalize! to_r to_c encode include? % * + unpack unpack1 count partition +@ -@ <=> << sum == === next =~ [] []= empty? casecmp eql? insert casecmp? match? bytesize match next! succ! index upto replace rindex chr clear byteslice getbyte setbyte freeze scrub scrub! dump inspect intern upcase downcase capitalize swapcase upcase! undump length size downcase! succ swapcase! hex capitalize! split chars oct grapheme_clusters concat codepoints lines bytes to_str end_with? start_with? reverse reverse! sub to_s to_i to_f rjust center prepend crypt ord chomp strip to_sym ljust delete_prefix delete_suffix lstrip gsub scan chomp! sub! gsub! rstrip delete_prefix! chop lstrip! rstrip! chop! delete_suffix! strip! tr_s delete squeeze tr! tr delete! squeeze! each_line each_byte tr_s! each_codepoint each_grapheme_cluster slice slice! each_char encoding force_encoding b valid_encoding? rpartition hash between? clamp <= >= < > singleton_class dup itself taint tainted? untaint untrust untrusted? trust methods singleton_methods protected_methods private_methods public_methods instance_variables instance_variable_get instance_variable_set instance_variable_defined? remove_instance_variable instance_of? kind_of? is_a? display class frozen? tap then yield_self public_send extend clone method public_method singleton_method define_singleton_method !~ nil? respond_to? object_id send to_enum enum_for __send__ ! instance_eval instance_exec != equal? __id__ Bem vindo ao meu programa Isaac
CĂłdigo-fonte mensagem.rb
:
nome = "Isaac"
mensagem = %Q(Bem vindo ao meu programa #{nome})
puts "O tamanho da minha string Ă©: #{mensagem.length()}"
(Input) Entrada:
ruby mensagem.rb
(Output) SaĂda:
O tamanho da minha string Ă©: 30
# 01234
"Isaac"[0] # "I"
"Isaac".chars # ["I", "s", "a", "a", "c"]
"Isaac"[0,3] # "Isa"
"-" * 10 # "----------"
" mensagem ".strip # "mensagem"
"isaac".upcase # upcase
"ISAAC".downcase # downcase
"isaac".capitalize
"cadu teste outra_nome".split
"cadu-teste-outro_nome".split("-")
o comando
p
imprime a string da sua forma natural inserida pelo programador, diferente do comando
nome = "Isaac"
nomes = "isaac matheus janaina alexandre jurema fĂĄbio cauĂŁ gabriela jade nemo marlim fanny jajĂĄ azul".split(",")
numero = 7
mensagem = "minha mensagem"
puts ["A", "B", "C"]
print ["A", "B", "C"]
p ["A", "B", "C"]
p "quebra automaticamente\"" # quebra de linha
p nome
p nome[0]
p nome[nome.length - 1]
p nome[-1]
p nome.chars
p nome.chars.length
p nome[0,3]
# multiplicação de strings
puts "Cabeçalho"
puts "---------"
puts "texto de informação"
puts "-" * 10
puts "O nĂșmero Ă© %05d" % numero
puts "*" * 10
puts mensagem.capitalize
# gsub
puts mensagem.gsub("mensagem","mulher")
p nomes
(Input) Entrada:
ruby main.rb
(Output) SaĂda:
A B C ["A", "B", "C"]["A", "B", "C"] "quebra automaticamente\"" "Isaac" "I" "c" ["I","s","a","a","c"] 5 "Isa" Cabeçalho --------- texto de informação --------- O nĂșmero Ă© 00007 Minha mulher
(Input) Entrada
irb
7.class
7.7.class
(Output) SaĂda
Integer Float
(Input) Entrada
puts 123_500
(Output) SaĂda
123500
(Input) Entrada
# soma um inteiro com um ponto flutuante
soma = 3 + 4.77
p soma
(Output) SaĂda
7.77
Os sĂmbolos sĂŁo tipos especiais de objeto que sĂŁo criados com o :
no inĂcio do identificador. Eles sĂŁo Ășnicos globalmente e imutĂĄveis, entĂŁo quando vocĂȘ utilizar um sĂmbolo no Ruby ele vai usar aquele objeto na memĂłria e vai usar o nome, por exemplo
Isaac`, o Ruby vai usar esse objeto na memĂłria a primeira vez e quando eu reutilizar esse sĂmbolo ele vai reutilizar esse mesmo objeto.
SĂŁo Ăłtimos substitutos para strings quando vocĂȘ for usado como label / chaves.
(Input) Entrada
irb
variavel = "isaac"
variavel.object_id
variavel = "isaac"
variavel.object_id
(Output) SaĂda
"isaac" 28420 "isaac" 35380
Toda vez que reutilizamos uma string, elas são imutåveis, ela vai gerar um novo objeto na memória. Então, toda vez que usar a string, o Ruby vai usar a memória do computador e vai referenciar ela, portanto vai ser criada vårias posiçÔes na memória dependendo do uso.
(Input) Entrada
irb
:"isaac"
:isaac # posso fazer desse modo, sem especificar a string com aspas duplas
:isaac.object_id
:isaac.object_id
(Output) SaĂda
:isaac :isaac 2290588 2290588
Note que ele nĂŁo muda o id do objeto, ou seja, toda vez ele vai gerar o mesmo objeto.
(Input) Entrada
irb
1.send("+", 2) # o sĂmbolo + estĂĄ sendo usado na memĂłria, nĂŁo reutilizada
1.send(:+, 2) # o sĂmbolo + estĂĄ sendo usado na memĂłria, sendo reutilizado
(Output) SaĂda
3 3
(Input) Entrada
irb
dicionario = {}
dicionario["isaac"] = "7"
dicionario["isaac"]
dicionario[:isaac] = "7"
dicionario[:isaac]
(Output) SaĂda
"7" "7" "7" "7"
Entretanto, toda vez que eu acessar esse Hash, ele estĂĄ criando na memĂłria. Portanto, Ă© muito perfomĂĄtico criar sĂmbolos do que texto na memĂłria toda vez.
Arrays ou listas sĂŁo listas de valores separados por vĂrgula.
lista = []
lista = Array.new
Os arrays no Ruby, assim como na maioria das linguagens de programação de alto-nĂvel, podem ser de diferentes tipos.
(Input) Entrada
lista = [1, 2.7, "3", "isaac", true] # elementos do tipo int, float, string e boolean (TrueClass)
lista[1] # Acessando um item da lista no Ăndice 1 = 2.7
p lista[1]
(Output) SaĂda
2.7
(Input) Entrada
lista = [1, 2.7, "3", "isaac", true] # elementos do tipo int, float, string e boolean (TrueClass)
lista << "novo item 1"
# ou
lista.append("novo item 2")
p lista
(Output) SaĂda
[1, 2.7, "3", "isaac", true, "novo item 1", "novo item 2"]
lista.length # tamanho do array
lista.empty? # verifica se o array estĂĄ vazio
lista.first # pegar o primeiro valor
lista.last # pegar o Ășltimo valor
lista.include?(1) # verifica se algum item da lista inclui o valor especĂfico
Somando listas com o Ruby:
(Input) Entrada
lista_1 = [0, 1, 2, 3]
lista_2 = [4, 5, 6, 7]
resultado = lista_1 + lista_2
p resultado
(Output) SaĂda
[0, 1, 2, 3, 4, 5, 6, 7]
Em algumas linguagens de programação o Hash Ă© chamado de Hash-Map ou dicionĂĄrio (Ă© uma estrutura de chave-valor). O Hash permite vocĂȘ acessar qualquer Ăndice diretamente na memĂłria do computador.
Para iniciar um Hash
hash = {}
# ou
hash = Hash.new
Sintaxe do Hash
hash = {
chave => valor,
chave => valor,
}
Um hash pode ser qualquer tipo primitivo de dados, pode ser um nĂșmero, uma string ou um sĂmbolo.
i = {} # hash i vazio
h = {} # hash h vazio
i.class
a.class
i = { "nome" => "Isaac", "idade" => 21 } # Strings e nĂșmeros
h = { :nome => "Isaac", :idade => 21 } # SĂmbolos
h[:nome] # acessando um hash
h[:nome] = "Novo nome" # Alterando um hash
h[77] = "New value" # Adicionando um novo item no hash
Ao acessar o hash, note que Ă© bem parecido com array, porĂ©m nele vocĂȘ estĂĄ acessando o Ăndice pelo prĂłprio nome dele.
Alguns atributos e métodos para o hash
hash.keys # retorna um array com as chaves
hash.values # retorna um array com os valores
hash.empty? # verifica se o hash estĂĄ vazio
Como faz para capturar um input da tela padrão do computador, existe um método chamado gets
, ele possibilita fazer um prompt da entrada padrĂŁo. Assim, que a gente entrar um valor na entrada padrĂŁo, esse valor vai ser acessado pra que a gente consiga acessa-lo depois.
gets()
# ou
gets
Sintaxe
nome = gets
nome
puts nome
nome.chomp() # Tira o Ășltimo caractere social, no caso, o \n
# ou
nome = nome.chomp
# ou
nome = gets.chomp
puts "Digite o seu nome: "
nome = gets
puts "Seu nome Ă© #(nome)"
if condicao
faca_algo
else
faca_outra_coisa
end
== # igualdade
!= # diferente
> # maior que
>= # maior ou igual a
< # menor que
<= # menor ou igual a
! # Negação
&& # And
|| # Or
valor = 20
if valor > 50
puts "Eu sou maior que 50"
else
puts "Eu sou menor que 50"
end
valor = 65
if valor >= 50 && valor <= 100
puts "Estou entre 50 e 100"
end
valor = 20
if valor > 50
puts "Eu sou maior que 50"
elsif valor == 50
puts "Eu sou igual a 50"
else # nesse caso, o else sempre vem por Ășltimo, depois do elsif
puts "Eu sou menor que 50"
end
Apenas
nil
efalse
sĂŁo avaliados como falso, se por acaso tiver um parĂȘnteses vazio serĂĄ do valor lĂłgico true.
valor = 20
puts "Eu sou maior que 50" if valor > 50
Se a condição não for verdadeira, ele iå executar o bloco de código dentro dela (faca_isso).
Sintaxe:
unless condicao
faca_isso
end
Usado para estruturas condicionais de pequeno porte.
valor > 50 ? puts "Eu sou maior que 50" : puts "Eu sou menor que 50"
# if valor > 50
# puts "Eu sou maior que 50"
# else
# puts "Eu sou menor que 50"
linguagem = "ruby"
case linguagem
when "ruby"
puts "bem vindo ao curso de ruby"
when "golang"
puts "curso nĂŁo disponĂvel"
else
puts "não conheço essa linguagem"
end
Entrada (Input):
valor gets.chomp.to_i # conversor para inteiro
p valor.class # String
p valor
if valor > 20
puts "Esse valor Ă© maior que 20"
elsif valor == 20
puts "Esse valor Ă© igual a 20"
else
puts "Esse valor Ă© menor que 20"
end
SaĂda (Output):
50 Integer 50 Esse valor Ă© maior que 20
Entrada (Input):
puts "Digitar um valor: "
valor = gets.chomp.to_i
if valor >= 50 && valor <= 100
puts "Estou entre 50 e 100"
else
puts "Eu nĂŁo estou entre 50 e 100"
end
SaĂda (Output):
Entrada (Input):
valor = ""
if valor
puts "Eu tenho alguma coisa" # true = vazio
else
puts "Eu nĂŁo tenho nada"
end
SaĂda (Output):
Eu tenho alguma coisa
O resultado se torna verdadeiro devido ao tipo do código inserido, para ele declarar falso, é preciso especificar uma negação na primeira condição
Entrada (Input):
valor = ""
if !valor.empty? # se valor nĂŁo Ă© vazio
puts "Eu tenho alguma coisa" # true = vazio
else
puts "Eu nĂŁo tenho nada"
end
SaĂda (Output):
Eu nĂŁo tenho nada
O mesmo pode ser feito com
unless
Entrada (Input):
valor = ""
unless valor # se valor nĂŁo Ă© vazio
puts "Eu tenho alguma coisa"
else
puts "Eu nĂŁo tenho nada"
end
SaĂda (Output):
Eu nĂŁo tenho nada
Os laços ou loops, são formas de executar repetitivamente uma operação a fim de obedecer a uma estrutura condicional.
O while
significa repetir enquanto a condição for verdadeira.
Entrada (Input)
valor = 5 # imprimindo de 5 até 1
while valor > 0 # true
puts valor
valor = valor - 1 # Outra forma: valor -= 1
end # quando parar em 0, irå retornar em `false`, a execução serå encerrada
SaĂda (Output)
5 4 3 2 1
Entrada (Input)
valor = 5
while valor > 0
puts valor
valor = valor - 0
end
SaĂda (Output)
`looping infinito do valor`
Funciona semelhante ao while
, porĂ©m vocĂȘ declara uma variĂĄvel em uma lista de objetos.
for i in [1, 2, 3, 4, 5] # para i em algum array, hash ou objeto que corresponde ao `.each`
puts "O nĂșmero Ă© #{i}"
end
Semelhante ao while
, a diferença estå na condição, que assim quando executar a condição for falsa.
valor = 0
until valor == 10
puts valor
valor += 1
end
break # sair do laço
return # sair do laço e do método onde o laço estå contido
next # vai imediatamente para a próxima iteração
redo # repete o laço do inĂcio (a condição nĂŁo serĂĄ reavaliada)
Entrada (Input):
valor = 0
while (valor < 10)
puts "O valor Ă© #{valor}"
valor += 1
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5 O valor Ă© 6 O valor Ă© 7 O valor Ă© 8 O valor Ă© 9
Entrada (Input):
valor = 0
while (valor < 10)
puts "O valor Ă© #{valor}"
break if valor == 5
valor += 1
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5
Entrada (Input):
valor = 0
while (valor < 10)
puts "O valor Ă© #{valor}"
break if valor == 5
valor += 1
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5
Entrada (Input):
for meu_valor in [0,1,2,3,4,5,6,7]
puts "Meu valor Ă© #{meu_valor}"
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5 O valor Ă© 6 O valor Ă© 7
Entrada (Input):
range = 0..7
for meu_valor in range
puts "Meu valor Ă© #{meu_valor}"
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5 O valor Ă© 6 O valor Ă© 7
Entrada (Input):
for meu_valor in 0..7
puts "Meu valor Ă© #{meu_valor}"
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5 O valor Ă© 6 O valor Ă© 7
Entrada (Input):
lista = [0,1,2,3,4,5,6,7]
for meu_valor in lista
puts "Meu valor Ă© #{meu_valor}"
end
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5 O valor Ă© 6 O valor Ă© 7
Entrada (Input):
lista = [0,1,2,3,4,5,6,7]
lista.each do |meu_valor|
puts "O valor Ă© #{meu_valor}"
end
Em JavaScript, podemos fazer algo parecido com o comando
for each
.
SaĂda (Output):
O valor Ă© 0 O valor Ă© 1 O valor Ă© 2 O valor Ă© 3 O valor Ă© 4 O valor Ă© 5 O valor Ă© 6 O valor Ă© 7
Entrada (Input):
hash = {nome: Isaac, idade: 21}
lista.each do |chave, valor|
puts "Meu nome Ă© #{chave} e tenho #{valor} anos"
end
SaĂda (Output):
Meu nome Ă© Isaac e tenho 21 anos
def meu_metodo
puts "meu_metodo foi executado"
end
def meu_metodo(parametro1, parametro2)
puts "meu_metodo foi executado com #{parametro1} e #{parametro2}"
end
a palavra
return
Ă© opcional. O ruby sempre retorna o resultado da execução da Ășltima linha.
Exemplo:
def soma (a, b)
return a + b
end
# Ă© igual
def soma(a, b)
a + b
end
Exemplo 2:
Entrada (Input):
def soma (valor1, valor2 = 0) # valor1 = 10 e valor2 = 0
puts "Estou somando #{valor1} e #{valor2}"
valor1 + valor2
end
puts "Vou executar a soma"
puts soma(10) # valor1
SaĂda (Output):
Vou executar a soma Estou somando 10 e 0 10
Exemplo 3:
Entrada (Input):
def soma (valor1, valor2 = 0) # valor1 = 10 e valor2 = 0
puts "Estou somando #{valor1} e #{valor2}"
valor1 + valor2
end
def soma_com_parametros_nomeados(valor1:,valor2:)
soma(valor1, valor2)
end
puts "Vou executar a soma"
puts soma_com_parametros_nomeados(valor1: 5)
SaĂda (Output):
Vou executar a soma Estou somando 5 e 0 5
variavel = nil
variavel = "Algum valor" if variavel.nil?
variavel = nil
variavel = "Algum valor" unless variavel
variavel ||= "Valor"
Exemplo:
variavel = 10
variavel ||= 20
variavel
variavel = nil
variavel
variavel ||= 20
variavel
nova_variavel ||= 100
nova_variavel
PalĂndromo: SĂŁo palavras que sĂŁo iguais quando lidas de frente para trĂĄs e de trĂĄs para frente.
Exemplos:
Ovo Osso Radar Pop Bob ...
Objetivo:
- Definir um mĂ©todo que verifica se Ă© palĂndromo
- Usar gets para pedir input de dados e chamar o método
- Imprimir se Ă© palĂndromo ou nĂŁo
Resolução:
Entrada (Input)
puts "Digite alguma palavra ou nĂșmero:"
palavra = gets.chomp
def palindromo?(palavra)
palavra.downcase == palavra.downcase.reverse
end
puts palindromo?(palavra)
SaĂda (Output)
Digite alguma palavra ou nĂșmero: Isaac false Digite alguma palavra ou nĂșmero: Pop true Digite alguma palavra ou nĂșmero: 7 true
Agora, iremos aprender sobre o paradigma orientado a objetos em Ruby, se vocĂȘ tiver o mesmo conhecimento em teorias e lĂłgicas sobre este paradigma Ă© bem mais fĂĄcil, basta somente usar com a semĂąntica do Ruby.
Na imagem acima, conseguimos ter uma boa ideia do que seria uma classe e objetos. A classe, ou class, é como se fosse uma planta ou esboço de um objeto ou partes de um objeto.
Um objeto, ou object, é a construção daquela classe (planta ou esboço) na memória do computador, portanto, chamamos essa construção de instùncia.
EntĂŁo, podemos obter vĂĄrios objetos na memĂłria do computador a partir dessa classe (desenho tĂ©cnico) como referĂȘncia (como esboço).
class NomeDaClasse
end
obj NomeDaClasse.new
class MinhaClasse
end
objeto = MinhaClasse.new
p objeto.object_id
irb
nome = "isaac"
nome.object_id
outra_variĂĄvel = "outro_nome"
outra_variĂĄvel.object_id
outro_nome = nome
nome
outro_nome
nome.object_id
outro_nome.object_id
nome.upcase
nome
nome.upcase!
nome
outro_nome
=> "isaac" => 180 => "outro_nome" => 200 => "isaac" => "isaac" => "isaac" => 180 => 180 => "ISAAC" => "isaac" => "ISAAC" => "ISAAC" => "ISAAC"
Foi feita uma classe chamada NomeDaClasse
, porém essa estå em branco (BLANK).
class NomeDaClasse
end
Vamos criar um comportamento pra ela:
class NomeDaClasse
def imprimir_ola(nome)
puts "OlĂĄ #{nome}"
end
end
objeto = NomeDaClasse.new # instĂąncia para o objeto NomeDaClasse
objeto.imprimir_ola("isaac")
Cujo o método (verbo) é imprimir_ola
com um argumento (parĂąmetro) que se chama nome
.
Portanto, estamos instanciando essa classe (cujo é o esboço do objeto) com a instùncia de classe
.new
, e assim criando esse objeto chamadoNomeDaClasse
.
Na Ășltima linha, estamos imprimindo o nome desse objeto com o argumento "isaac"
.
class NomeDaClasse
def imprimir_ola(nome)
@nome = nome
puts "OlĂĄ #{@nome}"
end
end
O diferencial dessa estrutura Ă© o @nome
, isso, pois a nossa variĂĄvel nome
irĂĄ ficar disponĂvel durante todo o ciclo de vida enquanto estiver na memĂłria. SĂł que nĂŁo podemos acessar essa variĂĄvel antes da classe.
NĂłs somente podemos corrigir essa variĂĄvel dentro da classe.
Se eu criar outro método, chamado imprimir_tchau()
, logo eu nĂŁo preciso receber como argumento mais, pois eu consigo pegar essa variĂĄvel nome
que estå dentro do objeto. Então, a gente cria um método e essa variåvel retorna pra gente no mundo exterior.
Na parte de
OlĂĄ #{@nome}
oOlĂĄ #
nĂŁo serĂĄ exibido na saĂda do cĂłdigo, apena o@nome
.
class NomeDaClasse
def imprimir_ola(nome)
@nome = nome
puts "OlĂĄ #{@nome}"
end
def nome
@nome
end
end
isaac = NomeDaClasse.new
isaac.imprimir_ola("isaac")
isaac.nome
Quando o mĂ©todo Ă© pĂșblico a gente sĂł pega e delega a palavra, ou seja, esse mĂ©todo sĂł vai retornar a palavra de instĂąncia. Portanto, essa variĂĄvel vai ficar disponĂvel durante todo o ciclo de vida do objeto na memĂłria e possuĂmos um mĂ©todo que retorna essa variĂĄvel.
class NomeDaClasse
def initialize(nome)
@nome = nome
end
def imprimir_ola(nome)
puts "OlĂĄ #{@nome}"
end
def nome
@nome
end
end
pessoa = NomeDaClasse.new("isaac")
pessoa.nome = "Foo"
pessoa.nome
No entanto, somente estamos imprimindo o nome no imprimir_ola
, entĂŁo para a gente alterar o nome, precisamos imprimir_ola
novamente. Então, eu quero passar o estado inicial para o método inicial e a partir desse conceito entra o método construtor. Em Ruby, o método construtor se chama initialize
, entĂŁo para inicializar um mĂ©todo, vocĂȘ precisa utiliza-lo e passamos o @nome
como argumento.
Podemos criar um objeto a partir da classe, no nosso initialize
podemos usar o nome
como parĂąmetro. EntĂŁo, no nosso new
devemos passar um nome, entĂŁo nas 3 Ășltimas linhas, estamos criando um objeto pessoa
e passo o nome "isaac"
, entĂŁo essa variĂĄvel vai ser inserida no @nome
e quando eu quiser o nome
.
Entretanto, e se eu quiser alterar o nome dessa variåvel? Eu posso criar um método que altera o nome dessa variåvel.
class NomeDaClasse
def initialize(nome)
@nome = nome
end
def imprimir_ola(nome)
puts "OlĂĄ #{@nome}"
end
def nome # retorna a variĂĄvel de instĂąncia
@nome
end
def nome=(novo_nome) # troca o valor da instĂąncia
@nome = novo_nome
end
end
pessoa = NomeDaClasse.new("isaac")
pessoa.nome = "Foo"
pessoa.nome
Para getters e setters em Ruby, utilizamos o método attr_accessor
para uma variĂĄvel :nome
. Dessa forma, faz o objeto se comportar da mesma forma como anteriormente, ou seja, a gente cria um objeto e a gente troca esse objeto com o atributo (variĂĄvel) :nome
e a gente retorna esse objeto.
class NomeDaClasse
attr_accessor :nome # getter e setter
# attr_reader :nome # apenas getter
# attr_writter :nome # apenas setter
def initialize(nome)
@nome = nome
end
def imprimir_ola(nome)
puts "OlĂĄ #{@nome}"
end
end
pessoa = NomeDaClasse.new("isaac")
pessoa.nome = Foo
pessoa.nome
Se for o caso de criar somente um getter podemos usar o attr_reader
e se for o caso de apenas um setter podemos usar o att_writter
.
class Pessoa
def initialize(nome)
@nome = nome
end
end
pessoa = Pessoa.new("isaac")
p pessoa
#<Pessoa:0x000000000304c2e0 @nome="isaac">
Analisando o código com o método
p
, esse método retorna a inspeção do métodopessoa
, ou seja, daria o mesmo resultado se fizessemos da seguinte forma:
class Pessoa
def initialize(nome)
@nome = nome
end
end
pessoa = Pessoa.new("isaac")
p pessoa.inspect # o inspect é um parùmetro de inspeção cujo podemos ver todas as variåveis na memória do objeto, que no caso é @nome="isaac"
E se fizermos outro objeto para uma nova pessoa?
class Pessoa
def initialize(nome)
@nome = nome
end
end
pessoa = Pessoa.new("isaac")
pessoa2 = Pessoa.new("matheus")
p pessoa, pessoa2
#<Pessoa:0x000000000313c2b8 @nome="isaac">
#<Pessoa:0x000000000313c268 @nome="matheus">
EntĂŁo, todo objeto tem a sua entidade na memĂłria e cada um tem um nome diferente.
Em seguida, criamos um método chamado imprimir_ola
:
class Pessoa
def initialize(nome)
@nome = nome
end
def imprimir_ola
puts "OlĂĄ, #{@nome}"
end
end
pessoa = Pessoa.new("isaac")
pessoa2 = Pessoa.new("matheus")
pessoa.imprimir_ola
pessoa2.imprimir_ola
OlĂĄ, isaac OlĂĄ, matheus
E se eu colocar um novo nome:
class Pessoa
def initialize(nome)
@nome = nome
end
def imprimir_ola
puts "OlĂĄ, #{@nome}"
end
def nome(novo_nome)
@nome = novo_nome
end
end
pessoa = Pessoa.new("isaac")
pessoa.imprimir_ola
pessoa.nome('Foo')
pessoa.imprimir_ola
Dessa forma, podemos trocar os valores de objetos no Ruby.
OlĂĄ, isaac OlĂĄ, Foo
Podemos também fazer o mesmo com uma linha só utilizando getters e setters:
class Pessoa
attr_writer :nome
def initialize(nome)
@nome = nome
end
def imprimir_ola
puts "OlĂĄ, #{@nome}"
end
end
pessoa = Pessoa.new("isaac")
pessoa.imprimir_ola
pessoa.nome='Foo'
pessoa.imprimir_ola
OlĂĄ, isaac OlĂĄ, Foo
Podemos fazer o Poo Ruby também com o irb
:
irb
class MinhaClasse
def initialize(nome)
@nome = nome
end
end
objeto = MinhaClasse.new("isaac")
:initialize
=> #<MinhaClasse:0x000000000351e020 @nome="isaac">
Podemos pegar a variĂĄvel de instĂąncia pelo irb
, da seguinte forma:
objeto.instance_variable_get(:@nome)
=> "isaac"
Imagine a seguinte estrutura de diretĂłrios:
âââ classes | âââ carro.rb | âââ pessoa.rb âââ principal.rb
Na seguinte hierarquia, possuimos o nosso cĂłdigo principal, onde chamarĂĄ as suas classes pelos arquivos localizados na pasta chamada classes
.
# arquivo: classes/pessoa.rb
class Pessoa
def initialize(nome)
@nome = nome
end
end
# arquivo: classes/carro.rb
class Carro
def initialize(modelo,dono)
@modelo = modelo
@dono = dono
end
end
# arquivo: principal.rb
require "./classes/pessoa"
require "./classes/carro"
foo = Pessoa.new("Foo")
carro = Carro.new("carro", foo)
Chamamos outro arquivo ruby pelo método de importação require
juntamente com o caminho do diretĂłrio.
Agora, vamos instalar uma biblioteca do Ruby chamada awesome_print
.
gem install awesome_print
Depois que instalamos essa biblioteca, também devemos importå-la no arquivo utilizando o require
.
# arquivo: principal.rb
require "awesome_print" # importando a biblioteca
require "./classes/pessoa"
require "./classes/carro"
foo = Pessoa.new("Foo")
carro = Carro.new("carro", foo)
ap foo # método da biblioteca importada
O conceito de herança é quando uma classe precisa herdar as funcionalidades de outra classe.
Em Ruby, o conceito de herança somente pode uma classe herdar de uma outra classe, portanto, heranças mĂșltiplas nĂŁo serĂŁo permitidas, como Ă© o caso das outras linguagens de programação.
Exemplo: A classe Filho herda os comportamentos da classe Pai.
Outro exemplo é a classe Cachorro herdar o comportamento da classe Animal, o comportamento no caso é o método, como por exemplo: Respirar()
, entĂŁo isso serĂĄ passado para a classe Cachorro.
Se a gente nĂŁo especifica qual a classe a gente deve herdar, essa classe herdarĂĄ da classe object (nĂŁo confunda com o objeto) que Ă© uma classe trazida pelo prĂłprio Ruby.
Quando chamamos um método, o Ruby vai avisar se esse método existe na classe do objeto, senão ele começa a analisar a hierarquia de classes procurando um método com aquele nome, senão ele vai avisar que esse método não existe.
Exemplo:
class Sensor
def iniciar
# iniciar o sensor
end
def coletar
# fazer uma coleta genérica
end
end
class SensorSolo < Sensor
def coletar
# coletar métricas no solo
end
end
class SensorTemperatura < Sensor
def coletar
# coletar métricas de temperatura
end
end
Podemos também fazer o mesmo em arquivos separados e importando a
classe Sensor
para cada um deles, onde o arquivo principal conterå toda a manipulação dessas classes dos sensores.
VocĂȘ pode utilizar tambĂ©m um mĂ©todo que foi sobrescrito na super classe base chamada
super
. EntĂŁo, vamos supor que vocĂȘ escreve todo o comportamento para o sensor genĂ©rico, entĂŁo ele irĂĄ fazer umas coisas antes que o sensor de solo irĂĄ coletar e fazer isso em passos (passo 1, passo 2 e passo 3, cujo o passo 3 Ă© o sensor regular, onde serĂĄ chamado osuper
).
super # executa o método sobrescrito da super classe
Herança é para reuso de funcionalidades.
Exemplo em somente um arquivo com todas as classes:
class Sensor
def instalar
# instala o sensor
puts "Sensor instalado"
end
def iniciar
# inicia o sensor
puts "Sensor iniciado"
end
def coletar_metricas
# coleta as métricas
puts "MĂ©tricas analisadas e coletadas"
puts "MĂ©tricas analisadas e coletadas novamente"
end
end
class SensorTemperatura < Sensor
# Sem nada dentro pode inicializar o SensorTemperatura herdando todos os métodos da classe Sensor
# Com algo dentro, podemos fazer algo mais exĂłtico, como abaixo:
def coletar_metricas
# inicializar componentes de temperatura
puts "MĂ©tricas de temperatura coletadas"
super # Logo, ao rodar a aplicação ela irå rodar a mensagem acima na impressão de sensor.coletar_metricas primeiro e posteriormente os da classe Sensor
end
# Logo, ao rodar a aplicação ela irå rodar a mensagem acima na impressão de sensor.coletar_metricas
end
sensor = SensorTemperatura.new # Sensor.new # Sensor.new = imprimir apenas os métodos da classe Sensor
sensor.instalar
sensor.iniciar
sensor.coletar_metricas
Sensor instalado Sensor iniciado MĂ©tricas de temperatura coletadas MĂ©tricas analisadas e coletadas MĂ©tricas analisadas e coletadas novamente
Até então foram feitos métodos de classe como Pessoa.new
que gerava uma nova classe a ser usada, mas tambĂ©m podemos definir as nossas prĂłprias classes e esses mĂ©todos sĂŁo chamados na classe, bem diferente daqueles que eram instĂąncias da classe para criação de um objeto especĂfico.
Pessoa.gerar
Os mĂ©todos de classe sĂŁo Ășteis quando possuĂmos uma funcionalidade que nĂŁo Ă© tĂŁo dependente do estado do objeto.
Para definirmos os métodos de classe basta somente inserir o prefixo self.nome_do_método
, isso Ă© claro depois de ser inserido o def
da função do nosso método.
class Pessoa
def self.gerar
puts "Estou gerando uma nova pessoa partir do método de classe"
end
end
Com isso, esse mĂ©todo de classe vai se tornar disponĂvel apenas para a classe e nĂŁo para as instĂąncias do objeto. Se vocĂȘ tentar executar esse mĂ©todo de classe em um objeto vai ocorrer um erro. Os mĂ©todos de classe nĂŁo usam o estado inicial de um objeto, mas vocĂȘ pode abordar um estado se vocĂȘ quiser.
class Pessoa
@@variavel_da_classe_pessoa = 100
def self.valor_da_variĂĄvel
@@variavel_da_classe_pessoa
end
def self.incrementar_valor_variavel
@@variavel_da_classe_pessoa += 1
end
end
Quando definimos
@@
estamos definindo variåveis (atributos) de classe e os métodos definidos comself
conseguem acessar e gravar nessas variĂĄveis, onde possuĂmos dois mĂ©todos, cujo o primeiro funciona como um getter e o outro Ă© um incremento dessa variĂĄvel.
class Pessoa
@@numero_de_pessoas = 0
def self.gerar
@@numero_de_pessoas += 1
puts "vou fazer antes"
Pessoa.new
end
end
pessoa = Pessoa.new # instĂąnciando o objeto Pessoa
pessoa = Pessoa.gerar # instùnciando a classe com o método de classe gerar
p pessoa
AtĂ© agora, todos os mĂ©todos que utilizamos na classe sĂŁo pĂșblicos, porque Ă© o padrĂŁo, isso quer dizer que eles sĂŁo acessĂveis em qualquer outro lugar no nosso cĂłdigo.
class MinhaClasse
def m1
puts "MĂ©todo 1"
m2
m3
end
def m2
puts "MĂ©todo 2"
end
def m3
puts "MĂ©todo 3"
end
end
O método
m1
imprime:MĂ©todo 1
,m2
em3
. Portanto, esses mĂ©todos sĂŁo pĂșblicos.
Vamos supor que nĂŁo queremos o m2
e o m3
acessĂveis a qualquer mĂ©todo, entĂŁo podemos deixar eles private
(privado). Para isso basta inseri-lo da seguinte forma:
class MinhaClasse
def m1
puts "MĂ©todo 1"
m2
m3
end
private
def m2
puts "MĂ©todo 2"
end
def m3
puts "MĂ©todo 3"
end
end
Tudo abaixo da palavra
private
fica privado, portanto om2
e om3
estĂŁo privados.
Os métodos privados podem também serem chamados por uma subclasse.
class MinhaSubClasse < MinhaClasse
def m4
puts "MĂ©todo m4 - subclass"
m3
end
end
Existem 3 tipos de acessibilidade de métodos no Ruby:
public
(padrão) podem ser acessados por qualquer método em qualquer objeto.private
sĂł podem ser chamados dentro de sua prĂłpria instĂąncia. NĂŁo Ă© possĂvel acessar MĂ©todos privados de outras instĂąncias, apenas pode ser chamada por uma subclasse.protected
podem ser chamados por qualquer instĂąncia se for da mesma Classe/SuperClasse.
Somente os mĂ©todos pĂșblicos podem ser açÔes para os controllers!
Vamos testar esses modos de acessibilidade de métodos!
Todos os mĂ©todos ficaram pĂșblicos.
class MinhaClasse
def m1
puts "MĂ©todo 1"
m2
m3
end
def m2
puts "MĂ©todo 2"
end
def m3
puts "MĂ©todo 3"
end
end
### a partir daqui, Ă© um outro contexto
obj = MinhaClasse.new
obj.m1
obj.m2
obj.m3
MĂ©todo 1 MĂ©todo 2 MĂ©todo 3
Todos os métodos ficaram privados.
class MinhaClasse
private
def m1
puts "MĂ©todo 1"
m2
m3
end
def m2
puts "MĂ©todo 2"
end
def m3
puts "MĂ©todo 3"
end
end
### a partir daqui, Ă© um outro contexto
obj = MinhaClasse.new
obj.m1
obj.m2
obj.m3
c:/Users/ipinheiro/Desktop/MinhaClasse.rb:23:in `': private method `m1' called for # (NoMethodError)
Como privatizar um mĂ©todo especĂfico:
m1
serĂĄ o Ășnico mĂ©todo privado da Classe.
class MinhaClasse
private def m1
puts "MĂ©todo 1"
m2
m3
end
def m2
puts "MĂ©todo 2"
end
def m3
puts "MĂ©todo 3"
end
end
### a partir daqui, Ă© um outro contexto
obj = MinhaClasse.new
obj.m1
obj.m2
obj.m3
Todavia, na saĂda do cĂłdigo, o
m1
serå o primeiro a ser executado, gerando a finalização dele por ser privado.
c:/Users/ipinheiro/Desktop/MinhaClasse.rb:23:in `': private method `m1' called for # (NoMethodError)
A diferença entre o
private
e oprotected
, oprotected
não funciona inline com o método e, além disso, oprotected
serve para poder chamar outros métodos dentro de outros objetos, diferente doprivate
que Ă© para privatizar o nosso objeto principal.
class MinhaClasse
def m1
puts "MĂ©todo 1"
m2
m3
end
private
def m2
puts "MĂ©todo 2"
end
def m3
puts "MĂ©todo 3 privado"
end
protected # Tudo aqui em baixo Ă© PROTECTED!
def m5
puts "MĂ©todo 5"
end
end
class MinhaSubClasse < MinhaClasse
def m4
m3
outro_obj = MinhaClasse.new
puts "MĂ©todo 4"
outro_obj.m5
end
end
### a partir daqui, Ă© um outro contexto
obj = MinhaSubClasse.new
obj.m4
obj.m5
c:/Users/ipinheiro/Desktop/MinhaClasse.rb:38:in `': protected method `m5' called for # (NoMethodError) MĂ©todo 3 privado MĂ©todo 4 MĂ©todo 5
No Ruby, possuĂmos algumas propriedades que podem acessar os mĂ©todos privados, como por exemplo o mĂ©todo
send(:método da classe)
.
irb
class Pessoa
private def falar
puts "Estou falando"
end
end
pessoa = Pessoa.new
pessoa.send(:falar)
- Criar uma classe responsĂĄvel para representar Contas BancĂĄrias.
- Criar um método que me permita transferir valor entre contas usando: "conta1.transferir(conta2,100)" onde 100 é o valor que eu desejo transferir.
- Plus: Criar um tipo de conta em que existe uma tarifa para se transferir dinheiro
Estrutura de arquivos
âââ classes | âââ conta_bancaria.rb âââ principal.rb
# principal.rb
require "./classes/conta_bancaria"
conta_cadu = ContaBancaria.new("cadu", 100)
conta_pessoa2 = ContaBancaria.new("pessoa2", 200)
conta_cadu.transferir(conta_pessoa2, 50)
p "Conta Cadu"
p conta_cadu.saldo # 50
p "Conta Pessoa 2"
p conta_cadu.saldo # 250
# caso de teste de conta sem saldo
conta_cadu.transferir(conta_pessoa2, 60) # falhar
p "Conta Cadu"
p conta_cadu.saldo # 50
p "Conta Pessoa 2"
p conta_pessoa2.saldo # 250
class ContaBancaria
def initialize(proprietario, valor_inicial)
@proprietario = proprietario
@valor = valor_inicial
end
def transferir(outra_conta, valor)
# logica de transferĂȘncia
if saldo >= valor
# consigo
debitar(valor)
outra_conta.depositar(valor)
else
# não consigo (não faço nada)
raise "NĂŁo consegui transferir! Saldo insuficiente."
end
end
def saldo
@valor
end
private
def debitar(valor_para_debitar)
@valor -= valor
@valor = valor_para_debitar
end
protected
def depositar(valor_para_depositar)
@valor += valor_para_depositar
end
end
Estrutura de arquivos
âââ classes | âââ conta_com_taxa.rb | âââ conta_bancaria.rb âââ principal.rb
# conta_com_taxa.rb
class ContaComTaxa < ContaBancaria
def transferir(outra_conta, valor)
if saldo >= valor
debitar(2)
super
end
end
end
# principal.rb
require "./classes/conta_bancaria"
require "./classes/conta_com_taxa"
conta_cadu = ContaComTaxa.new("cadu", 100)
conta_pessoa2 = ContaBancaria.new("pessoa2", 200)
conta_cadu.transferir(conta_pessoa2, 50)
p "Conta Cadu"
p conta_cadu.saldo # 50
p "Conta Pessoa 2"
p conta_cadu.saldo # 250
# caso de teste de conta sem saldo
begin
conta_cadu.transferir()
conta_cadu.transferir(conta_pessoa2, 60) # falhar
# o codigo abaixo nĂŁo foi executado, pois a linha acima gerou um erro.
p "Conta Cadu"
p conta_cadu.saldo # 50
p "Conta Pessoa 2"
p conta_pessoa2.saldo # 250
O Rails Ă© um framework/biblioteca para fazer aplicaçÔes web escritas na linguagem Ruby, ele foi criado em 2004 por David Heinemeier Hanson (DHH) e foi extraĂdo pelo software Basecamp, da empresa do DHH, cujo era um software de gerenciamento de tarefas.
A biblioteca Rails trabalha mais especificamente com um padrão de arquitetura de software chamado MVC (Model View Controller) que separa a representação da informação da interação do usuårio.
Existem vårias maneiras de instalar o Rails, a mais famosa consiste na instalação a partir da gem
oficial liberada pelo RubyGems.
gem install rails
O comando abaixo mostra as seguintes opçÔes que temos para criar um projeto RubyOnRails:
rails new -h
Logo, podemos criar o nosso primeiro projeto utilizando o Rails:
rails new meu_projeto
ApĂłs isso, vai ser criado o seguinte diretĂłrio do projeto com os seguintes arquivos:
/meu_projeto âââ app â âââ assets â â âââ config â â âââ images â â âââ stylesheets â âââ channels â âââ controllers â âââ views âââ bin âââ config âââ db | âââ â âââ seeds.rb âââ lib â âââ assets â âââ tasks âââ log â âââ .keep â âââ development.log âââ public âââ storage âââ test âââ tmp âââ vendor â âââ javascript | | âââ .keep â âââ .keep âââ .gitattributes âââ .gitattributes âââ .gitignore âââ .ruby.version âââ config.ru âââ Gemfile âââ Gemfile.lock âââ Rakefile âââ README.md
O Gemfile Ă© um arquivo onde instalamos todas as gems que iremos usar no projeto, se vocĂȘ for incluir alguma, Ă© sĂł copiar e colar o nome e a versĂŁo da gem, disponibilizada no RubyGems, no arquivo e apĂłs salvĂĄ-lo basta somente rodar o comando bundle install
que ele irĂĄ instalar essa nova gem.
Jå o arquivo Gemfile.lock é um arquivo que nem deve ser alterado, pois é gerado após a instalação do bundle.
O Gemfile Ă© similar ao package.json.
Resumidamente, o conjunto de comandos para iniciar uma aplicação em RubyOnRails é:
# rails new -h
rails new meu_projeto
cd meu_projeto
bundle install
# bundle update
rails server # rails s
O banco de dados padrão para o desenvolvimento em Rails é o SQLite. No entanto, geralmente, em alguns ambientes esse banco funciona apenas para a etapa de desenvolvimento e testes, não servindo para produção. Portanto, utilize outro banco de dados para produção como o MySQL ou PostgreSQL.
O comando abaixo permite vocĂȘ definir, no inĂcio do seu projeto, o banco de dados necessĂĄrio:
rails new meu_projeto -d postgresql
Caso se nĂŁo for especificado, vocĂȘ irĂĄ utilizar o SQLite.
VocĂȘ pode editar essas configuraçÔes instalando uma gem e configurando em config/database.yml
. E, também vale ressaltar, que ao criar e migrar o banco de dados do PostgreSQL, o arquivo do banco de dados não irå aparecer no diretório db
, como é o caso do SQLite. Então é necessårio a instalação do banco de dados PostgreSQL (com acesso ao pgAdmin ou psql).
Com isso, a sua aplicação RoR irå se conectar ao banco de dados do PostgreSQL no endereço: http://localhost:5432
AlĂ©m disso, vocĂȘ pode consultar os dados pelo console do Rails ou pelo prĂłprio banco utilizando uma ferramenta como o DBeaver, na qual Ă© sĂł definir o caminho do banco de dados e gerenciar o banco de dados pela ferramenta.
Com o projeto criado, projeto mvc_test
, iremos utilizar o scaffold
(traduzido no inglĂȘs como "andaime"), ele Ă© uma extensĂŁo do Rails que permite criar um CRUD rapidamente somente a partir dos comandos de declaração do Model.
rails g scaffold User name:string email:string
O comando acima serve para gerar (g
= generate
) um scaffold
com User
onde name
e email
recebem o valor string
.
A partir da versĂŁo 5 do Rails nĂŁo Ă© preciso inserir o tipo
string
. Portanto o comando ficarĂĄ dessa forma:rails g scaffold User name email
O comando abaixo serve para excluir as tabelas criadas para fazer o CRUD, com isso o CRUD serĂĄ desfeito.
rails db:rollback
O comando abaixo deleta tudo relacionado ao scaffold criado.
rails d scaffold Product
Após o diretório da aplicação Rails funcionar, no diretório ./db/
foi criado uma pasta ./migrate/
onde possui um model para a criação da tabela proposta.
rails db:migrate db:create
Portanto, rodar o comando acima: rails db:create
irå instanciar a ação do model em criar um banco de dados e o outro comando: db:migrate
para criação daquela tabela.
Um controller Ă© simplesmente uma classe que Ă© definida para herdar do ApplicationController
. Ă dentro dessa classe que vocĂȘ vai definir as açÔes por este controller. Aquelas açÔes vĂŁo performar as operaçÔes do CRUD nos posts.
rails generate model Post title:string body:text
Dessa forma, ele vai gerar um model com tĂtulo e corpo automaticamente, sem precisarmos escrever isso no cĂłdigo.
rails db:migrate
Dessa forma, serão criadas as tabelas no banco de dados juntamente com os models e uma pasta chamada migrate onde estå o model de criação da tabela, como mostrado abaixo:
class CreatePosts < ActiveRecord::Migration[7.0]
def change
create_table :posts do |t|
t.string :title, null: false
t.text :body, null: false
t.timestamps
end
end
end
O comando
null: false
significa que o dado nĂŁo serĂĄ aceito ser ele conter o valornull
(nulo).
rails console
Vamos dizer que eu queira acessar a classe Posts:
irb(main):003:0> Post => Post (call 'Post.connection' to establish a connection) irb(main):004:0>
Para contar quantos posts tem na tabela:
irb(main):004:0> Post.count() (2.4ms) SELECT sqlite_version(*) Post Count (0.3ms) SELECT COUNT(*) FROM "posts" => 0 irb(main):005:0>
Para criar um post na tabela diretamente pelo console:
irb(main):005:0> post = Post.create(title: "Isaac", body: "lindo") TRANSACTION (0.1ms) begin transaction Post Create (1.4ms) INSERT INTO "posts" ("title", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "Isaac"], ["body", "lindo"], ["created_at", "2022-07-12 18:56:22.030795"], ["updated_at", "2022-07-12 18:56:22.030795"]] TRANSACTION (4.0ms) commit transaction =>
Para contar todos os itens da tabela do maior ao menor:
irb(main):021:0> Post.last Post Load (0.3ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] => # irb(main):022:0>
Para consultar o post:
irb(main):022:0> post
=>
#<Post:0x0000026fa2a5bd60
id: 1,
title: "Isaac",
body: "lindo",
created_at: Tue, 12 Jul 2022 18:56:22.030795000 UTC +00:00,
updated_at: Tue, 12 Jul 2022 18:56:22.030795000 UTC +00:00>
irb(main):023:0>
Depois que fizemos todo aquele processo anterior, o Rails gera todo o MVC com as rotas prontas pra criação do CRUD com o seguinte resource: resources :users
.
- Endereço para saber informaçÔes sobre as rotas da aplicação: http://localhost:3000/rails/info/routes
E agora, vamos aprender a criar as nossas rotas para um projeto RoR:
Rails.application.routes.draw do
resources :users
get 'usuarios', to: 'users#index'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
end
Dessa forma, com o método HTTP get
mirando em 'usuarios'
, onde to: 'users#index'
que irĂĄ criar uma nova rota e nela conter as mesmas funcionalidades da rota users
, o que é interessante caso o cliente queira acessar essa rota e insire errado, então ele irå acessar rota certa jå que foi configurado na aplicação.
Para mais detalhes de como inserir o bootstrap numa aplicação RoR: https://gorails.com/forum/install-bootstrap-with-webpack-with-rails-6-beta
Para saber mais acesse: https://docs.docker.com/samples/rails/