it-swarm-pt.tech

Recursos ocultos de Ruby

Continuando o meme "Recursos ocultos de ...", vamos compartilhar os recursos menos conhecidos mas úteis da Ruby.

Tente limitar esta discussão com o Ruby principal, sem nenhum material Ruby on Rails.

Veja também:

(Por favor, apenas um recurso oculto por resposta.)

Obrigado

160
squadette

From Ruby 1.9 Proc # === é um apelido para a chamada Proc #, o que significa que os objetos Proc podem ser usados ​​em declarações de caso como estas:

def multiple_of(factor)
  Proc.new{|product| product.modulo(factor).zero?}
end

case number
  when multiple_of(3)
    puts "Multiple of 3"
  when multiple_of(7)
    puts "Multiple of 7"
end
80
Farrel

Peter Cooper tem um boa lista de Ruby truques. Talvez o meu favorito dele seja permitir que itens e coleções individuais sejam enumerados. objeto de coleção como uma coleção que contém apenas esse objeto.) É assim:

[*items].each do |item|
  # ...
end
76
James A. Rosen

Não sei o quanto isso está oculto, mas achei útil ao precisar criar um Hash a partir de uma matriz unidimensional:

fruit = ["Apple","red","banana","yellow"]
=> ["Apple", "red", "banana", "yellow"]

Hash[*fruit]    
=> {"Apple"=>"red", "banana"=>"yellow"}
64
astronautism

Um truque que eu gosto é usar o splat (*) expansor em objetos que não sejam Arrays. Aqui está um exemplo de uma correspondência de expressão regular:

match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)

Outros exemplos incluem:

a, b, c = *('A'..'Z')

Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
54
tomafro

Uau, ninguém mencionou o operador flip-flop:

1.upto(100) do |i|
  puts i if (i == 3)..(i == 15)
end
52
Konstantin Haase

Uma das coisas legais sobre Ruby é que você pode chamar métodos e executar código em locais que outras linguagens desaprovariam, como nas definições de método ou classe).

Por exemplo, para criar uma classe que tem uma superclasse desconhecida até o tempo de execução, ou seja, é aleatória, você pode fazer o seguinte:

class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample

end

RandomSubclass.superclass # could output one of 6 different classes.

Isso usa o 1.9 Array#sample método (somente na versão 1.8.7, consulte Array#choice), e o exemplo é bastante artificial, mas você pode ver o poder aqui.

Outro exemplo interessante é a capacidade de colocar valores de parâmetro padrão que não são fixos (como outros idiomas costumam exigir):

def do_something_at(something, at = Time.now)
   # ...
end

Obviamente, o problema com o primeiro exemplo é que ele é avaliado no momento da definição, não no tempo de chamada. Assim, uma vez escolhida uma superclasse, ela permanece nessa superclasse pelo restante do programa.

No entanto, no segundo exemplo, sempre que você chamar do_something_at, a variável at será a hora em que o método foi chamado (bem, muito, muito próximo a ele)

49
Bo Jeanes

Outro pequeno recurso - converta um Fixnum em qualquer base até 36:

>> 1234567890.to_s(2)
=> "1001001100101100000001011010010"

>> 1234567890.to_s(8)
=> "11145401322"

>> 1234567890.to_s(16)
=> "499602d2"

>> 1234567890.to_s(24)
=> "6b1230i"

>> 1234567890.to_s(36)
=> "kf12oi"

E, como Huw Walters comentou, converter para o outro lado é igualmente simples:

>> "kf12oi".to_i(36)
=> 1234567890
47
tomafro

Hashes com valores padrão! Uma matriz neste caso.

parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []

parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"

Muito útil em metaprogramação.

40
August Lilleaas

Faça o download Ruby 1.9, e edite make golf, então você pode fazer coisas assim:

make golf

./goruby -e 'h'
# => Hello, world!

./goruby -e 'p St'
# => StandardError

./goruby -e 'p 1.tf'
# => 1.0

./goruby19 -e 'p Fil.exp(".")'
"/home/manveru/pkgbuilds/Ruby-svn/src/trunk"

Leia o golf_prelude.c para coisas mais legais se escondendo.

39
manveru

Outra adição divertida na funcionalidade 1.9 Proc é o Proc # curry, que permite transformar um Proc que aceita n argumentos em um que aceita n-1. Aqui é combinado com a dica Proc # === que mencionei acima:

it_is_day_of_week = lambda{ |day_of_week, date| date.wday == day_of_week }
it_is_saturday = it_is_day_of_week.curry[6]
it_is_sunday = it_is_day_of_week.curry[0]

case Time.now
when it_is_saturday
  puts "Saturday!"
when it_is_sunday
  puts "Sunday!"
else
  puts "Not the weekend"
end
38
Farrel

Operadores booleanos em valores não booleanos.

&& e ||

Ambos retornam o valor da última expressão avaliada.

É por isso que o ||= atualizará a variável com o valor retornado pela expressão no lado direito se a variável for indefinida. Isso não está explicitamente documentado, mas o conhecimento comum.

No entanto, o &&= não é tão amplamente conhecido.

string &&= string + "suffix"

é equivalente a

if string
  string = string + "suffix"
end

É muito útil para operações destrutivas que não devem prosseguir se a variável não estiver definida.

35
EmFi

A função Symbol # to_proc que Rails fornece é muito legal.

Ao invés de

Employee.collect { |emp| emp.name }

Você pode escrever:

Employee.collect(&:name)
29
hoyhoy

Uma final - em Ruby você pode usar qualquer caractere que queira delimitar cadeias de caracteres. Pegue o seguinte código:

message = "My message"
contrived_example = "<div id=\"contrived\">#{message}</div>"

Se você não quiser escapar das aspas duplas na cadeia, basta usar um delimitador diferente:

contrived_example = %{<div id="contrived-example">#{message}</div>}
contrived_example = %[<div id="contrived-example">#{message}</div>]

Além de evitar a necessidade de escapar dos delimitadores, você pode usá-los para obter seqüências multilinhas mais agradáveis:

sql = %{
    SELECT strings 
    FROM complicated_table
    WHERE complicated_condition = '1'
}
28
tomafro

Acho que o uso do comando define_método para gerar métodos dinamicamente bastante interessantes e pouco conhecidos. Por exemplo:

((0..9).each do |n|
    define_method "press_#{n}" do
      @number = @number.to_i * 10 + n
    end
  end

O código acima usa o comando 'define_method' para criar dinamicamente os métodos "press1" a "press9". Em vez de digitar todos os 10 métodos que contêm essencialmente o mesmo código, o comando define method é usado para gerar esses métodos rapidamente, conforme necessário.

26
CodingWithoutComments

Use um objeto Range como uma lista lenta infinita:

Inf = 1.0 / 0

(1..Inf).take(5) #=> [1, 2, 3, 4, 5]

Mais informações aqui: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-Ruby/

26
horseyguy

module_function

Os métodos do módulo declarados como module_function criarão cópias de si mesmos como métodos da instância private na classe que inclui o módulo:

module M
  def not!
    'not!'
  end
  module_function :not!
end

class C
  include M

  def fun
    not!
  end
end

M.not!     # => 'not!
C.new.fun  # => 'not!'
C.new.not! # => NoMethodError: private method `not!' called for #<C:0x1261a00>

Se você usar module_function sem nenhum argumento, qualquer método de módulo que venha após a instrução module_function se tornará automaticamente ele próprio o module_functions.

module M
  module_function

  def not!
    'not!'
  end

  def yea!
    'yea!'
  end
end


class C
  include M

  def fun
    not! + ' ' + yea!
  end
end
M.not!     # => 'not!'
M.yea!     # => 'yea!'
C.new.fun  # => 'not! yea!'
23
newtonapple

Injeção curta, assim:

Soma do intervalo:

(1..10).inject(:+)
=> 55
23
user130730

Aviso: este item foi votado como o número 1 O corte mais horrendo de 2008, portanto, use com cuidado. Na verdade, evite-o como uma praga, mas certamente é Ruby Oculto.

Operadores adicionam novos operadores ao Ruby

Você já desejou um operador de handshake super secreto para alguma operação exclusiva em seu código? Como jogar código de golfe? Tente operadores como - ~ + ~ - ou <--- Esse último é usado nos exemplos para reverter a ordem de um item.

Não tenho nada a ver com o Projeto Superators além de admirá-lo.

21
Captain Hammer

Estou atrasado para a festa, mas:

Você pode facilmente pegar duas matrizes de tamanho igual e transformá-las em um hash, com uma matriz fornecendo as chaves e a outra os valores:

a = [:x, :y, :z]
b = [123, 456, 789]

Hash[a.Zip(b)]
# => { :x => 123, :y => 456, :z => 789 }

(Isso funciona porque a matriz # Zip "fecha os valores das duas matrizes:

a.Zip(b)  # => [[:x, 123], [:y, 456], [:z, 789]]

E o Hash [] pode receber exatamente essa matriz. Vi pessoas fazerem isso também:

Hash[*a.Zip(b).flatten]  # unnecessary!

O que produz o mesmo resultado, mas o splat e o achatamento são totalmente desnecessários - talvez não existissem no passado?)

19
Jordan Running

Hastes vivificadoras automáticas em Ruby

def cnh # silly name "create nested hash"
  Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
end
my_hash = cnh
my_hash[1][2][3] = 4
my_hash # => { 1 => { 2 => { 3 =>4 } } }

Isso pode ser muito útil.

19
Trevoke

Reestruturando uma matriz

(a, b), c, d = [ [:a, :b ], :c, [:d1, :d2] ]

Onde:

a #=> :a
b #=> :b
c #=> :c
d #=> [:d1, :d2]

Usando essa técnica, podemos usar uma atribuição simples para obter os valores exatos que queremos da matriz aninhada de qualquer profundidade.

16
horseyguy

Class.new()

Crie uma nova classe em tempo de execução. O argumento pode ser uma classe para derivar, e o bloco é o corpo da classe. Você também pode querer olhar para const_set/const_get/const_defined? para registrar sua nova classe corretamente, para que inspect imprima um nome em vez de um número.

Não é algo que você precisa todos os dias, mas bastante útil quando precisa.

15
Justin Love

crie uma matriz de números consecutivos:

x = [*0..5]

define x para [0, 1, 2, 3, 4, 5]

13
horseyguy

Muita mágica que você vê em Rubyland tem a ver com metaprogramação, que é simplesmente escrever código que escreve código para você. Ruby attr_accessor, attr_reader e attr_writer são todos metaprogramas simples, pois criam dois métodos em uma linha, seguindo um padrão padrão. Rails faz muita metaprogramação com seus métodos de gerenciamento de relacionamento como has_one e belongs_to.

Mas é bastante simples criar seus próprios truques de metaprogramação usando class_eval para executar código gravado dinamicamente.

O exemplo a seguir permite que um objeto wrapper encaminhe determinados métodos para um objeto interno:

class Wrapper
  attr_accessor :internal

  def self.forwards(*methods)
    methods.each do |method|
      define_method method do |*arguments, &block|
        internal.send method, *arguments, &block
      end
    end
  end

  forwards :to_i, :length, :split
end

w = Wrapper.new
w.internal = "12 13 14"
w.to_i        # => 12
w.length      # => 8
w.split('1')  # => ["", "2 ", "3 ", "4"]

O método Wrapper.forwards pega símbolos para os nomes dos métodos e os armazena na matriz methods. Então, para cada um desses dados, usamos define_method para criar um novo método cujo trabalho é enviar a mensagem, incluindo todos os argumentos e blocos.

Um ótimo recurso para questões de metaprogramação é Por que o "Seeing Metaprogramming Clearly" de Lucky Stiff .

13
TALlama

use qualquer coisa que responda a ===(obj) para comparações de casos:

case foo
when /baz/
  do_something_with_the_string_matching_baz
when 12..15
  do_something_with_the_integer_between_12_and_15
when lambda { |x| x % 5 == 0 }
  # only works in Ruby 1.9 or if you alias Proc#call as Proc#===
  do_something_with_the_integer_that_is_a_multiple_of_5
when Bar
  do_something_with_the_instance_of_Bar
when some_object
  do_something_with_the_thing_that_matches_some_object
end

Module (e, portanto, Class), Regexp, Date, e muitas outras classes definem um método de instância: === (other) e podem todos ser usado.

Obrigado a Farrel pelo lembrete de Proc#call sendo um alias como Proc#=== in Ruby 1.9.

12
James A. Rosen

O binário "Ruby" (pelo menos ressonância magnética) suporta muitos dos switches que tornaram o Perl bastante popular.

Significativos:

  • -n Configura um loop externo com apenas "gets" - que funciona magicamente com o nome de arquivo ou STDIN, configurando cada linha de leitura em $ _
  • -p Semelhante a -n, mas com um puts automático no final de cada iteração de loop
  • -uma chamada automática para .split em cada linha de entrada, armazenada em $ F
  • -i Editar arquivos de entrada no local
  • -l Chamada automática para .chomp na entrada
  • -e Executar um pedaço de código
  • -c Verifique o código fonte
  • -w Com avisos

Alguns exemplos:

# Print each line with its number:
Ruby -ne 'print($., ": ", $_)' < /etc/irbrc

# Print each line reversed:
Ruby -lne 'puts $_.reverse' < /etc/irbrc

# Print the second column from an input CSV (dumb - no balanced quote support etc):
Ruby -F, -ane 'puts $F[1]' < /etc/irbrc

# Print lines that contain "eat"
Ruby -ne 'puts $_ if /eat/i' < /etc/irbrc

# Same as above:
Ruby -pe 'next unless /eat/i' < /etc/irbrc

# Pass-through (like cat, but with possible line-end munging):
Ruby -p -e '' < /etc/irbrc

# Uppercase all input:
Ruby -p -e '$_.upcase!' < /etc/irbrc

# Same as above, but actually write to the input file, and make a backup first with extension .bak - Notice that inplace edit REQUIRES input files, not an input STDIN:
Ruby -i.bak -p -e '$_.upcase!' /etc/irbrc

Sinta-se à vontade para pesquisar no Google "one-liners de Ruby" e "one-liners de Perl" para obter exemplos mais úteis e práticos. Essencialmente, permite que você use Ruby como um substituto bastante poderoso para awk e sed.

11
minaguib

O método send () é um método de uso geral que pode ser usado em qualquer classe ou objeto no Ruby. Se não for substituído, send () aceita uma string e chama o nome do método cuja string é passada. Por exemplo, se o usuário clicar no botão "Clr", a string 'press_clear' será enviada para o método send () e o método 'press_clear' será chamado. O método send () permite uma maneira divertida e dinâmica de chamar funções no Ruby.

 %w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn|
    button btn, :width => 46, :height => 46 do
      method = case btn
        when /[0-9]/: 'press_'+btn
        when 'Clr': 'press_clear'
        when '=': 'press_equals'
        when '+': 'press_add'
        when '-': 'press_sub'
        when '*': 'press_times'
        when '/': 'press_div'
      end

      number.send(method)
      number_field.replace strong(number)
    end
  end

Eu falo mais sobre esse recurso em Blogging Shoes: The Simple-Calc Application

10
CodingWithoutComments
private unless Rails.env == 'test'
# e.g. a bundle of methods you want to test directly

Parece um recurso legal e (em alguns casos) interessante/útil do Ruby.

9
Szymon Jeż

Fixnum#to_s(base) pode ser realmente útil em alguns casos. Um desses casos é gerar tokens únicos aleatórios (pseudo), convertendo número aleatório em string usando a base de 36.

Token de comprimento 8:

Rand(36**8).to_s(36) => "fmhpjfao"
Rand(36**8).to_s(36) => "gcer9ecu"
Rand(36**8).to_s(36) => "krpm0h9r"

Token de comprimento 6:

Rand(36**6).to_s(36) => "bvhl8d"
Rand(36**6).to_s(36) => "lb7tis"
Rand(36**6).to_s(36) => "ibwgeh"
9
sickill

Engane alguma classe ou módulo dizendo que exigiu algo que realmente não era necessário:

$" << "something"

Isso é útil, por exemplo, ao exigir A que, por sua vez, requer B, mas não precisamos de B em nosso código (e A não o utilizará também através de nosso código):

Por exemplo, o bdrb_test_helper requires Do Backgroundrb 'test/spec', Mas você não o usa, portanto, no seu código:

$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
9
olegueret

Definindo um método que aceita qualquer número de parâmetros e apenas descarta todos eles

def hello(*)
    super
    puts "hello!"
end

O método hello acima só precisa de puts"hello" na tela e chame super - mas desde que a superclasse hello defina os parâmetros que ele também precisa - no entanto, como ele realmente não precisa usar os parâmetros em si - ele não tem que dar um nome a eles.

9
horseyguy

Para combinar várias expressões regulares com |, você pode usar

Regexp.union /Ruby\d/, /test/i, "cheat"

para criar um Regexp semelhante a:

/(Ruby\d|[tT][eE][sS][tT]|cheat)/
8
J-_-L

Acho isso útil em alguns scripts. Torna possível usar variáveis ​​de ambiente diretamente, como nos scripts Shell e Makefiles. Variáveis ​​de ambiente são usadas como fallback para indefinidas Ruby constantes.

>> class <<Object
>>  alias :old_const_missing :const_missing
>>  def const_missing(sym)
>>   ENV[sym.to_s] || old_const_missing(sym)
>>  end
>> end
=> nil

>> puts Shell
/bin/zsh
=> nil
>> TERM == 'xterm'
=> true
8
Ropez

Que tal abrir um arquivo com base no ARGV [0]?

readfile.rb:

$<.each_line{|l| puts l}

Ruby readfile.rb testfile.txt

É um ótimo atalho para escrever scripts únicos. Há toda uma confusão de variáveis ​​predefinidas que a maioria das pessoas não conhece. Use-os com sabedoria (leia-se: não desarrume uma base de código que planeja manter com elas, pode ficar confuso).

8
Scott Holden

Sou fã de:

%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]

É meio engraçado quantas vezes isso é útil.

5
Judson

Vários valores de retorno

def getCostAndMpg
    cost = 30000  # some fancy db calls go here
    mpg = 30
    return cost,mpg
end
AltimaCost, AltimaMpg = getCostAndMpg
puts "AltimaCost = #{AltimaCost}, AltimaMpg = #{AltimaMpg}"

Atribuição Paralela

i = 0
j = 1
puts "i = #{i}, j=#{j}"
i,j = j,i
puts "i = #{i}, j=#{j}"

Atributos virtuais

class Employee < Person
  def initialize(fname, lname, position)
    super(fname,lname)
    @position = position
  end
  def to_s
     super + ", #@position"
  end
  attr_writer :position
  def etype
     if @position == "CEO" || @position == "CFO"
         "executive"
     else
         "staff"
     end
  end
end
employee = Employee.new("Augustus","Bondi","CFO")
employee.position = "CEO"
puts employee.etype    =>  executive
employee.position = "Engineer"
puts employee.etype    =>  staff

method_missing - uma ideia maravilhosa

(Na maioria dos idiomas, quando um método não pode ser encontrado e o erro é lançado e o programa é interrompido. Em Ruby você pode realmente pegar esses erros e talvez fazer algo inteligente com a situação))

class MathWiz
  def add(a,b) 
    return a+b
  end
  def method_missing(name, *args)
    puts "I don't know the method #{name}"
  end
end
mathwiz = MathWiz.new
puts mathwiz.add(1,4)
puts mathwiz.subtract(4,2)

5

Eu não sei o método subtrair

nada

5
Ramiz Uddin

A dica de James A. Rosen é legal ([* items] .each), mas acho que ela destrói hashes:

irb(main):001:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):002:0> [*h]
=> [[:name, "Bob"]]

Prefiro essa maneira de lidar com o caso quando aceito uma lista de itens a serem processados, mas sou indulgente e permito que o chamador forneça um:

irb(main):003:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):004:0> [h].flatten
=> [{:name=>"Bob"}]

Isso pode ser combinado com uma assinatura de método como esta:

def process(*entries)
  [entries].flatten.each do |e|
    # do something with e
  end
end
4
minaguib

Eu apenas amo a palavra-chave em linha rescue assim:
EXEMPLO EDITADO:

@user #=> nil (but I did't know)
@user.name rescue "Unknown"
link_to( d.user.name, url_user( d.user.id, d.user.name)) rescue 'Account removed'

Isso evita a quebra do meu aplicativo e é muito melhor que o recurso lançado em Rails . Try ()

4
Fabiano Soriani

Chamar um método definido em qualquer lugar da cadeia de herança, mesmo se substituído

Os objetos do ActiveSupport às vezes se disfarçam como objetos internos.

 exige 'suporte_serviço ativo' 
 dias = 5. dias 
 dias.classe # => Fixnum 
 days.is_a? (Fixnum) # => true 
 Fixnum === dias # => false (hein? O que você realmente é?) 
 Object.instance_method (: class) .bind (days) .call # => ActiveSupport :: Duration (aha!) 
 ActiveSupport :: Duration === dias # => true 

O acima exposto, é claro, depende do fato de o active_support não redefinir o Object # instance_method; nesse caso, estaríamos realmente no riacho. Por outro lado, sempre poderíamos salvar o valor de retorno de Object.instance_method (: class) antes de qualquer biblioteca de terceiros ser carregada.

Object.instance_method (...) retorna um UnboundMethod que você pode ligar a uma instância dessa classe. Nesse caso, você pode vinculá-lo a qualquer instância de Object (subclasses incluídas).

Se a classe de um objeto incluir módulos, você também poderá usar o UnboundMethod desses módulos.

 módulo Mod 
 def var_add (mais); @ var + more; fim 
 fim 
 classe Cla 
 inclui Mod 
 def initialize (var); @ var = var; final 
 # substituir 
 def var_add (mais); @ var + more + more; fim 
 fim 
 cla = Cla.new ('abcdef') 
 cla.var_add ('ghi') # => "abcdefghighi" 
 Mod.instance_method ( : var_add) .bind (cla) .call ('ghi') # => "abcdefghi" 

Isso funciona mesmo para métodos singleton que substituem um método de instância da classe à qual o objeto pertence.

 classe Foo 
 def mymethod; 'original'; fim 
 fim 
 foo = Foo.novo 
 foo.mymethod # => 'original' 
 def foo.mymethod; 'singleton'; fim 
 foo.mymethod # => 'singleton' 
 Foo.instance_method (: mymethod) .bind (foo) .call # => 'original' 
 
 # Você também pode chamar o método #instance nas classes singleton: 
 Class << foo; auto; end.instance_method (: mymethod) .bind (foo) .call # => 'singleton' 
4
Kelvin

Existem alguns aspectos dos literais de símbolos que as pessoas devem conhecer. Um caso resolvido por literais de símbolos especiais é quando você precisa criar um símbolo cujo nome cause um erro de sintaxe por algum motivo com a sintaxe literal de símbolo normal:

:'class'

Você também pode fazer a interpolação de símbolos. No contexto de um acessador, por exemplo:

define_method :"#{name}=" do |value|
  instance_variable_set :"@#{name}", value
end
3
Tom

each_with_index método para qualquer objeto enumarable (array, hash, etc.) talvez?

myarray = ["la", "li", "lu"]
myarray.each_with_index{|v,idx| puts "#{idx} -> #{v}"}

#result:
#0 -> la
#1 -> li
#2 -> lu

Talvez seja mais conhecido do que outras respostas, mas não tão conhecido por todos Ruby :)

3
mhd
class A

  private

  def my_private_method
    puts 'private method called'
  end
end

a = A.new
a.my_private_method # Raises exception saying private method was called
a.send :my_private_method # Calls my_private_method and prints private method called'
2
Chirantan

O Ruby possui um mecanismo call/cc que permite saltar livremente para cima e para baixo na pilha.

Exemplo simples a seguir. Certamente não é assim que alguém multiplicaria uma sequência em Ruby, mas demonstra como alguém pode usar call/cc para alcançar a pilha e causar um curto-circuito em um algoritmo. Nesse caso, multiplicamos recursivamente uma lista de números até que tenhamos visto todos os números ou zero (os dois casos em que sabemos a resposta). No caso zero, podemos ser arbitrariamente profundos na lista e encerrar.

#!/usr/bin/env Ruby

def rprod(k, rv, current, *nums)
  puts "#{rv} * #{current}"
  k.call(0) if current == 0 || rv == 0
  nums.empty? ? (rv * current) : rprod(k, rv * current, *nums)
end

def prod(first, *rest)
  callcc { |k| rprod(k, first, *rest) }
end

puts "Seq 1:  #{prod(1, 2, 3, 4, 5, 6)}"
puts ""
puts "Seq 2:  #{prod(1, 2, 0, 3, 4, 5, 6)}"

Você pode ver a saída aqui:

http://codepad.org/Oh8ddh9e

Para um exemplo mais complexo, apresentando continuações movendo a outra direção na pilha, leia a fonte em Generator .

2
Dustin

Acabei de ler todas as respostas ... uma omissão notável foi a desestruturação da tarefa:

> (a,b),c = [[1,2],3]
=> [[1,2],3]
> a
=> 1

Também funciona para parâmetros de bloco. Isso é útil quando você aninha matrizes, cada elemento representando algo distinto. Em vez de escrever código como "array [0] [1]", você pode dividir esse array aninhado e fornecer um nome descritivo para cada elemento, em uma única linha de código.

2
Alex D
@user #=> nil (but I did't know)
@user.name rescue "Unknown"
2
haoqi

O atalho do sprintf

Meu favorito Ruby. A sintaxe é format_string % argument

"%04d"  % 1         # => "0001"
"%0.2f" % Math::PI  # => "3.14"

Também funciona para matrizes (format_string % array_of_arguments)

"%.2f %.3f %.4f" % ([Math::PI]*3) 
# => "3.14 3.142 3.1416"
1
iblue