2009-07-29 7 views
3

Est-il possible de définir un bloc dans une instruction en ligne avec ruby? Quelque chose comme ceci:pouvez-vous définir un bloc en ligne avec ruby?

tasks.collect(&:title).to_block{|arr| "#{arr.slice(0, arr.length - 1).join(", ")} and #{arr.last}" } 

Au lieu de cela:

titles = tasks.collect(&:title) 
"#{titles.slice(0, titles.length - 1).join(", ")} and #{titles.last}" 

Si vous avez dit tasks.collect(&:title).slice(0, this.length-1) comment pouvez-vous faire « ceci » se réfèrent à la gamme complète qui a été passé à trancher()? Fondamentalement, je suis à la recherche d'un moyen de passer l'objet retourné d'une déclaration dans un autre, ne pas nécessairement itérer par-dessus.

Répondre

4

Vous êtes un peu confus en transmettant une valeur de retour à une méthode/fonction et en appelant une méthode sur la valeur retournée. La façon de faire ce que vous avez décrit est le suivant:

lambda {|arr| "#{arr.slice(0, arr.length - 1).join(", ")} and #{arr.last}"}.call(tasks.collect(&:title)) 

Si vous voulez faire la façon dont vous tentiez, la plus proche est instance_eval, ce qui vous permet d'exécuter un bloc dans le contexte d'un objet. Donc, ce serait:

tasks.collect(&:title).instance_eval {"#{slice(0, length - 1).join(", ")} and #{last}"} 

Cependant, je ne ferais pas non plus de ceux-ci, comme il est plus long et moins lisible que l'alternative.

1

Je ne sais pas exactement ce que vous essayez de faire, mais:

Si vous avez dit tasks.collect (&: titre) .slice (0, this.length-1) Comment vous faites 'ceci' se référer au tableau complet qui a été passé à slice()?

Utilisez un nombre négatif:

tasks.collect(&:title)[0..-2] 

En outre, dans:

"#{titles.slice(0, titles.length - 1).join(", ")} and #{titles.last}" 

vous avez quelque chose de bizarre se passe avec vos citations, je pense.

+0

Merci, bon de connaître le nombre négatif. – bwizzy

1

Je ne comprends pas vraiment pourquoi vous voulez, mais vous pouvez ajouter une fonction aux classes de rubis qui prend un bloc, et se fait passer comme paramètre ...

class Object 
    def to_block 
    yield self 
    end 
end 

À ce stade vous seriez en mesure d'appeler:

tasks.collect(&:title).to_block{|it| it.slice(0, it.length-1)} 

Bien sûr, la modification de la classe d'objet ne doit pas être prise à la légère car il peut y avoir de graves conséquences lors de la combinaison avec d'autres bibliothèques.

+0

est-il un moyen de faire le bloc, céder soi-même en ligne? – bwizzy

+0

Je suppose que vous pourriez aussi créer une fonction globale qui prend un objet en paramètre, prend un bloc, puis appelle yield sur le bloc avec le paramètre passé. La fonction serait: def to_block (para) céder para fin Votre appel deviendrait alors: to_block (tâches.collecter (&: titre)) {| it.slice (0, it.length-1)} À mon avis, cela va à l'encontre du flux naturel du code ruby, mais cela pourrait être fait. Je ne vois pas d'autre moyen d'organiser cela, vraiment. – krdluzni

0

Bien qu'il existe beaucoup de bonnes réponses ici, peut-être vous cherchez quelque chose de plus comme celui-ci en termes d'un objectif:

class Array 
    def andjoin(separator = ', ', word = ' and ') 
    case (length) 
    when 0 
     '' 
    when 1 
     last.to_s 
    when 2 
     join(word) 
    else 
     slice(0, length - 1).join(separator) + word + last.to_s 
    end 
    end 
end 

puts %w[ think feel enjoy ].andjoin # => "think, feel and enjoy" 
puts %w[ mitchell webb ].andjoin # => "mitchell and webb" 
puts %w[ yes ].andjoin # => "yes" 

puts %w[ happy fun monkeypatch ].andjoin(', ', ', and ') # => "happy, fun, and monkeypatch" 
Questions connexes