You are currently browsing the category archive for the 'Ruby' category.
Palavras-chave: Ruby, código fonte, ruby2ruby
Podemos obter o código de um método como uma String usando a gem ruby2ruby:
require "rubygems"
require "ruby2ruby"
class Teste
def metodo
puts "oi!"
end
end
teste = Teste.new
metodo = teste.method(:metodo)
puts metodo.to_ruby
Rodando o código:
$ ruby r2r.rb
def metodo
puts("oi!")
end
Vale mencionar que isso só funciona nos métodos de uma instância.
Palavras-chave: Ruby, array
Para contar a frequência com que os valores de um array se repetem, podemos utilizar:
array = %w(morango abacaxi banana morango pera morango abacate banana)
p array.inject(Hash.new(0)) {|memo,value| memo[value] += 1; memo}
Será retornada uma hash com os valores como chave e a frequência de repetição como valores.
O segredo é usar uma hash com valor default e retorná-la no final do bloco do inject. Rodando o programa vamos ter:
{"banana"=>2, "abacate"=>1, "pera"=>1, "abacaxi"=>1, "morango"=>3}
Palavras-chave: Ruby, array, divide
Suponha que você tenha um array de X elementos e precise dividi-lo em arrays com Y elementos cada. A flexibilidade de Ruby nos permite definir operadores novos para as classes, então vamos criar um operador de dividir (/) para a classe Array:
class Array
def / len
inject([]) do |ary, x|
ary << [] if [*ary.last].nitems % len == 0
ary.last << x
ary
end
end
end
Vamos rodar agora com alguns arrays para ver o que aconteceu:
p (1..10).to_a / 2 => [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] p %w(hiro ando nikki jessica sylar) / 2 => [["hiro", "ando"], ["nikki", "jessica"], ["sylar"]] p (1..10).to_a / 4 => [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
Vamos analisar cada caso:
- Aqui temos um array de 10 elementos e dividimos por 2, retornando vários arrays com 2 elementos.
- Aqui temos um array ímpar de 5 elementos que dividimos por 2, retornando dois arrays com 2 elementos e um último com apenas um elemento (deixa aquele cara longe!).
- Aqui temos um array de 10 elementos que é dividido por 4, retornando dois arrays com 4 elementos e um último array com 2 elementos.
Ou seja, sempre que o resultado da divisão não for exata, temos o resto no último elemento retornado. As expressões que usei acima do tipo (1..10).to_a nada mais fazem do que converter uma Range em um Array.
O código do método “/” é meio críptico, mas se eu tentar explicar aqui vai ficar meio comprido e vou levar uma bronca, então dêem uma queimada nos neurônios aí. ;-)
Palavras-chave: Ruby, método, nome, corrente, method, current
Se você quiser saber o nome do método onde se encontra, terá que criar um outro método que quando chamado descubra o nome do método que o chamou. Assim:
class MinhaClasse
def self.nome_do_metodo
caller.first
end
def self.meu_metodo
puts "Estou no método '#{nome_do_metodo}'"
end
end
MinhaClasse.meu_metodo =>
Estou no método 'method_name.rb:6:in `meu_metodo''
No retorno acima, veio o nome do arquivo “method_name.rb” e logo após, o nome do método de onde imprimi a mensagem: “meu_metodo”.
Usando expressões regulares é possível filtrar essa mensagem, para torná-la mais amigável. Como Ruby permite que alteremos até as classes básicas da linguagem (dê um tiro no pé apenas se você quiser!), vamos gerar um método do Kernel para que possamos usá-lo globalmente:
module Kernel
def nome_do_metodo
caller.first =~ /`([^']*)'/ and $1
end
end
class MinhaClasse
def self.meu_metodo
puts "Estou no método '#{nome_do_metodo}'"
end
end
class OutraClasse
def self.meu_outro_metodo
puts "Estou no método '#{nome_do_metodo}'"
end
end
MinhaClasse.meu_metodo => Estou no método 'meu_metodo'
OutraClasse.meu_outro_metodo => Estou no método 'meu_outro_metodo'
Explicando:
A chamada em caller.first retorna de onde o método foi chamado (justamente o método que queremos saber o nome), e compara com a expressão regular para ver se achou algum nome de método no final.
Ali é feito um “curto-circuito” onde é testado se a expressão regular “casou”, fazendo um and lógico com a última condição avaliada, que no caso, é $1.
Esse $1 é a primeira variável de Ruby que traz o conteúdo que “casou” da expressão regular. Se não casou, a segunda parte do and nem é avaliada e é retornado nil. Se casou, é retornada a parte que casou, que nesse caso, é o nome do método que queremos.
Palavras-chave: Ruby, Fixnum, object_id
Uma jogada legal com objetos do tipo Fixnum em Ruby é descobrir o valor do objeto através do seu object_id, fazendo um simples deslocamento binário:
n = 123456 n.object_id >> 1 => 123456
Palavras-chave: Ruby, Fixnum, object_id
Em Ruby podemos facilmente verificar se um objeto é da classe Fixnum através do seu object_id (os números podem variar):
s = "oi" s.object_id => -605527578 n = 123456 n.object_id => 246913 s.object_id & 0x1 => 0 n.object_id & 0x1 => 1
Fazendo um and com o object_id e 0×1, somente os objetos da classe Fixnum irão retornar 1.
Palavras-chave: ruby, array, hash, splat
Podemos converter facilmente um array com um número de elementos pares para uma hash da seguinte maneira:
array = %w(um 1 dois 2 tres 3) hash = Hash[*array] p hash
Executando o código:
{"tres"=>"3", "um"=>"1", "dois"=>"2"}
Convém prestar atenção no *, que nesse caso recebe o apelido carinhoso de operador splat. Ele vai “abrir” o array para o método [] da hash.
Se esquecermos de usar o * o método vai reclamar dizendo que recebeu um valor ímpar para a hash (e recebeu mesmo, apenas um array).
Palavras-chave: Ruby, hash, default, blocos
Em Ruby podemos permitir que um valor default seja retornado na tentativa de acesso à um elemento que não existe ainda em uma hash, dessa maneira:
hash = Hash.new(0) puts hash["abobora"] 0 puts hash["batata"] 0
Mais interessante ainda é criarmos o valor de um elemento que não existe através da execução de um bloco de código. Vamos supor que queremos uma hash que contenha a data de criação de domínios, a qual terá como chave a URL do domínio e a data de criação como valor, retornado após uma consulta à uma determinada URL:
require "open-uri"
hash = Hash.new do |hash,url|
html = open("http://reports.internic.net/cgi/whois?
whois_nic=#{url}&type=domain").read
hash[url] = html.grep(/Creat/i).join.split(/:/,2)[1].strip.chomp
end
hash["eustaquiorangel.com"]
hash["codare.net"]
hash["ruby-lang.org"]
hash.each {|url,date| puts "#{url}: #{date}"}
O resultado será:
codare.net: 19-sep-2006 ruby-lang.org: 16-Sep-1999 09:28:50 UTC eustaquiorangel.com: 13-jul-2006
Palavras-chave: object_id, negativo, __id__
Em Ruby, bem como em outras linguagens que trabalham orientadas a objetos, existe o conceito do ObjectID (ou id de objeto), que nada mais é do que uma identificação única para um objeto instanciado dentro de uma aplicação.
Para ter acesso ao ObjectID em Ruby basta utilizar o método object_id ou __id__. De acordo com a própria documentação da linguagem, o método retorna “um identificador inteiro do objeto. Esse número será retornado em todas as chamadas ao objeto e dois objetos ativos nunca compartilharão o mesmo id.”
Nada demais. Contudo, existe uma peculiaridade nessa definição que às vezes é passada despercebida:
$ ruby -e "class Foo; end; f = Foo.new; p f; puts f.object_id;" #<Foo:0xb7d921c8> -605253404
O trecho de código acima cria uma instância da class Foo e imprime o endereçamento da memória onde o objeto foi alocado, juntamento com seu respectivo ObjectID. Observou o número negativo? Ele é a representação inteira da posição da memória do objeto. (0xb7d921c8 <-> -605253404).
Assim, o ObjectID em Ruby é sempre um número inteiro, positivo ou negativo.
Palavras-chave: ruby, bloco, objeto, contexto
Um meio de executar um bloco dentro do contexto de um determinado objeto é adicionar um método direto no módulo Kernel do Ruby. Ele aceitará ser chamado diretamente como método do objeto ou passando o objeto como parâmetro:
module Kernel
def with(obj=nil,&block)
(obj || self).instance_eval &block
end
end
(0..5).with { puts "#{min}/#{max}" }
with("TaQ") do
puts "Oi, #{self}!"
puts "Seu gêmeo malvado se chama #{self.reverse}."
end
[1,2,3,4,5].with do
puts "Número aleatório de #{min} a #{max}: #{self[rand(size)]}"
end
A dica foi inspirada em outras pairagens, mas é boa e merecia uma referência (copião na cara dura). ;-)
Palavras-chave: Ruby, array, caracteres, byte
Para gerar um array com todos os caracteres de uma string em Ruby, nada mais simples que:
irb(main):001:0> "TaQ".scan(/./) => ["T", "a", "Q"]
Se quisermos um array com o código do byte, podemos utilizar:
irb(main):002:0> "TaQ".unpack("c*")
=> [84, 97, 81]
Palavras-chave: Ruby, conversão, binária
É muito fácil fazer conversões de uma string binária para um número e vice-versa em Ruby:
irb(main):001:0> i = "11111111".to_i(2) => 255 irb(main):002:0> i.to_s(2) => "11111111"
Os métodos to_i e to_s, com a base desejada (2), fazem o trabalho perfeitamente.
Palavras-chave: strings, otimização, concatenação
Para fazer uma concatenação de strings sem perder a performance do seu programa em Ruby, ao invés de fazer
s = ""
puts ObjectSpace.each_object(String){}
1000.times {s += "x"}
puts ObjectSpace.each_object(String){}
puts s.length
faça
s = ""
puts ObjectSpace.each_object(String){}
1000.times {s << "x"}
puts ObjectSpace.each_object(String){}
puts s.length
O operador << funciona adicionando a nova string no objeto corrente, sem criar um novo a cada chamada igual o +=.
Rodando esses dois programas vamos ter:
160 2161 1000 e 160 1161 1000
Uau! de 2161 para 1161 strings alocadas é uma boa vantagem. Vamos rodar usando o profiler do Ruby para vermos a diferença “nas internas” (somente as linhas que interessam):
% cumulative self self total time seconds seconds calls ms/call ms/call name 40.00 0.05 0.02 1000 0.02 0.02 String#+ e % cumulative self self total time seconds seconds calls ms/call ms/call name 75.00 0.03 0.03 1000 0.03 0.03 String#<<
Já tivemos alguma diferença nos milissegundos ali. Reparem que += gasta 40% do tempo e << 75%, mas mesmo assim é mais rápido (resultados variáveis!). O garbage collector agradece. ;-)
Agora, se a string adicionada for sempre a mesma, que tal se fizermos:
s = ""
x = "x"
puts ObjectSpace.each_object(String){}
1000.times {s << x}
puts ObjectSpace.each_object(String){}
puts s.length
Rodando o programa:
162 163 1000
O resultado no profiler vai ser praticamente igual, mas que economia de strings, hein?
Palavras-chave: HTML, escape, escapar, cgi
Para “escapar” e “desescapar” caracteres especiais HTML:
require "cgi"
s = CGI.escapeHTML("a > x && y < 0")
puts s
puts CGI.unescapeHTML(s)
Rodando:
a > x && y < 0 a > x && y < 0
Palavras-chave: instance, object, objeto, eval, runtime, variable, variável, atributo
Vamos supor que você deseja criar atributos para o seu objeto no runtime, lendo, por exemplo, as propriedades do objeto em um arquivo. Vamos testar com um hash simulando o arquivo:
class Carro
end
carro = Carro.new
{:cor=>"azul",:modelo=>"Gol",:ano=>1995}.each do |key,value|
carro.instance_variable_set("@#{key}",value)
carro.instance_eval("def #{key}; @#{key}; end")
carro.instance_eval("def #{key}=(v); @#{key}=v; end")
end
puts carro.inspect
Rodando o programa:
#<Carro:0xb7d5674c @cor="azul", @ano=1995, @modelo="Gol">







Comentários Recentes