Referência técnica da linguagem Ruby, baseado no material preparado por John Voloski (johnvoloski).
- @johnvoloski
- github
- bitbucket
- gmail.com
- cwi.com.br
- Projeto Atual ( Fábrica RoR )
- Yukihiro "Matz" Matsumoto
- Se tornou pública em 1995
- Ganhou muita popularidade com o Rails
- Open Source
- Orientada a Objetos
- Blocos de Código
- Mixins
- RubyGems
- Linguagem Interpretada
- MRI
- YARV
- JRuby
- Rubinius
- MagLev
- MacRuby
- irb
- Vim - Usem este :D
- TextMate
- Emacs
- RubyMine
- SublimeText
- Ruby Lang - Site Oficial do Ruby
- TryRuby - Console Online de Ruby
- Ruby ToolBox - Pesquisa da gem melhor conceituada para algum propósito
- RoR Brasil - Ruby on Rails Brasil
- RoR - Ruby on Rails
- RubyGems - Gems disponíveis para o Ruby
- Rails for Zombies - Site para aprendizado de Rails
- Rails Casts - Vídeo aula de Rails
- Akita on Rails - Blog de Ruby
Uma "RubyGem" ou simplesmente "Gem" é uma biblioteca, um conjunto de arquivos Ruby reusáveis, etiquetada com um nome e uma versão (via um arquivo chamado de "gemspec").
- RubyGems Commands
gem dependency GEMNAME- Mostra as dependências da gem instalada.gem fetch GEMNAME- Baixa a gem e coloca no diretório atual.gem help- Ajudagem install GEMNAME- Instala uma gem.gem list GEMNAME- Lista as gems que começam com a GEMNAMEgem outdated- Exibe todas as gems que necessitam de update.gem push- Sobe uma gem para orubygemsgem search GEMNAME- Pesquisa uma gem norubygemscom a GEMNAME.gem uninstall GEMNAME- Desinstala uma gem.gem update GEMNAME- Atualiza a gem para a última versão.gem yank GEMNAME -v VERSION- Remove uma versão da gem norubygems.
É um gerenciador de gems da aplicação. Gerando uma lista de gems ele se encarrega de instalar, verificar versões e compatibilidades, após instaladas o bundler ajuda a atualizar quando tiver versões novas disponíveis, e registra as versões instaladas pra que se possa replicar exatamente as mesmas versões em diversas máquinas.
É um automatizador de tarefas, você consegue criar tarefas utilizando a sintaxe do ruby como por exemplo publicar algo em um ssh ou ftp automaticamente.
# Rakefiletask:ftpdo ... end# SpongeBob SquarePants.=begin SpongeBob SquarePants. Patrick isn't SquarePants.=endTrue representa o verdadeiro, False o falso e nil representa a abstenção de valor. Qualquer valor sem ser False e Nil é True.
putstrue.class# TrueClassputsfalse.class# FalseClassputsnil.class# NilClassPode ser utilizado o _ para melhor visualização.
puts1_000_000_00# 100000000puts1_000_000_00.class# FixnumSão inteiros que se encaixam dentro de 31 bits então sua instância é um Fixnum.
puts999999999999999999.class# FixnumSão inteiros que se encaixam acima de 31 bits então sua instância é um Bignum.
puts9999999999999999999.class# BignumSão números que utilizam pontos flutuantes, sua instância é um Float.
99.99.class# FloatSão números racionais, sua instância é um Rational.
putsRational(8/4).class# Rationalputs'Sou uma string com aspas simples e com instância String'.class# Stringputs'Sou uma string com aspas simples'# Sou uma string com aspas simplesputs'Sou uma string \' com um "escape"'# Sou uma string ' com um "escape"puts'Sou uma string quebrada' \ 'em multiplas linhas' \ 'não somente em uma'# Sou uma string quebrada em multiplas linhas não somente em umaputs"Sou uma string com aspas duplas e com instância String".class# Stringputs"Sou uma string com aspas duplas"# Sou uma string com aspas duplasInterpolações em string são feitas através do #{}:
adjective='SquarePants'puts"SpongeBob #{adjective}"# SpongeBob SquarePantsUm símbolo é um identificador único no ruby. O símbolo referencia ele mesmo. Um símbolo tem uma comparação muito mais rápida que uma string. Símbolos são ideais para definerem uma chave dentro de um hash, pois é um valor que não será alterado.
friends=['SpongeBob','Patrick']putsfriends# ["SpongeBob", "Patrick"]friends=[:SpongeBob,:Patrick]putsfriends# [:SpongeBob, :Patrick]Um array é uma sequência de valores acessíveis pela sua posição ou indíce. Em ruby o valor do primeiro indíce é 0.
puts[1,2,3,4]# [1, 2, 3, 4]putsArray.new(4)# [nil, nil, nil, nil]Um hash em ruby é composto por objetos formados por chave => valor.
sb={'SpongeBob'=>'SquarePants'}putssb['SpongeBob']# SquarePantssb={:SpongeBob=>'SquarePants'}putssb[:SpongeBob]# SquarePantssb={SpongeBob: 'SquarePants'}putssb[:SpongeBob]# SquarePantsO range representa o intervalo entre um início e um final.
# Irá gerar um intervalo de 1 à 10 incluindo o 10.puts1..10# 1..10# Irá gerar um intervalo de 1 à 10 excluíndo o 10.puts1...10# 1...10# Pode ser usado com strings também.puts'a'..'f'# 'a'..'f'- Em
rubyas expressões regulares são representadas por/
puts'SpongeBob'.gsub(/[aeiou]/,'')# SpngBb- Variáveis globais começam com $. Não inicializadas seu valor padrão é nil.
- Elas são visíveis de qualquer lugar.
$global_variable =0classHelloWorldOnedefincrement $global_variable += 1enddefoutputputs $global_variable endendclassHelloWorldTwodefoutputputs $global_variable endendclassOne=HelloWorldOne.newclassOne.incrementclassOne.output# 1classTwo=HelloWorldTwo.newclassOne.incrementclassTwo.output# 2- Variáveis de instância começam com @. Não inicializadas seu valor padrão é nil.
- Elas são visíveis apenas dentro da instância, compartilhada entre os métodos de instância.
- Elas podem ser acessadas externamente criando um
attr.
classHelloWorldOnedefinitialize(value)@instance_variable=valueenddefoutputputs@instance_variableendendclassHelloWorldTwodefinitialize(value)@instance_variable=valueenddefoutputputs@instance_variableendendHelloWorldOne.new("SpongeBob SquarePants").output# SpongeBob SquarePantsHelloWorldTwo.new("Patrick").output# Patrick- Variáveis de classe começam com @@. Devem ser inicializadas.
- Elas são visíveis e compartilhadas entre métodos de classe, métodos de instância e classes do mesmo tipo.
- Elas são encapsuladas, só podem ser acessadas e usadas na implementação e não de fora.
classHelloWorldOne@@class_variable=''defassign_variable(value)@@class_variable=valueenddefoutputputs@@class_variableendendone=HelloWorldOne.newone.assign_variable("SpongeBob SquarePants")one.output# SpongeBob SquarePantstwo=HelloWorldOne.newtwo.output# SpongeBob SquarePants- Variáveis locais começam com uma letra minúscula ou _ .
- O escopo de uma variável local varia de classe, módulo, método ou a abertura e fechamento de um bloco, que corresponde ao final de seu ciclo.
classHelloWorlddefinitialize(value)putsvalueendendHelloWorld.new('SpongeBob SquarePants')# SpongeBob SquarePants- Constantes começam com uma letra maiúscula.
- Constantes podem ser visualizadas internamente de uma classe ou módulo, apenas pelo seu nome, ou externamente através do seu módulo/classe mais o seu nome.
classHelloWorldHELLO_WORLD='Hello SpongeBob SquarePants'defoutputHELLO_WORLDendendputsHelloWorld.new.output# Hello SpongeBob SquarePantsputsHelloWorld::HELLO_WORLD# Hello SpongeBob SquarePants+
# Soma o valor da variável a com o valor da variável b e returna o resultado.a=10b=20putsa + b# 30-
# Subtrai da variável a o valor da váriavel b e returna o resultado.a=10b=20putsa - b# -10*
# Multiplica o valor da variável a com o valor da variável b e retorna o resultado.a=10b=20putsa * b# 200/
# Divide o valor da variável b por o valor da variável a e retorna o resultado.a=10b=20putsb / a# 2%
# Divide o valor da váriavel b por o valor da variável a e retorna o quociente da divisão.a=10b=20putsb % a# 0**
# Executa o cálculo exponencial sobre o valor da variável a quando o valor de seu expoente é o valor da variável b e retorna o resultado.a=10b=2putsa**b# 100==
# Verifica se o valor da variável a é igual ao valor da variável b, se sim retorna true.a=10b=20puts(a == b)# false!=
# Verifica se o valor da váriavel a é diferente do valor da variável b, se sim retorna true.a=10b=20puts(a != b)# true>
# Verifica se o valor da variável a é maior que o valor da variável b, se sim retorna true.a=10b=20puts(a > b)# false<
# Verifica se o valor da variável a é menor que o valor da variável b, se sim retorna true.a=10b=20puts(a < b)# true>=
# Verifica se o valor da variável a é maior ou igual ao valor da variável b, se sim retorna true.a=10b=20puts(a >= b)# false<=
# Verifica se o valor da variável a é menor ou igual ao valor da variável b, se sim retorna true.a=10b=20puts(a <= b)# true<=>
# Verifica se o valor da variável a é igual ao valor da váriavel b, então retorna 0, verifica se o valor da variável a é maior que o valor da váriavel b, então retorna 1, e verifica se o valor da variável a é menor que o valor da variável b, então retorna -1.a=10b=20puts(a <=> b)# -1===
# É um sinônimo do operador ==, e muda dependendo da implementação do seu contexto.a=10putsa === 10# trueputsObject === a# trueputsFixnum === a# trueputsInteger === a# trueputs(1..10) === a# true.eql?
# Verifica se o valor da variável a é igual ao valor da variável b, mas muda dependendo do seu contexto.a=10b=10.0putsa == b# true# a.class(Fixnum) and b.class(Float)putsa.eql?(b)# false.equal?
# Compara se os mesmos apontam para o mesmo objeto em memória.a=10a.__id__21b=10b.__id__21putsa.equal?(b)truea="word"a.__id__87897809b="word"b.__id__87893729putsa.equal?(b)false=
# Atruibui o valor da variável a para a váriavel b.a=10b=aputsb# 10+=
# Atribui somando o valor da variável a por o valor da váriavel b.a=10b=10b += aputsb# 20-=
# Atribui subtraindo o valor da variável a por o valor da váriavel b.a=10b=10b -= aputsb# 0*=
# Atribui multiplicando o valor da variável a por o valor da váriavel b.a=10b=10b *= aputsb# 100/=
# Atribui dividindo o valor da variável a por o valor da váriavel b.a=10b=10b /= aputsb# 1%=
# Atribui o quociente da divisão do valor da variável a por o valor da váriavel b.a=10b=10b %= aputsb# 0**=
# Atribui calculando o valor exponencial do valor da variável a por o valor da váriavel b.a=10b=2b **= aputsb# 1024# Atribui paralelizadamente valores à variáveis seguindo sua ordem de definição.a,b,c=10,20,30andou&&
# Se o valor da variável a e o valor da variável b forem verdadeiros, a condição é verdadeira.a=trueb=trueputs'True'ifaandb# Trueputs'True'ifa && b# Trueorou||
# Se o valor da variável a ou o valor da variável b forem verdadeiros, a condição é verdadeira.a=trueb=falseputs'True'ifaorb# Trueputs'True'ifa || b# True!ounot
# Se o valor da variável a e o valor da variável b forem falsos, a condição é verdadeira.a=falseb=falseputs'True'if !(a && b)# Trueputs'True'if not(a && b)# True?:
# Cria uma expressão condicional.condition=falseputsconditidion ? true : false# true..
# Cria um intervalo entre o ponto de partida e o ponto de chegada incluido ele.puts(1..10).to_a# 1, 2, 3, 4, 5, 6, 7, 8, 9, 10...
# Cria um intervalo entre o ponto de partida e o ponto de chegada excluíndo ele.puts(1...10).to_a# 1, 2, 3, 4, 5, 6, 7, 8, 9conditional=1ifconditional > 2puts'conditional is greater than 2'elsifconditional <= 2 && conditional != 0puts'conditional is 1'elseputs'I can`t guess the number'end# conditional is 1conditional=trueputs'Is true.'ifconditional# Is trueconditional=1unlessconditional > 2puts'conditional is less than 2'elseputs'conditional is greater than 2'end# conditional is less than 2conditional=falseputs'Is false.'unlessconditional# Is falseconditional=10caseconditionalwhen1puts'Is 1.'when2 .. 5puts'Is between 2 and 5'when6 .. 9puts'Is between 6 and 9'when10puts'is 10'elseputs'I can`t guess the number'end# is 10a=0b=5whilea < bdoputsaa += 1end# 0, 1, 2, 3, 4a=0b=5beginputsaa += 1endwhilea < b# 0, 1, 2, 3, 4a=0b=5untila > bdoputsaa += 1end# 0, 1, 2, 3, 4, 5a=0b=5beginputsaa += 1enduntila > b# 0, 1, 2, 3, 4, 5forain0..5putsaend# 0, 1, 2, 3, 4, 5Os blocks assim como é definido são blocos de códigos formados por delimitadores {... } ou do ... end, a convensão que usamos é {... } para uma linha e do ... end para mais de uma linha. O bloco serve para armazenar uma implementação que for desejada, e será executada em um certo momento, com seu pŕoprio escopo. Blocos só podem ser usados com métodos. Eles podem ser executados atráves do & chamando na implementação block.call, ou também através do yield, o yield tem como função executar um bloco anônimo sem precisar ser especificado no método.
classSpongeBobdefis_squarepants?(&block)block.callenddefi_live_in_ocean?yieldendendSpongeBob.new.is_squarepants?{putstrue}# trueSpongeBob.new.i_live_in_ocean?doputstrueend# trueforain0..5returnaifa > 2putsaend# 0, 1, 2forain0..5breakifa > 2putsaend# 0, 1, 2forain0..5nextifa < 2putsaend# 2, 3, 4, 5forain0..5putsa redo ifa < 2end# Loop infinitoa=0begina += 1raiseNoMethodErrorrescueputsaretryend# Retry infinitoHierarquia da Classe de Exceção do Ruby:
- Object
- Exception
- NoMemoryError
- ScriptError
- LoadError
- NotImplementedError
- SyntaxError
- SecurityError
- SignalException
- Interrupt
- SystemExit
- SystemStackError
- StandardError
- ArgumentError
- FiberError
- IOError
- EOFError
- IndexError
- KeyError
- StopIteration
- LocalJumpError
- NameError
- NoMethodError
- RangeError
- FloatDomainError
- RegexpError
- RuntimeError
- SystemCallError
- ThreadError
- TypeError
- ZeroDivisionError
- Exception
Definindo uma exception class:
classMyError < StandardError;endLevantando uma exception:
classMyError < StandardError;endraiseMyErrorraiseMyError,'Exception'Tratando exception com rescue:
classMyError < StandardError;endbegin# Minha implementação aqui.raiseMyErroriftruerescue=>ex# Aqui o tratamento da minha exception.puts"#{ex.class}: #{ex.message}"end# MyError: MensagemTratando exception com rescue pelo tipo:
classMyError < ArgumentError;endbegin# Minha implementação aqui.raiseMyErroriftruerescueNoMethodError=>ex# Aqui o tratamento de método não definido.puts"NoMethodError: #{ex.class}: #{ex.message}"rescueArgumentError=>ex# Aqui o tratamento de erro nos argumentos.puts"ArgumentError: #{ex.class}: #{ex.message}"end# ArgumentError: MyError: MensagemQuando ocorre um exceção durante um tratamento, então é propagada uma nova exceção.
Usando o retry dentro de um tratamento de exceção:
tries=0begintries += 1xMethodrescueNoMethodError=>exputsex.messageretryiftries < 4end# Mensagem# Mensagem# Mensagem# MensagemA cláusula else geralmente é utilizada para um tratamento genérico onde outros tratamentos utilizando o rescue não forma efetivos:
beginraiseStandardErrorrescueNoMethodError=>exputs"NoMethodError: #{ex.message}"elseputs"GenericError"end# GenericErrorA Cláusula ensure é utilizada como finalização do tratamento, ela é chama sempre após executar um rescue e até mesmo o else:
beginraiseNoMethodErrorrescueNoMethodError=>exputs"NoMethodError: #{ex.message}"ensureputs"E finalizou a exceção."end# NoMethodError: Mensagem# E finalizou a exceção.beginraiseStandardErrorrescueNoMethodError=>exputs"NoMethodError: #{ex.message}"elseputs"GenericError"ensureputs"E finalizou a exceção."end# GenericError# E finalizou a exceção.Utilizando o rescue em um método, classe ou módulo.
classPatrick;endclassSpongeBob;endclassSquidward;endclassNotSpongeBobError < StandardError;endclassNotPatrickError < StandardError;enddefis_squarepants?(name)raiseNotSpongeBobErrorif !name.is_a?SpongeBobrescueraiseNotPatrickErrorif !name.is_a?Patrickelseputs"O nome da classe é:{Squidward.name}."ensureputs"Ele também é um personagem."endis_squarepants?(Squidward)# O nome da classe é: Squidward# Ele também é um personagem.Utilizando o rescue como modificador:
putsis_squarepants?(Patrick)# NoMethodErrorputsis_squarepants?(SpongeBob)rescuetrue# trueDefinindo um método:
classSpongeBob;enddefis_squarepants?(name)name.is_a?(SpongeBob) ? true : falseendInvocando um método:
classSpongeBob;enddefis_squarepants?(name)name.is_a?(SpongeBob) ? true : falseendis_squarepants?(SpongeBob.new)# trueDefinindo um método Singleton:
bob='SpongeBob'defbob.is_squarepants?trueendbob.is_squarepants?# trueIndefinindo um método:
defis_squarepants?trueendis_squarepants?# true undef is_squarepants?is_squarepants?# NoMethodErrorPor convensão nomes de métodos começam sempre com letra minúscula, podem começar com letra maiúscula mas irão se parecer com uma constante. Quando o nome do método é maior que uma palavra, por convensão utiliza-se "_" para separa as palavras: "is_squarepants?". A convensão para métodos com ? no final, são métodos cujo valor retornado sempre será um boleano. A conversão para métodos com ! no final, são métodos cuja utilização deve ser com cautela, por exemplo, o método sort de um Array, ele copia o Array e ordena, já o método sort!, efetua o sort!` no mesmo array o redefinindo.
classSpongeBobdefis_squarepants?@squarepants || falseenddefis_squarepants!@squarepants=trueendendbob=SpongeBob.newputsbob.is_squarepants?# falsebob.is_squarepants!putsbob.is_squarepants?# trueRedefinindo os Métodos Operadores:
classSpongeBobdef +(value)"SpongeBob #{value}"endendputsSpongeBob.new + "SquarePants"# SpongeBob SquarePantsDefinindo "alias" para os Métodos: (Não é possível fazer "Overloading" em um "alias")
defis_squarepants?trueendaliasis_sp?is_squarepants?putsis_squarepants?# trueputsis_sp?# trueLista de Argumentos como Parâmetros:
defis_squarepants?(name, *args)puts"Name: #{name}"puts"Qualquer outro parâmetro informado: #{args}"endis_squarepants?('SpongeBob',true,'Patrick')# Name: SpongeBob# Qualquer outro parâmetro informado: [true, "Patrick"]Hash como parâmetro:
defis_squarepants?(name='SpongeBob',options={squarepants: true})putsnameputsoptions[:squarepants]endputsis_squarepants?# SpongeBob# trueputsis_squarepants?('Patrick',squarepants: false)# Patrick# falseBloco como parâmetro:
Se você prefere um controle explícito sobre o bloco, adicione um parâmetro final com um & na frente, então esse parâmetro irá referenciar o bloco, se for passado para o método, o tipo desse bloco sera um Proc ao invés de usar o yield você invocará através do método call.
defis_squarepants?(name, &block)block.call(name)endputsis_squarepants?('SpongeBob'){ |name| puts"#{name} SquarePants"}# SpongeBob SquarePantsputsis_squarepants?('Patrick'){ |name| puts"#{name} isn't SquarePants"}# Patrick isn't SquarePantsSe você prefere um controle mais específico ainda, defina um parâmetro como sendo o do bloco, o tipo deste parâmetro será um Proc e será invocado através do método call.
defis_squarepants?(name,block)block.call(name)endputsis_squarepants?('SpongeBob',proc{ |name| puts"#{name} SquarePants"})# SpongeBob SquarePantsputsis_squarepants?('Patrick',proc{ |name| puts"#{name} isn't SquarePants"})# Patrick isn't SquarePantsBlocos são estruturas sintáticas em Ruby, não são objetos e não tem como os manipular como objetos. Então é possível criar um objeto representante de um bloco. Dependendo de como é criado o objeto, ele é chamado de proc ou lambda. Procs tem um comportamento como o de um bloco, e Lambdas tem um comportamento como um método. No entando os dois são instâncias da classe Proc.
Criando Procs:
p=Proc.new{ |adjective| "SpongeBob #{adjective}"}p.call('SquarePants')# SpongeBob SquarePantsp=proc{ |adjective| "SpongeBob #{adjective}"}p.call('SquarePants')# SpongeBob SquarePantsCriando Lambdas:
l=lambda{ |adjective| "SpongeBob #{adjective}"}l.call('SquarePants')# SpongeBob SquarePantsl=->(adjective){"SpongeBob #{adjective}"}l.call('SquarePants')# SpongeBob SquarePantsDescubrindo a quantidade de parâmetros obrigatórios de uma Proc:
p=proc{ |adjective| "SpongeBob is #{adjective}"}putsp.arity# 1l=->(adjective){"SpongeBob is #{adjective}"}l.arity# 1Como diferenciar um lambda de um proc: O proc se parece como um bloco e tem um comportamento de bloco, o lambda é levemente modificado para parecer como um método. Para descobrir se o objeto é um lambda ou proc existe o método lambda? que retorna true se for um lambda e false se for um proc. O proc funciona como um bloco, seu retorno é propagado no contexto e não para o próprio proc. O lambda funciona como um método, seu retorno é propagado para o próprio lambda.
defis_squarepants?p=proc{puts'SpongeBob is SquarePants';return}p.callputs' and Patrick also'end# SpongeBob is SquarePantsdefis_squarepants?p=->{puts'SpongeBob is SquarePants';return}p.callputs" and Patrick isn't"end# SpongeBob is SquarePants and Patrick isn't classSpongeBob;endclassSpongeBob;endsb=SpongeBob.newputssb.class# SpongeBobputssb.is_a?(SpongeBob)# trueclassSpongeBobdefinitialize(squarepants)@squarepants=squarepantsendendProvendo os acessos a uma váriavel de instância de forma manual:
classSpongeBobdefinitialize(squarepants)@squarepants=squarepantsenddefsquarepants;@squarepants;enddefsquarepants=(value)@squarepants=valueendendsb=SpongeBob.new(true)sb.squarepants=trueputssb.squarepants# truePara prover esses acessos de formá automática o ruby fornece os métodos para serem definidos:
- attr_reader - Cria o acesso de leitura
classSpongeBobattr_reader:squarepantsdefinitialize@squarepants=falseendendsb=SpongeBob.newputssb.squarepants# falsesb.squarepants=true# Erro- attr_writer - Cria o acesso de escrita
classSpongeBobattr_writer:squarepantsdefinitialize@squarepants=falseendendsb=SpongeBob.newsb.squarepants=trueputssb.squarepants# Erro- attr_accessor - Cria o acesso de leitura e escrita
classSpongeBobattr_accessor:squarepantsdefinitialize@squarepants=falseendendsb=SpongeBob.newsb.squarepants=trueputssb.squarepants# trueEm ruby você pode redefinir os operadores de uma classe:
- Alguns operadores que podem ser definidos:
+-*/%-@+@~!======
classSpongeBobdefinitialize@he='SpongeBob'enddef +(value)"#{@he}#{value}"enddef ! "#{@he} isn't SquarePants"endendsb=SpongeBob.newputssb + 'SquarePants'# SpongeBob SquarePantsputs !sb# SpongeBob isn't SquarePantsMétodos de Classe são métodos dos quais não dependem de uma instância ativa da classe.
classSpongeBobdefPoint.is_squarepants?(instance)instance.is_a?(SpongeBob)enddefself.is_squarepants?(instance)instance.is_a?(SpongeBob)endclass << selfdefis_squarepants?(instance)instance.is_a?(SpongeBob)endendendputsSpongeBob.is_squarepants?(SpongeBob.new)# trueMétodo de Instância são os métodos dos quais dependem de uma instância ativa da classe.
classSpongeBobdefis_squarepants?(instance)instance.is_a?(SpongeBob)endendputsSpongeBob.new.is_squarepants?(SpongeBob.new)# true- Métodos de classe podem ser definidos públicos com este comando:
public_class_method:squarepants- Todos métodos normalmente são públicos, exceto o
initializeque é sempre privado. Os métodos públicos podem ser invocados por qualquer um, não existe restrições.
classSpongeBobdefis_squarepants?self.is_a?SpongeBobendendsb=SpongeBob.newsb.is_squarepants?# true- Métodos de classe podem ser definidos privados com este comando:
private_class_method:squarepants- Os métodos privados, são métodos que só podem ser acessados internamente.
classKrustyKrabprivatedefis_employee?(instance)instance.is_a?(SpongeBob)end# Pode ser definido privado desta maneira também:# private :is_employee?endclassSpongeBob < KrustyKrabdefjobputsis_employee?(self)putsself.is_employee?(self)rescueputs'Não pode chamar o método privado por uma referência.'putsSpongeBob.new.is_employee?(SpongeBob.new)rescueputs'Não pode chamar o método privado externamente.'endendSpongeBob.new.job# true# Não pode chamar o método privado por uma referência.# Não pode chamar o método privado externamente.- Os métodos protegidos, são métodos iguais ao privados, só difere na medida em que pode ser explicitamente chamado em qualquer instância da classe.
classKrustyKrabprotecteddefis_employee?(instance)instance.is_a?(SpongeBob)end# Pode ser definido protegido desta maneira também:# protected :is_employee?endclassSpongeBob < KrustyKrabdefjobputsis_employee?(self)putsself.is_employee?(self)puts'Pode chamar o método protegido por uma referência.'putsSpongeBob.new.is_employee?(SpongeBob.new)puts'Pode chamar o método protegido externamente.'endendSpongeBob.new.job# true# Pode chamar o método protegido por uma referência# true# Pode chamar o método protegido externamente.Herança não é muito diferente em ruby, quando você tem um classe SpongeBob que herda de Ocean dizemos que SpongeBob é uma subclass e Ocean é uma superclass. Uma classe pode ter infinitas subclasses mas apenas uma superclass. ruby não possui herança múltipla. Variáveis de instância, classe e constantes são herdadas e podem ser modificadas. O detalhes se for uma constante é que se estivermos criando alguma instância na superclass dela, a instância da subclass será diferente, pois sera criada uma nova.
- Herança de métodos:
classOceandefhas_squarepants_here?trueendendclassSpongeBob < Ocean;endputsSpongeBob.new.has_squarepants_here?# true- Sobrescrevendo métodos:
classOceandefhas_squarepants_here?falseendendclassSpongeBob > Oceandefhas_squarepants_here?trueendendputsSpongeBob.new.has_squarepants_here?# true- Sobrescrevendo métodos privados e protegidos:
classOceanprivatedefhas_squarepants_here?falseendprotecteddefwhoiam?'Ocean'endendclassSpongeBob > Oceandefhas_squarepants_here?trueenddefwhoiam?'SpongeBob'endendputsSpongeBob.new.has_squarepants_here?# trueputsSpongeBob.new.whoiam?# SpongeBob- Algumas vezes necessitamos sobrescrever um método mas continuar com a implementação antiga, então usamos o
super: (chaining)
classOceandefinitialize(whoiam='Ocean')@whoiam="I am #{whoiam}"endendclassSpongeBob < Oceanattr_accessor:presentationdefinitializesuper('SpongeBob')@presentation="#{@whoiam}, and I live in the ocean."endendputsSpongeBob.new.presentation# I am SpongeBob, and I live in the ocean.Módulos são um coleção de módulos, constantes, classes e variáveis de classe. Um módulo não é instânciavel e não possui herança. Módulos usam namespaces e mixins, classes podem usar namespaces assim como os módulos, mas classes não usam mixins.
moduleOceandefself.spongebob_live_here?trueenddefself.patrick_live_here?trueendclassSpongeBobdefwhoiam?'SpongeBob'endendclassPatrickdefwhoiam?'Patrick'endendendputsOcean::SpongeBob.new.whoiam?# SpongeBobputsOcean.spongebob_live_here?# trueputsOcean::Patrick.new.whoiam?# PatrickputsOcean.patrick_live_here?# trueA diferença de mixins e herança é apenas que quando uma classe inclui um módulo ela não se torna filha deste módulo, apenas implementa os seus métodos. Os módulos e os mixins:
O include implementa os métodos do módulo como um método de instância na classe.
moduleOceandefself.whoiam?'Ocean'enddefi_live_in_ocean?trueendendclassSpongeBobincludeOceandefwhoiam?'SpongeBob'endendsb=SpongeBob.newputssb.whoiam?# SpongeBobputssb.i_live_in_ocean?# trueputsOcean.whoiam?# OceanO extend implementa os métodos do módulo como um método de classe na classe.
moduleOceandefself.whoiam?'Ocean'enddefi_live_in_ocean?trueendendclassSpongeBobextendOceandefwhoiam?'SpongeBob'endendsb=SpongeBob.newputssb.whoiam?# SpongeBobputsSpongeBob.i_live_in_ocean?# trueputsOcean.whoiam?# Ocean$LOAD_PATH ou $ :- Variável global que contém um array com referência dos arquivos.
require
- Faz a inclusão e a leitura do arquivo.
require'some_file'- require_relative
- É utilizando quando existe a necessidade de referênciar um diretório/arquivo. Faz a leitura do arquivo.
require_relative'some_path/some_file'- load
- Tem um comportamento semelhante ao
require, a diferença é que necessita da extensão do arquivo, e pode ser executada diversas vezes.
- Tem um comportamento semelhante ao
load'some_path/some_file.rb'- autoload
- Tem um comportamento semelhante ao
require, porém só faz a leitura do arquivo quando acessado pela primeira vez.
- Tem um comportamento semelhante ao
autoload:SomeClass,'some_class'Todo objeto do Ruby está associado a duas classes: a classe que a instanciou e uma classe anônima, escondida, específica do objeto. Esta classe anônima é chamada de Singleton Class, mas antes de ter um nome oficial também era chamada de anonymous class, metaclass, eigenclass ou ghost class. A sintaxe mais comum para acessar a classe Singleton é:
classSpongeBobclass << selfdefwhoiam?'SpongeBob'endendendputsSpongeBob.whoiam?# SpongeBobputsSpongeBob.singleton_methods# [:whoiam?]Toda vez que injeta métodos em um objeto, eles são adicionados como métodos singleton. O que é realmente importante saber é que estes métodos pertecem unicamente ao objeto em que foram definidos, não afetando nenhum outro objeto da hieraquia.


