开发者

In Ruby, how does one add to an object a method with access to variables in outer scope?

开发者 https://www.devze.com 2023-04-12 16:12 出处:网络
I\'m new to Ruby. I\'m at the stage where I\'m unsuccessfully attempting to write things in Ruby as I would in some other language.

I'm new to Ruby. I'm at the stage where I'm unsuccessfully attempting to write things in Ruby as I would in some other language.

I'm trying to add a method to an object – a humble array, let's say. Not to all arrays, just to one specific one. This method must have access to a variable in outer scope.

My understanding is that I can use def to add a method to an object, but that methods do not have access to variables in outer scope. For开发者_开发技巧 that I'd need to use lambda or Proc.new, but I can't see how I'd "attach" the lambda/proc to the array as a property.

In JavaScript this is straightforward, as this silly example demonstrates:

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

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

Is something similar to the above possible in Ruby?


You can't use def keyword to define the method here because it will introduce another scope. If you would like to define a method to only a specific object, then you have to define it in singleton class.

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

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

But if you are are using Ruby 1.8.x, you have to do this:

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

Note: It's not related to this question, but if you would like to see different ways to define singleton methods.


Monkey-patching Array would do this, but it would do it for all instances of Array.

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

If you want to arbitrarily monkey-patch a method onto an existing object, I don't think this is really possible.

One thing that you could do is use a Hash with a lambda:

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

You'd then call the multiply_by lambda like so:

hash[:multiply_by].call


I would rather do like that:

ary = [1, 2, 3, 4]

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

p ary.multyply_by 10

As a side note, it is much better to use function parameters than highly-scoped variables. Scopes are a way to avoid clashes, not obstacles.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号