如何使用define_method通过闭包来维护变量?

时间:2014-08-07 06:13:36

标签: ruby

我正在尝试创建一个宏" has_accessor_for",它接受一个符号,该符号用作它使用的内部对象的参数(Accessorizer对象)。我遇到的问题是,当多个模块执行has_accessors_for时,参数(范围)最终会被卡在分配给它的最后一个值上。

我在define_method之前添加了一个puts,它显示了它的scope1,然后是scope2 ......但是在define_method中,它始终是scope2。我正在寻找一种基本上封装该变量的方法,这样当第一个模块调用has_accessor_for时,无论何时调用my_wut,它都将绑定到scope1 ...并且无论何时调用my_bleah,它都将绑定到scope2。但正如我所说,现在,my_bleah和my_wut都绑定到scope2--如果我更改MyModel中包含的顺序,那么它们都将绑定到scope1。

class Accessorizer
  def initialize(record, scope)
    @record = record
    @scope = scope
  end

  def value_for(key)
    @record.send key
  end
end


module Magic
  def has_accessors_for(scope)
    accessors = {}

    puts "initial: #{scope}"
    define_method :get_value_for do |key|
      puts "inside method #{scope}"
      accessor.value_for key
    end

    define_method :accessor do
      accessors[:scope] ||= Accessorizer.new(self, scope)
    end
  end
end

module SomeAccessor
  extend Magic
  has_accessors_for :scope1

  def my_wut
    get_value_for :wut
  end
end

module SomeOtherAccessor
  extend Magic
  has_accessors_for :scope2

  def my_bleah
    get_value_for :bleah
  end
end


class MyModel
  include SomeAccessor
  include SomeOtherAccessor
  attr_accessor :wut, :bleah
end

m = MyModel.new
m.wut = 'wut'
m.bleah = 'bleah'
m.my_bleah
m.my_wut

输出:

initial: scope1
initial: scope2
inside method scope2
inside method scope2

1 个答案:

答案 0 :(得分:0)

简短的回答:问题不在于闭包。

答案很长:

define_method :get_value_for do |key|
  puts "inside method #{scope}"
  accessor.value_for key
end

在给定的类上,只能有一个名为get_value_for的方法 - 第二个定义将覆盖第一个。

这并不重要,因为你在两种情况下都调用了accessor,但是这个方法遇到了同样的问题 - 你定义了两次,所以第二个定义会覆盖第一个定义而你最终会只有一个Accessorizer对象。

我认为你需要在这里重新考虑你的设计。