В Ruby, как добавить к объекту метод с доступом к переменным во внешней области видимости? - PullRequest
1 голос
/ 11 октября 2011

Я новичок в Ruby. Я нахожусь на стадии, когда я безуспешно пытаюсь написать что-то на Ruby, как на каком-то другом языке.

Я пытаюсь добавить метод к объекту - скажем, скромный массив. Не для всех массивов, только для одного конкретного. Этот метод должен иметь доступ к переменной во внешней области видимости.

Насколько я понимаю, я могу использовать def для добавления метода к объекту, но у этих методов нет доступа к переменным во внешней области видимости. Для этого мне нужно будет использовать lambda или Proc.new, но я не вижу, как бы я "прикрепил" лямбда / proc к массиву как свойство.

В JavaScript это просто, как показывает этот глупый пример:

var x = 3
var array = [1, 2, 3, 4]

array.multiply_by_x = function() {
  var i = this.length
  while (i--) {
    this[i] *= x
  }
}

Возможно ли что-то похожее на вышеперечисленное в Ruby?

Ответы [ 3 ]

4 голосов
/ 11 октября 2011

Вы не можете использовать ключевое слово def, чтобы определить метод здесь, потому что он представит другую область видимости. Если вы хотите определить метод только для конкретного объекта, то вы должны определить его в одноэлементном классе.

x = 3
array = [1, 2, 3, 4]

array.define_singleton_method(:multiply_by_x) do
  self.map!{|e| e * x }
end

Но если вы используете Ruby 1.8.x, вы должны сделать это:

(class << array; self; end).send(:define_method, :multiply_by_x) do
  self.map!{|e| e * x }
end

Примечание: это не связано с этим вопросом, но если вы хотите увидеть различные способы определения одноэлементных методов.

1 голос
/ 11 октября 2011

Monkey-patching Array сделает это, но он сделает это для всех случаев Array.

class Array
  def multiply_by(x)
     self.map! {|n|
        n * x
     }
  end
end

Если вы хотите произвольно прикрепить метод к существующему объекту, я не думаю, что это действительно возможно.

Одна вещь, которую вы могли бы сделать, это использовать Hash с lambda:

x = 3
hash = {:array => [1,2,3]}
hash[:multiply_by] = lambda {
   hash[:array].map! {|num|
      num * x
   }
}

Затем вы бы назвали multiply_by лямбду следующим образом:

hash[:multiply_by].call
0 голосов
/ 11 октября 2011

Я бы предпочел сделать так:

ary = [1, 2, 3, 4]

def ary.multyply_by(x)
  self.map! {|e| e * x}
end

p ary.multyply_by 10

В качестве примечания, гораздо лучше использовать параметры функции, чем переменные с высокой степенью видимости.Прицелы - это способ избежать столкновений, а не препятствий.

...