Установка переменных с блоками в ruby - PullRequest
2 голосов
/ 02 декабря 2009

Я часто использую PHP-подобные циклы в Ruby, и кажется, что неправильно, когда остальная часть языка такая аккуратная. Я получаю такой код:

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

Я чувствую, что должен быть в состоянии сделать что-то подобное

conditions_string = zips.each_with_index do |zip, i|

    << ' OR ' if i > 0
    << "npa = ?"

end

Есть ли "аккуратный" способ установить переменную с блоком в Ruby?

Ответы [ 5 ]

4 голосов
/ 02 декабря 2009

Первое, о чем я подумал, было:

a = %w{array of strings}             => ["array", "of", "strings"]
a.inject { |m,s| m + ' OR ' + s }    => "array OR of OR strings"

Но это можно сделать просто

a.join ' OR '

И хотя я думаю, что вам понадобится эта конструкция в ближайшее время, чтобы дублировать ваш точный пример, я мог бы просто использовать:

([' npa = ? '] * a.size).join 'OR'
4 голосов
/ 02 декабря 2009

Поскольку вы не используете значение zip, я бы предложил

zips.map {|zip| "npa = ?" }.join(" OR ")

но в целом я бы посоветовал взглянуть на функцию Enumerable # inject, чтобы избежать такого рода циклов.

1 голос
/ 02 декабря 2009

Хотя другие дали идиоматические решения вашей конкретной проблемы, на самом деле есть классный метод Object#instance_eval, который является стандартным приемом, который используют многие Ruby DSL. Он устанавливает self для получателя instance_eval внутри своего блока:

Краткий пример:

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"

Он не охватывает все, как это делает $_ в Perl, но позволяет вам неявно отправлять методы одному объекту.

1 голос
/ 02 декабря 2009

Похоже, вы не обращаетесь к zip в цикле, поэтому должно работать следующее:

conditions_string = (['npa = ?'] * zips.length).join(' OR ')

Если вам нужен доступ к zip, вы можете использовать:

conditions_string = zips.collect {|zip| 'npa = ?'}.join(' OR ')
0 голосов
/ 02 декабря 2009

В 1.8.7+ вы можете использовать each_with_object

Он заменяет идиому DigitalRoss 'inject' следующим образом:

a = %w{hello my friend}  => ["hello", "my", "friend"]
a.each_with_object("") { |v, o| o << v << " NOT " }  => "hello NOT my NOT friend NOT"
...