2009-06-26 7 views
9

J'ai une méthode arbitraire dans Ruby qui donne des valeurs multiples de sorte qu'il peut être remis à un bloc:Une méthode Ruby peut-elle produire un itérateur ou renvoyer un tableau en fonction du contexte?

def arbitrary 
    yield 1 
    yield 2 
    yield 3 
    yield 4 
end 

arbitrary { |x| puts x } 

J'aimerais modifier cette méthode de sorte que, s'il n'y a pas de bloc, il retourne juste la valeurs en tant que tableau. Donc, cette construction fonctionnerait également:

myarray = arbitrary 
p a -----> [1, 2, 3, 4, 5] 

Est-ce possible dans Ruby?

Répondre

13

Il y a une syntaxe que:

def arbitrary(&block) 
    values = [1, 2, 3, 4] 
    if block 
    values.each do |v| 
     yield v 
    end 
    else 
    values 
    end 
end 

Note:

yield v 

peut être remplacé par:

block.call v 
+0

Parfait, merci. –

+10

Si vous remplacez "if block" par "if block_given?", Vous n'avez même pas besoin de rendre l'argument "& block" explicite, et vous pouvez suffire avec "def arbitrarary". C'est une pratique courante de Ruby. – molf

+0

@Molf: Vous avez absolument raison. – bltxd

19
def arbitrary 
    values = [1,2,3,4] 
    return values unless block_given? 
    values.each { |val| yield(val) } 
end 
arbitrary { |x| puts x } 
arbitrary 
+0

Fonctionne également, a choisi blue.tuxedo depuis qu'il était premier. –

+1

+1: plus propre, plus nette et plus facile à suivre –

12

En ruby ​​1.9+ vous pouvez utiliser Enumerator pour mettre en œuvre cela.

def arbitrary(&block) 
    Enumerator.new do |y| 
    values = [1,2,3,4] 
    values.each { |val| y.yield(val) } 
    end.each(&block) 
end 

Il a l'avantage que cela fonctionne pour les flux infinis aussi:

# block-only version 
# 
def natural_numbers 
    0.upto(1/0.0) { |x| yield x } 
end 

# returning an enumerator when no block is given 
# 
def natural_numbers(&block) 
    Enumerator.new do |y| 
    0.upto(1/0.0) { |x| y.yield(x) } 
    end.each(&block) 
end 

Mais la façon la plus idiomatiques de le faire est de garder votre méthode avec to_enum(your_method_name, your_args) comme ceci:

def arbitrary 
    return to_enum(:arbitrary) unless block_given? 

    yield 1 
    yield 2 
    yield 3 
    yield 4 
end 

Il s'agit d'un idiome que les bibliothèques de rubis utilisent elles-mêmes à plusieurs endroits.

+0

+1 pour l'énumérateur! <3 – grilix

Questions connexes