我在Ruby中有一个Config模块,希望能够向其中添加任意变量。我使用method_missing和instance_variable_set创建了它,如下所示:
module Conf
#add arbitrary methods to config array
def self.method_missing(m, *args)
args = args.pop if args.length==1
instance_variable_set("@#{m}", args)
end
end
但是,我在动态创建访问器时遇到了麻烦。当我尝试如下使用attr_accessor时:
module Conf
#add arbitrary methods to config array
def self.method_missing(m, *args)
args = args.pop if args.length==1
instance_variable_set("@#{m}", args)
module_eval("attr_accessor :#{m}")
end
end
我得到以下内容:
Conf :: s3_key('1234ABC')#Conf :: s3_key = nil
如果我尝试单独创建访问器,请执行以下操作:
module Conf
#add arbitrary methods to config array
def self.method_missing(m, *args)
args = args.pop if args.length==1
instance_variable_set("@#{m}", args)
module_eval("def self.#{m};@#{m};end")
module_eval("def self.#{m}=(val);@#{m}=val;end")
end
end
发生以下情况:
Conf::s3_key('1234ABC') # Conf::s3_key='1234ABC' - correct
但是,如果我尝试覆盖该值,则会收到错误消息
Conf::s3_key('1234ABC') # ok
Conf::s3_key('4567DEF') #(eval):1:in `s3_key': wrong number of arguments (1 for 0) (ArgumentError)
我究竟做错了什么?
首先,attr_accessor
即使正常描述,它也无法用于模块。
module Conf
attr_accessor :s3_key
end
其次,覆盖错误是因为method_missing
仅执行一次
def self.method_missing(m, *args)
#:
instance_variable_set("@#{m}", args)
module_eval("def self.#{m};@#{m};end") # <- method defined
该方法在首次调用中定义。并且参数的数量为0
Conf::s3_key('1234ABC') # call method_missing
Conf::s3_key('4567DEF') # call self.s3_key()
例如,如何这样:
module Conf
def self.method_missing(m, *args)
args = args.pop if args.length==1
instance_variable_set("@#{m}", args)
module_eval(<<EOS)
def self.#{m}(*args)
if (args.empty?)
@#{m}
else
@#{m} = (args.length==1) ? args.pop : args
end
end
EOS
end
end
Conf::s3_key('foo')
Conf::s3_key('bar')
p Conf::s3_key # "bar"
或者
module Conf
def self.method_missing(m, *args)
if (m.to_s =~ /^(.+)=$/)
args = args.pop if args.length==1
instance_variable_set("@#{$1}", args)
else
instance_variable_get("@#{m}")
end
end
end
Conf::s3_key = 'foo'
Conf::s3_key = 'bar'
p Conf::s3_key # "bar"
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句