Définition de variables avec des blocs en ruby
Question
Je me retrouve avec des boucles comme PHP beaucoup en Ruby et il se sent mal quand le reste de la langue est si propre. Je termine avec le code comme ceci:
conditions_string = ''
zips.each_with_index do |zip, i|
conditions_string << ' OR ' if i > 0
conditions_string << "npa = ?"
end
# Now I can do something with conditions string
Je sens que je devrais être en mesure de faire quelque chose comme ceci
conditions_string = zips.each_with_index do |zip, i|
<< ' OR ' if i > 0
<< "npa = ?"
end
Est-il possible de définir une variable « Neat » avec un bloc Ruby?
La solution
Vous ne semblez pas être accès zip
dans votre boucle, de sorte que la suivante devrait fonctionner:
conditions_string = (['npa = ?'] * zips.length).join(' OR ')
Si vous avez besoin d'accéder à zip
, vous pouvez utiliser:
conditions_string = zips.collect {|zip| 'npa = ?'}.join(' OR ')
Autres conseils
Puisque vous ne je vous suggère de ne pas utiliser réellement la valeur de zip,
zips.map {|zip| "npa = ?" }.join(" OR ")
mais en général je suggère à la recherche à la fonction Enumerable # inject pour éviter ce genre de boucles.
La première chose que je pensais était le suivant:
a = %w{array of strings} => ["array", "of", "strings"]
a.inject { |m,s| m + ' OR ' + s } => "array OR of OR strings"
Mais cela peut être fait avec seulement
a.join ' OR '
Et alors que je pense que vous aurez besoin que construire bientôt, pour dupliquer votre exemple précis que je pourrais simplement utiliser:
([' npa = ? '] * a.size).join 'OR'
Bien que d'autres ont donné des solutions plus idiomatiques à votre problème spécifique, il y a en fait une méthode fraîche Object#instance_eval
, qui est un truc standard beaucoup Ruby DSLs utilisent. Il fixe self
au récepteur de instance_eval
dans son bloc:
court exemple:
x = ''
x.instance_eval do
for word in %w(this is a list of words)
self << word # This means ``x << word''
end
end
p x
# => "thisisalistofwords"
Il ne couvre pas tout pervasively de la manière la $_
de Perl, mais il vous permet d'envoyer implicitement les méthodes à un seul objet.
Dans 1.8.7+ vous pouvez utiliser each_with_object
Il remplace l'expression 'injectent' de DigitalRoss avec ceci:
a = %w{hello my friend} => ["hello", "my", "friend"]
a.each_with_object("") { |v, o| o << v << " NOT " } => "hello NOT my NOT friend NOT"