You are on page 1of 88

Conhecendo Ruby

por Nando Vieira


Copyright Hellobits & Nando Vieira. Todos os direitos reservados.
Nenhuma parte desta publicao pode ser reproduzida sem o consentimento dos
autores.
Todas as marcas registradas so de propriedade de seus respectivos donos.
Conhecendo Ruby, Nando Vieira, 1a verso
Introduo
Ruby uma linguagem de programao interpretada, com tipagam forte e dinmica,
que tem como foco a simplicidade e produtividade. Sua sintaxe extremamente
elegante, o que facilita a leitura e escrita de cdigos.
Criada pelo japons Yukihiro_Matz_Matsumoto em meados de 1993, a linguagem s
foi lanada publicamente em 1995. Matz combinou partes de suas linguagens
favoritas (Perl, Smalltalk, Eiffel, Ada e Lisp) para criar uma linguagem que
fosse, segundo suas_prprias_palavras, mais poderosa que Perl e mais orientada
a objetos que Python.
Muitas linguagens no tratam nmeros e outros tipos primitivos como objetos,
mas no Ruby isso diferente. No Ruby, tudo objeto. Tipos primitivos possuem
mtodos e podem ter atributos. Classes so objetos.
O Ruby uma linguagem extremamente flexvel.
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Nando Vieira, Janeiro de 2012
Sobre o Ruby
Instalao
O Ruby pode ser instalado em todos os sistemas operacionais. Veja abaixo como
instalar em sua mquina de desenvolvimento. sempre uma boa ideia utilizar a
ltima verso estvel do Ruby, a menos que voc tenha razes muito fortes para
no fazer isso. Enquanto este livro est sendo escrito, a ltima verso estvel
1.9.3-p0.
Instalando no Windows
A maneira mais simples de instalar Ruby no Windows utilizando o Ruby
Installer. Acesse o endereo http://rubyinstaller.org/downloads/ e faa o
download do instalador da ltima verso estvel.
Download do Ruby Installer
Download do Ruby Installer
Execute o arquivo baixado, algo como rubyinstaller-1.9.3-p0.exe, e o instalar
ser iniciado. Aceite os termos de uso. Ser exibida, ento, uma janela onde
voc deve marcar a configurao Add Ruby executables to your PATH. Sem essa
opo, o Ruby no ficar disponvel globalmente no seu terminal.
Configurando o instalador
Configurando o instalador
Clique em Install e, depois, clique em Finish. Pronto! Voc j tem o Ruby
instalado. Para certificar-se que tudo est funcionando corretamente, abra o
terminal. Para isso, clique no menu Windows e execute powershell para
listar o terminal. Execute o comando ruby -v para listar a verso do Ruby. Em
verses mais antigas do Windows, voc pode usar o comando cmd. Se preferir,
voc tambm pode instalar_o_PowerShell_manualmente.
Usando o terminal
Usando o terminal

Se aparecer alguma mensagem muito diferente de ruby 1.9.3-p0 (2011-10-30)


[i386-mingw32], a instalao provavelmente no foi completada com sucesso.
Neste caso, reinicie a instalao e siga exatamente os passos descritos acima.
Instalando no Mac OS X
Embora o Mac OS X j venha com o Ruby instalado por padro, a sua verso
muito antiga.
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Instalando no Linux Ubuntu
No Linux ns tambm iremos utilizar o RVM para gerenciar as instalaes do
Ruby. Assim como no Mac OS X, execute o comando abaixo em seu terminal.
bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/
binscripts/rvm-installer)
Isso ir baixar e instalar o RVM.
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Tipo
O Ruby uma linguagem dinamicamente tipada, o que significa dizer que voc no
precisa definir o tipo de dado que uma varivel ir armazenar. Alm disso, uma
mesma varivel pode receber tipos diferentes a qualquer momento.
value = 1234
puts value.class
#=> Fixnum
value = "Hello"
puts value.class
#=> String
O Ruby tambm uma linguagem fortemente tipada, j que o tipo do objeto
verificado antes de efetuar determinadas operaes.
number = 1234
string = "Hello"
number + string
#=> TypeError: String can't be coerced into Fixnum
Ao tentar somar o nmero 1234 com a string Hello, o Ruby lanar a exceo
TypeError. Isso acontece porque a coero precisa ser feita explicitamente.
Duck Typing
No Ruby, ns no declaramos o tipo de objetos, nem o tipo do retorno de
mtodos. Embora isso possa parecer algo muito ruim para quem est acostumado
com linguagens como Java, linguagens dinamicamente tipadas como o Ruby so
muito flexveis, produtivas e, acredite, seguras. Na maioria das vezes, o medo
de no poder contar com o compilador para fazer verificaes de tipos no tem
fundamento.
Desenvolvedores Ruby esto mais acostumados em definir objetos pelo que eles
podem fazer, do que por seu tipo. Esta tcnica chamada de duck typing.
Se anda como um pato e faz barulho como um pato, ento deve ser um pato. E o

interpretador ficar feliz em fazer com que o objeto seja tratado como um pato.
Na prtica, isso significa que em vez de fazer verificaes de tipo de um
objeto, voc deve se preocupar se este objeto capaz de executar o mtodo que
voc precisa.
Pegue como exemplo strings, arquivos e arrays. As classes Array, File e String
implementam o mtodo de instncia <<, que quase sempre significa append. Voc
pode se aproveitar desta interface para criar, por exemplo, uma classe de log
que no se importa com o tipo de objeto que ir armazenar esses logs.
class SimpleLogger
def initialize(io)
@io = io
end
def log(message)
@io << "#{Time.now} - #{message}\n"
end
end
A classe SimpleLogger consegue enviar os logs para arrays, strings, arquivos e,
se quiser, para qualquer outro objeto que implemente o mtodo <<.
O Ruby realmente abraa o duck typing por toda a linguagem. Diversos protocolos
exigem que o objeto apenas implemente um mtodo to_<protocol>. Muitas operaes
que envolvem arrays, por exemplo, exigem que o objeto do lado direito da
expresso apenas implemente o mtodo to_ary.
class Numbers
def to_ary
[4, 5, 6]
end
end
[1, 2, 3] + Numbers.new
#=> [1, 2, 3, 4, 5, 6]
A classe Hash, por exemplo, permite que voc una dois objetos, desde que o
mtodo to_hash seja implementado.
class Configuration
def to_hash
{root: "/etc"}
end
end
config = Configuration.new
{name: "Custom config"}.merge(config)
#=> {:name=>"Custom config", :root=>"/etc"}
No preciso dizer que este tipo de protocolo por conveno permite criar
cdigos muito mais flexveis, com extrema facilidade.
Isso no significa que saber o tipo de objetos no seja til. Veja, por
exemplo, as operaes matemticas. Qualquer objeto pode ser convertido em
nmeros. Para isso, basta implementar o mtodo coerce, que recebe o objeto que
est solicitando a coero. O exemplo abaixo mostra como criar uma classe cuja
instncia pode ser convertida em nmeros inteiros e flutuantes, mas no em
instncias da classe BigDecimal.
class NumberOne
def coerce(object)

case object
when Integer
[object, 1]
when Float
[object, 1.0]
else
raise TypeError, "#{self.inspect} can't be coerced into #
{object.class}"
end
end
end
puts 1 + NumberOne.new
#=> 2
puts 1.0 + NumberOne.new
#=> 2.0
require "bigdecimal"
puts BigDecimal.new("1.0") + NumberOne.new
#=> TypeError: FakeNumber can't be coerced into BigDecimal
O duck typing vai alm de simples regras; um estilo de programao. Antes de
exigir tipos de objetos, pergunte-se se isso realmente necessrio. s vezes,
o tipo do objeto muito importante, mas muitas vezes isso simplesmente no
importa.
Variveis e constantes
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Mtodos
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Entendendo o self
self ser sempre uma referncia ao receiver atual e pode ser diferente
dependendo do contexto em que voc estiver. Por exemplo, quando estamos no
namespace global, nosso self ser o objeto main. J em uma classe, nosso self
ser a prpria classe.
puts self
#=> main
class Thing
puts self
end
#=> Thing
Sempre que executar um mtodo, o Ruby ir verificar se esse mtodo existe no
receiver padroself a menos que voc especifique-o explicitamente. E, pelo
fato de o receiver padro ser self, voc nem precisa especific-lo se no
quiser.
class Thing
def do_something
puts "doing something"

end
def do_something_else
do_something
end
end
No mtodo do_something_else poderamos usar self.do_something, mas isso faria
com que nosso cdigo apenas ficasse mais poludo. No entanto, definir o
receiver uma coisa muito comum e que, voc pode at no se dar conta, mas o
faz constantemente quando escreve cdigo Ruby.
numbers = [3,1,2]
numbers.sort
#=> [1,2,3]
text = "some string"
text.upcase
#=> "SOME STRING"
Na prtica, o receiver especificado antes do ponto na chamada de mtodos,
como em numbers.sort ou text.upcase.
Alm de ser o receiver padro, self tambm o responsvel por armazenar
variveis de instncia de um objeto. Veja o exemplo abaixo.
class Person
def initialize(name)
@name = name
end
def name
@name
end
end
john = Person.new("John Doe")
john.name
#=> "John Doe"
A instncia da classe Person possui uma nica varivel de instncia associada
ao seu objeto, self, que retornada pelo mtodo Person#name. Analogamente,
podemos definir variveis de instncia em qualquer objeto, como classes.
class Person
def self.count
@count ||= 0
end
def self.count=(increment)
@count = increment
end
def initialize(name)
@name = name
self.class.count += 1
end
def name
@name
end

end
john = Person.new("John Doe")
Person.count
#=> 1
O exemplo acima mostra como variveis de instncia podem ser usadas em
contextos diferentes. Primeiro, estamos definindo um contador de instncias da
classe Person, cujo valor ser armazenado em @count. Depois, em nossa prpria
instncia, definimos o nome com a varivel @name.
Convenes
Os desenvolvedores Ruby seguem uma srie de convenes enquanto esto
escrevendo seus cdigos. Embora voc no seja obrigado seguir essas
convenes, sempre uma boa ideia garantir que est escrevendo cdigos do
mesmo jeito que um desenvolvedor mais experiente.
Confira neste captulo quais so as convenes mais utilizadas e evite olhares
estranhos.
Nomeando classes, variveis e constantes
Use o formato snake_case para definir variveis.
# recomendado
success_message = "You're done!"
# estranho
successMessage = "You're wrong!"
Classes e mdulos so nomeados em camel case.
* Rails
* ActiveSupport
* Net
Se sua classe ou mdulo for um acrnimo, mantenha todas as letras em
maisculas.
* HTTP
* HTTP::POST
* XML
Outras constantes devem usar o formato SNAKE_CASE.
# recomendado
SUCCESS_MESSAGE = "You're done!"
# estranho
SuccessMessage = "You're wrong!"
Mtodos predicados (aqueles que retornam valores booleanos) devem terminar com
? e no precisam de um prefixo is.
# recomendado
def ready?
status == "ready"
end
# estranho

def is_ready?
status == "ready"
end
Mtodos que modificam self, lanam excees ou so potencialmente perigosos/
destrutivos devem terminar com uma exclamao.
# recomendado
def save!
save or raise("OMG!")
end
Indentao, espaamento e quebras de linha
No Ruby, trechos de cdigo so indentados em 2 espaos.
# recomendado: 2 espaos
def hello
puts "Hello!"
end
# estranho: 4 espaos
def hello
puts "Hello!"
end
# mais estranho: hard tabs
def hello
puts "Hello!"
end
Adicione espaamento em torno de operadores e depois de vrgulas.
# recomendado
sum = 1 + 1
x, y = 1, 2
# estranho
sum = 1+1
x,y = 1,2
No coloque espaamentos depois de [ e (, nem antes de ] e ).
# recomendado
hello("John")
numbers = [1, 2, 3]
# estranho
hello( "John" )
numbers = [ 1, 2, 3 ]
As quebras de linha devem seguir o estilo Unix, ou seja, devem ser inseridas
como \n. Sempre adicione uma nova linha \n ao final do seu arquivo.
Evite deixar espaamentos ao final da linha (trailing spaces).
Definindo e executando mtodos
Quando o mtodo receber argumentos, sempre coloque os parnteses e separe os
argumentos corretamente.

# recomendado
def sum(n1, n2)
n1 + n2
end
# estranho
def sum( n1, n2 )
n1 + n2
end
# mais estranho
def sum n1, n2
n1 + n2
end
Se o mtodo no recebe nenhum argumento, no adicione os parnteses.
# recomendado
def message
"Hello"
end
# estranho
def message()
"Hello"
end
A mesma regra deve ser aplicada quando voc estiver executando mtodos.
# recomendado
user.run
# estranho
user.run()
Esta regra possui uma exceo. Quando um mtodo definido com o mesmo nome de
uma constante, voc deve usar os parnteses. Caso contrrio, voc estar
acessando a prpria constante, que normalmente ser um mdulo ou classe.
class Foo; end
def Foo
puts "You called the Foo method"
end
Foo.new
Foo()

#=> Instancia a classe Foo


#=> Executa o mtodo Foo()

Retorno de mtodos e blocos


Mtodos e blocos no Ruby retornam o resultado da ltima linha executada,
dispensando o uso de return.
def message
"Hello"
end
puts message

#=> Hello
No entanto, se voc precisar encerrar o fluxo de execuo antes da ltima
linha, deve usar o return.
def message(text)
return "Hello stranger!" unless text
text
end
message(nil)
#=> Hello stranger!
message("Hello there!")
#=> Hello there!
Usando blocos
Mtodos podem receber blocos2. Quando o seu bloco possuir mais de uma instruo
ou precisar encadeado, utilize chaves ({ e }) para criar blocos inline.
contents = File.open("file.txt") {|file| file.read}
#=> Ruby #nice
numbers = [1,2,3].map {|n| n * 2}.reject {|n| n % 2 == 0}
#=> [2]
Se o seu bloco possuir mais de uma instruo, voc deve utilizar as palavraschave do..end.
File.open("file.txt", "w+") do |file|
file.write "Ruby"
file.write " #nice"
end
Escrevendo sobre o Ruby
Uma conveno do Ruby que usada em textos que mtodos estticos (aqueles
que podem ser acessados diretamente em uma classe ou mdulo) so referenciados
como Modulo.metodo ou Modulo::metodo. Logo, se voc quiser escrever alguma
documentao ou texto que cita o mtodo enable do mdulo GC, voc deve escrever
GC.enable ou GC::enable.
J mtodos de instncia, como "Hello".upcase devem ser referenciados como
String#upcase.
Esta conveno tambm utilizada para acessar a documentao atravs da linha
de comando, como voc ver mais frente.
Atribuio de variveis
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Constantes e variveis globais
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Conhecendo o IRB

O Ruby vem com um shell REPL1 chamado Interactive Ruby (IRB). Ele faz
exatamente o que o nome sugere: ele l uma linha, executa esta linha, exibe o
resultado da execuo e faz o loop, esperando por uma nova linha. O IRB a
melhor maneira de testar q
Para iniciar o IRB, execute o comando irb.
$ irb
irb(main):001:0>
Neste shell voc pode digitar qualquer cdigo Ruby. Experimente digitar alguma
expresso matemtica simples.
irb(main):001:0> 1 + 1
=> 2
No Ruby, tudo3 objeto. Voc pode descobrir qual a classe de um objeto com o
mtodo Object#class.
irb(main):002:0> 1234.class
=> Fixnum
irb(main):003:0> "Hello".class
=> String
Mtodos so aes que um objeto pode realizar. No exemplo acima, o mtodo
Object#class apenas informa qual a classe que instanciou um determinado objeto.
Voc tambm pode acessar a lista de todos os mtodos que um objeto possui com o
mtodo Object#methods. Veja, por exemplo, quais so os mtodos de uma string:
irb(main):004:0> "Hello".methods
=> [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert,
:length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :
next!,
:upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :
byteslice,
:to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :
capitalize,
:swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :
split,
:lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :
prepend,
:crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan,
:ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :
rstrip,
:sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :
delete,
:squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte,
:each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition,
:encoding, :force_encoding, :valid_encoding?, :ascii_only?, :unpack, :encode,
:encode!, :to_r, :to_c, :>, :>=, :<, :<=, :between?, :nil?, :!~, :class,
:singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint,
:tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :
methods,
:singleton_methods, :protected_methods, :private_methods, :public_methods,
:instance_variables, :instance_variable_get, :instance_variable_set,
:instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send,
:public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method,
:public_method, :define_singleton_method, :object_id, :to_enum, :enum_for,
:equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Perceba como o shell do IRB muda sua apresentao, de acordo com o nvel de
indentao do cdigo.
irb(main):005:0> def sum(n1, n2)
irb(main):006:1> n1 + n2
irb(main):007:1> end
=> nil
irb(main):008:0> sum(3, 2)
=> 5
irb(main):009:0>
O IRB permite testar cdigos Ruby interativamente. Escreva outros tipos de
expresses para se familiarizar com esta excelente ferramenta.
Executando cdigos Ruby
A maneira mais comum de escrever Ruby colocando cdigos em um ou mais
arquivos. Normalmente, estes arquivos possuem a extenso .rb, embora voc possa
usar qualquer extenso (ou nenhuma extenso).
Crie o arquivo hello.rb com o seguinte cdigo:
puts "Hello!"
puts "Current time: #{Time.now}"
Para executar este cdigo, basta executar o interpretador Ruby, passando o
caminho do arquivo como argumento.
$ ruby hello.rb
Hello!
Current time: 2011-12-23 10:39:20 -0200
Em sistemas operacionais Unix, possvel especificar o shebang, que determina
qual o tipo de interpretador que ser usado para executar aquele arquivo.
#!/usr/bin/env ruby
puts "Hello!"
puts "Current time: #{Time.now}"
Agora voc pode fazer com que o arquivo seja executvel com o comando chmod +x
hello.rb. Ao fazer isso, voc no mais precisar executar o interpretador Ruby.
$ ./hello.rb
Hello!
Current time: 2011-12-23 10:44:30 -0200
Acessando a documentao do Ruby
Atualmente existem bibliotecas Ruby para tudo (ou quase tudo) o que voc possa
imaginar. A maioria delas documentada com RDoc, que so apenas comentrios
Ruby que podem ser extrados em HTML e no formato ri.
Esta ferramenta ri permite visualizar a documentao de mtodos, constantes
classes e mdulos da Standard Library (que j vem com o Ruby) e de cdigos de
desenvolvedores 3rd party.
Para visualizar a documentao do mdulo GC, execute o comando ri GC.
$ ri GC
= GC
(from ruby core)

----------------------------------------------------------------------------The GC module provides an interface to Ruby's mark and sweep garbage


collection mechanism. Some of the underlying methods are also available via
the ObjectSpace module.
You may obtain information about the operation of the GC through GC::
Profiler.
----------------------------------------------------------------------------= Class methods:
count, disable, enable, malloc_allocated_size, malloc_allocations, start,
stat, stress, stress=
= Instance methods:
garbage_collect
Voc tambm pode visualizar a documentao de um mtodo especfico. Veja, por
exemplo, a documentao do mtodo String#upcase.
$ ri String#upcase
= String#upcase
(from ruby core)
----------------------------------------------------------------------------str.upcase -> new_str
----------------------------------------------------------------------------Returns a copy of str with all lowercase letters replaced with their
uppercase counterparts. The operation is locale insensitive---only characters
``a'' to ``z'' are affected. Note: case replacement is effective only in
ASCII
region.
"hEllO".upcase

#=> "HELLO"

Voc tambm pode visualizar a documentao de mtodos estticos como GC.enable.


$ ri GC.enable
= GC.enable
(from ruby core)
----------------------------------------------------------------------------GC.enable
-> true or false
----------------------------------------------------------------------------Enables garbage collection, returning true if garbage collection was
previously disabled.
GC.disable

#=> false

GC.enable
GC.enable

#=> true
#=> false

1 Read-Eval-Print-Loop
2 No se preocupe com o que so blocos por enquanto. Voc ver mais sobre este
assunto mais__frente.
3 Na verdade, quase tudo no Ruby objeto. Algumas coisas no so objetos
diretamente, embora voc consiga acess-las de outras maneiras.
Ruby Core Classes
String
Strings so sequncias de caracteres normalmente delimitadas por aspas ou
apstrofos.
hello = "Hello"
ruby = 'Ruby'
A diferena entre os dois delimitadores que os apstrofos ignoram caracteres
como \n e \t.
puts "Ruby is really\nnice language."
#=> Ruby is really
#=> nice language.
puts 'Ruby is really\nbeautiful.'
#=> Ruby is really\nbeautiful.
Outra diferena que strings delimitadas por apstrofos no podem ser
interpoladas. Interpolao o processo de definir uma expresso Ruby dentro de
uma string, de modo que seu resultado substitua os delimitadores #{} que
englobam a expresso.
now = Time.now
puts "Time: #{now}"
#=> Time: 2011-12-21 01:35:30 -0200
puts 'Time: #{now}'
#=> Time: #{now}
Voc pode definir strings com mltiplas linhas sem precisar de nenhuma sintaxe
especial.
text = "This can be a long text with
multiple lines."
text = 'This can be a long text with
multiple lines.'
Caracteres podem ser escapados com uma barra invertida antes do caracter.
puts "Ruby for \"rubyists\"."
#=> Ruby for "rubyists".
puts "Ruby for\\nrubyists."
#=> Ruby for\nrubyists.
Voc pode definir strings de outras formas. Uma delas usando o formato

heredoc, que possui duas variaes.


text = <<TEXT
This can be a long text with
multiple lines. And I don't
need to escape "quotes".
TEXT
text = <<-TEXT
This can be a long text with
multiple lines. And I don't
need to escape "quotes".
TEXT
A string heredoc precisa de um identificador (escrito em letras maisculas) que
ser usado para iniciar e terminar a string. A diferena entre as duas
variaes que a primeira forma exige que o identificador de trmino esteja no
comeo da linha.
Voc pode executar mtodos em strings heredoc.
puts <<-TEXT.upcase
This can be a long text with
multiple lines.
TEXT
#=> THIS CAN BE A LONG TEXT WITH
#=> MULTIPLE LINES.
Uma outra caracterstica de strings heredoc que elas preservam espaos em
branco no comeo da linha.
puts <<-TEXT
This can be a long text with
multiple lines.
TEXT
#=> This can be a long text with
#=>
multiple lines.
Outra forma de especificar strings utilizando os delimitadores %, %q, %Q.
puts %q[Time: #{Time.now}]
#=> Time.now #{Time.now}
puts %Q(Time: #{Time.now})
#=> Time: 2011-12-21 01:40:09 -0200
puts %!Time: #{Time.now}!
#=> Time: 2011-12-21 01:40:09 -0200
Perceba nos exemplos acima que foram usados diferentes tipos de delimitadores:
%q[], %Q() e %!!. Na prtica, voc pode usar qualquer caracter como
delimitador. Note que voc precisar escapar os caracteres da string que forem
iguais ao delimitador.
puts %q~Time: #{Time.now}~
#=> Time.now #{Time.now}
puts %Q/Time: #{Time.now}/
#=> Time: 2011-12-21 01:40:09 -0200
puts %<Time: #{Time.now}>

#=> Time: 2011-12-21 01:40:09 -0200


puts %:Time\: #{Time.now}:
#=> Time: 2011-12-21 01:40:09 -0200
Nmeros
O Ruby possui 8 classes para representar nmeros. Todos os objetos que
representam nmeros no Ruby so instncias da classe Numeric. Nmeros so
imutveis e, por este motivo, no existem mtodos que podem mudar o valor de um
nmero; se voc tentar fazer isso, receber a mensagem de erro Can't change the
value of self.
Em verses mais antigas do Ruby, as classes Complex e Rational no so nativas
do Ruby, embora sejam distribudas como parte da Standard Library1.
Fixnum
Nmeros inteiros no possuem um tamanho determinado, pois o seu tamanho
definido pela quantidade de memria disponvel. Quando definidos nos intervalos
entre 230 e 230-1 ou 262 e 262-1, inteiros so definidos como instncias da
classe Fixnum. Inteiros fora deste intervalo so automaticamente definidos como
objetos da classe Bignum, em um processo totalmente transparente e automtico.
number = 1000
3.times do
number *= number
puts "#{number.class} => #{number}"
end
#
#
#
#

Output:
Fixnum => 1000000
Fixnum => 1000000000000
Bignum => 1000000000000000000000000

Voc pode definir nmeros inteiros usando um sinal de + ou - opcional para


definir valores positivos e negativos, um indicador opcional da base do nmero,
seguidos pela sequncia de nmeros especificados na base escolhida.
1234
0d1234
1_234
-1234
0x4d2
02322
0b10011010010

#=>
#=>
#=>
#=>
#=>
#=>
#=>

1234
1234
1234
-1234
1234
1234
1234

Base decimal, padro


Underscores so ignorados
Negativo
Hexadecimal
Octal
Binrio

Float
Nmeros de ponto flutuante so definidos pelo . (ponto decimal) aps um ou mais
nmeros decimais, seguido por mais nmeros decimais. Voc tambm pode,
opcionalmente, utilizar um expoente. Ao contrrio dos nmeros inteiros, nmeros
com ponto flutuante no podem ser definidos em outra base diferente de 10.
puts
puts
puts
puts

1.234
-1.234
1_234.0
12e2

#=>
#=>
#=>
#=>

1.234
-1.234 - Negativo
1234.0 - Underscores so ignorados
1200.0 - 12.0 x 10e2

puts 12.3e2
puts 12.3E2

#=> 1230.0 - 12.3 x 10e2


#=> 1230.0 - 12.3 x 10e2

No Ruby, no possvel definir nmeros com ponto flutuante sem ter um nmero
antes do ponto decimal. Se voc tentar definir um nmero como .1 ir receber
uma mensagem de erro como no .<digit> floating literal anymore; put 0 before
dot.
Nmeros de ponto flutuante seguem a especificao IEEE-754, assim como a
maioria das linguagens e hardwares do mercado. Dada a forma como os nmeros de
ponto flutuante so tratados, fraes como 1/10 e 1/100 no podem ser
representadas corretamente. muito comum clculos como o exemplo seguir
causarem espanto, mesmo ele acontecendo em muitas outras linguagens2.
0.3 - 0.2 == 0.1
#=> false
O Ruby consegue efetuar clculos deste tipo quando objetos da classe BigNumber
so utilizados.
BigDecimal
A classe BigDecimal permite realizar clculos onde o arredondamento muito
importante, como em clculos financeiros. Nmeros do tipo BigDecimal so
praticamente ilimitados (expoentes acima de 1 bilho so suportados) e possuem
controle preciso dos modos de arredondamento.
require "bigdecimal"
BigDecimal("0.3") - BigDecimal("0.2") == 0.1
#=> true
Voc pode especificar os modos de arredondamento e quantidade de dgitos
decimais que sero computados. Para ver a referncia completa, acesse a
documentao.
Complex
Para ver a referncia completa, acesse a documentao.
Rational
Para ver a referncia completa, acesse a documentao.
Array
O Ruby possui arrays, que so listas que podem guardar qualquer tipo de objeto
e no precisam ser criadas com tamanho determinado; novos tens podem ser
adicionados a qualquer momento.
Para criar um novo array, basta instanciar a classe Array ou utilizar o atalho
[].
items = Array.new(10, "Hello", :ruby)
items = [10, "Hello", 3.5]
O mtodo Array#initialize pode ser utilizado de maneiras diferentes. Voc pode
dizer com quantos tens o array deve ser iniciado. Por padro, o array ser
iniciado com o valor nil.
items = Array.new(5)
#=> [nil, nil, nil, nil, nil]

Voc tambm pode passar um valor inicial que ser usado para popular este
array.
items = Array.new(5, "hello")
#=> ["hello", "hello", "hello", "hello", "hello"]
Tambm possvel iniciar um array com um bloco. Neste caso, o valor retornado
pelo bloco ser usado.
items = Array.new(5) {|i| i * 2}
#=> [0, 2, 4, 6, 8]
Se todos os elementos do array forem strings, voc pode utilizar a sintaxe %w
ou %W. Assim como as strings, voc pode utilizar qualquer delimitador.
words = %w[jan fev mar apr may jun jul aug sep oct nov dec]
#=> ["jan", "fev", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct",
"nov", "dec"]
letters = %w(a b c)
#=> ["a", "b", "c"]
Para adicionar elementos que contm espaos, escape o espao com \.
words = %w[John\ Doe Jane\ Doe]
#=> ["John Doe", "Jane Doe"]
Se voc precisa interpolar alguma varivel, utilize %W.
name = "John Doe"
words = %w[Jane\ Doe #{name}]
#=> ["Jane Doe", "\#{name}"]
words = %W[Jane\ Doe #{name}]
#=> ["Jane Doe", "John Doe"]
Arrays s podem ter ndices numricos. Os ndices comeam em 0 e tambm podem
ser acessados de forma negativa.
numbers = Array.new(10) {|n| n * 2}
#=> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
numbers[0]
numbers.first
numbers[4]
numbers[-1]
numbers.last

#=>
#=>
#=>
#=>
#=>

0
0
8
18 - A mesma coisa que numbers[numbers.size - 1]
18

Tambm possvel acessar intervalos passando dois nmeros.


numbers[0, 2]
numbers[-2, 2]
elementos.

#=> [0, 2]
#=> [16, 18]

- partir do ndice 0, pegue dois elementos.


- partir do ndice size - 2, pegue dois

Hash
Um outro tipo de estrutura de dados do Ruby o Hash. Hashes so como arrays,
com a diferena que o ndice de um hash pode ser qualquer objeto. partir do

Ruby 1.9, hashes enumeram seus valores na ordem que as chaves foram inseridas.
No Ruby 1.8 esse comportamento era imprevisvel.
user = {"name" => "John Doe", "age" => 32}
Voc pode definir o valor-padro de uma chave que ainda no existe no array.
Para isso, basta passar um argumento na hora que for instanciar o hash.
options = Hash.new("OMG!!!")
options["invalid key"]
#=> OMG!!!
Voc tambm pode definir o valor-padro atravs de um bloco.
options = Hash.new {|hash, key| "OMG!!!"}
options["invalid key"]
#=> OMG!!!
Perceba que os valores-padro que so retornados no so armazenados no hash.
de responsabilidade do bloco fazer esta atribuio.
options = Hash.new {|hash, key| "OMG!!!"}
options["invalid key"] #=> retorna "OMG!!!"
options.keys
#=> []
options = Hash.new {|hash, key| hash[key] = "OMG!!!"}
options["invalid key"] #=> retorna "OMG!!!"
options.keys
#=> ["invalid key"]
Voc tambm pode inicializar arrays usando o mtodo Hash.[]. Voc pode passar
uma lista de argumentos que alternam entre chave e valor.
user = Hash["name", "John Doe", "age", 32]
#=> {"name" => "John Doe", "age" => 32}
O mtodo Hash.[] tambm aceita um array de arrays de dois elementos que
identificam a chave e o valor.
user = Hash[[["name", "John Doe"], ["age", 32]]]
#=> {"name" => "John Doe", "age" => 32}
Por ltimo, voc pode passar um objeto que pode ser convertido em hash atravs
do mtodo to_hash.
user = {"name" => "John Doe", "age" => 32}
Hash[user]
#=> {"name" => "John Doe", "age" => 32}
partir do Ruby 1.9 possvel definir hashes usando uma sintaxe semelhante a
do JavaScript. Uma caracterstica dessa sintaxe que as chaves so geradas
como smbolos.
user = {name: "John Doe", age: 32}
user.keys
#=> [:name, :age]

Symbol
Smbolos so objetos que representam nomes no Ruby e so muito utilizados como
identificadores, principalmente como chaves de hashes. Eles so gerados atravs
da sintaxe :symbol ou :"symbol", alm dos mtodos String#to_sym e
String#intern.
symbol
symbol
symbol
symbol

=
=
=
=

:john
:"john doe"
"john".to_sym
"john doe".intern

Alternativamente voc pode usar o delimitador %s.


symbol = %s[john doe]
symbol.class
#=> Symbol
Smbolos compartilham sempre o mesmo espao em memria, independente do lugar
onde foram criados.
name = :john
name.object_id
#=> 302248
other_name = :john
other_name.object_id
#=> 302248
Boolean
No Ruby os valores booleanos so true e false, que so instncias das classes
TrueClass e FalseClass. Infelizmente, ambas as classes no possuem uma
superclasse comum.
true.class
#=> TrueClass
false.class
#=> FalseClass
Os valores booleanos tambm podem ser acessados atravs das constantes TRUE e
FALSE.
TRUE.class
#=> TrueClass
FALSE.class
#=> FalseClass
Os valores booleanos true e false ocupam sempre o mesmo espao em memria,
atravs dos ids 2 e 0, respectivamente.
true.object_id
#=> 2
false.object_id
#=> 0

nil
O Ruby define o tipo nulo atravs do do objeto nil, que uma instncia da
classe NilClass. O nil ocupa sempre o mesmo espao em memria com o id 4.
nil.class
#=> NilClass
nil.object_id
#=> 4
Este o valor de retorno de blocos e mtodos que no retornam nada, o que
explicitamente usam as palavras-chave return e next sem nenhum valor.
def hello
end
hello.class
#=> NilClass
def hello
return
end
hello.class
#=> NilClass
Range
Para definir intervalos de nmeros e strings podemos utilizar a classe Range.
numbers = 1..10
numbers.class
#=> Range
letters = "a".."z"
letters.class
#=> Range
possvel definir um intervalo excluindo o ltimo elemento.
numbers = 1...10
numbers.cover?(10)
#=> false
Voc pode converter um intervalo em array com o mtodo to_a.
letters = "a".."z"
letters.to_a
#=> [
#=> "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
#=> "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
#=> "u", "v", "w", "x", "y", "z"
#=> ]
Voc pode definir limites de strings com mais de um caracter.
strings = "1a".."1e"

strings.to_a
#=> ["1a", "1b", "1c", "1d", "1e"]
Sempre que precisar descobrir se um valor est includo em um intervalo,
utilize o mtodo Range#cover?. Ele muito mais rpido que transformar o
intervalo em array e depois verificar se o tem est includo com o mtodo
Array#include?.
("aaa".."zzz").cover?("def") #=> bom
#=> true
("aaa".."zzz").to_a.include?("def") #=> ruim
#=> true
Expresses regulares
Expresses regulares so padres (ou patterns) que permitem descrever o
contedo de uma string. Elas podem ser utilizadas para verificar se uma string
contm um determinado padro ou para extrair partes dessa string. Para criar
uma expresso regular voc deve definir o padro utilizando a sintaxe /pattern/
ou %r(pattern).
regex = /hello/
Alguns caracteres precisam ser escapados pois eles tem um significado especial
em expresses regulares. So os chamados metacaracteres: (, ), [, ], {, }, .,
?, + e *.
regex = /\Ahttps?:\/\//
Perceba que estamos escapando a /. Este caracter em particular pode continuar
sendo utilizado sem precisar ser escapado se definirmos a expresso regular com
%r(). Note que voc pode utilizar qualquer caracter como delimitador.
regex = %r(\Ahttps?://)
regex = %r[\Ahttps?://]
Expresses regulares so extremamente poderosas. Elas permitem verificar
padres que seriam difceis (e em alguns casos impossveis) de serem feitas de
outras maneiras. Se voc deseja aprender mais sobre assunto, leia o livro
Expresses_Regulares:_uma_abordagem_divertida, escrito por Aurlio Marinho
Jargas, e que est disponvel gratuitamente para leitura_online.
Procs e lambdas
Procs so blocos de cdigo que podem ser associados a uma varivel e que
funcionam como funes anonnimas. Muitas vezes voc precisa de um mtodo
utilitrio que ir fazer algumas pequenas computaes onde criar um mtodo
propriamente dito seria muito trabalho; a que entram as procs.
Para definir uma nova proc, voc pode utilizar o mtodo Proc.new ou o mtodo
Kernel#proc.
# alternativa 1
message = Proc.new { "Hello" }
# alternativa 2
message = proc { "Hello" }
Para executar essas procs voc pode utilizar trs mtodos diferentes.

message = proc { "Hello" }


message.call
message[]
message.()
A ltima maneira de execuo (sum.(1, 2)) est disponvel partir do Ruby 1.9.
Por conveno, procs que possuem uma nica expresso devem ser definidas por
chaves.
message = proc { "One-line proc" }
E, tambm por conveno, quando uma proc possuir mais de uma expresso elas
devem ser definidas pelas palavras-chave do..end.
message = proc do
puts "Hello!"
puts "Ruby!"
end
Procs podem receber parmetros, assim como mtodos. Basta delimitar os
parmetros com |. Para receber mais de um parmetro, separe-os com vrgula.
sum = proc {|n1, n2| n1 + n2}
sum.call(1, 2)
sum[1, 2]
sum.(1, 2)
O valor de retorno de uma proc, assim como mtodos, a ltima expresso que
for executada. Se voc quiser encerrar o fluxo de execuo retornando um valor
antes da ltima expresso, deve usar next, em vez do return utilizado por
mtodos.
divide = proc do |n1, n2|
next 0 if n1.zero?
next nil if n2.zero?
n1 / n2
end
divide[3.0, 2]
#=> 1.5
divide[0, 2]
#=> 0
divide[2, 0]
#=> nil
O Ruby 1.9 tambm introduziu uma nova sintaxe para a definio de procs.
message = -> { "Hello" }
message.call
#=> Hello
Esta nova sintaxe tambm pode aceitar parmetros, mas faz com que a
legibilidade do cdigo seja prejudicada.

sum = -> n1, n2 { n1 + n2 }


sum[1, 2]
#=> 3
Procs podem ser convertidas em blocos3. Basta adicionar um &amp; na hora que
passar o bloco como parmetro.
def sum(n1, n2, &amp;block)
block[n1 + n2]
end
# Passando um bloco explicitamente
sum(1, 2) {|result| puts result}
# Convertendo uma proc em bloco
output = proc {|result| puts result}
sum(1, 2, &amp;output)
Existem ainda as procs criadas com o mtodo Kernel#lambda.
sum = lambda {|n1, n2| n1 + n2}
sum[1, 2]
#=> 3
Embora o mtodo Kernel#lambda seja semelhante ao mtodo Kernel#proc, eles
possui uma diferena muito importante. Lambdas iro validar a quantidade de
parmetros que foram passados e lanaro a exceo ArgumentError: wrong number
of arguments caso o nmero de argumentos seja incorreto. J as procs iro
atribuir o valor nil para cada um dos parmetros.
proc_message = proc {|message| p message}
lambda_message = lambda {|message| p message}
proc_message.call
#=> nil
lambda_message.call
#=> ArgumentError: wrong number of arguments (0 for 1)
Uma outra diferena que se um return for definido em uma proc, o mtodo que
executou esta proc tambm ir encerrar o fluxo de execuo. No caso de lambdas,
o fluxo de execuo ser encerrado apenas no lambda que originou a chamada ao
return.
def return_proc
proc { return }.call
puts "return_proc"
end
def return_lambda
lambda { return }.call
puts "return_lambda"
end
return_proc
return_lambda
# Output:
# return_lambda

Para descobrir quantos parmetros obrigatrios uma proc espera, use o mtodo
Proc#arity. Se a proc possui argumentos opcionais, o valor de retorno ser -n 1, onde n a quantidade de parmetros obrigatrios.
Proc.new
Proc.new
Proc.new
Proc.new
Proc.new
Proc.new
Proc.new
Proc.new

{}.arity
{||}.arity
{|a|}.arity
{|a,b|}.arity
{|a,b,c|}.arity
{|*a|}.arity
{|a,*b|}.arity
{|a,*b, c|}.arity

#=>
#=>
#=>
#=>
#=>
#=>
#=>
#=>

0
0
1
2
3
-1
-2
-3

Para pegar uma representao dos parmetros que um bloco pode receber, use o
mtodo Proc#parameters. Note que a representao muda quando um lambda
definido.
proc {|a, b = 42, *args|}.parameters
#=> [[:opt, :a], [:opt, :b], [:rest, :args]]
lambda {|a, b = 42, *args|}.parameters
#=> [[:req, :a], [:opt, :b], [:rest, :args]]
Set
Existem situaes onde voc pode precisar de uma lista com valores nicos. Isso
pode ser facilmente resolvido com arrays e o mtodo Array#include? ou
Array#uniq.
items = [1, 2, 3]
# alternativa 1: verificar se o tem existe antes de adicion-lo
items << 3 unless items.include?(3)
# alternativa 2: adicione o tem e depois pegue os elementos nicos
items << 3
items.uniq
Embora essas tcnicas funcionem, elas no so otimizadas. O Ruby possui a
classe Set que faz justamente isso: garante que apenas tens nicos sero
adicionados lista.
require "set"
items = Set.new([1, 2, 3])
# adiciona novamente o nmero 2
items << 2
# converte o set em array
items.entries #=> [1, 2, 3]
items.to_a
#=> [1, 2, 3]
Alternativamente, voc pode criar um novo Set usando o mtodo Array#to_set.
require "set"
[1, 2, 3, 3, 2, 4].to_set
#=> #<Set: {1, 2, 3, 4}>

1 A Standard Library o conjunto de bibliotecas que vem com a instalao do


Ruby.
2 O mesmo problema acontece no C, Java, Python e JavaScript.
3 Para saber mais sobre blocos, leia Blocos.
Estruturas condicionais
A estrutura de controle mais comum em qualquer linguagem de programao a
condicional. apenas uma maneira de executar um trecho de cdigo se alguma
condio for satisfeita. Uma condio uma expresso que quando verificada
retorna um valor diferente de false e nil.
O Ruby possui diferentes formas de expresses condies, como voc pode
conferir seguir.
if
O if a forma mais direta de se definir uma expresso condicional. Sua sintaxe
bastante simples.
if expression
# do something
end
O trecho de cdigo definido dentro de if..end ser executado somente se o valor
de expression for diferente de false e nil. Note que no necessrio adicionar
parnteses em torno das condies.
O resultado de um if pode ser atribudo a uma varivel.
x = 1
y = 0
y = if x > 0
y + 1
end
puts y
#=> 1
No exemplo acima, estamos atribuindo o valor y + 1 sempre que o valor de x for
maior que zero. Embora seja uma construo vlida e muito flexvel, nem sempre
a melhor maneira. A mesma expresso poderia ser escrita de um modo muito mais
legvel.
x = 1
y = 0
if x > 0
y += 1
end
puts y
#=> 1
O if pode ser usado de forma inline, agindo como um modificador.
x = 0
x += 1 if x.zero?
A condio ser sempre a primeira a ser executada, mesmo ela sendo escrita por
ltimo.

else
O if pode conter uma clusula else, que ser executada quando a condio no
for satisfeita. Caso o valor expression seja igual a false ou nil, ento o
cdigo associado ao else ser executado.
if expression
# do something
else
# do something else
end
elsif
Se voc precisar adicionar mais clusulas else que dependem de outras
condies, pode usar o elsif.
if expression
# do something
elsif expression2
# do something else
elsif expressionN
# do something else
else
# do something else
end
Cada uma das expresses ir falhar caso o valor de retorno seja false ou nil,
at que seja executada a ltima expresso else. Note que o else opcional.
x = 4
name = nil
if x == 1
name = "one"
elsif x == 2
name = "two"
elsif x == 3
name = "three"
end
puts name.inspect
#=> nil
No exemplo acima, estamos verificando se o x possui os valores 1, 2 ou 3. Como
o valor de x 4, nenhuma das condies de nosso if ser satisfeita, o que faz
com que o valor original de name no seja alterado. No Ruby o mtodo inspect
normalmente retorna uma representao do self como uma string.
unless
Uma tendncia natural quando queremos executar alguma expresso somente se uma
condio falhar adicionar uma exclamao antes da condio ou,
alternativamente, usar a palavra-chave not, que tambm tem suporte no Ruby.
if !expression
# do something
end

O if acima poderia ser escrito de uma forma diferente usando o unless.


unless expression
# do something
end
O unless tambm suporta uma clusula else, mas seu uso desencorajado; neste
caso, seria muito mais simples escrever um if que coloca a expresso a ser
executada se o valor da condio no for false ou nil primeiro!
# estranho
unless x
x = 1
else
x += 1
end
# recomendado
if x
x += 1
else
x = 1
end
Assim como o if, o unless tambm pode ser usado de forma inline.
x = 0
x += 1 unless x.nonzero?
Operador ternrio ?:
O operador ?: o nico operador ternrio (que possui trs operandos) suportado
pelo Ruby.
* O primeiro operando que vem antes da interrogao a condio.
* O segundo operando que vem antes dos dois-pontos a expresso que ser
executada caso a condio seja diferente de false ou nil.
* O terceiro e ltimo operando que vem depois dos dois-pontos a expresso que
ser executada caso a condio falhe.
No exemplo seguir temos um mtodo que ir retornar uma string levando em
considerao a quantidade de tens. Se o count for igual a 1, uma string que
representa o singular retornada. Caso contrrio, uma string que representa o
plural retornada.
def pluralize(count, singular, plural)
if count == 1
singular
else
plural
end
end
A mesma condio poderia ser simplificada usando o operador ternrio ?:.
def pluralize(count, singular, plural)
count == 1 ? singular : plural
end

case
O case expresso condicional que permite fazer diversos tipos de comparaes
e que pode ser usada de duas formas diferentes.
A primeira forma que apenas uma alternativa para if..elsif..else a mais
simples, mas tambm a menos utilizada.
case
when
when
when
else
end

x == 1 then "one"
x == 2 then "two"
x == 3 then "three"
"other"

#
#
#
#
#

if x == 1 then "one"
elsif x == 2 then "two"
elsif x == 3 then "three"
else "other"
end

A palavra-chave then s necessria se voc quiser utilizar expresses na


mesma linha do comparador. Alternativamente, voc pode utilizar o caracter ;.
A segunda forma ir receber um objeto que pode ser comparado com diversos tipos
de expresses diferentes. Esse modo extremamente poderoso e permite fazer
comparaes com expresses regulares, classes e intervalos.
O exemplo anterior poderia ser expressado de uma forma um pouco menos
repetitiva.
case
when
when
when
else
end

x
1 then "one"
2 then "two"
3 then "three"
"other"

O case tambm retorna o valor da expresso que for executada, podendo ser
atribuda a uma varivel.
number = case
when
when
when
else
end

x
1 then "one"
2 then "two"
3 then "three"
"other"

Voc pode definir diversas comparaes em uma mesma expresso.


case
when
when
else
end

x
1, 2, 3 then "one, two, or three"
4, 5, 6 then "for, five, or six"
"other"

O case usa o operador === para fazer as comparaes. Em alguns casos, esse
operador exatamente o mesmo que ==. Mas em outros casos, como classes e
mdulos, o comportamento um pouco diferente. O operador === implementado1
pelas classes e mdulos ir verificar se um objeto uma instncia desta classe
ou mdulo ou de um de seus descendentes.
Vamos ver na prtica como funcionam os operadores String.=== e String#===.
hello = "hello"
one = 1
String === hello

#=> true
hello === String
#=> false
String === one
#=> false
Perceba que String === "hello" retorna true, mas o contrrio no verdade.
Isso acontece porque a implementao de String.=== (que na verdade
implementada por Module#===) diferente de String#===, que compara se o objeto
uma string e se ela possui o mesmo contedo.
Voltando ao case, se a expresso de comparao for uma classe, ento ele ir
verificar se a classe daquela instncia a prpria classe ou um de seus
descendentes.
value = "Hello"
case
when
"A
else
"Y
end

value
String
String was provided"
U MAD BRO?"

J o operador === implementado pelas expresses regulares ir verificar se um


determinado padro foi satisfeito pela string.
text = "Hello Ruby!"
case text
when /\bruby\b/
"You passed a lowercased Ruby"
when /\bRuby\b/
"You passed a capitalized Ruby"
when /\bRUBY\b/
"You passed an uppercased Ruby"
else
"WAT? NO RUBY?"
end
O operador === implementado por intervalos (Range) tambm diferente. Ele
verifica se um determinado tem est presente naquele intervalo.
number = 100
case number
when 0..10
"Between 0 and 10"
when 11..20
"Between 11 and 20"
else
"You're outside my limits"
end
Essa conveno de se utilizar o operador === faz com que o case do Ruby seja
muito mais poderoso que seu equivalente de outras linguagens.
1 Sim! O operador === apenas um mtodo e voc pode defin-lo em seus prprios
objetos.

Estruturas de repetio
O Ruby possui trs expresses que definem loops: for..in, while e until. Mas
alm deles, possvel usar iteradores em objetos enumerveis como arrays e
hashes, alm de outros objetos.
for..in
O loop for..in permite iterar em objetos que so enumerveis, como o caso de
arrays e hashes. A cada iterao, um elemento ser atribudo para a varivel
especificada. Sua sintaxe bastante simples:
for item in collection
# do something
end
Note que cada valor atribudo varivel pode ser acessado fora da expresso
for..in.
numbers = [1,2,3]
for number in numbers
puts "inside loop: #{number}"
end
puts "outside loop: #{number}"
Ao executar este cdigo, voc ver as seguintes mensagens.
inside loop: 1
inside loop: 2
inside loop: 3
outside loop: 3
No caso de hashes, voc pode definir duas variveis que iro receber a chave e
o valor, respectivamente.
numbers = {one: 1, two: 2, three: 3}
for key, value in numbers
puts "#{key} => #{value}"
end
Caso voc fornea apenas uma varivel, esta varivel ir armazenar um array com
dois elementos: a chave e o valor.
numbers = {one: 1, two: 2, three: 3}
for array in numbers
puts "#{array.first} => #{array.last}"
end
#
#
#
#

Output:
one => 1
two => 2
three => 3

Embora esse tipo de loop funcione muito bem, no assim que os desenvolvedores
Ruby mais experientes costumam fazer. Mais frente voc ver como utilizar os
iteradores em objetos enumerveis.

while e until
O while e until so as formas mais bsicas de looping do Ruby. Eles iro
executar algum trecho de cdigo enquanto uma condio for verdadeira ou at que
uma condio se torne verdadeira. Note que primeiro a condio testada e,
ento, o cdigo executado.
x = 3
while x.nonzero?
puts x
x -= 1
end
O mesmo exemplo poderia ser escrito com o until.
x = 3
until x.zero?
puts x
x -= 1
end
Tambm possvel usar o while e until como modificadores. Eles iro executar
alguma expresso at que a condio seja satisfeita.
items = []
items.push(items.size + 1) while items.size < 3
p items
#=> [1, 2, 3]
No exemplo acima estamos adicionando um nmero ao array enquanto seu tamanho
for menor que trs. O nmero que adicionado ser a quantidade de elementos
mais um.
O mesmo exemplo poderia ser escrito com o until.
items = []
items.push(items.size + 1) until items.size >= 3
p items
#=> [1, 2, 3]
Tambm possvel definir blocos begin..end para utilizar estes modificadores
com mais de uma expresso.
items = []
begin
items.push(items.size + 1)
puts "index #{items.size - 1} => #{items.last}"
end while items.size < 3
#
#
#
#

Output:
index 0 => 1
index 1 => 2
index 2 => 3

Mas ao contrrio das expresses de uma linha, o bloco executado antes de a

condio ser testada. Sendo assim, o bloco begin..end seguir sempre exibir a
mensagem OH NOES! THIS WILL BE DISPLAYED ANYWAY!.
begin
puts "OH NOES!"
puts "THIS WILL BE DISPLAYED ANYWAY!"
end while false
Embora seja uma
desencorajado e
possvel ter um
basta delimitar

construo aceita pela linguagem, o uso de begin..end


pode, inclusive, ser removido em verses futuras do Ruby.
comportamento semelhante sem que voc caia nesta armadilha:
diversas expresses com parnteses.

(
puts "OH NOES!"
puts "AIN'T GONNA BE DISPLAYED! :("
) while false
loop
Para loops que no devem interrompidos, uma alternativa usar algo como while
true. No entanto, o Ruby possui o loop, que ir executar indefinidamente um
bloco.
loop do
puts Time.now
sleep 1
end
#
#
#
#
#

Output:
2011-12-24 15:42:06 -0200
2011-12-24 15:42:07 -0200
2011-12-24 15:42:08 -0200
... continua at que voc interrompa a execuo do script

Controlando o loop
Muitas vezes necessrio controlar o fluxo de execuo de um loop. s vezes
preciso interromper a execuo, outras preciso passar para o prximo tem da
iterao em alguma condio especfica. O Ruby possui algumas maneiras de fazer
isso.
Interrompendo a execuo do loop
Para encerrar um loop a qualquer momento, utilize a palavra-chave break. Isso
far com que a execuo seja imediatamente interrompida.
x = 0
while x < 10
x += 1
puts x
break if x == 3
end
# Output:
# 1

# 2
# 3
Pulando para a prxima iterao
Para pular para a prxima iterao, utilize a palavra-chave next. Isso far com
que a execuo seja imediatamente interrompida.
O exemplo seguir ir exibir apenas o valor 4.
x = 0
while x < 5
x += 1
next unless x == 4
puts x
end
# Output:
# 4
Reiniciando a iterao
Para reiniciar a iterao, utilize a palavra-chave redo. Isso far com que a
execuo seja reiniciada imediatamente.
O exemplo seguir ir executar 3 vezes o output do elemento 3.
numbers = [1,2,3,4]
tries = 1
for number in numbers
puts "number: #{number}, tries: #{tries}"
if tries < 3 &amp;&amp; number == numbers[-2]
tries += 1
redo
end
end
#
#
#
#
#
#
#
#

Output:
number:
number:
number:
number:
number:
number:
number:

1,
2,
3,
3,
3,
3,
4,

tries:
tries:
tries:
tries:
tries:
tries:
tries:

0
0
0
1
2
3
3

Usando iteradores
Embora loops como for..in, while/until e loop sejam teis para algumas
situaes, mais provvel que voc escreva loops utilizando mtodos chamados
iteradores. Os iteradores so provavelmente uma das funcionalidades mais
importantes do Ruby.
Um dos exemplos mais comuns de iteradores do Ruby pode ser visto seguir.
5.times { puts "Ruby!" }

O mtodo Integer#times ir executar o bloco que foi fornecido 5 vezes. esse


tipo de construo do Ruby que faz com que a linguagem seja elegante.
Existem outros iteradores numricos, que nada mais so que mtodos iteradores
implementados pela classe Integer, assim como o mtodo Integer#times.
O mtodo Integer#upto ir executar o bloco especificado o nmeros de vezes que
for definido pelo inteiro, at atingir o nmero que foi passado como argumento.
O bloco especificado ir receber o nmero da iterao como argumento.
partir do Ruby 1.9 mtodos iteradores no exigem que voc passe um bloco para
execuo; neste caso, ele ir retornar um objeto do tipo Enumerator.
1.upto(3) do |number|
puts number
end
#
#
#
#

Output:
1
2
3

O mtodo Integer#downto funciona como o mtodo Integer#upto, mas faz a contagem


de modo descrescente.
3.downto(1) do |number|
puts number
end
#
#
#
#

Output:
3
2
1

Existe ainda um outro mtodo chamado Integer#step. Este mtodo permite fazer
iteraes usando nmeros inteiros e de ponto-flutuante.
O exemplo seguir ir iterar de 0 a 1, com passos de 0.25.
0.step(1, 0.25) do |number|
puts number
end
#
#
#
#
#
#

Output:
0.0
0.25
0.5
0.75
1.0

Objetos enumerveis
Objetos instanciados partir das classes Array, Hash e Range so enumerveis.
O objeto considerado enumervel quando implementa o mtodo each, que deve
receber um bloco e fazer o yield daquele bloco.
A classe Array, por exemplo, implementa o iterador Array#each, o que permite
passar por cada um dos tens de um array, assim como o for..in.
[1,2,3].each do |number|
puts number
end
A maioria dos objetos enumerveis que implementa o iterador each inclui tambm

o mdulo Enumerable. Este mdulo adiciona muitos mtodos que agem em cima do
mtodo each e que permitem iterar, buscar e ordenar os tens da coleo.
O mdulo Enumerable, por exemplo, inclui os mtodos Enumerable#map,
Enumerable#select, Enumerable#reject, Enumerable#find e Enumerable#inject, s
para citar alguns.
O mtodo Enumerable#map permite criar um novo array contendo os elementos
retornados pelo bloco.
[1,2,3].map {|number| number * 2}
#=> [2, 4, 6]
O mtodo Enumerable#select permite criar um novo array contendo os elementos
cujo valor retornado pelo bloco sejam diferentes de false ou nil.
(1..10).select {|number| number.even?}
#=> [2, 4, 6, 8, 10]
O mtodo Enumerable#reject faz exatamente o contrrio do mtodo
Enumerable#select e ir retornar um array contendo os elementos cujo valor do
bloco sejam false ou nil.
(1..10).reject {|number| number.odd?}
#=> [2, 4, 6, 8, 10]
O mtodo Enumerable#find ir retornar o primeiro elemento cujo valor de retorno
do bloco seja diferente de false ou nil.
(1..10).find {|number| number == 3}
#=> 3
J o mtodo Enumerable#inject mais complexo que todos os iteradores que voc
viu at aqui. Ele permite passar um objeto que ser o acumulador e que ir
armazenar o resultado de iteraes passadas. O bloco que foi fornecido pode ou
no incrementar este acumulador, dependendo de suas condies. O acumulador
deve ser o valor de retorno do bloco.
Veja, por exemplo, como retornar um nico nmero que ser a soma do dobro dos
mltiplos de 2.
sum = (1..10).inject(0) do |acc, number|
acc += number * 2 if number.even?
acc
end
Alternativamente, voc poderia implementar este mesmo acumulador em mais de uma
etapa. Um cdigo que faz a mesma coisa, mas de forma muito menos elegante, pode
ser visto seguir.
sum = 0
(1..10).each do |number|
sum += number * 2 if number.even?
end
Blocos
Os blocos so essenciais no uso de iteradores. Embora tenhamos usado blocos
quando falamos sobre objetos_enumerveis, no dedicamos tempo para explicar o
que eles so.
Blocos nunca podem estar sozinhos; eles sempre precisam estar associados a uma

execuo de mtodo. Todo mtodo que executado pode receber um bloco, mas
apenas os mtodos que esperam este bloco e que faam o yield que iro de fato
execut-los; caso contrrio, o bloco ser ignorado silenciosamente. Por baixo
dos panos, blocos so apenas procs.
Assim como as procs, blocos seguem a conveno de se usar chaves para blocos
com uma nica expresso e do..end para blocos com mais de uma expresso.
# Apenas uma expresso
[1, 2, 3].map {|number| number * 2}
# Diversas expresses
[1, 2, 3, 4, 5].inject(0) do |acc, number|
acc += number if number.even?
acc
end
Lembre-se! Como blocos sempre esto associados execuo de mtodos, voc no
deve usar este termo para se referir a procs ou lambdas.
Escopo de variveis
Blocos introduzem um novo escopo de variveis. Toda vez que voc define
parmetros que sero recebidos pelo bloco, estas variveis sero acessveis
apenas no contexto do bloco.
O exemplo seguir mostra como a varivel i definida apenas no escopo local
do bloco.
1.upto(5) {|i| }
p defined?(i)
#=> nil
No entanto, blocos tambm podem referenciar variveis do contexto externo ao
bloco e, nesse caso, podem inclusive modificar estas variveis.
total = 0
1.upto(10) {|i| total += i}
puts total
#=> 55
partir do Ruby 1.9 os parmetros esperados pelo bloco no mais modificam
variveis de mesmo nome que foram definidas no contexto externo ao bloco. O
exemplo seguir mostra exatamente isso. Este mesmo exemplo quando executado no
Ruby 1.8 ir exibir o valor da ltima iterao, ou seja, 10.
i = 0
1.upto(10) {|i| }
puts i
#=> 0
Interagindo com blocos
Como foi dito antes, mtodos podem receber blocos mesmo quando eles no esperam
um. Para interagir com um bloco que foi passado, voc deve usar a palavra-chave
yield. Ela ir executar o bloco que foi passado ao mtodo.
def say
puts yield
end

say { "Hello" }
#=> Hello
O bloco ser executado toda vez que voc usar yield. Ento, se em um mesmo
mtodo voc usar trs vezes a palavra-chave yield, o bloco ser executado trs
vezes.
def hello
yield "Hello!"
yield "Hi!"
yield "Wassup!"
end
hello {|message| puts message}
#
#
#
#

Output:
Hello!
Hi!
Wassup!

Se nenhum bloco for passado para este mtodo say, uma exceo LocalJumpError
ser lanada. Para evitar que isto acontea, voc pode verificar se algum bloco
foi passado com o mtodo Kernel#block_given? e tomar as aes necessrias.
No exemplo seguir lanamos uma exceo caso um bloco no seja passado.
def say
raise "Y U MAD BRO? JUST GIMME A BLOCK!" unless block_given?
puts yield
end
say { "Hello" }
begin
say
rescue Exception => error
puts error.message
end
# Output:
#=> Hello
#=> Y U MAD BRO? JUST GIMME A BLOCK!
Para passar parmetros para o bloco que foi fornecido, basta fazer o yield
passando os argumentos.
def first_and_last(list)
yield list.first, list.last
end
first_and_last([1,2,3]) do |first, last|
puts "First item: #{first}"
puts "Last item: #{last}"
end
O yield quase sempre suficiente. Mas s vezes, voc quer ter um pouco mais de
controle, seja passando o bloco como parmetro para outro mtodo ou agindo como
proxy de um outro mtodo que tambm espera um bloco. O Ruby permite que voc
capture blocos passados para mtodos usando a construo &amp;variavel. A nica
exigncia que essa varivel deve ser sempre a ltima varivel da lista.

O exemplo anterior poderia ser reescrito usando essa construo.


def first_and_last(list, &amp;block)
block.call(list.first, list.last)
end
first_and_last([1,2,3]) do |first, last|
puts "First item: #{first}"
puts "Last item: #{last}"
end
Note que no estamos mais usando o yield; agora, executamos o mtodo Proc#call
passando os argumentos. Alternativamente, poderamos usar algum outro mtodo
que executa procs, como Proc#[].
Classes
O Ruby, como voc pode perceber at agora,
Tudo o que manipulamos no Ruby so objetos e
indiretamente de uma classe. Classes definem
responder. Elas tambm podem estender ou ser

uma linguagem orientada a objetos.


cada objeto gerado direta ou
os mtodos que objetos podem
subclasses de outras classes.

Criando classes
Para definir uma classe use a palavra-chave class. Classes so constantes e,
por este motivo, devem comear com uma letra maiscula.
class Page
end
Classes so apenas objetos instanciados partir da classe Class. Por isso,
voc pode instanciar classes dinamicamente1. Isso faz com que a linguagem se
torne extremamente poderosa e flexvel.
class Page
end
AnotherPage = Class.new
Page.class
#=> Class
AnotherPage.class
#=> class
Embora ainda no tenhamos adicionado nenhum mtodo classe Page, ns j
podemos instnci-la. Para isso voc ir usar o mtodo Page.new.
page = Page.new
Mesmo no tendo definido atributos e mtodos, ns podemos executar alguns
mtodos fornecidos pelas superclasses da classe Page. Voc pode, por exemplo,
perguntar que tipo de objeto ele .
page.class
#=> Page
page.is_a?(Page)
#=> true

As superclasses da classe Page implementam muitos outros mtodos. Para saber


quais so as superclasses de uma classe, use o mtodo Class.ancestors. Note que
a prpria classe ser adicionada lista.
Page.ancestors
#=> [Page, Object, Kernel, BasicObject]
Toda vez que o mtodo Class.new for executado, ele ir iniciar a instncia com
o mtodo construtor. No Ruby, o mtodo construtor Class#initialize. Este
mtodo definido automaticamente como privado e no pode ser executado
diretamente de fora do objeto.
Vamos fazer o mtodo Page#initialize receber dois argumentos que iro definir o
ttulo e contedo da pgina.
class Page
def initialize(title, content)
@title = title
@content = content
end
end
Todos os valores que devem ser persistidos em objetos devem ser definidos como
variveis de instncia, identificados por uma arroba na frente da varivel.
Elas pertencem ao objeto self que referencia o prprio objeto instanciado. Cada
instncia da classe Page ter sua prpria cpia das variveis @title e
@content.
O mtodo Page#initialize define duas variveis de instncia, que receber os
argumentos passados no momento da instanciao. No entanto, ainda no temos
nenhuma maneira de acessar tais valores diretamente.
Definindo mtodos
Para acessar as variveis de instncia que definimos no mtodo Page#initialize,
ns iremos definir dois getters, que so mtodos que apenas retornam valores.
Isso precisa ser feito pois variveis de instncia no podem ser acessadas
diretamente. Variveis de instncia so encapsuladas de tal forma que apenas os
mtodos de um prprio objeto que podem acess-las e modific-las diretamente.
page = Page.new("Ruby", "OMG! Ruby is awesome!")
page.title
#=> NoMethodError: undefined method title for #<Page:0x007f88e3061648>
Para acessar estas variveis de instncia que foram definidas no nosso mtodo
construtor, voc precisa definir mtodos que iro retorn-las. Embora o nome do
mtodo no precise necessariamente refletir o nome da varivel, sempre uma
boa ideia dar nomes que possam identificar rapidamente o contexto de uso.
class Page
def initialize(title, content)
@title = title
@content = content
end
def title
@title
end
def content
@content
end

end
Agora ns j podemos acessar as variveis armazenadas na instncia da classe
Page.
page = Page.new("Ruby", "OMG! I'm learning Ruby!")
page.title
#=> Ruby
page.content
#=> OMG! I'm learning Ruby!
Ainda no existe nenhuma maneira de definir essas variveis de instncia sem
ser pelo mtodo construtor. Para fazer isso, preciso definir mtodos setters.
Em outras linguagens, normalmente isso feito com um mtodo setTitle(title) ou
set_title(title), ou algo parecido. No Ruby, voc pode definir o seu prprio
mtodo title=.
class Page
def initialize(title, content)
@title = title
@content = content
end
def title
@title
end
def title=(title)
@title = title
end
def content
@content
end
def content=(content)
@content = content
end
end
O Ruby permite usar o operador = para executar mtodos como este. Agora, j
possvel atribuir valores para as variveis @title e @content com os mtodos
setters.
page = Page.new("Ruby", "OMG! I'm learning Ruby!")
page.title
#=> Ruby
page.title = "Learning Ruby"
page.title
#=> Learning Ruby
Esta definio de getters e setters em classes to comum que o prprio Ruby
fornece uma maneira de automatizar esta definio. Basta usar os mtodos
Module#attr_reader e Module#attr_writer2.
class Page

attr_reader :title
attr_writer :title
attr_reader :content
attr_writer :content
def initialize(title, content)
@title = title
@content = content
end
end
O mtodo Module#attr_reader ir definir o mtodo de instncia de leitura
(getter), enquanto o mtodo Module#attr_writer ir definir o mtodo de
instncia de escrita (setter). Para os casos onde voc sempre define tanto o
getter quanto o setter, possvel usar o mtodo Module#attr_accessor, que far
isso de uma vez s!
Com esta alterao, nossa classe pode ficar muito mais simples.
class Page
attr_accessor :title, :content
def initialize(title, content)
@title = title
@content = content
end
end
Lembre-se que os mtodos Module#attr_accessor e companhia permitem criar apenas
getters e setters que mapeiam para uma varivel de instncia de mesmo nome.
Voc ter que implementar os seus prprios mtodos se eles forem mais complexos
(se eles precisarem computar valores, por exemplo) ou definirem variveis de
instncia de nomes diferentes.
Alternativamente, voc pode fazer com que o mtodo construtor use os mtodos
Page#title= e Page#content=, em vez de atribuir as variveis de instncia. Um
erro muito comum de iniciantes no definir o objeto que ir receber o valor,
chamado de receiver.
O exemplo seguir define variveis locais, em vez de executar os mtodos
setters.
class Page
attr_accessor :title, :content
def initialize(_title, _content)
title = _title
content = _content
end
end
Para atribuir os atributos Page#title e Page#content corretamente, preciso
explicitamente executar os mtodos atravs do receiver self.
class Page
attr_accessor :title, :content
def initialize(title, content)
self.title = title
self.content = content
end
end

A atribuio direta das variveis de instncia mais rpida que executar os


mtodos atravs do receiver. A menos que voc manipule as variveis no mtodo
setter antes de atribu-las, prefira sempre definir as variveis de instncia.
Definindo mtodos de classe
Classes tambm podem ter mtodos. Algumas linguagens chamam estes mtodos de
estticos. No Ruby, eles so apenas mtodos adicionados a um objeto que uma
instncia da classe Class.
Vamos implementar o mtodo Page.load, que ir ler um arquivo em formato YAML
(Yet Another Markup Language) e retornar uma nova instncia da classe Page com
os valores j atribudos.
require "yaml"
class Page
attr_accessor :title, :content
def Page.load(filepath)
attrs = YAML.load_file(filepath)
Page.new(attrs["title"], attrs["content"])
end
def initialize(title, content)
@title = title
@content = content
end
end
No Ruby, voc pode ler e gerar a representao de objetos com a classe YAML.
Para isso, basta carregar a standard library com o mtodo Kernel#require. O
mtodo YAML.load_file l um arquivo e converte seu contudo em objetos Ruby.
Neste exemplo, nosso arquivo deve retornar um hash.
Classes possuem um objeto self, assim como todos os objetos. Dentro da
instruo class..end, o self faz referncia prpria classe. Por isso, uma
abordagem mais comum usada por desenvolvedores mais experientes definir
mtodos de classe usando def self.load(file)..end, em vez de usar o nome da
prpria constante.
require "yaml"
class Page
attr_accessor :title, :content
def self.load(filepath)
attrs = YAML.load_file(filepath)
Page.new(attrs["title"], attrs["content"])
end
def initialize(title, content)
@title = title
@content = content
end
end
Como o nosso mtodo de classe est no contexto da prpria classe (lembre-se, o
self faz referncia a prpria classe), ns podemos fazer mais uma alterao. Em
vez de instanciar a classe Page.new, basta executar o mtodo new diretamente.

require "yaml"
class Page
attr_accessor :title, :content
def self.load(filepath)
attrs = YAML.load_file(filepath)
new(attrs["title"], attrs["content"])
end
def initialize(title, content)
@title = title
@content = content
end
end
A classe Page ainda no permite salvar sua representao em YAML. Vamos
adicionar um mtodo Page#save_to(file) que faz exatamente isso.
require "yaml"
class Page
attr_accessor :title, :content
def self.load(filepath)
attrs = YAML.load_file(filepath)
new(attrs["title"], attrs["content"])
end
def initialize(title, content)
@title = title
@content = content
end
def save_to(filepath)
File.open(filepath, "w") {|file| file.write to_yaml }
end
end
A biblioteca YAML injeta um mtodo Object#to_yaml, que retorna uma string
representando aquele objeto. No nosso caso, ele ir retornar algo como a string
abaixo.
--- !ruby/object:Page
title: Ruby
content: OMG! I'm learning Ruby!
Como a representao em YAML inclui a informao sobre qual classe este objeto
foi instanciado, no precisamos mais fazer isso manualmente no mtodo
Page#load. Agora, podemos simplesmente retornar o objeto instanciado com o
mtodo YAML.load_file.
require "yaml"
class Page
attr_accessor :title, :content
def self.load(filepath)
YAML.load_file(filepath)
end

def initialize(title, content)


@title = title
@content = content
end
def save_to(filepath)
File.open(filepath, "w") {|file| file.write to_yaml }
end
end
Visibilidade de mtodos e controle de acesso
O Ruby possui trs nveis diferentes de visibilidade e controle de acesso dos
mtodos de um objeto.
* Mtodos pblicos podem ser executados em qualquer situao. Mtodos so
pblicos por padro, com uma nica exceo: o mtodo Class#initialize
sempre privado.
* Mtodos protegidos podem ser executados por objetos de uma classe e suas
subclasses.
* Mtodos privados no podem ser executados atravs de um receiver explcito. O
receiver sempre ser o objeto atual self.
Para definir a visibilidade de mtodos voc utilizar os mtodos Module.public,
Module.private e Module.protected.
class SomeClass
def method1
end

# mtodos so pblicos por padro

private
privados
def method2
end

# todos os mtodos definidos partir daqui sero

protected
protegidos
def method3
end

# todos os mtodos definidos partir daqui sero

public
pblicos
def method4
end
end

# todos os mtodos definidos partir daqui sero

Alternativamente voc poderia ter definido a visibilidade dos mtodos passando


uma lista de nomes de mtodos.
class SomeClass
def method1
end
def method2
end
def method3
end

def method4
end
public :method1, :method4
private :method2
protected :method3
end
O controle de acesso determinado dinamicamente. Somente quando o mtodo for
executado que o controle de acesso ser determinado. Se a visibilidade deste
mtodo for violada, uma exceo NoMethodError ser lanada.
class SomeClass
private
def some_private_method
end
end
object = SomeClass.new
object.some_private_method
#=> NoMethodError: private method some_private_method called for
#<SomeClass:0x007fc8f3853860>
Voc pode contornar o controle de acesso de mtodos utilizando o mtodo
Object.__send__.
object.__send__ :some_private_method

# nenhuma exceo lanada

Para garantir que mensagens sejam enviadas apenas para mtodos pblicos, use o
mtodo Object.public_send, introduzido no Ruby 1.9.
object = SomeClass.new
object.public_send :some_private_method
#=> NoMethodError: private method `some_private_method' called for
#<SomeClass:0x007f9441897bf0>
Definindo constantes
Muitas classes podem usar constantes para armazenar informaes que poderiam
ficar espalhadas pelo cdigo, como nmeros mgicos. Vamos alterar a classe
Page de modo que ela possa receber tambm um permalink, uma representao de
como essa pgina poderia ser referenciada.
class Page
attr_accessor :title, :content
def self.load(filepath)
YAML.load_file(filepath)
end
def initialize(title, content, permalink)
@title = title
@content = content
@permalink = permalink
end
def save_to(filepath)
File.open(filepath, "w") {|file| file.write to_yaml }

end
end
Vamos renomear o mtodo Page#save_to para Page#save. Este mtodo ir salvar os
arquivos sempre em um mesmo diretrio, usando o atributo permalink como nome do
arquivo.
class Page
attr_accessor :title, :content
def self.load(filepath)
YAML.load_file(filepath)
end
def initialize(title, content, permalink)
@title = title
@content = content
@permalink = permalink
end
def save
File.open("/tmp/#{permalink}.yml", "w") {|file| file.write to_yaml }
end
end
Em vez de deixar o diretrio onde os arquivos sero salvos no mtodo Page#save,
vamos extrair esta informao para uma constante. Essa alterao permite,
dentre outras coisas, expor esta informao na documentao RDoc.
class Page
attr_accessor :title, :content
ROOT = "/tmp"
def self.load(filepath)
YAML.load_file(filepath)
end
def initialize(title, content, permalink)
@title = title
@content = content
@permalink = permalink
end
def filepath
File.join(ROOT, "#{permalink}.yml")
end
def save
File.open(filepath, "w") {|file| file.write to_yaml }
end
end
Entendendo classes Singleton
Todo objeto do Ruby est associado a duas classes: a classe que a instanciou e
uma classe annima, escondida, especfica do objeto. Esta classe annima
chamada de Singleton Class, mas antes de ter um nome oficial tambm era chamada
de anonymous class, metaclass, eigenclass ou ghost class.

O nome Singleton usado pelo Ruby nada tem a ver com o Singleton Pattern, que
tambm est disponvel com a biblioteca Singleton.
A sintaxe mais comum para acessar a classe Singleton class << object..end,
onde object o objeto cuja classe Singleton voc quer. muito comum vermos
algo como o exemplo seguir para definir mtodos em uma classe.
class Person
class << self
def count
@count ||= 0
end
end
end
Aqui, estamos definindo um mtodo na classe Singleton do objeto Person (lembrese: tudo no Ruby objeto, inclusive classes). Como consequncia, isso ir
definir o mtodo Person.count. O efeito exatamente o mesmo que o cdigo
abaixo, porm este mais objetivo e fcil de entender.
class Person
def self.count
@count ||= 0
end
end
No Ruby 1.9, foi adicionado o mtodo Object#singleton_class, que apenas um
atalho para a sintaxe class << self; self; end. Em verses mais antigas, voc
pode injetar este mtodo com o cdigo abaixo.
class Object
def singleton_class
class << self; self; end
end unless respond_to?(:singleton_class)
end
Toda vez que injeta mtodos em um objeto, eles so adicionados como mtodos
singleton. O que realmente importante saber que estes mtodos pertecem
unicamente ao objeto em que foram definidos, no afetando nenhum outro objeto
da hieraquia.
string = "Hi there!"
another_string = "Hi there!"
def string.to_yo
self.gsub(/\b(Hi|Hello)( there)\b?!?/, "Yo! Wassup?")
end
string.to_yo
#=> "Yo! Wassup?"
another_string.respond_to?(:to_yo)
#=> false
E para provar que o mtodo to_yo singleton, podemos utilizar o mtodo
Object#singleton_methods.
string.singleton_methods
#=> ["to_yo"]
another_string.singleton_methods

#=> []
Voc tambm pode adicionar mtodos singleton de outras maneiras. Uma delas
estendendo um objeto com um mdulo.
module Extension
def sum
self.reduce(:+)
end
end
numbers = [1,2,3]
numbers.extend Extension
numbers.singleton_methods
#=> ["sum"]
Outra maneira usando a prpria classe Singleton.
numbers = [1,2,3]
class << numbers
def sum
self.reduce(:+)
end
end
numbers.singleton_methods
#=> ["sum"]
Ou ainda, executando cdigo no contexto do objeto.
numbers = [1,2,3]
numbers.instance_eval do
def sum
self.reduce(:+)
end
end
numbers.singleton_methods
#=> ["sum"]
Quando voc cria uma classe Singleton em um objeto, no poder mais utilizar o
mtodo Marshal.dump, j que a biblioteca Marshal3 no suporta objetos com
classes Singleton (ela ir lanar a exceo TypeError: singleton can't be
dumped). A nica maneira de fazer isso e ainda poder utilizar o Marshal
utilizando o mtodo Object#extend.
Agora, sabendo que voc pode adicionar mtodos em um objeto com uma sintaxe
como def object.some_method; end, perceba que exatamente isso que fazemos
quando definimos um mtodo em uma classe; a nica diferena que passamos o
prprio self.
class Person
def self.say_hello
"Hello there!"
end
end
Person.singleton_methods
#=> ["say_hello"]

Com base nesse exemplo, possvel afirmar que mtodos de classe no existem no
Ruby! Pelo menos no no sentido de mtodos estticos! O que acontece que
estes mtodos pertencem a um objeto, que por acaso uma classe.
1 Classes criadas dinamicamente podem ser atribudas a qualquer tipo de
varivel, e no apenas a constantes.
2 A classe Class possui a classe Module como superclasse. Para saber mais sobre
mdulos, leia Mdulos.
3 A biblioteca Marshal permite converter objetos Ruby em uma sequncia de bytes
que podem ser restaurados por outros scripts, que podem reconstituir os objetos
originais.
Mdulos
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Trabalhando com strings
Concatenando strings
Para concatenar strings, voc pode utilizar os mtodos String#+, String#<< e
String#concat.
puts "Ruby" + " is nice!"
#=> Ruby is nice!
puts "Ruby" << " is nice!"
#=> Ruby is nice!
puts "Ruby".concat(" is nice!")
#=> Ruby is nice!
Embora os trs mtodos atingem o objetivoconcatenar strings, existe uma
diferena muito importante. O mtodo String#+ ir criar um novo objeto em
memria, enquanto os mtodos String#<< e String#concat iro realocar a memria
previamente utilizada.
hello = "Hello"
ruby = "Ruby"
hello2 = hello + " " + ruby
puts "#{hello2}: #{hello2.object_id}"
#=> Hello Ruby: 70310699719020
puts "#{hello}: #{hello.object_id}"
#=> Hello: 70310699719100
hello << " "
hello << ruby
puts "#{hello}: #{hello.object_id}"
#=> Hello Ruby: 70310699719100
Formatando strings
Voc j viu que no Ruby possvel utilizar expresses arbitrrias que podem
ser interpoladas.

language = "Ruby"
puts "#{language} is nice!"
#=> Ruby is nice!
O Ruby tambm suporta outros tipos de formatao de strings que tambm permitem
interpolar expresses. o caso dos mtodos String#%, Kernel#printf e
Kernel#sprintf. Estes mtodos permitem ter maior controle no espaamento e
formatao de nmeros. Alm disso, eles permitem desacoplar os valores que
devem ser interpolados da string, facilitando, por exemplo, a
internacionalizao de strings.
A mesma string que foi interpolada acima pode ser formatada com os mtodos
mencionados.
language = "Ruby"
"%s is nice!" % language
#=> retorna a string "Ruby is nice!"
sprintf("%s is nice!", language) #=> retorna a string "Ruby is nice!"
printf("%s is nice!\n", language) #=> exibe a mensagem "Ruby is nice!" e
retorna nil
Para formatar mais de um valor, passe um array.
"%s is %s!" % ["Ruby", "nice"]
#=> Ruby is nice!
Embora seja fcil interpolar mltiplos valores com arrays, seu cdigo pode
acabar confuso quando a lista de parmetros muito grande. Neste caso, prefira
usar um hash. Note que esta funcionalidade foi introduzida no Ruby 1.9.
"language isadjective!" % {language: "Ruby", adjective: "nice"}
#=> Ruby is nice!
Existem diversos campos que permitem formatar nmeros.
"%d" %
"%f" %
"%.2f"
"%x" %
"%X" %
"%o" %
"%e" %
"%E" %
"%b" %

1.5
1.1245
% 1
1234
1234
1234
1234
1234
1234

#=>
#=>
#=>
#=>
#=>
#=>
#=>
#=>
#=>

1
1.124500
1.00
4d2
4D2
2322
1.234000e+03
1.234000E+03
10011010010

nmero inteiro
ponto-flutuante com todos os nmeros
ponto-flutuante com duas casas decimais
hexadecimal com letras minsculas
hexadecimal com letras maisculas
nmero inteiro ctal
nmero exponencial
nmero exponencial em maiscula
nmero binrio

Para saber mais sobre os formatos aceitos, acesse a documentao; basta


executar o comando ri String#sprintf.
Convertendo em maisculas e minsculas
Para converter uma string em letras maisculas, utilize o mtodo String#upcase.
text = "ruby is nice!"
puts text.upcase
#=> RUBY IS NICE!
Para converter uma string em letras minsculas, utilize o mtodo
String#downcase.
text = "RUBY IS NICE!"
puts text.downcase

#=> ruby is nice!


Note que os mtodos String#upcase e String#downcase iro retornar uma nova
string. Para alterar a string existente, utilize os mtodos String#upcase! e
String#downcase!.
text = "Ruby is nice!"
puts text.object_id
#=> 70347156470500
text.upcase!
puts text.object_id
#=> 70347156470500
Tamanho de uma string
Para saber o tamanho de uma string, utilize os mtodos String#size ou
String#length. Note que esses mtodos iro retornar a quantidade de caracteres.
Se voc precisa saber a quantidade de bytes necessrios para representar a
string, utilize o mtodo String#bytes1.
text = "Ruby is nice!"
puts text.size
#=> 13
puts text.length #=> 13
Substrings
O Ruby permite pegar substrings (trechos de uma determinada string) com o
mtodo String#[].
Em verses anteriores ao Ruby 1.9, o mtodo String#[] com um nmero inteiro
retorna a representao numrica daquela posio, o que nem sempre reflete a
represeno de caracteres com mais de um byte.
A maneira mais simples passar um nmero inteiro que identifica o caracter que
ser retornado. Se o ndice for negativo, a posio ser movida partir do fim
da string.
text = "Ruby is nice!"
text[8] #=> n
text[-1] #=> !
No Ruby, ndices de array e strings iniciam em zero.
Voc tambm pode passar como segundo parmetro, a quantidade de caracteres que
a substring deve ter.
text = "Ruby is nice!"
text[8,4]
#=> nice
text[-5, 4] #=> nice
s vezes, pode ser mais conveniente passar o ndice inicial e final. Neste
caso, voc pode passar um Range. Note que voc tambm pode utilizar intervalos
com valores negativos.
text = "Ruby is nice!"
text[0..3]
#=> Ruby
text[-5..-2]
#=> nice
O mtodo String#[] tambm pode receber expresses regulares. Neste caso, o

primeiro resultado ser retornado.


text = "Ruby is nice!"
text[/ruby/i] #=> Ruby
Voc pode especificar o nmero ou nome do grupo quando estiver usando uma
expresso regular.
text = "ruby RUBY rUbY Ruby"
text[/(ruby) (ruby) (ruby) (ruby)/i, 2]
#=> RUBY
text[/(ruby) (?<upcase>ruby) (ruby) (ruby)/i, :upcase] #=> RUBY
Por ltimo, se voc passar uma string qualquer e ela estiver presente, ela
retornada. Caso contrrio, nil retornado.
text = "Ruby is nice!"
text["Ruby"] #=> Ruby
text["ruby"] #=> nil
Codificao
Uma das grandes mudanas introduzidas pelo Ruby 1.9 foi a codificao das
strings, que agora so verdadeiramente sequncias de caracteres que no
precisam estar contidas na tabela de caracteres ASCII. Caracteres definidos
como UTF-8, por exemplo, que usam um nmero varivel de bytes para representar
os caracteres, no possuem mais uma relao um-para-um de bytes e caracteres.
A classe String foi reescrita no Ruby 1.9 para que pudesse ter suporte a
caracteres multibytes. Quando uma string contm caracteres multibytes, a
quantidade de bytes usados para represent-la no ser a mesma do nmero de
caracteres.
# -*- encoding: utf-8 -*text = "ruby legal!"
puts text.size
#=> 13
puts text.bytesize #=> 14
Perceba que a primeira linha define qual o tipo de codificao ser usada no
arquivo. Esse comentrio chamado de magic comment e sem ele o Ruby no
saberia decidir qual codificao utilizar. O magic comment pode ser qualquer
string que consiga ser casada pela seguinte expresso regular2. Magic comments
devem ser a primeira linha do arquivo ou vir aps a linha de shebang.
/coding[:=] ?/
Os seguintes comentrios so vlidos na hora de definir a codificao do
arquivo.
#
#
#
#
#

coding: utf-8
encoding: utf-8
-*- coding: utf-8 -*vim:fileencoding=utf-8
vim:set fileencoding=utf-8 :

A codificao de uma string baseada na codificao do cdigo-fonte, mas no


ser necessariamente a mesma.
# -*- encoding: utf-8 -*text = "hello".encode("iso-8859-1")
puts text.encoding

#=> ISO-8859-1
Nem todas as strings so compatveis entre diferentes codificaes. Toda vez
que voc tentar fazer a converso entre codificaes que no so compatveis,
uma exceo ser lanada.
# -*- encoding: utf-8 -*text = "".encode("iso-8859-1")
#=> Encoding::UndefinedConversionError: U+221A from UTF-8 to ISO-8859-1
Neste caso voc pode forar a codificao utilizando o mtodo String#encode,
passando a estratgia de converso e qual string ser usada no lugar dos
caracteres que no so reconhecidos.
# -*- encoding: utf-8 -*text = "Learn Ruby ".encode("iso-8859-1", :undef => :replace, :replace => "
[DONE]")
puts text
#=> Learn Ruby [DONE]
Voc pode forar a codificao de uma string com o mtodo
String#force_encoding. Este mtodo no faz qualquer verificao ou converso de
caracteres; apenas muda a interpretao que o Ruby faz dos caracteres, mas sem
alterar os bytes que representam a string. Para validar se os bytes daquela
string so vlidos na codificao escolhida, utilize o mtodo
String#valid_encoding?.
text = "\xF4".force_encoding("utf-8") #=> Fora um valor binrio em UTF-8
puts text.valid_encoding?
#=> false
Para acessar a representao nmerica de cada caracter de uma string, utilize o
mtodo String#codepoints. Este mtodo espera um bloco, mas voc pode utilizar o
mtodo Enumerator#to_a para converter este iterador em um array.
"hello".codepoints.to_a
#=> [104, 101, 108, 108, 111]
"ma".codepoints.to_a
#=> [109, 97, 231, 227]
" ".codepoints.to_a
#=> [9731]
Alternativamente, voc pode utilizar o mtodo String#ord para pegar a
representao nmerica de um nico caracter.
"".ord
#=> 9786
Voc tambm pode acessar os bytes de uma string com o mtodo String#bytes.
Assim como o mtodo String#codepoints, voc pode converter este iterador em um
array.
"hello".bytes.to_a
#=> [104, 101, 108, 108, 111]
"ma".bytes.to_a
#=> [109, 97, 195, 167, 195, 163]

"".bytes.to_a
#=> [195, 161, 195, 169, 195, 173, 195, 179, 195, 186]
Note como a string possui apenas 5 caracteres, mas precisa de 10 bytes
para ser representada.
Para acessar a lista de codificaes disponveis no Ruby, utilize o mtodo
Encoding.list. Algumas codificaes possuem um alias, cuja listagem completa
pode ser retornada pelo mtodo Encoding.aliases. O cdigo seguir far o
output das codificaes disponveis com seus respectivos aliases.
list = Encoding.list.collect do |encoding|
info = encoding.name
alias_name = Encoding.aliases.key(encoding.name)
info << " (#{alias_name})" if alias_name
info
end
puts list.sort_by(&amp;:downcase)
O resultado do cdigo acima, quando executado no Ruby 1.9.3-p0, pode ser visto
seguir (os nomes foram listados em colunas para no ocupar tanto espao).
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

ASCII-8BIT (BINARY)
Big5
Big5-HKSCS (Big5-HKSCS:2008)
Big5-UAO
CP50220
CP50221
CP51932
CP850 (IBM850)
CP852
CP855
CP949
CP950
CP951
Emacs-Mule
EUC-JP (eucJP)
EUC-KR (eucKR)
EUC-TW (eucTW)
eucJP-ms (euc-jp-ms)
GB12345
GB18030
GB1988
GB2312 (EUC-CN)
GBK (CP936)
IBM437 (CP437)
IBM737 (CP737)
IBM775 (CP775)
IBM852
IBM855
IBM857 (CP857)
IBM860 (CP860)
IBM861 (CP861)
IBM862 (CP862)
IBM863 (CP863)
IBM864 (CP864)
IBM865 (CP865)
IBM866 (CP866)
IBM869 (CP869)
ISO-2022-JP (ISO2022-JP)

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

ISO-2022-JP-2 (ISO2022-JP2)
ISO-2022-JP-KDDI
ISO-8859-1 (ISO8859-1)
ISO-8859-10 (ISO8859-10)
ISO-8859-11 (ISO8859-11)
ISO-8859-13 (ISO8859-13)
ISO-8859-14 (ISO8859-14)
ISO-8859-15 (ISO8859-15)
ISO-8859-16 (ISO8859-16)
ISO-8859-2 (ISO8859-2)
ISO-8859-3 (ISO8859-3)
ISO-8859-4 (ISO8859-4)
ISO-8859-5 (ISO8859-5)
ISO-8859-6 (ISO8859-6)
ISO-8859-7 (ISO8859-7)
ISO-8859-8 (ISO8859-8)
ISO-8859-9 (ISO8859-9)
KOI8-R (CP878)
KOI8-U
macCentEuro
macCroatian
macCyrillic
macGreek
macIceland
MacJapanese (MacJapan)
macRoman
macRomania
macThai
macTurkish
macUkraine
Shift_JIS
SJIS-DoCoMo
SJIS-KDDI
SJIS-SoftBank
stateless-ISO-2022-JP
stateless-ISO-2022-JP-KDDI
TIS-620
US-ASCII (ASCII)
UTF-16
UTF-16BE (UCS-2BE)
UTF-16LE
UTF-32
UTF-32BE (UCS-4BE)
UTF-32LE (UCS-4LE)
UTF-7 (CP65000)
UTF-8 (CP65001)
UTF8-DoCoMo
UTF8-KDDI
UTF8-MAC (UTF-8-MAC)
UTF8-SoftBank
Windows-1250 (CP1250)
Windows-1251 (CP1251)
Windows-1252 (CP1252)
Windows-1253 (CP1253)
Windows-1254 (CP1254)
Windows-1255 (CP1255)
Windows-1256 (CP1256)
Windows-1257 (CP1257)
Windows-1258 (CP1258)
Windows-31J (CP932)

* Windows-874 (CP874)
1 Veja mais detalhes sobre codificao de caracteres em Codificao.
2 Na verdade, magic comments seguem a PEP-263 definida pelo Python.
Trabalhando com nmeros
Operadores matemticos
Para efetuar somas, utilize o mtodo Numeric#+.
1 + 1 #=> 2
1 + 2.1 #=> 3.1
-1 + -1 #=> -2
Para efetuar subtraes, utilize o mtodo Numeric#-.
2 - 1 #=> 1
2 - 1.3 #=> 0.7
-1 - -2 #=> 1
Para efetuar multiplicaes, utilize o mtodo Numeric#*.
2 * 2
#=> 4
2 * 1.3 #=> 2.6
-2 * 1.3 #=> -2.6
Para efetuar divises, utilize o mtodo Numeric#/. Note que o resultado depende
da classe do nmero que ser usado como divisor. No caso de nmeros inteiros, o
resultado ser um nmero inteiro.
3 / 2
#=> 1
3 / 2.0 #=> 1.5
2 / 1.75 #=> 1.1428571428571428
Para efetuar potenciaes, utilize o mtodo Numeric#**.
2 ** 2
2 ** 3
3 ** 2

#=> 4
#=> 8
#=> 9

Nmeros absolutos
Para pegar o valor absoluto de um nmero, use o mtodo Numeric#abs.
1.abs
-1.abs
+1.2.abs
-1.2.abs
-1.2.magnitude

#=>
#=>
#=>
#->
#=>

1 - Mtodo Numeric#abs o mais utilizado


1
1.2
1.2
1.2

Verificando nmeros pares e mpares


Para descobrir se um determinado nmero par ou mpar, voc pode utilizar o
operador %, que retorna o mdulo de um nmero.
4 % 2 == 0 # true - significa que um nmero par

5 % 2 == 1 # true - significa que um nmero mpar


Felizmente a classe Integer implementa dois mtodos que permitem fazer a mesma
verificao, mas de uma forma muito mais elegante.
4.even? #=> true - um nmero par
5.odd? #=> true - um nmero mpar
Verificando zeros e no-zeros
O Ruby possui dois mtodos muito teis que permitem verificar se um nmero
zero ou no.
1.zero?
1.nonzero?

#=> false
#=> true

0.zero?
0.nonzero?

#=> true
#=> false

Converso entre diferentes bases


Nmeros inteiros podem ser convertidos entre diferentes bases. possvel fazer
converses entre bases de 2 a 36.
1234.to_s(2)
1234.to_s(8)
1234.to_s(10)
1234.to_s(16)
1234.to_s(36)

#=>
#=>
#=>
#=>
#=>

10011010010
2322
1234 - base 10 o padro
4d2
ya

O valor retornado ser uma string que pode ser convertida novamente em nmero
com o mtodo String#to_i.
"10011010010".to_i(2)
"2322".to_i(8)
"1234".to_i(10)
"4d2".to_i(16)
"ya".to_i(36)

#=>
#=>
#=>
#=>
#=>

1234
1234
1234 - base 10 o padro
1234
1234

Fazendo arredondamentos
O Ruby possui dois mtodos que permitem arredondar nmeros de ponto flutuantes
para inteiros. O mtodo Float#ceil ir arredondar para o prximo nmero inteiro
maior ou igual o prprio nmero.
1.0.ceil #=> 1
1.1.ceil #=> 2
-1.1.ceil #=> -1
J o mtodo Float#floor ir arredondar para o nmero inteiro que for menor ou
igual ao prprio nmero.
1.0.floor #=> 1
1.1.floor #=> 1
-1.1.floor #=> -2
O mtodo Float#round ir arredondar nmeros de ponto flutuante para o nmero de

casas decimais que foram especificadas. Por padro, a preciso zero e pode
ser um nmero negativo (nesse caso, o nmero retornado ser um inteiro).
1.4.round
1.5.round
1.6.round
-1.5.round

#=>
#=>
#=>
#=>

1
2
2
-2

1.234567.round(2)
1.234567.round(3)
1.234567.round(4)
1.234567.round(5)

#=>
#=>
#=>
#=>

1.23
1.235
1.2346
1.23457

12345.67.round(-5)
12345.67.round(-4)
12345.67.round(-3)
12345.67.round(-2)
12345.67.round(-1)
12345.67.round(0)

#=>
#=>
#=>
#=>
#=>
#=>

0
10000
12000
12300
12350
12346

Tambm possvel fazer o truncamento de um nmero de ponto flutuante para


inteiro.
1.1.to_i
#=> 1 - O mtodo Float#to_i mais utilizado
-1.1.to_i
#=> -1
1.0.truncate #=> 1
Trabalhando com arrays
Acessando os elementos
Embora voc tenha visto algumas maneiras de como acessar_elementos_de_arrays,
existe um mtodo muito interessante chamado Array#fetch. Este mtodo permite
retornar um valor padro caso o ndice especificado no exista.
items = [1, 2, 3]
items.fetch(0)
#=> 1
items.fetch(4, "not found") #=> not found
items.fetch(4) do |index|
#=> index 4 not found
"index #{index} not found"
end
Outra caracterstica interessante que se nenhum valor padro for
especificado, uma exceo IndexError ser lanada.
items = [1, 2, 3]
items.fetch(4)
#=> IndexError: index 4 outside of array bounds: -3...3
Adicionando novos elementos
Para adicionar novos elementos ao final de um array, use os mtodos Array#<<1
ou o mtodo Array#push.
items = []

items << 1
items << 2
items.push(3)
p items
#=> [1, 2, 3]
Para adicionar novos elementos ao comeo de um array, use o mtodo
Array#unshift.
items = [1, 2, 3]
items.unshift(0)
#=> [0, 1, 2, 3]
Voc tambm pode inserir novos elementos em uma posio especfica com o mtodo
Array#add_elements.rb#insert. Note que o ndice pode ser um valor negativo.
items = [1, 2, 3]
items.insert(0, 4)
#=> [4, 1, 2, 3]

#=> insere o nmero 4 na posio 0.

items.insert(-1, 5)
#=> [4, 1, 2, 3, 5]

#=> insere o nmero 5 no final do array.

items.insert(3, 6, 7, 8) #=> insere os nmeros 6, 7 e 8 na posio 3.


#=> [4, 1, 2, 6, 7, 8, 3, 5]
Removendo elementos
Para remover sempre o ltimo elemento de um array, use o mtodo Array#pop. O
elemento removido ser o valor de retorno do mtodo.
items = [1, 2, 3]
items.pop
#=> 3
p items
#=> [1, 2]
Voc tambm pode especificar a quantidade de elementos que sero removidos.
items = [1, 2, 3, 4, 5]
items.pop(3)
#=> [3, 4, 5]
p items
#=> [1, 2]
Para remover todos os elementos de um determinado valor, use o mtodo
Array#delete. Caso este elemento no seja encontrado, nil ser retornado. Voc
tambm pode fornecer um bloco, cujo valor ser retornado quando o elemento no
for encontrado no array.
items = [1, 2, 3, "a", "b", "c"]

items.delete("a")
#=> a
items.delete("d")
#=> nil
items.delete("e") { "Y U MAD BRO?" }
#=> Y U MAD BRO?
Para remover um elemento em um determinado ndice, use o mtodo
Array#delete_at. Se o ndice especificado no existir, nil ser retornado.
items = [1, 2, 3]
items.delete_at(1)
#=> 2
items.delete_at(3)
#=> nil
Para remover o primeiro elemento de um array, use o mtodo Array#shift.
items = [1, 2, 3]
items.shift
#=> 1
Alternativamente, voc pode utilizar o mtodo Array#drop com o nmero de
elementos que devem ser removidos. Note que o array original no modificado.
items = [1, 2, 3]
items.drop(1)
#=> [2, 3]
items
#=> [1, 2, 3]
items = items.drop(2)
#=> [3]
Por fim, para remover todos os elementos de um array, use o mtodo Array#clear.
items = [1, 2, 3]
items.clear
items
#=> []
Filtrando elementos
Para gerar um novo array com todos os elementos que satisfaam uma determinada
condio, use o mtodo Array#select. Caso o bloco retorne um valor que seja
detectado como true2, o elemento ser adicionado ao novo array. partir do
Ruby 1.9, todos os mtodos iteradores que no recebem um bloco iro retornar um
objeto Enumerator.
items = [1, 2, 3, 4, 5]
items.select {|n| n.odd?}
#=> [1, 3, 5]

No Ruby 1.9, o exemplo acima pode ser ainda mais simples. partir desta verso
do Ruby, o mtodo Symbol#to_proc permite criar um bloco que ir executar o
mtodo identificado pelo smbolo que foi passado.
items = [1, 2, 3, 4, 5]
items.select(&amp;:odd?)
#=> [1, 3, 5]
Se voc precisa apenas do primeiro elemento que satisfaa a condio, utilize o
mtodo Array#find.
items = [1, 2, 3, 4, 5]
# recomendado
items.find(&amp;:odd?)
#=> 1
# estranho
items.select(&amp;:odd?).first
#=> 1
O mtodo Array#select possui uma contra-parte; trata-se do mtodo Array#reject.
Caso o bloco retorne false ou nil, o elemento ser adicionado ao novo array.
items = [1, 2, 3, 4, 5]
items.reject(&amp;:odd?)
#=> [2, 4]
Ordenando elementos
Para ordenar os elementos de um array, utilize o mtodo Array#sort. A
comparao feita usando o operador <=>.
items = %w[a d c b i k]
items.sort
#=> ["a", "b", "c", "d", "i", "k"]
A classe Array possui muitos mtodos que modificam o array original. o caso
de Array#sort! e Array#sort_by!.
items = %w[a d c b i k]
items.sort!
items
#=> ["a", "b", "c", "d", "i", "k"]
Voc tambm pode especificar qual o tipo de valor deve ser usado na comparao.
Isso pode ser feito com o mtodo Enumerator#sort_by. O mdulo Enumerator
includo pela classe Array.
Veja, por exemplo, como ordenar um array pelo tamanho das strings.
items = %w[Ruby Python PHP C JavaScript]
items.sort_by(&amp;:size)
#=> ["C", "PHP", "Ruby", "Python", "JavaScript"]
Para ordenar os elementos aleatriamente, utilize o mtodo Array#shuffle.
items = %w[Ruby Python PHP C JavaScript]
items.shuffle

#=> ["C", "PHP", "Ruby", "JavaScript", "Python"]


Para pegar um nico elemento aleatriamente, utilize o mtodo Array#sample,
disponvel partir do Ruby 1.9.
items = %w[Ruby Python PHP C JavaScript]
items.sample
#=> JavaScript
Buscando elementos
Para verificar se um elemento existe em um determinado array, use o mtodo
Array#include?. A comparao feita atravs do mtodo ==.
items = [1, "a"]
items.include?(1)
items.include?("a")
items.include?(0)

#=> true
#=> true
#=> false

O mtodo Array#index ir retornar o ndice do primeiro elemento encontrado.


items = [1, 2, 3, 1]
items.index(1) #=> 0
items.index(0) #=> nil
Se um bloco for passado para o mtodo Array#index, o ndice ser cujo bloco
retorne true.
items = [1, 2, 3, 1]
items.index {|i| i == 3} #=> 2
Existe ainda o mtodo Array#rindex, que funciona como o mtodo Array#index mas
atua nos elementos de forma reversa.
items = [1, 2, 3, 1]
items.rindex(1)
items.rindex {|i| i == 1}

#=> 3
#=> 3

Iterando elementos
A classe Array inclui o mdulo Enumerator, que implementa diversos mtodos
iteradores, mas outros destes mtodos so implementados pela prpria classe.
items = [1, 2, 3]
items.each {|item| puts item}
#
#
#
#

Output:
1
2
3

O mtodo Array#reverse_each permite iterar no array de trs para frente.


items.reverse_each {|item| puts item}

#
#
#
#

Output:
3
2
1

Para iterar em cada ndice de um array, use o mtodo Array#each_index.


items = %w[Ruby Python PHP]
items.each_index {|i| puts i}
#
#
#
#

Output:
0
1
2

Para iterar em cada elemento e, ainda por cima, ter o ndice da iterao, use o
mtodo Array#each_with_index.
items = %w[Ruby Python PHP]
items.each_with_index {|item, i| puts "#{i} => #{item}"}
#
#
#
#

Output:
0 => Ruby
1 => Python
2 => PHP

Compondo novos arrays


O mtodo Array#map permite criar um novo array com os valores retornados pelo
bloco, sem modificar o array original.
[1, 2, 3].map {|i| i * 2}
#=> [2, 4, 6]
%w[Ruby Python PHP].map {|i| i.downcase}
#=> ["ruby", "python", "php"]
Alternativamente, voc pode usar o mtodo Array#collect.
[1, 2, 3].collect {|i| i * 2}
#=> [2, 4, 6]
%w[Ruby Python PHP].collect {|i| i.downcase}
#=> ["ruby", "python", "php"]
O mtodo Array#inject ou Array#reduce permite reduzir um array a um nico
objeto. Se um valor inicial no for fornecido, o primeiro elemento do array
ser utilizado.
items = [1, 2, 3, 4, 5]
items.reduce(:+)
#=> 15 - Inicia em 1 e soma todos os elementos
items.reduce(10, :+)
#=> 25 - Inicia em 10 e soma todos os elementos
items.reduce(10) do |acc, i| #=> 19 - Inicia em 10 e soma apenas os nmeros
mpares
acc += i if i.odd?
acc
end
Perceba como estamos utilizando o mtodo Symbol#to_proc para executar a soma

dos elementos. Esta tcnica ser til apenas para operaes mais simples. Para
executar operaes mais complexas, fornea um bloco, que ir receber o
acumulador e o elemento da iterao.
1 Este mtodo tambm conhecido como shovel.
2 Ou seja, qualquer valor diferente de false e nil.
Trabalhando com hashes
Lista de chaves e valores
Para pegar uma lista das chaves de um hash, voc deve usar o mtodo Hash#keys.
options = {name: "John Doe", age: 32}
options.keys
#=> [:name, :age]
J a lista de valores pode ser acessada com o mtodo Hash#values.
options = {name: "John Doe", age: 32}
options.values
#=> ["John Doe", 32]
Verificando a existncia de chaves e valores
Hashes so muito eficientes em buscar um determinado valor atravs de uma
chave. Voc tambm pode fazer buscas de chaves atravs de um valor, embora esta
operao no seja to eficiente quanto o contrrio.
A classe Hash possui quatro mtodos diferentes para detectar se uma chave foi
definida. Trata-se dos mtodos Hash#key?, Hash#has_key?, Hash#member? e
Hash#include?.
options = {color: "green", width: 150, height: 30}
options.key?(:color)
#=> true
options.key?("color")
#=> false - As chaves so smbolos
options.has_key?(:color) #=> true
options.include?(:width) #=> true
options.member?(:height) #=> true
Para descobrir se um hash possui um determinado valor, use os mtodos
Hash#value? e Hash#has_value?.
options = {color: "green", width: 150, height: 30}
options.value?("green")
#=> true
options.has_value?("150")
#=> false
Para pegar a primeira chave que define um determinado valor, utilize o mtodo
Hash#key. No Ruby 1.8, este mtodo se chama Hash#index.
options = {color: "green", width: 150, height: 30}
options.key("green")
#=> :color
options.key("missing") #=> nil
Acessando o hash
O mtodo mais utilizado para acessar valores de hashes Hash#[]. Caso uma
chave no tenha sido definida, nil ser retornado por padro.

options = {name:
options[:name]
options[:age]
options[:email]

"John Doe", age: 32}


#=> "John Doe"
#=> 32
#=> nil

Voc tambm pode usar o mtodo Hash#fetch para acessar valores em um hash. Ele
possui mais opes na hora de lidar com chaves inexistentes.
options = {name: "John Doe", age: 32}
options.fetch(:name)
#=> John Doe - Funciona como o mtodo Hash#[]
options.fetch(:email)
#=> Lana a exceo "KeyError: key not found:
:email"
options.fetch(:email, nil)
#=> Retorna nil caso chave no exista
options.fetch(:email) do |key| #=> Executa o bloco caso a chave no exista
"Missing #{key}"
end
Para extrair mais de um valor de um hash, use o mtodo Hash#values_at. Se uma
determina chave no existir, nil ser retornado.
options = {name: "John Doe", age: 32}
options.values_at(:name, :age, :email)
#=> ["John Doe", 32, nil]
Filtrando elementos
Para gerar um novo hash com todos os elementos que satisfaam uma determinada
condio, use o mtodo Hash#select. Caso o bloco retorne um valor que seja
detectado como true, o elemento ser adicionado ao novo array. No Ruby 1.8,
este mtodo retorna um array contendo as chaves e valores.
items = {:one => 1, :two => 2, :three => 3, :four => 4, :five => 5}
items.select {|key, value| value.even?}
#=> {:two=>2, :four=>4}
- Ruby 1.9
#=> [[:four, 4], [:two, 2]] - Ruby 1.8
Assim como nos arrays, o mtodo Hash#select possui sua contra-parte
Hash#reject. Caso o bloco retorne false ou nil, o elemento ser adicionado ao
novo hash.
items = {:one => 1, :two => 2, :three => 3, :four => 4, :five => 5}
items.reject {|key, value| value.odd?}
#=> {:two=>2, :four=>4}
Removendo valores de um hash
Para remover uma determinada chave de um hash, use o mtodo Hash#delete. O
valor retornado ser o valor removido. Caso a chave no exista, nil ser
retornado. Se voc fornecer um bloco, o valor de retorno do bloco ser usado em
vez de nil.
options = {:color => "green", "size" => "300x50"}
options.delete("color")
options.delete(:color)
options.delete(:invalid) do |key|

#=> nil
#=> green
#=> Executa o bloco caso a chave no

exista
raise KeyError, "key not found: #{key.inspect}"
end
Para remover diversas chaves caso uma condio no seja satisfeita, use o
mtodo Hash#delete_if.
options = {one: 1, two: 2, three: 3, four: 4}
options.delete_if do |key, value|
value.odd?
end
options
#=> {:two=>2, :four=>4}
Alternativamente, voc pode usar o mtodo Hash#reject! que tambm ir modificar
o hash original.
options = {one: 1, two: 2, three: 3, four: 4}
options.reject! do |key, value|
value.odd?
end
options
#=> {:two=>2, :four=>4}
Por fim, para remover todos os elementos de um hash, use o mtodo Hash#clear.
options = {a: 1, b: 2, c: 3}
options.clear
options
#=> {}
Compondo novos hashes
O mtodo Hash#map ir converter o hash para um array, usando o valor retornado
pelo bloco. Para compor um hash partir de array, voc pode utilizar o mtodo
Hash.[].
options = {color: "red", language: "Ruby"}
options.map {|key, value| value.upcase}
#=> ["RED", "RUBY"]
Hash[options.map {|key, value| [key, value.upcase]}]
#=> {:color=>"RED", :language=>"RUBY"}
Alternativamente, voc pode usar o mtodo Hash#inject ou Hash#reduce, passando
um hash vazio como valor inicial.
options = {color: "red", language: "Ruby"}
options.reduce({}) do |acc, (key, value)|
acc.merge(key => value.upcase)
end
Note que estamos explodindo a chave e valor em duas variveis diferentes,
conforme vimos em Atribuio_de_variveis.

Iterando hashes
Para iterar em hashes, utilize o mtodo Hash#each. O bloco ir receber a chave
e o valor em cada iterao.
options = {name: "John Doe", age: 32}
options.each {|key, value| puts "#{key} => #{value}"}
# Output:
# name => John Doe
# age => 32
Voc tambm pode iterar apenas nas chaves com o mtodo Hash#each_key.
options = {name: "John Doe", age: 32}
options.each_key {|key| puts "#{key} => #{options[key]}"}
# Output:
# name => John Doe
# age => 32
Por fim, para iterar somente nos valores, use o mtodo Hash#each_value.
options = {name: "John Doe", age: 32}
options.each_value {|value| puts value}
# Output:
# John Doe
# 32
Trabalhando com arquivos e diretrios
Manipulando nomes de arquivos
A classe File
diretrios. O
operacionais,
Windows, pode

possui alguns mtodos que permitem manipular nomes de arquivos e


Ruby usa o separador de diretrios / em todos os sistemas
inclusive Windows. No entanto, se voc estiver executando Ruby no
tambm definir o separador como sendo \.

fullpath = "/Users/fnando/ruby/samples.rb"
dir = File.dirname(fullpath)
#=> /Users/fnando/ruby
file = File.basename(fullpath)
#=> samples.rb
extension = File.extname(file)
#=> .rb
File.basename(fullpath, extension) #=> samples - Remove a extenso
File.dirname(file)
#=> retorna ".", o diretrio atual
File.join(dir, file)
#=> concatena com o separator de
diretrios
Nenhum destes mtodos ir verificar a existncia de arquivos e diretrios. Eles
apenas permitem compor nomes, sem se importar com sua existncia e tipo (voc
pode usar o mtodo File.basename em um diretrio, por exemplo.).
O mtodo File.expand_path permite expandir caminhos partir do diretrio atual
ou de um caminho raz.
Dir.chdir("/usr/bin")
usr/bin
File.expand_path("ruby")

#=> muda o diretrio atual para /


#=> /usr/bin/ruby

File.expand_path("~/ruby")
#=> /Users/fnando/ruby
File.expand_path("ruby", "/usr/local/bin") #=> /usr/local/bin/ruby
File.expand_path("~fnando/ruby")
#=> /Users/fnando/ruby
# Lana a exceo "ArgumentError: user fnando doesn't exist"
# caso o diretrio `~/fnando` no exista.
Para expandir o caminho de links simblicos, use o mtodo File.readlink.
File.readlink("/usr/bin/ruby")
#=> ../../System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/
ruby
Manipulando arquivos
O Ruby possui algumas maneiras distintas de abrir arquivos. O modo mais manual
que existe exige que voc mesmo encerre o uso de IO deste arquivo. Neste caso,
no ser possvel efetuar nenhuma operao aps executar o mtodo File#close e,
caso alguma tentativa de uso seja realizada, a exceo IOError: closed stream
ser lanada.
file = File.new(__FILE__) #=> Abre o prprio arquivo para leitura
content = file.read
#=> Armazena o contedo do arquivo
file.close
#=> Encerra o uso de IO
Embora seja extremamente flexvel, este fluxo est sujeito
desenvolvedor mais descuidado pode no encerrar o uso de IO.
isto acontea, recomendado que voc use o mtodo File#open
bloco ir receber o objeto File e, aps a execuo do bloco,
automaticamente encerrado.

falhas. Um
Para evitar que
com um bloco. Este
ter o uso de IO

File.open(__FILE__) do |file|
content = file.read
end
Por padro, os mtodos File.open e File.new iro abrir o arquivo em modo de
leitura. Voc pode especificar a flag que ser usada na hora de abrir um
arquivo.
path = "/tmp/sample.txt"
File.open(path)
File.open(path,
File.open(path,
existente.
File.open(path,
existente.
File.open(path,
File.open(path,
File.open(path,

"r")
"w")

#=> Usa a flag "r" (leitura) por padro.


#=> Abre o arquivo para leitura.
#=> Abre o arquivo para escrita, apagando o contedo

"a")

#=> Abre o arquivo para escrita, mantendo o contedo

"w+")
"a+")
"rb")

#=> Abre o arquivo para escrita e leitura.


#=> Abre o arquivo para escrita e leitura.
#=> Abre o arquivo para leitura binria.

Para ler um arquivo apenas, use o mtodo File.read.


puts File.read(__FILE__)
Veja um exemplo que mostra como ler uma URL, salvar seu contedo em um arquivo
e depois exibir o contedo salvo.
require "open-uri"

page = open("http://localhost/").read
path = "/tmp/localhost.html"
File.open(path, "w") do |file|
file.write page
end
puts File.read(path)
Note que estamos usando o mtodo File#write para adicionar o contedo ao
arquivo. Voc tambm poderia ter usado o mtodo File#<<.
Para modificar um arquivo existente, voc deve se certificar que est usando a
flag a. Caso contrrio, todo o contedo de seu arquivo ser substitudo. O
exemplo abaixo mostra como normalizar as quebras de linha de um arquivo para
\n.
path = "/tmp/editing.txt"
File.open(path, "w") do |file|
file << "This is the first line\r\n"
file << "This is the second line\n"
end
content = File.read(path)
File.open(path, "w") do |file|
file.write content.gsub(/\r?\n/, "\n")
end
p File.read(path)
#=> "This is the first line\nThis is the second line\n"
Para apagar um arquivo existente, use o mtodo File.unlink ou File.delete.
paths = ["/tmp/1.txt", "/tmp/2.txt"]
# Itera em cada um dos caminhos e cria seu arquivo.
paths.each do |path|
File.open(path, "w") {|file| file << "OH NOES!"}
end
# Apaga diversos arquivos. O valor de retorno a
# quantidade de nomes que foram passados como argumentos.
File.unlink(*paths)
#=> 2
Definindo a codificao do arquivo
Assim como a classe String, a classe File tambm tem suporte a codificao, que
pode ser especificada no momento da abertura do arquivo para leitura e/ou
escrita. Voc pode fazer converso entre diferentes tipos de codificao na
hora da leitura e escrita.
O exemplo abaixo mostra como abrir um arquivo UTF-8 e convert-lo para ISO-8859
no momento da leitura. Na hora da gravao, a codificao ser feita no caminho
contrrio, convertendo o texto de ISO-8859-1 para UTF-8.
file = File.open("/tmp/sample.txt", "w+:utf-8:iso-8859-1")

# verifica a codificao de gravao do arquivo


file.external_encoding
#=> <Encoding:UTF-8>
# verifica a codificao de leitura do arquivo
file.internal_encoding
#=> <Encoding:ISO-8859-1>
# escreve uma string em UTF-8 no arquivo
file.write "".encode("iso-8859-1")
# l o contedo do arquivo
content = file.read
# retorna a codificao do contedo do arquivo (string)
content.encoding
#=> <Encoding:ISO-8859-1>
file.close
Manipulando diretrios
Para listar todos os arquivos e diretrios, voc pode usar o mtodo
Dir.entries. Note que este mtodo ir adicionar os caminhos . e .., que fazem
referncia ao diretrio atual e diretrio-pai, respectivamente.
Dir.entries(".")
#=> [".", "..", "dir.rb", "editing.rb", "encoding.rb", "expand_path.rb",
"filename.rb", "new.rb",
# "open.rb", "open_flags.rb", "read.rb", "save_page.rb", "unlink.rb"]
O mtodo Dir.[] permite listar todas as entradas que atenderem um determinado
padro. Este mtodo apenas um atalho para Dir.glob e aceita os mesmos
padres. Para conhecer todos os padres aceitos, acesse a documentao com o
comando ri Dir.glob.
# Arquivos no diretrio atual com a extenso .rb
Dir["*.rb"]
# Arquivos no diretrio atual que comeam com a letra e.
Dir["e*"]
# Arquivos com nomes "encoding" e/ou "open" que tenham a extenso .rb
Dir["{encoding,open}.rb"]
# Qualquer arquivo, de qualquer diretrio, partir do diretrio atual.
Dir["./**/{.*,*.*}"]
# Qualquer arquivo, de qualquer diretrio, partir do diretrio atual e que
# tenha a extenso .rb
Dir["./**/*.rb"]
# Arquivos que no tenham extenso comeadas com a letra r.
Dir["*.[^r]*"]
Para criar um diretrio, use o mtodo Dir.mkdir. Se o diretrio j existir, a
exceo Errno::EEXIST: File exists ser lanada.
Dir.mkdir("/tmp/sample")

Para remover um diretrio, use o mtodo Dir.delete, Dir.unlink ou Dir.rmdir. O


diretrio precisa estar vazio. Caso o diretrio no esteja vazio, a exceo
Errno::ENOTEMPTY: Directory not empty ser lanada.
Dir.delete("/tmp/sample")
Muitas dessas limitaes que a classe Dir impe podem ser removidas se voc
carregar a biblioteca padro FileUtils. Ela possui uma srie de mtodos que
permitem criar e remover diretrios, dentre outros mtodos muito teis.
require "fileutils"
dir = "/tmp/a/b/c/d/e/f"
FileUtils.mkdir_p(dir)
File.open(File.join(dir, "sample.txt"), "w") do |file|
file << "sample text"
end
FileUtils.rm_rf(dir)
Testando arquivos e diretrios
Para verificar se um caminho um arquivo ou diretrio, voc pode usar os
mtodos File.file? e File.directory?.
file = __FILE__
dir = File.dirname(file)
File.file?(file)
File.directory?(file)

#=> true
#=> false

File.file?(dir)
File.directory?(dir)

#=> false
#=> true

File.file?("/invalid")
File.directory?("/invalid")

#=> false
#=> false

Voc tambm pode verificar se um caminho um link simblico.


path = "/usr/bin/ruby"
File.file?(path)
File.directory?(path)
File.symlink?(path)

#=> true
#=> false
#=> true

Voc tambm pode verificar se arquivos e diretrios podem ser lidos ou


escritos.
path = "/usr/bin/ruby"
File.executable?(path)
File.readable?(path)
File.writable?(path)
File.world_readable?(path)
File.world_writable?(path)

#=>
#=>
#=>
#=>
#=>

true
true
false
493
nil

Datas de modificao e acesso de arquivos


Para saber quando um arquivo foi modificado, use o mtodo File.mtime.
File.mtime(__FILE__)
#=> 2011-12-31 12:32:11 -0200
Para saber quando um arquivo foi acessado, use o mtodo File.atime.
File.atime(__FILE__)
#=> 2011-12-31 12:35:30 -0200
Trabalhando com data e hora
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
URLs e requisies HTTP
Hmmm.
Este contedo est sendo escrito e estar disponvel em breve.
Lidando com excees
No importa quo bem testado seja seu cdigo ou quo cuidadoso voc seja, bugs
sempre existiro. No Ruby, erros na execuo do cdigo so sinalizados com
excees, que so instncias da classe Exception.
Excees podem ser lanadas com os mtodos Kernel#raise e Kernel#fail. Estes
mtodos podem ser executados com trs argumentos opcionais, mas a assinatura
completa do mtodo raise(exception_class, message, backtrace).
raise ArgumentError
raise ArgumentError, "you've failed"
raise ArgumentError, "you've failed", caller
Quando o mtodo Kernel#raise chamado sem nenhum argumento, uma exceo do
tipo RuntimeError lanada. As duas excees seguir so equivalentes.
raise
raise RuntimeError
Alternativamente, voc pode passar uma string para o mtodo Kernel#raise, que
equivalente a lanar uma exceo com raise(RuntimeError, message).
raise "You've failed"
raise RuntimeError, "You've failed"
Quando uma exceo lanada, a classe que foi utilizada para definir a exceo
ser instanciada. O processo completo pode ser descrito em quatro etapas:
1. Caso uma classe tenha sido passada como argumento, ela instanciada com o
mtodo Exception.exception. Se uma instncia da classe Exception for
fornecida, ento a exceo obtida com o mtodo Exception#exception.
2. O backtrace da exceo definido.
3. A varivel global @$! definida com a ltima exceo ativa.
4. A exceo lanada na pilha de execuo.

Capturando excees
O Ruby permite capturar excees com a clusula rescue.
begin
raise "OH NOES!"
rescue
puts "An exception has been raised"
end
# An exception has been raised
Voc pode atribuir o objeto de erro a uma varivel, ou pode utilizar a varivel
global $!.
begin
raise "OH NOES!"
rescue => error
puts "error: #{error.message}"
puts "$!: #{$!.message}"
end
Por padro, apenas as classes que herdam de StandardError sero capturadas.
Para capturar outras classes, voc pode passar uma lista de argumentos com as
classes de exceo.
begin
raise "OH NOES!"
rescue StandardError => error
puts "error: #{error.message}"
end
begin
raise LoadError
rescue Exception, LoadError => error
puts "error: #{error.message}"
end
Muitas excees nativas do Ruby so lanadas como Exception, em vez de
StandardError. o caso das classes LoadError e SyntaxError, lanadas quando um
arquivo no consegue ser carregado com o mtodo Kernel#require e quando o Ruby
encontra uma sintaxe invlida, respectivamente. Embora seja possvel capturar a
classe base Exception, isso no uma boa ideia. Seja especfico quanto s
excees que voc quer capturar.
Voc pode ter diversas clusulas rescue que tratam excees diferentes de modos
diferentes. Voc pode, inclusive, adicionar vrias classes de excees em uma
nica clusula enquanto define diferentes pontos de captura da exceo.
exceptions = [LoadError, RuntimeError, ScriptError, SyntaxError]
exceptions.each do |exception_class|
begin
raise exception_class, "just playing with exceptions!"
rescue LoadError => error
puts "#{error.class} => OH NOES! I couldn't load the specified file"
rescue RuntimeError => error
puts "#{error.class} => Dammit! Something went wrong"
rescue ScriptError, SyntaxError => error
puts "#{error.class} => Y U MAD? JUST GIMME SOME VALID RUBY!"
end

end
#
#
#
#

LoadError => OH NOES! I


RuntimeError => Dammit!
ScriptError => Y U MAD?
SyntaxError => Y U MAD?

couldn't load the specified file


Something went wrong
JUST GIMME SOME VALID RUBY!
JUST GIMME SOME VALID RUBY!

O Ruby tambm possui uma clusula chamada ensure, que ser sempre executada
independente de uma exceo ter sido lanada. Isso permite efetuar operaes
que, em outras situaes, poderia deixar a sua aplicao em um estado
inconsistente.
begin
puts "Starting execution"
raise
puts "Won't be displayed"
rescue
puts "OH NOES! An exception has occurred"
ensure
puts "I'll be always executed"
end
# Starting execution
# OH NOES! An exception has occurred
# I'll be always executed
Uma boa prtica fazer com que a clusula ensure execute apenas operaes
simples e seguras, diminuindo a probabilidade de uma segunda exceo ser
lanada, o que pode fazer com que as operaes de limpeza no sejam concludas,
alm de tornar a depurao do erro mais complexa.
Em algumas situaes, pode fazer sentido executar novamente um determinado
bloco begin..end quando uma exceo lanada. a que entra a clusula retry.
O exemplo abaixo mostra como tentar executar um determinado bloco trs vezes
antes de desistir.
tries = 0
begin
tries += 1
puts "Trying ##{tries}"
raise "OH NOES!"
rescue
retry if tries < 3
puts "Sorry! I couldn't make it work!"
end
#
#
#
#

Trying
Trying
Trying
Sorry!

#1
#2
#3
I couldn't make it work!

Dentro da clusula rescue pode existir qualquer tipo de cdigo. Voc pode,
inclusive, lanar uma nova exceo ou, se preferir, a mesma exceo que foi
capturada inicialmente. Isso permite criar, por exemplo, mecanismos que iro
rastrear uma exceo lanada.
O exemplo seguir mostra como enviar para um arquivo de log qualquer tipo de
exceo, antes de lan-la novamente.
require "logger"

LOGGER = Logger.new(STDOUT)
def bogus_method
raise "OMG! Something went wrong!"
end
begin
bogus_method
rescue Exception => error
LOGGER.error "#{error.class} => #{error.message}"
LOGGER.error error.backtrace.join("\n")
raise error
end
# E, [2012-01-05T14:23:04.338482 #17431] ERROR -- : RuntimeError => OMG!
Something went wrong!
# E, [2012-01-05T14:23:04.339039 #17431] ERROR -- : /Users/fnando/exceptions/
log.rb:6:in `bogus_method'
# /Users/fnando/Sites/howto-books/ruby/code/exceptions/log.rb:10:in `<main>'
Lembre-se que as excees utilizam os mtodos Exception#exception e
Exception.exception para definir se uma nova exceo deve ser instnciada ou se
a prpria instncia que deve ser utilizada.
Embora excees possam ser utilizadas para controlar fluxos de aplicaes, este
no o mecanismo mais recomendado para a tarefa. Neste caso, voc deve usar os
mtodos Kernel#throw e Kernel#catch, criados para interromper rapidamente a
execuo de loops aninhados e chamadas a mtodos sem necessariamente lanar uma
exceo.
O mtodo Kernel#throw permite lanar um smbolo que pode ser capturado com o
mtodo Kernel#catch. Se voc executar o mtodo Kernel#throw com um argumento
que ser usado como valor de retorno do mtodo Kernel#catch.
O exemplo abaixo mostra como descobrir quantas vezes um loop teve que ser
executado at que o nmero 42 fosse encontrado.
count = catch :done do
tries = 0
loop do
tries += 1
throw(:done, tries) if rand(100) == 42
end
end
puts "We tried #{count} times until we get 42"
#=> We tried 82 times until we get 42
Um outro uso seria para interromper loops aninhados. Veja, por exemplo, como
para a execuo dos loops quando a letra n e o nmero 42 forem encontrados e,
ainda assim, ter acesso aos valores encontrados.
number, letter = catch :done do
("a".."z").each do |l|
(1..100).each do |n|
throw(:done, [n, l]) if l == "n" &amp;&amp; n == 42
end
end
end
puts "number: #{number}"

puts "letter: #{letter}"


# number: 42
# letter: n
Escrevendo testes com Test::Unit
Unit testing uma tcnica de testes que foca em pequenos trechos de cdigos,
normalmente cada um dos mtodos pblicos que seu cdigo implementa.
Testes ajudam os desenvolvedores a escrever cdigos melhores. Quando seu cdigo
ainda no foi escrito, testes ajudam a pensar em um design de cdigo mais
desacoplado. Enquanto seu cdigo est sendo escrito, testes ajudam a verificar
que suas alteraes no quebraram outras partes do cdigo. Depois que seu
cdigo foi escrito, testes ajudam no processo de refatorao, dando feedback
instntaneo caso alguma coisa deixe de funcionar, alm de ajudar novos
desenvolvedores que tenham que manter uma base de cdigo.
O Ruby vem com seu prprio framework de testes chamado Test::Unit. No Ruby 1.9
ele foi reescrito em cima de um outro framework mais simples, que tambm j vem
como uma standard library, chamado MiniTest::Unit. Resumindo, no Ruby 1.9, o
Test::Unit apenas uma camada de compatibilidade em cima do MiniTest::Unit.
O MiniTest::Unit vem ainda com um outro idioma chamado MiniTest::Spec, que
tenta ser algo prximo do RSpec, um framework de testes mantido por David
Chelimsky.
Independente do framework de testes que voc venha a utilizar, todos eles
seguem mais ou menos o mesmo padro. Voc ir especificar um resultado esperado
e ir compar-lo com o resultado gerado por seu cdigo. Caso esta comparao
falhe, o framework de testes ir exibir uma mensagem dizendo qual trecho de
cdigo falhou. No nem preciso dizer que este tipo de abordagem
infinitamente melhor que testar todo um fluxo de aes cada vez que uma
alterao for realizada.
Para mostrar como usar o framework de testes Test::Unit, ns iremos implementar
um conversor de temperaturas. Antes de comear, vamos organizar o nosso cdigo
de modo que ele possa ser facilmente distribudo depois como uma gem.
Organizando o cdigo
Bibliotecas do Ruby seguem mais ou menos o mesmo padro. O cdigo-fonte
normalmente fica em um diretrio lib. Caso sua biblioteca seja composta por
mais de um arquivo, um diretrio com o mesmo nome da biblioteca deve ser criado
no diretrio lib. Arquivos de teste devem ser criados no diretrio test.
Organize seu diretrio de modo que ele seja parecido com a imagem seguir.
Estrutura inicial da biblioteca Temperature
Estrutura inicial da biblioteca Temperature
Para executar os testes ns iremos utilizar uma rake task. Crie o arquivo
Rakefile na raz de seu projeto com o seguinte contedo.
require "rake/testtask"
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList["test/*_test.rb"]
t.verbose = true
end
Agora, voc poder executar os seus testes com o comando rake test. Para
visualizar todas as tarefas disponveis, execute o comando rake -T. Se tudo
estiver certo, voc ver algo como isto:
$ rake -T

rake test # Run tests


Convertendo temperaturas
Nossa classe Temperature dever receber dois argumentos: o primeiro identifica
a temperatura e o segundo a unidade de temperatura utilizada. Nossa API ser
algo como Temperature.new(32, :celsius). Vamos escrever um primeiro teste que
ir garantir que estes atributos esto sendo definidos corretamente.
Crie o arquivo test/temperature_test.rb. Esse arquivo ser responsvel por
carregar o cdigo de nossa biblioteca, alm de definir um caso de teste, que
apenas uma classe que herda da classe Test::Unit::TestCase. Todos os testes so
mtodos que comeam com as letras test, mas o padro utilizar test_.
Download temperature/test/temperature_test.rb
require "temperature"
require "test/unit"
class TemperatureTest < Test::Unit::TestCase
def test_assign_attributes
temp = Temperature.new(32, :celsius)
assert_equal 32, temp.number
assert_equal :celsius, temp.unit
end
end
Todas as verificaes que seu teste far so chamadas de asseres. No Test::
Unit, voc ir usar os mtodos assert_* para garantir que seu cdigo est de
acordo com uma determinada condio.
Execute os testes com o comando rake test. Voc ver que este teste ir falhar
com um erro. Isso acontece porque ainda no definimos nossa classe Temperature.
$ rake test
# Running tests:
E
Finished tests in 0.000755s, 1324.5033 tests/s, 0.0000 assertions/s.
1) Error:
test_assign_attributes(TemperatureTest):
NameError: uninitialized constant TemperatureTest::Temperature
/Users/fnando/temperature/test/temperature_test.rb:7:in
`test_assign_attributes'
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
rake aborted!
Abra o arquivo temperature/lib/temperature.rb e crie a classe Temperature.
Download temperature/lib/temperature.rb
class Temperature
end
Como a ideia evoluir o seu cdigo em pequenos passos, voc deve executar os
testes a cada alterao. Faa isso mais uma vez com o comando rake test. Voc
que nosso teste continua falhando com um erro, embora o erro seja diferente.

1) Error:
test_assign_attributes(TemperatureTest):
ArgumentError: wrong number of arguments(2 for 0)
/Users/fnando/temperature/test/temperature_test.rb:6:in `initialize'
/Users/fnando/temperature/test/temperature_test.rb:6:in `new'
/Users/fnando/temperature/test/temperature_test.rb:6:in
`test_assign_attributes'
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
Desta vez, o erro que temos : ArgumentError: wrong number of arguments(2 for
0). Isso significa que nossa classe no espera receber nenhum argumento, mas
estamos passando dois. Crie o mtodo Temperature#initialize de forma que ele
receba estes dois parmetros.
Download temperature/lib/temperature.rb
class Temperature
def initialize(number, unit)
end
end
Execute os testes mais uma vez. Agora, o teste ir falhar novamente com um
erro. O motivo agora que no definimos os atributos number e unit.
1) Error:
test_assign_attributes(TemperatureTest):
NoMethodError: undefined method `number' for #<Temperature:0x007fa1b40d6dc8>
/Users/fnando/temperature/test/temperature_test.rb:8:in
`test_assign_attributes'
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
Defina os atributos utilizando o mtodo Module.attr_accessor.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
end
end
Execute os testes mais uma vez. Deste vez, o teste ir falhar, mas sem erros.
1) Failure:
test_assign_attributes(TemperatureTest) [/Users/fnando/temperature/test/
temperature_test.rb:8]:
<32> expected but was
<nil>.
1 tests, 1 assertions, 1 failures, 0 errors, 0 skips
Agora, podemos ver que o motivo da falha exatamente o ponto que queremos
testar. O atributo number no est sendo definido. Para fazer isso, basta fazer
a atribuio dos valores recebidos como argumentos para as variveis de
instncia de mesmo nome.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit

def initialize(number, unit)


@number = number
@unit = unit
end
end
Execute os testes mais uma vez e voc ver que agora eles iro passar!
Voc deve ter percebido que seguimos um fluxo bem definido. Primeiro,
escrevemos um teste que falhou. Depois, fomos corrigindo cada uma das falhas
individualmente, sempre depois de rodar os testes, at que o prprio teste
passasse. Esta tcnica chamada de Test-Driven Development.
Nossa classe Temperature ter trs mtodos diferentes que iro permitir a
converso entre as diferentes unidades. Estes mtodos sero chamados de
Temperature#to_fahrenheit, Temperature#to_celsius e Temperature#to_kelvin.
Primeiro, vamos escrever um teste que garanta que estamos convertendo uma
temperatura em Celsius para Fahrenheit. Neste teste, iremos converter 40 C, que
so equivalentes a 104 F. Adicione o teste seguir ao arquivo temperature/
test/temperature_test.rb.
Download temperature/test/temperature_test.rb
def test_convert_celsius_to_fahrenheit
temp = Temperature.new(40, :celsius)
assert_equal 104, temp.to_fahrenheit
end
Execute os testes. Eles devem falhar dizendo que o mtodo
Temperature#to_fahrenheit no existe. Adicione este mtodo.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
end
end
Execute os testes mais uma vez. Ele ir falhar dizendo que o valor esperado era
diferente de nil. A frmula que faz a converso de Celsius para Fahrenheit F
= C * (9 / 5) + 32, onde F significa Fahrenheit e C significa Celsius.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
number * (9 / 5.0) + 32
end
end

Perceba que estamos utilizando 5.0 para garantir que a diviso no seja feita
entre dois nmeros inteiros.
Execute os testes mais uma vez. Veja que a converso est sendo feita de forma
correta.
Um problema de nossa implementao que estamos assumindo que a temperatura
inicial ser sempre em Celsius. Mas o que acontece se passarmos uma unidade
diferente, que exige a aplicao de uma outra frmula? Obviamente, o clculo
ser feito de forma incorreta.
Para evitar que nossos mtodos tenham diversas expresses condicionais que iro
fazer o clculo de acordo com a unidade atual, ns iremos sempre utilizar o
mtodo Temperature#to_celsius como base para os demais clculos. Dessa forma,
teremos que converter apenas de Celsius para Fahrenheit e de Celsius para
Kelvin.
Altere a classe Temperature de modo que o mtodo que o mtodo
Temperature#to_fahrenheit utilize o retorno do mtodo Temperature#to_celsius,
em vez de Temperature#number.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
to_celsius * (9 / 5.0) + 32
end
end
Ao executar os testes, eles iro falhar dizendo que o mtodo
Temperature#to_celsius ainda no existe. Vamos adicionar alguns testes para
garantir que este mtodo converta os valores corretamente. Primeiro, vamos
escrever um teste para a converso de Celsius para Celsius.
Download temperature/test/temperature_test.rb
def test_convert_celsius_to_celsius
temp = Temperature.new(40, :celsius)
assert_equal 40, temp.to_celsius
end
Execute os testes, que continuaro falhando. Altere o mtodo
Temperature#to_celsius, adicionando um case.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
to_celsius * (9 / 5.0) + 32
end
def to_celsius
case unit

when :celsius then number


end
end
end
Execute os testes. Agora, ambos os testes iro passar.
Adicione mais um teste para garantir que a converso de Fahrenheit para Celsius
est sendo feita de forma correta.
Download temperature/test/temperature_test.rb
def test_convert_fahrenhet_to_celsius
temp = Temperature.new(104, :fahrenheit)
assert_equal 40, temp.to_celsius
end
Execute os testes. Esse teste que acabamos de adicionar deve falhar.
1) Failure:
test_convert_fahrenhet_to_celsius(TemperatureTest) [/Users/fnando/
temperature/test/temperature_test.rb:24]:
<40> expected but was
<nil>.
4 tests, 5 assertions, 1 failures, 0 errors, 0 skips
Adicione mais esta converso ao mtodo Temperature#to_celsius. A frmula que
faz a converso de Fahrenheit para Celsius C = (F - 32) * (5 / 9).
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
to_celsius * (9 / 5.0) + 32
end
def to_celsius
case unit
when :celsius
number
when :fahrenheit
(number - 32) * (5 / 9.0)
end
end
end
Execute os testes, que devem passar novamente.
A ltima converso que precisa ser feita de Kelvin para Celsius. Esta frmula
a mais simples de todas: C = K - 273.15, onde C significa Celsius e K
significa Kelvin. Primeiro adicione o teste.
Download temperature/test/temperature_test.rb
def test_convert_kelvin_to_celsius
temp = Temperature.new(323.15, :kelvin)
assert_equal 50, temp.to_celsius

end
Execute os testes, que devem falhar dizendo que o valor esperado diferente de
nil. Agora, podemos implementar a converso de Kelvin para Celsius.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
to_celsius * (9 / 5.0) + 32
end
def to_celsius
case unit
when :celsius
number
when :fahrenheit
(number - 32) * (5 / 9.0)
when :kelvin
number - 273.15
end
end
end
Execute os testes. Eles devem passar mais uma vez!
Muito bem! A converso de temperaturas em Fahrenheit e Kelvin em Celsius j
podem ser realizadas, embora o contrrio ainda no seja verdade. Ainda falta
implementarmos a converso para Kelvin. O prximo teste ir garantir que uma
temperatura em Celsius seja convetida em Kelvin.
def test_convert_celsius_to_kelvin
temp = Temperature.new(50, :celsius)
assert_equal 323.15, temp.to_kelvin
end
Ao executar os testes, voc ver que ele ir falhar dizendo que o mtodo
Temperature#to_kelvin no foi definido. Voc pode, ento, implementar este
mtodo. A frmula de converso de Celsius para Kelvin K = C + 273.15.
Download temperature/lib/temperature.rb
class Temperature
attr_accessor :number, :unit
def initialize(number, unit)
@number = number
@unit = unit
end
def to_fahrenheit
to_celsius * (9 / 5.0) + 32
end
def to_celsius
case unit

when :celsius
number
when :fahrenheit
(number - 32) * (5 / 9.0)
when :kelvin
number - 273.15
end
end
def to_kelvin
to_celsius + 273.15
end
end
Parabns! Voc acabou de escrever uma biblioteca que converte temperaturas
entre diferentes unidades com testes. Para deixar o exemplo completo, sua
classe de testes deve se parecer com isto:
Download temperature/test/temperature_test.rb
require "temperature"
require "test/unit"
class TemperatureTest < Test::Unit::TestCase
def test_assign_attributes
temp = Temperature.new(32, :celsius)
assert_equal 32, temp.number
assert_equal :celsius, temp.unit
end
def test_convert_celsius_to_kelvin
temp = Temperature.new(50, :celsius)
assert_equal 323.15, temp.to_kelvin
end
def test_convert_celsius_to_fahrenheit
temp = Temperature.new(40, :celsius)
assert_equal 104, temp.to_fahrenheit
end
def test_convert_celsius_to_celsius
temp = Temperature.new(40, :celsius)
assert_equal 40, temp.to_celsius
end
def test_convert_kelvin_to_celsius
temp = Temperature.new(323.15, :kelvin)
assert_equal 50, temp.to_celsius
end
def test_convert_fahrenhet_to_celsius
temp = Temperature.new(104, :fahrenheit)
assert_equal 40, temp.to_celsius
end
end
Lista de mtodos de assero
Embora tenhamos escritos alguns testes, todos eles usaram o mesmo mtodo de

assero assert_equal. O Test::Unit implementa muito mais mtodos como voc


pode conferir abaixo.
assert(boolean)
Falha se boolean for nil ou false
assert_block
Falha se o bloco block for nil ou false
(&amp;block)
assert_empty(list)
Falha se o mtodo list#empty? retornar false
assert_equal
Passa se expected for igual a actual quando o operador ==
usado
(expected, actual)
assert_in_delta
Passa se o nmero de ponto flutuante expected for igual a ac
tual dentro do delta
(expected, actual,
esperado
delta)
assert_in_epsilon
Calcula o delta com epsilon * min(expected, actual) e ento
executa
(expected, actual,
assert_in_delta com este valor
epsilon)
assert_includes
Verifica se collection inclui o objeto element com o mtodo
collection#include?
(collection, element)
assert_instance_of
Verifica se object uma instncia da classe klass
(klass, object)
assert_kind_of(klass, Verifica se object do tipo da classe klass com o mtodo obje
ct.kind_of?(klass)
object)
assert_match(regexp, Verifica se string casa a expresso regular regexp
string)
assert_nil(object)
Verifica se object nil
assert_operator
Verifica se o envio da mensagem operator para object1 com
o parmetro object2
(object1, operator, retorna true
object2)
assert_raises
(Exception, ...,
&amp;block)
Verifica se o bloco block lana uma das excees listadas quando
executado
assert_raise
(Exception, ...,
&amp;block)
assert_respond_to
Verifica se object responde a message com o mtodo object.re
spond_to?
(object, message)
assert_same(expected, Verifica se expected igual a actual com o mtodo expected.eq
ual?
actual)
assert_send(array)
Verifica se o valor de retorno do envio da mensagem array[
1] para o objeto array
[0], com o restante do array como parmetros, true
assert_throws
Verifica se a execuo do bloco block lana o smbolo expected com
o mtodo
(expected,
throw
&amp;block)
assert_not_equal
Verifica expected diferente de actual quando o operador ==
usado
(expected, actual)
assert_not_match
Verifica se a string string no casa a expresso regular regex
p
(regexp, string)
assert_not_nil
Verifica se object no nil

(object)
assert_not_same
ed.equal?
(expected, actual)
assert_nothing_raised
(Exception, ...,
&amp;block)
assert_nothing_thrown
(expected,
m o mtodo throw
&amp;block)
flunk(message = "Epic
Fail!")
skip(message = nil)
pass

Verifica se expected diferente de actual com o mtodo expect

Verifica se o bloco executado sem lanar as excees listadas


Verifica se o bloco executado sem lanar o smbolo expected co
Sempre falha o teste com a mensagem message
Faz com que o teste no seja executado
Faz com que o teste sempre passe

Criando e distribuindo gems


RubyGems o gerenciador de pacotes padro do Ruby. partir do Ruby 1.9,
comeou a ser distribudo como parte da standard library. Ele permite resolver
dependncias e resolve, inclusive, dependncias entre verses.
Cada pacote, chamado de gem, pode conter arquivos Ruby que podem ser carregados
pelo seu prprio cdigo. Voc pode instalar gems disponibilizadas por outros
desenvolvedores e pode criar e distribuir suas prprias gems com muita
facilidade. Atualmente existem mais 30 mil gems cadastradas no site http://
rubygems.org/, o site que hospeda os pacotes disponibilizados pela comunidade
Ruby.
A estrutura de uma gem
O arquivo mais importante de uma gem , sem dvida, o arquivo .gemspec. nele
que so definidas as informaes sobre como seu pacote ser distribudo. Este
arquivo contm o nome e verso da sua gem, arquivos que podem ser carregados,
informaes sobre os autores, dentre outras informaes.
Os cdigos que podem ser carregados ficam no diretrio lib. Caso sua gem inclua
arquivos executveis, eles devem ficar no diretrio bin. Uma estrutura muito
usada por conveno pode ser vista seguir:
example
Rakefile
bin
example
example.gemspec
lib
example
version.rb
example.rb
test
example_test.rb
Criando sua prpria gem
Neste captulo voc ver como distribuir a biblioteca Temperature, criada no
captulo anterior. O primeiro passo definir o arquivo .gemspec. Crie o
arquivo simple_temperature.gemspec1 na raz de seu projeto.
Download temperature/simple_temperature.gemspec
require "./lib/temperature/version"

Gem::Specification.new do |s|
s.name
= "simple_temperature"
s.version
= Temperature::Version::STRING
s.description = "Convert temperature between different units."
s.summary
= s.description
s.author
= "Nando Vieira"
s.email
= "fnando.vieira@gmail.com"
s.files
= Dir["lib/**/*"]
s.test_files = Dir["test/**/*"]
s.homepage
= "http://rubygems.org/gems/simple_temperature"
end
Nesta especificao, estamos definindo uma srie de informaes:
* o nome da gem, definido como simple_temperature
* a verso da gem, que vem do arquivo lib/temperature/version.rb e que ainda
no foi criado.
* uma pequena descrio sobre o que nossa gem faz e que pode ser exibida com o
comando gem list simple_temperature.
* os arquivos que compes a gem, que neste exemplo tudo o que est dentro do
diretrio lib.
* os arquivos de teste, que neste exemplo tudo o que est dentro do diretrio
test.
Crie o arquivo lib/temperature/version.rb.
Download temperature/lib/temperature/version.rb
class Temperature
module Version
MAJOR = 0
MINOR = 1
PATCH = 0
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
end
end
Sua gem j est pronta para ser empacotada. partir da raz do seu projeto,
execute o comando gem build simple_temperature.gemspec. Este comando ir gerar
o arquivo simple_temperature.gem, que o seu pacote, propriamente dito.
$ gem build simple_temperature.gemspec
Successfully built RubyGem
Name: simple_temperature
Version: 0.1.0
File: simple_temperature-0.1.0.gem
Para instalar a sua gem localmente, use o comando gem install
simple_temperature --local. Para ver mais detalhes sobre a instalao, use o
parmetro --verbose.
$ gem install simple_temperature --local
Successfully installed simple_temperature-0.1.0
1 gem installed
Agora, vamos nos certificar que est tudo funcionando. Voc pode fazer isso
atravs do IRB.
$ irb
>> require "temperature"

=> true
>> Temperature.new(60, :celsius).to_fahrenheit
=> 140.0
>>
Note que no estamos carregando a gem simple_temperature. Toda vez que voc usa
require, todos os arquivos das gems que esto no diretrio lib ficam
disponveis no $LOAD_PATH. Por isso podemos simplesmente carregar o arquivo
temperature.rb. Em uma situao normal, onde o nome do arquivo principal da gem
reflete o nome da prpria gem, isso no seria motivo de confuso.
Distribuindo sua gem
Como voc pode ver, uma vez que temos o arquivo .gem, podemos instalar nossa
biblioteca. Se voc passar este arquivo para qualquer desenvolvedor Ruby, ele
poder instal-la com o mesmo comando que voc utilizou, embora isso no seja
muito prtico.
Uma outra maneira distribuir sua gem publicamente atravs do site http://
rubygems.org/. Para fazer isso, voc precisar criar sua conta. Acesse o
endereo https://rubygems.org/users/new, informe seu e-mail, username e senha e
voc est pronto para continuar.
Execute o comando gem push simple_temperature-0.1.0.gem. Este comando ir
solicitar suas credenciais. Informe as mesmas que foram cadastradas no
RubyGems.org. Voc s precisar fazer isso desta vez; futuras publicaes sero
feitas automaticamente.
$ gem push simple_temperature-0.1.0.gem
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at http://rubygems.org/sign_up
Email: fnando.vieira@gmail.com
Password:
Pushing gem to https://rubygems.org...
Signed in.
Pushing gem to https://rubygems.org...
Successfully registered gem: simple_temperature (0.1.0)
A publicao da gem pode demorar alguns minutos. Para verificar se sua gem j
est disponvel execute o comando gem list simple_temperature -rd.
$ gem list simple_temperature -rd
*** REMOTE GEMS ***
simple_temperature (0.1.0)
Author: Nando Vieira
Homepage: http://rubygems.org/gems/simple_temperature
Convert temperature between different units.
Sua gem tambm pode ser acessada atravs do endereo https://rubygems.org/gems/
simple_temperature. Aproveite que voc acessou a pgina de sua gem e atualize
as outras informaes como endereo de onde as pessoas podero reportar bugs e
visualizar o cdigo-fonte.
Mais sobre RubyGems
Uma gem basicamente o que voc acabou de ver. No entanto, voc pode ir alm.
possvel, por exemplo, criar extenses nativas usando C.
Voc tambm pode criar o seu prprio servidor de gems, privado, onde s suas
aplicaes podem acessar. Desta forma, voc pode distribuir bibliotecas entre

os diversos aplicativos de sua empresa sem se preocupar com a privacidade e


segurana.
Para mais informaes sobre como fazer estas e outras coisas, visite o guia
publicado pelo site RubyGems.org no endereo http://guides.rubygems.org/.
1 Como a gem Temperature j existe, vamos usar um outro nome qualquer. Voc
provavelmente vai querer manter o nome do arquivo gemspec igual ao nome de sua
gem.
Copyright Hellobits &amp; Nando Vieira. Todos os direitos reservados.
Veja outras publicaes em http://howtocode.com.br.

You might also like