I have a class that contains some private attributes. What I would like to do is to dynamically add some setters for these only for the execution of a specific block.
我有一个包含一些私有属性的类。我想要做的是为这些仅为执行特定块动态添加一些setter。
Example of what I would like to be able to:
我希望能够做到的例子:
class Content
attr_reader :a, :b
def initialize
@a = 1
@b = "plop"
end
def set(&block)
extend(Setter)
instance_eval(&block)
unextend(Setter) ????
end
module Setter
def a(value)
@a = value
end
def b(value)
@b = value
end
end
end
content = Content.new
content.set do
a 2
b "yeah!"
end
content.a # should return 2
EDIT: Thanks for the great answers so far. I clarified the question because I actually need to define attribute readers in the class itself that may conflict with the setters defined in the module. I forgot about this part when posting the question. (It was late ^^)
编辑:谢谢你到目前为止的伟大答案。我澄清了这个问题,因为我实际上需要在类本身中定义属性读取器,这可能与模块中定义的setter冲突。在发布问题时我忘记了这一部分。 (已经很晚了^^)
CLARIFICATION: This class is intended for a DSL to write a configuration file. It is targeted at non-developer so the less operators, the better.
CLARIFICATION:此类用于DSL编写配置文件。它针对的是非开发人员,因此运营商越少越好。
I currently implement this using a proxy class that instance_eval
the block but I have to mess with instance_variable_set
in order to set the values and I don't like it. I am just trying another way to see if I can make my code more readable.
我目前使用instance_eval块的代理类来实现它,但我必须弄乱instance_variable_set才能设置值而我不喜欢它。我只是尝试另一种方式来看看我是否可以使我的代码更具可读性。
def set(&block)
extend(Setter)
instance_eval(&block)
Setter.instance_methods.each do |m|
instance_eval "undef #{m}"
end
end
I don't know of any method that would do that for you although there might be something.. This should do the job though, by finding all the instance methods of Setter and undefining them in Content.
我不知道有什么方法会为你做这件事虽然可能有些东西..但是应该通过找到Setter的所有实例方法并在Content中取消它们来完成这项工作。
There's no native way to "unextend" modules in Ruby. The mixology gem implements this pattern as a C (and Java, for JRuby) extension, creating mixin
and unmix
methods. It appears you may need to apply a patch if you need Ruby 1.9 support, however.
在Ruby中没有本地方法来“扩展”模块。 mixology gem将此模式实现为C(和Java,用于JRuby)扩展,创建mixin和unmix方法。但是,如果您需要Ruby 1.9支持,则可能需要应用补丁。
If you'd prefer to avoid using third-party libraries, another approach might simply be to make the setters private:
如果您更愿意避免使用第三方库,另一种方法可能只是将setter设为私有:
class Content
def initialize
@a = 1
@b = "plop"
end
def set(&block)
instance_eval(&block)
end
private
def a(val)
@a = val
end
def b(val)
@b = val
end
end
content = Content.new
#This will succeed
content.set do
a 2
b "yeah!"
end
# This will raise a NoMethodError, as it attempts to call a private method
content.a 3
You could use _why's mixico library (available on github)
你可以使用_why的mixico库(在github上提供)
It would let you do this:
它会让你这样做:
require 'mixology'
#...
def set(&block)
Setter.mix_eval(Setter, &block)
end
The mixology gem does much the same thing, just slightly differently.
mixology gem做了很多相同的事情,只是略有不同。
if you're feeling in an experimental mood also check out: dup_eval
如果你感觉有实验心情,请查看:dup_eval
It's similar in some ways to mixico but with some interesting extras (object2module)
它在某些方面类似于mixico但有一些有趣的附加功能(object2module)
本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2009/06/09/6facf8f496ff7179faf9e10d76ed8ad6.html。