Ruby pequeno tutorial

download Ruby pequeno tutorial

of 88

Transcript of Ruby pequeno tutorial

  • 8/10/2019 Ruby pequeno tutorial

    1/88

    Conhecendo Ruby

    por Nando VieiraCopyright Hellobits & Nando Vieira. Todos os direitos reservados.Nenhuma parte desta publicao pode ser reproduzida sem o consentimento dosautores.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 extremamenteelegante, o que facilita a leitura e escrita de cdigos.Criada pelo japons Yukihiro_Matz_Matsumoto em meados de 1993, a linguagem sfoi lanada publicamente em 1995. Matz combinou partes de suas linguagensfavoritas (Perl, Smalltalk, Eiffel, Ada e Lisp) para criar uma linguagem quefosse, segundo suas_prprias_palavras, mais poderosa que Perl e mais orientadaa 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 possuemmtodos 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 comoinstalar em sua mquina de desenvolvimento. sempre uma boa ideia utilizar altima verso estvel do Ruby, a menos que voc tenha razes muito fortes parano 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 RubyInstaller. Acesse o endereo http://rubyinstaller.org/downloads/ e faa odownload do instalador da ltima verso estvel.Download do Ruby InstallerDownload do Ruby InstallerExecute o arquivo baixado, algo como rubyinstaller-1.9.3-p0.exe, e o instalarser iniciado. Aceite os termos de uso. Ser exibida, ento, uma janela ondevoc deve marcar a configurao Add Ruby executables to your PATH. Sem essaopo, o Ruby no ficar disponvel globalmente no seu terminal.

    Configurando o instaladorConfigurando o instaladorClique em Install e, depois, clique em Finish. Pronto! Voc j tem o Rubyinstalado. Para certificar-se que tudo est funcionando corretamente, abra oterminal. Para isso, clique no menu Windows e execute powershell paralistar o terminal. Execute o comando ruby -v para listar a verso do Ruby. Emverses mais antigas do Windows, voc pode usar o comando cmd. Se preferir,voc tambm pode instalar_o_PowerShell_manualmente.Usando o terminalUsando o terminal

  • 8/10/2019 Ruby pequeno tutorial

    2/88

    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 doRuby. Assim como no Mac OS X, execute o comando abaixo em seu terminal.

    bash -s stable < 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 exceoTypeError. 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 demtodos. Embora isso possa parecer algo muito ruim para quem est acostumadocom linguagens como Java, linguagens dinamicamente tipadas como o Ruby somuito flexveis, produtivas e, acredite, seguras. Na maioria das vezes, o medode no poder contar com o compilador para fazer verificaes de tipos no temfundamento.Desenvolvedores Ruby esto mais acostumados em definir objetos pelo que elespodem 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

  • 8/10/2019 Ruby pequeno tutorial

    3/88

    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 umobjeto, voc deve se preocupar se este objeto capaz de executar o mtodo quevoc precisa.Pegue como exemplo strings, arquivos e arrays. As classes Array, File e Stringimplementam o mtodo de instncia

  • 8/10/2019 Ruby pequeno tutorial

    4/88

    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 deexigir tipos de objetos, pergunte-se se isso realmente necessrio. s vezes,

    o tipo do objeto muito importante, mas muitas vezes isso simplesmente noimporta.

    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 selfself ser sempre uma referncia ao receiver atual e pode ser diferentedependendo do contexto em que voc estiver. Por exemplo, quando estamos nonamespace global, nosso self ser o objeto main. J em uma classe, nosso selfser 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 noreceiver padroself a menos que voc especifique-o explicitamente. E, pelofato de o receiver padro ser self, voc nem precisa especific-lo se noquiser.

    class Thing def do_something puts "doing something"

  • 8/10/2019 Ruby pequeno tutorial

    5/88

    end

    def do_something_else do_something end end

    No mtodo do_something_else poderamos usar self.do_something, mas isso fariacom que nosso cdigo apenas ficasse mais poludo. No entanto, definir oreceiver uma coisa muito comum e que, voc pode at no se dar conta, mas ofaz 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 armazenarvariveis 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 associadaao 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

  • 8/10/2019 Ruby pequeno tutorial

    6/88

    end

    john = Person.new("John Doe") Person.count #=> 1

    O exemplo acima mostra como variveis de instncia podem ser usadas emcontextos diferentes. Primeiro, estamos definindo um contador de instncias daclasse Person, cujo valor ser armazenado em @count. Depois, em nossa prpriainstncia, definimos o nome com a varivel @name.

    Convenes

    Os desenvolvedores Ruby seguem uma srie de convenes enquanto estoescrevendo seus cdigos. Embora voc no seja obrigado seguir essasconvenes, sempre uma boa ideia garantir que est escrevendo cdigos domesmo jeito que um desenvolvedor mais experiente.Confira neste captulo quais so as convenes mais utilizadas e evite olharesestranhos.

    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

  • 8/10/2019 Ruby pequeno tutorial

    7/88

    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 inseridascomo \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 osargumentos corretamente.

  • 8/10/2019 Ruby pequeno tutorial

    8/88

    # 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 estaracessando a prpria constante, que normalmente ser um mdulo ou classe.

    class Foo; end

    def Foo puts "You called the Foo method" end

    Foo.new #=> Instancia a classe Foo 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

  • 8/10/2019 Ruby pequeno tutorial

    9/88

    #=> Hello

    No entanto, se voc precisar encerrar o fluxo de execuo antes da ltimalinha, 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 instruoou 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 palavras-chave do..end.

    File.open("file.txt", "w+") do |file| file.write "Ruby" file.write " #nice" end

    Escrevendo sobre o RubyUma conveno do Ruby que usada em textos que mtodos estticos (aquelesque podem ser acessados diretamente em uma classe ou mdulo) so referenciadoscomo Modulo.metodo ou Modulo::metodo. Logo, se voc quiser escrever algumadocumentao ou texto que cita o mtodo enable do mdulo GC, voc deve escreverGC.enable ou GC::enable.J mtodos de instncia, como "Hello".upcase devem ser referenciados comoString#upcase.Esta conveno tambm utilizada para acessar a documentao atravs da linhade 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

  • 8/10/2019 Ruby pequeno tutorial

    10/88

    O Ruby vem com um shell REPL1 chamado Interactive Ruby (IRB). Ele fazexatamente o que o nome sugere: ele l uma linha, executa esta linha, exibe oresultado da execuo e faz o loop, esperando por uma nova linha. O IRB amelhor maneira de testar qPara iniciar o IRB, execute o comando irb.

    $ irb irb(main):001:0>

    Neste shell voc pode digitar qualquer cdigo Ruby. Experimente digitar algumaexpresso matemtica simples.

    irb(main):001:0> 1 + 1 => 2

    No Ruby, tudo3 objeto. Voc pode descobrir qual a classe de um objeto com omtodo 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 mtodoObject#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 omtodo 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, :=, :

  • 8/10/2019 Ruby pequeno tutorial

    11/88

    Perceba como o shell do IRB muda sua apresentao, de acordo com o nvel deindentao 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 deexpresses para se familiarizar com esta excelente ferramenta.

    Executando cdigos Ruby

    A maneira mais comum de escrever Ruby colocando cdigos em um ou maisarquivos. Normalmente, estes arquivos possuem a extenso .rb, embora voc possausar 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 ocaminho 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 determinaqual 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 +xhello.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 possaimaginar. 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, constantesclasses e mdulos da Standard Library (que j vem com o Ruby) e de cdigos dedesenvolvedores 3rd party.Para visualizar a documentao do mdulo GC, execute o comando ri GC.

    $ ri GC = GC

    (from ruby core)

  • 8/10/2019 Ruby pequeno tutorial

    12/88

    ----------------------------------------------------------------------------- - 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, porexemplo, 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

  • 8/10/2019 Ruby pequeno tutorial

    13/88

    GC.enable #=> true GC.enable #=> false

    1 Read-Eval-Print-Loop2 No se preocupe com o que so blocos por enquanto. Voc ver mais sobre esteassunto mais__frente.3 Na verdade, quase tudo no Ruby objeto. Algumas coisas no so objetosdiretamente, embora voc consiga acess-las de outras maneiras.

    Ruby Core Classes

    String

    Strings so sequncias de caracteres normalmente delimitadas por aspas ouapstrofos.

    hello = "Hello" ruby = 'Ruby'

    A diferena entre os dois delimitadores que os apstrofos ignoram caracterescomo \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 serinterpoladas. Interpolao o processo de definir uma expresso Ruby dentro deuma string, de modo que seu resultado substitua os delimitadores #{} queenglobam 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 sintaxeespecial.

    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

  • 8/10/2019 Ruby pequeno tutorial

    14/88

    heredoc, que possui duas variaes.

    text = 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 foremiguais 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 %

  • 8/10/2019 Ruby pequeno tutorial

    15/88

    #=> 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 querepresentam nmeros no Ruby so instncias da classe Numeric. Nmeros soimutveis e, por este motivo, no existem mtodos que podem mudar o valor de umnmero; se voc tentar fazer isso, receber a mensagem de erro Can't change thevalue of self.Em verses mais antigas do Ruby, as classes Complex e Rational no so nativasdo 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 intervalosentre -230e 230-1 ou -262e 262-1, inteiros so definidos como instncias daclasse Fixnum. Inteiros fora deste intervalo so automaticamente definidos comoobjetos 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 #=> 1234 0d1234 #=> 1234 - Base decimal, padro 1_234 #=> 1234 - Underscores so ignorados -1234 #=> -1234 - Negativo 0x4d2 #=> 1234 - Hexadecimal 02322 #=> 1234 - Octal 0b10011010010 #=> 1234 - Binrio

    Float

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

    puts 1.234 #=> 1.234 puts -1.234 #=> -1.234 - Negativo puts 1_234.0 #=> 1234.0 - Underscores so ignorados puts 12e2 #=> 1200.0 - 12.0 x 10e2

  • 8/10/2019 Ruby pequeno tutorial

    16/88

    puts 12.3e2 #=> 1230.0 - 12.3 x 10e2 puts 12.3E2 #=> 1230.0 - 12.3 x 10e2

    No Ruby, no possvel definir nmeros com ponto flutuante sem ter um nmeroantes do ponto decimal. Se voc tentar definir um nmero como .1 ir receberuma mensagem de erro como no . floating literal anymore; put 0 beforedot.Nmeros de ponto flutuante seguem a especificao IEEE-754, assim como amaioria das linguagens e hardwares do mercado. Dada a forma como os nmeros deponto flutuante so tratados, fraes como 1/10 e 1/100 no podem serrepresentadas corretamente. muito comum clculos como o exemplo seguircausarem 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 BigNumberso utilizados.

    BigDecimal

    A classe BigDecimal permite realizar clculos onde o arredondamento muitoimportante, como em clculos financeiros. Nmeros do tipo BigDecimal sopraticamente 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 dgitosdecimais que sero computados. Para ver a referncia completa, acesse adocumentao.

    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 objetoe no precisam ser criadas com tamanho determinado; novos tens podem seradicionados 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 podedizer com quantos tens o array deve ser iniciado. Por padro, o array seriniciado com o valor nil.

    items = Array.new(5) #=> [nil, nil, nil, nil, nil]

  • 8/10/2019 Ruby pequeno tutorial

    17/88

    Voc tambm pode passar um valor inicial que ser usado para popular estearray.

    items = Array.new(5, "hello") #=> ["hello", "hello", "hello", "hello", "hello"]

    Tambm possvel iniciar um array com um bloco. Neste caso, o valor retornadopelo 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 %wou %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 podemser acessados de forma negativa.

    numbers = Array.new(10) {|n| n * 2} #=> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

    numbers[0] #=> 0 numbers.first #=> 0 numbers[4] #=> 8 numbers[-1] #=> 18 - A mesma coisa que numbers[numbers.size - 1] numbers.last #=> 18

    Tambm possvel acessar intervalos passando dois nmeros.

    numbers[0, 2] #=> [0, 2] - partir do ndice 0, pegue dois elementos. numbers[-2, 2] #=> [16, 18] - partir do ndice size - 2, pegue dois elementos.

    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

  • 8/10/2019 Ruby pequeno tutorial

    18/88

    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 passaruma 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 queidentificam 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 atravsdo 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 ado JavaScript. Uma caracterstica dessa sintaxe que as chaves so geradascomo smbolos.

    user = {name: "John Doe", age: 32}

    user.keys #=> [:name, :age]

  • 8/10/2019 Ruby pequeno tutorial

    19/88

    Symbol

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

    symbol = :john symbol = :"john doe" symbol = "john".to_sym symbol = "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 lugaronde 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 classesTrueClass e FalseClass. Infelizmente, ambas as classes no possuem umasuperclasse comum.

    true.class

    #=> TrueClass false.class #=> FalseClass

    Os valores booleanos tambm podem ser acessados atravs das constantes TRUE eFALSE.

    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

  • 8/10/2019 Ruby pequeno tutorial

    20/88

    nil

    O Ruby define o tipo nulo atravs do do objeto nil, que uma instncia daclasse 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 queexplicitamente 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"

  • 8/10/2019 Ruby pequeno tutorial

    21/88

    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 ointervalo em array e depois verificar se o tem est includo com o mtodoArray#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 ocontedo de uma string. Elas podem ser utilizadas para verificar se uma stringcontm um determinado padro ou para extrair partes dessa string. Para criaruma 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 especialem expresses regulares. So os chamados metacaracteres: (, ), [, ], {, }, .,?, + e *.

    regex = /\Ahttps?:\/\//

    Perceba que estamos escapando a /. Este caracter em particular pode continuarsendo 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 verificarpadres que seriam difceis (e em alguns casos impossveis) de serem feitas deoutras maneiras. Se voc deseja aprender mais sobre assunto, leia o livroExpresses_Regulares:_uma_abordagem_divertida, escrito por Aurlio MarinhoJargas, e que est disponvel gratuitamente para leitura_online.

    Procs e lambdas

    Procs so blocos de cdigo que podem ser associados a uma varivel e quefuncionam como funes anonnimas. Muitas vezes voc precisa de um mtodoutilitrio que ir fazer algumas pequenas computaes onde criar um mtodopropriamente dito seria muito trabalho; a que entram as procs.

    Para definir uma nova proc, voc pode utilizar o mtodo Proc.new ou o mtodoKernel#proc.

    # alternativa 1 message = Proc.new { "Hello" }

    # alternativa 2 message = proc { "Hello" }

    Para executar essas procs voc pode utilizar trs mtodos diferentes.

  • 8/10/2019 Ruby pequeno tutorial

    22/88

    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 porchaves.

    message = proc { "One-line proc" }

    E, tambm por conveno, quando uma proc possuir mais de uma expresso elasdevem ser definidas pelas palavras-chave do..end.

    message = proc do puts "Hello!" puts "Ruby!" end

    Procs podem receber parmetros, assim como mtodos. Basta delimitar osparmetros 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 quefor executada. Se voc quiser encerrar o fluxo de execuo retornando um valorantes da ltima expresso, deve usar next, em vez do return utilizado pormtodos.

    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 alegibilidade do cdigo seja prejudicada.

  • 8/10/2019 Ruby pequeno tutorial

    23/88

    sum = -> n1, n2 { n1 + n2 } sum[1, 2] #=> 3

    Procs podem ser convertidas em blocos3. Basta adicionar um & na hora quepassar o bloco como parmetro.

    def sum(n1, n2, &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, &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, elespossui uma diferena muito importante. Lambdas iro validar a quantidade deparmetros que foram passados e lanaro a exceo ArgumentError: wrong numberof arguments caso o nmero de argumentos seja incorreto. J as procs iroatribuir 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 queexecutou 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 aoreturn.

    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

  • 8/10/2019 Ruby pequeno tutorial

    24/88

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

    Proc.new {}.arity #=> 0 Proc.new {||}.arity #=> 0 Proc.new {|a|}.arity #=> 1 Proc.new {|a,b|}.arity #=> 2 Proc.new {|a,b,c|}.arity #=> 3 Proc.new {|*a|}.arity #=> -1 Proc.new {|a,*b|}.arity #=> -2 Proc.new {|a,*b, c|}.arity #=> -3

    Para pegar uma representao dos parmetros que um bloco pode receber, use omtodo 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. Issopode ser facilmente resolvido com arrays e o mtodo Array#include? ouArray#uniq.

    items = [1, 2, 3]

    # alternativa 1: verificar se o tem existe antes de adicion-lo items #

  • 8/10/2019 Ruby pequeno tutorial

    25/88

    1 A Standard Library o conjunto de bibliotecas que vem com a instalao doRuby.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 acondicional. apenas uma maneira de executar um trecho de cdigo se algumacondio for satisfeita. Uma condio uma expresso que quando verificadaretorna um valor diferente de false e nil.O Ruby possui diferentes formas de expresses condies, como voc podeconferir 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 adicionarparnteses 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 formaior 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 maislegvel.

    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 porltimo.

  • 8/10/2019 Ruby pequeno tutorial

    26/88

    else

    O if pode conter uma clusula else, que ser executada quando a condio nofor satisfeita. Caso o valor expression seja igual a false ou nil, ento ocdigo 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 outrascondies, 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. Comoo valor de x 4, nenhuma das condies de nosso if ser satisfeita, o que fazcom que o valor original de name no seja alterado. No Ruby o mtodo inspectnormalmente retorna uma representao do self como uma string.

    unless

    Uma tendncia natural quando queremos executar alguma expresso somente se umacondio 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

  • 8/10/2019 Ruby pequeno tutorial

    27/88

    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; nestecaso, seria muito mais simples escrever um if que coloca a expresso a serexecutada 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) suportadopelo 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 emconsiderao a quantidade de tens. Se o count for igual a 1, uma string querepresenta o singular retornada. Caso contrrio, uma string que representa oplural 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

  • 8/10/2019 Ruby pequeno tutorial

    28/88

    case

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

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

    A palavra-chave then s necessria se voc quiser utilizar expresses namesma linha do comparador. Alternativamente, voc pode utilizar o caracter ;.A segunda forma ir receber um objeto que pode ser comparado com diversos tiposde expresses diferentes. Esse modo extremamente poderoso e permite fazercomparaes com expresses regulares, classes e intervalos.O exemplo anterior poderia ser expressado de uma forma um pouco menosrepetitiva.

    case x when 1 then "one" when 2 then "two" when 3 then "three" else "other" end

    O case tambm retorna o valor da expresso que for executada, podendo seratribuda a uma varivel.

    number = case x when 1 then "one" when 2 then "two"

    when 3 then "three" else "other" end

    Voc pode definir diversas comparaes em uma mesma expresso.

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

    O case usa o operador === para fazer as comparaes. Em alguns casos, esse

    operador exatamente o mesmo que ==. Mas em outros casos, como classes emdulos, o comportamento um pouco diferente. O operador === implementado1pelas classes e mdulos ir verificar se um objeto uma instncia desta classeou mdulo ou de um de seus descendentes.Vamos ver na prtica como funcionam os operadores String.=== e String#===.

    hello = "hello" one = 1

    String === hello

  • 8/10/2019 Ruby pequeno tutorial

    29/88

    #=> 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 irverificar se a classe daquela instncia a prpria classe ou um de seusdescendentes.

    value = "Hello"

    case value when String "A String was provided" else "Y U MAD BRO?" end

    J o operador === implementado pelas expresses regulares ir verificar se umdeterminado 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. Eleverifica 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 sejamuito mais poderoso que seu equivalente de outras linguagens.1 Sim! O operador === apenas um mtodo e voc pode defin-lo em seus prpriosobjetos.

  • 8/10/2019 Ruby pequeno tutorial

    30/88

    Estruturas de repetio

    O Ruby possui trs expresses que definem loops: for..in, while e until. Masalm deles, possvel usar iteradores em objetos enumerveis como arrays ehashes, alm de outros objetos.

    for..in

    O loop for..in permite iterar em objetos que so enumerveis, como o caso dearrays e hashes. A cada iterao, um elemento ser atribudo para a varivelespecificada. Sua sintaxe bastante simples:

    for item in collection # do something end

    Note que cada valor atribudo varivel pode ser acessado fora da expressofor..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 eo 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 comdois 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 desenvolvedoresRuby mais experientes costumam fazer. Mais frente voc ver como utilizar ositeradores em objetos enumerveis.

  • 8/10/2019 Ruby pequeno tutorial

    31/88

    while e until

    O while e until so as formas mais bsicas de looping do Ruby. Eles iroexecutar algum trecho de cdigo enquanto uma condio for verdadeira ou at queuma 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 executaralguma 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 tamanhofor menor que trs. O nmero que adicionado ser a quantidade de elementosmais 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 modificadorescom 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

  • 8/10/2019 Ruby pequeno tutorial

    32/88

    condio ser testada. Sendo assim, o bloco begin..end seguir sempre exibir amensagem OH NOES! THIS WILL BE DISPLAYED ANYWAY!.

    begin puts "OH NOES!" puts "THIS WILL BE DISPLAYED ANYWAY!" end while false

    Embora seja uma construo aceita pela linguagem, o uso de begin..end desencorajado e pode, inclusive, ser removido em verses futuras do Ruby. possvel ter um comportamento semelhante sem que voc caia nesta armadilha:basta delimitar 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 whiletrue. No entanto, o Ruby possui o loop, que ir executar indefinidamente umbloco.

    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 loopMuitas vezes necessrio controlar o fluxo de execuo de um loop. s vezes preciso interromper a execuo, outras preciso passar para o prximo tem daiterao em alguma condio especfica. O Ruby possui algumas maneiras de fazerisso.

    Interrompendo a execuo do loop

    Para encerrar um loop a qualquer momento, utilize a palavra-chave break. Issofar com que a execuo seja imediatamente interrompida.

    x = 0

    while x < 10 x += 1 puts x

    break if x == 3 end

    # Output: # 1

  • 8/10/2019 Ruby pequeno tutorial

    33/88

    # 2 # 3

    Pulando para a prxima iterao

    Para pular para a prxima iterao, utilize a palavra-chave next. Isso far comque 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 aexecuo 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 && number == numbers[-2] tries += 1 redo

    end end

    # Output: # number: 1, tries: 0 # number: 2, tries: 0 # number: 3, tries: 0 # number: 3, tries: 1 # number: 3, tries: 2 # number: 3, tries: 3 # number: 4, tries: 3

    Usando iteradores

    Embora loops como for..in, while/until e loop sejam teis para algumassituaes, mais provvel que voc escreva loops utilizando mtodos chamadositeradores. Os iteradores so provavelmente uma das funcionalidades maisimportantes do Ruby.Um dos exemplos mais comuns de iteradores do Ruby pode ser visto seguir.

    5.times { puts "Ruby!" }

  • 8/10/2019 Ruby pequeno tutorial

    34/88

    O mtodo Integer#times ir executar o bloco que foi fornecido 5 vezes. essetipo de construo do Ruby que faz com que a linguagem seja elegante.Existem outros iteradores numricos, que nada mais so que mtodos iteradoresimplementados pela classe Integer, assim como o mtodo Integer#times.O mtodo Integer#upto ir executar o bloco especificado o nmeros de vezes quefor 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 paraexecuo; 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 contagemde 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 fazeriteraes 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 devereceber um bloco e fazer o yield daquele bloco.A classe Array, por exemplo, implementa o iterador Array#each, o que permitepassar 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

  • 8/10/2019 Ruby pequeno tutorial

    35/88

    o mdulo Enumerable. Este mdulo adiciona muitos mtodos que agem em cima domtodo 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, spara citar alguns.O mtodo Enumerable#map permite criar um novo array contendo os elementosretornados pelo bloco.

    [1,2,3].map {|number| number * 2} #=> [2, 4, 6]

    O mtodo Enumerable#select permite criar um novo array contendo os elementoscujo 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 mtodoEnumerable#select e ir retornar um array contendo os elementos cujo valor dobloco 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 retornodo 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 vocviu at aqui. Ele permite passar um objeto que ser o acumulador e que irarmazenar o resultado de iteraes passadas. O bloco que foi fornecido pode ouno incrementar este acumulador, dependendo de suas condies. O acumuladordeve ser o valor de retorno do bloco.Veja, por exemplo, como retornar um nico nmero que ser a soma do dobro dosmltiplos 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 umaetapa. Um cdigo que faz a mesma coisa, mas de forma muito menos elegante, podeser 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 blocosquando falamos sobre objetos_enumerveis, no dedicamos tempo para explicar oque eles so.Blocos nunca podem estar sozinhos; eles sempre precisam estar associados a uma

  • 8/10/2019 Ruby pequeno tutorial

    36/88

    execuo de mtodo. Todo mtodo que executado pode receber um bloco, masapenas os mtodos que esperam este bloco e que faam o yield que iro de fatoexecut-los; caso contrrio, o bloco ser ignorado silenciosamente. Por baixodos panos, blocos so apenas procs.Assim como as procs, blocos seguem a conveno de se usar chaves para blocoscom 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 nodeve usar este termo para se referir a procs ou lambdas.

    Escopo de variveis

    Blocos introduzem um novo escopo de variveis. Toda vez que voc defineparmetros que sero recebidos pelo bloco, estas variveis sero acessveisapenas no contexto do bloco.

    O exemplo seguir mostra como a varivel i definida apenas no escopo localdo bloco.

    1.upto(5) {|i| } p defined?(i) #=> nil

    No entanto, blocos tambm podem referenciar variveis do contexto externo aobloco 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 modificamvariveis de mesmo nome que foram definidas no contexto externo ao bloco. Oexemplo seguir mostra exatamente isso. Este mesmo exemplo quando executado noRuby 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 esperamum. Para interagir com um bloco que foi passado, voc deve usar a palavra-chaveyield. Ela ir executar o bloco que foi passado ao mtodo.

    def say puts yield end

  • 8/10/2019 Ruby pequeno tutorial

    37/88

    say { "Hello" } #=> Hello

    O bloco ser executado toda vez que voc usar yield. Ento, se em um mesmomtodo voc usar trs vezes a palavra-chave yield, o bloco ser executado trsvezes.

    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 LocalJumpErrorser lanada. Para evitar que isto acontea, voc pode verificar se algum blocofoi 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 yieldpassando 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 decontrole, seja passando o bloco como parmetro para outro mtodo ou agindo comoproxy de um outro mtodo que tambm espera um bloco. O Ruby permite que voccapture blocos passados para mtodos usando a construo &variavel. A nicaexigncia que essa varivel deve ser sempre a ltima varivel da lista.

  • 8/10/2019 Ruby pequeno tutorial

    38/88

    O exemplo anterior poderia ser reescrito usando essa construo.

    def first_and_last(list, &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#callpassando os argumentos. Alternativamente, poderamos usar algum outro mtodoque executa procs, como Proc#[].

    Classes

    O Ruby, como voc pode perceber at agora, uma linguagem orientada a objetos.Tudo o que manipulamos no Ruby so objetos e cada objeto gerado direta ouindiretamente de uma classe. Classes definem os mtodos que objetos podemresponder. Elas tambm podem estender ou ser 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 setorne 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 jpodemos instnci-la. Para isso voc ir usar o mtodo Page.new.

    page = Page.new

    Mesmo no tendo definido atributos e mtodos, ns podemos executar algunsmtodos fornecidos pelas superclasses da classe Page. Voc pode, por exemplo,perguntar que tipo de objeto ele .

    page.class #=> Page

    page.is_a?(Page) #=> true

  • 8/10/2019 Ruby pequeno tutorial

    39/88

    As superclasses da classe Page implementam muitos outros mtodos. Para saberquais so as superclasses de uma classe, use o mtodo Class.ancestors. Note quea 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 como mtodo construtor. No Ruby, o mtodo construtor Class#initialize. Estemtodo definido automaticamente como privado e no pode ser executadodiretamente de fora do objeto.Vamos fazer o mtodo Page#initialize receber dois argumentos que iro definir ottulo 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 comovariveis 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 [email protected] mtodo Page#initialize define duas variveis de instncia, que receber osargumentos passados no momento da instanciao. No entanto, ainda no temosnenhuma 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 acessadasdiretamente. Variveis de instncia so encapsuladas de tal forma que apenas osmtodos 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 #

    Para acessar estas variveis de instncia que foram definidas no nosso mtodoconstrutor, voc precisa definir mtodos que iro retorn-las. Embora o nome domtodo no precise necessariamente refletir o nome da varivel, sempre umaboa 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

  • 8/10/2019 Ruby pequeno tutorial

    40/88

    end

    Agora ns j podemos acessar as variveis armazenadas na instncia da classePage.

    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 semser pelo mtodo construtor. Para fazer isso, preciso definir mtodos setters.Em outras linguagens, normalmente isso feito com um mtodo setTitle(title) ouset_title(title), ou algo parecido. No Ruby, voc pode definir o seu prpriomtodo 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 mtodossetters.

    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 Rubyfornece uma maneira de automatizar esta definio. Basta usar os mtodosModule#attr_reader e Module#attr_writer2.

    class Page

  • 8/10/2019 Ruby pequeno tutorial

    41/88

    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 deinstncia de escrita (setter). Para os casos onde voc sempre define tanto ogetter quanto o setter, possvel usar o mtodo Module#attr_accessor, que farisso 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 apenasgetters 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 deinstncia de nomes diferentes.Alternativamente, voc pode fazer com que o mtodo construtor use os mtodosPage#title= e Page#content=, em vez de atribuir as variveis de instncia. Umerro 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 mtodossetters.

    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

  • 8/10/2019 Ruby pequeno tutorial

    42/88

    A atribuio direta das variveis de instncia mais rpida que executar osmtodos atravs do receiver. A menos que voc manipule as variveis no mtodosetter 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 deestticos. No Ruby, eles so apenas mtodos adicionados a um objeto que umainstncia 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 comos 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. Omtodo 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 dainstruo class..end, o self faz referncia prpria classe. Por isso, umaabordagem mais comum usada por desenvolvedores mais experientes definir

    mtodos de classe usando def self.load(file)..end, em vez de usar o nome daprpria 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, oself faz referncia a prpria classe), ns podemos fazer mais uma alterao. Emvez de instanciar a classe Page.new, basta executar o mtodo new diretamente.

  • 8/10/2019 Ruby pequeno tutorial

    43/88

    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. Vamosadicionar 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

    endA biblioteca YAML injeta um mtodo Object#to_yaml, que retorna uma stringrepresentando aquele objeto. No nosso caso, ele ir retornar algo como a stringabaixo.

    --- !ruby/object:Page title: Ruby content: OMG! I'm learning Ruby!

    Como a representao em YAML inclui a informao sobre qual classe este objetofoi instanciado, no precisamos mais fazer isso manualmente no mtodoPage#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

  • 8/10/2019 Ruby pequeno tutorial

    44/88

    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 dosmtodos 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 # mtodos so pblicos por padro end

    private # todos os mtodos definidos partir daqui sero privados def method2 end

    protected # todos os mtodos definidos partir daqui sero protegidos def method3 end

    public # todos os mtodos definidos partir daqui sero pblicos def method4 end end

    Alternativamente voc poderia ter definido a visibilidade dos mtodos passandouma lista de nomes de mtodos.

    class SomeClass def method1 end

    def method2 end

    def method3 end

  • 8/10/2019 Ruby pequeno tutorial

    45/88

    def method4 end

    public :method1, :method4 private :method2 protected :method3 end

    O controle de acesso determinado dinamicamente. Somente quando o mtodo forexecutado que o controle de acesso ser determinado. Se a visibilidade destemtodo 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 #

    Voc pode contornar o controle de acesso de mtodos utilizando o mtodoObject.__send__.

    object.__send__ :some_private_method # nenhuma exceo lanada

    Para garantir que mensagens sejam enviadas apenas para mtodos pblicos, use omtodo 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 #

    Definindo constantes

    Muitas classes podem usar constantes para armazenar informaes que poderiamficar espalhadas pelo cdigo, como nmeros mgicos. Vamos alterar a classePage de modo que ela possa receber tambm um permalink, uma representao decomo 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 }

  • 8/10/2019 Ruby pequeno tutorial

    46/88

    end end

    Vamos renomear o mtodo Page#save_to para Page#save. Este mtodo ir salvar osarquivos sempre em um mesmo diretrio, usando o atributo permalink como nome doarquivo.

    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 euma classe annima, escondida, especfica do objeto. Esta classe annima chamada de Singleton Class, mas antes de ter um nome oficial tambm era chamadade anonymous class, metaclass, eigenclass ou ghost class.

  • 8/10/2019 Ruby pequeno tutorial

    47/88

    O nome Singleton usado pelo Ruby nada tem a ver com o Singleton Pattern, quetambm est disponvel com a biblioteca Singleton.A sintaxe mais comum para acessar a classe Singleton class

  • 8/10/2019 Ruby pequeno tutorial

    48/88

    #=> []

    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 ["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 omtodo Marshal.dump, j que a biblioteca Marshal3 no suporta objetos comclasses Singleton (ela ir lanar a exceo TypeError: singleton can't bedumped). 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 sintaxecomo def object.some_method; end, perceba que exatamente isso que fazemosquando 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"]

  • 8/10/2019 Ruby pequeno tutorial

    49/88

    Com base nesse exemplo, possvel afirmar que mtodos de classe no existem noRuby! Pelo menos no no sentido de mtodos estticos! O que acontece queestes mtodos pertencem a um objeto, que por acaso uma classe.1 Classes criadas dinamicamente podem ser atribudas a qualquer tipo devarivel, e no apenas a constantes.2 A classe Class possui a classe Module como superclasse. Para saber mais sobremdulos, leia Mdulos.3 A biblioteca Marshal permite converter objetos Ruby em uma sequncia de bytesque podem ser restaurados por outros scripts, que podem reconstituir os objetosoriginais.

    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# Ruby is nice!

    puts "Ruby" Ruby is nice!

    puts "Ruby".concat(" is nice!") #=> Ruby is nice!

    Embora os trs mtodos atingem o objetivoconcatenar strings, existe umadiferena muito importante. O mtodo String#+ ir criar um novo objeto emmemria, enquanto os mtodos String# Hello Ruby: 70310699719020

    puts "#{hello}: #{hello.object_id}" #=> Hello: 70310699719100

    hello

  • 8/10/2019 Ruby pequeno tutorial

    50/88

    language = "Ruby" puts "#{language} is nice!" #=> Ruby is nice!

    O Ruby tambm suporta outros tipos de formatao de strings que tambm permiteminterpolar expresses. o caso dos mtodos String#%, Kernel#printf eKernel#sprintf. Estes mtodos permitem ter maior controle no espaamento eformatao de nmeros. Alm disso, eles permitem desacoplar os valores quedevem ser interpolados da string, facilitando, por exemplo, ainternacionalizao de strings.A mesma string que foi interpolada acima pode ser formatada com os mtodosmencionados.

    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 podeacabar confuso quando a lista de parmetros muito grande. Neste caso, prefirausar 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" % 1.5 #=> 1 - nmero inteiro "%f" % 1.1245 #=> 1.124500 - ponto-flutuante com todos os nmeros "%.2f" % 1 #=> 1.00 - ponto-flutuante com duas casas decimais

    "%x" % 1234 #=> 4d2 - hexadecimal com letras minsculas "%X" % 1234 #=> 4D2 - hexadecimal com letras maisculas "%o" % 1234 #=> 2322 - nmero inteiro ctal "%e" % 1234 #=> 1.234000e+03 - nmero exponencial "%E" % 1234 #=> 1.234000E+03 - nmero exponencial em maiscula "%b" % 1234 #=> 10011010010 - nmero binrio

    Para saber mais sobre os formatos aceitos, acesse a documentao; bastaexecutar 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 mtodoString#downcase.

    text = "RUBY IS NICE!" puts text.downcase

  • 8/10/2019 Ruby pequeno tutorial

    51/88

    #=> ruby is nice!

    Note que os mtodos String#upcase e String#downcase iro retornar uma novastring. Para alterar a string existente, utilize os mtodos String#upcase! eString#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 ouString#length. Note que esses mtodos iro retornar a quantidade de caracteres.Se voc precisa saber a quantidade de bytes necessrios para representar astring, 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 omtodo String#[].Em verses anteriores ao Ruby 1.9, o mtodo String#[] com um nmero inteiroretorna a representao numrica daquela posio, o que nem sempre reflete arepreseno de caracteres com mais de um byte.A maneira mais simples passar um nmero inteiro que identifica o caracter queser 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 quea 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. Nestecaso, voc pode passar um Range. Note que voc tambm pode utilizar intervaloscom 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

  • 8/10/2019 Ruby pequeno tutorial

    52/88

    primeiro resultado ser retornado.

    text = "Ruby is nice!" text[/ruby/i] #=> Ruby

    Voc pode especificar o nmero ou nome do grupo quando estiver usando umaexpresso regular.

    text = "ruby RUBY rUbY Ruby" text[/(ruby) (ruby) (ruby) (ruby)/i, 2] #=> RUBY text[/(ruby) (?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 dasstrings, que agora so verdadeiramente sequncias de caracteres que no

    precisam estar contidas na tabela de caracteres ASCII. Caracteres definidoscomo UTF-8, por exemplo, que usam um nmero varivel de bytes para representaros 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 acaracteres multibytes. Quando uma string contm caracteres multibytes, aquantidade de bytes usados para represent-la no ser a mesma do nmero decaracteres.

    # -*- 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 noarquivo. Esse comentrio chamado de magic comment e sem ele o Ruby nosaberia decidir qual codificao utilizar. O magic comment pode ser qualquerstring que consiga ser casada pela seguinte expresso regular2. Magic commentsdevem 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 doarquivo.

    # 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 noser necessariamente a mesma.

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

  • 8/10/2019 Ruby pequeno tutorial

    53/88

    #=> ISO-8859-1

    Nem todas as strings so compatveis entre diferentes codificaes. Toda vezque 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 doscaracteres 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 mtodoString#force_encoding. Este mtodo no faz qualquer verificao ou converso decaracteres; apenas muda a interpretao que o Ruby faz dos caracteres, mas semalterar os bytes que representam a string. Para validar se os bytes daquela

    string so vlidos na codificao escolhida, utilize o mtodoString#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 omtodo String#codepoints. Este mtodo espera um bloco, mas voc pode utilizar omtodo 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 arepresentao 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 umarray.

    "hello".bytes.to_a #=> [104, 101, 108, 108, 111]

    "ma".bytes.to_a #=> [109, 97, 195, 167, 195, 163]

  • 8/10/2019 Ruby pequeno tutorial

    54/88

    "".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 bytespara ser representada.Para acessar a lista de codificaes disponveis no Ruby, utilize o mtodoEncoding.list. Algumas codificaes possuem um alias, cuja listagem completapode ser retornada pelo mtodo Encoding.aliases. O cdigo seguir far ooutput das codificaes disponveis com seus respectivos aliases.

    list = Encoding.list.collect do |encoding| info = encoding.name alias_name = Encoding.aliases.key(encoding.name) info

  • 8/10/2019 Ruby pequeno tutorial

    55/88

    * 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)

  • 8/10/2019 Ruby pequeno tutorial

    56/88

  • 8/10/2019 Ruby pequeno tutorial

    57/88

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

    Felizmente a classe Integer implementa dois mtodos que permitem fazer a mesmaverificao, 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? #=> false 1.nonzero? #=> true

    0.zero? #=> true 0.nonzero? #=> 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) #=> 10011010010 1234.to_s(8) #=> 2322 1234.to_s(10) #=> 1234 - base 10 o padro 1234.to_s(16) #=> 4d2 1234.to_s(36) #=> ya

    O valor retornado ser uma string que pode ser convertida novamente em nmerocom o mtodo String#to_i.

    "10011010010".to_i(2) #=> 1234 "2322".to_i(8) #=> 1234

    "1234".to_i(10) #=> 1234 - base 10 o padro "4d2".to_i(16) #=> 1234 "ya".to_i(36) #=> 1234

    Fazendo arredondamentos

    O Ruby possui dois mtodos que permitem arredondar nmeros de ponto flutuantespara inteiros. O mtodo Float#ceil ir arredondar para o prximo nmero inteiromaior 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 ouigual 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

  • 8/10/2019 Ruby pequeno tutorial

    58/88

    casas decimais que foram especificadas. Por padro, a preciso zero e podeser um nmero negativo (nesse caso, o nmero retornado ser um inteiro).

    1.4.round #=> 1 1.5.round #=> 2 1.6.round #=> 2 -1.5.round #=> -2

    1.234567.round(2) #=> 1.23 1.234567.round(3) #=> 1.235 1.234567.round(4) #=> 1.2346 1.234567.round(5) #=> 1.23457

    12345.67.round(-5) #=> 0 12345.67.round(-4) #=> 10000 12345.67.round(-3) #=> 12000 12345.67.round(-2) #=> 12300 12345.67.round(-1) #=> 12350 12345.67.round(0) #=> 12346

    Tambm possvel fazer o truncamento de um nmero de ponto flutuante parainteiro.

    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 permiteretornar um valor padro caso o ndice especificado no exista.

    items = [1, 2, 3] items.fetch(0) #=>