我有两个A和B类,它们都有一些选项,通常我会使用一个Hash来存储@options[:name]='xxxx'
等选项;现在我想用元编程重构它,
class A
set_option :name, "james"
set_option :address, "some street"
def hello
puts @options[:name]
puts @options[:address]
end
end
class B
set_option :age, 18
def greeting
put @options[:age]
end
end
在这里,我想使用set_option
将密钥和值对设置为一个哈希实例@options
,我该怎么办?
此外,我想将解决方案包装到一个单独的模块中。
更新:
先谢谢,你的所有答案对我都很有价值,让我更清楚,现在我意识到我想要的东西不是那么正确,那么如果我提出这样的问题该怎么办呢?
option
替换@options
?@@options
可能不起作用?我希望不同的类可以有不同的哈希实例。``` 像这样:
class A
set_option :name, "james"
set_option :provider, 'twitter'
def hello
puts option[:name]
end
end
class B
set_option :name, "not james"
def greeting
put option[:name]
end
end
经过深思熟虑后,我认为我真正想要的是不同类的不同选项哈希实例,而不是类的实例。
这是我想要的,它可以工作。
module HasOptions
def self.included(cls)
cls.class_eval do
def self.set_option(key, value)
options[key] = value
end
def self.options
@options ||= {}
end
def options
self.class.options
end
end
end
end
class Baz
include HasOptions
set_option :name, "bad"
def greeting
puts options[:name]
end
end
class Foo
include HasOptions
set_option :name, "foo"
def greeting
puts options[:name]
end
end
感谢您的帮助。
答案 0 :(得分:5)
使用实例变量,正如您尝试的那样,将无法正常工作。但是,您可以使用以下方法:
module HasOptions
def self.included(cls)
cls.class_eval do
def self.set_option(key, value)
(@@options ||= {})[key] = value
end
end
end
def options
@options ||= @@options.dup
end
end
此实现允许您设置每个实例选项,而不会覆盖所有实例的公共选项。
答案 1 :(得分:2)
看起来你正在弄乱一些东西。让我试着列出你想要解决的问题:
Hash
的实例中存储选项(我是否正确了? - 所有类的实例都有一个哈希值); 上述任何内容实际上都不需要元编程。为了满足第一个条件,您只需找到所有类的第一个共同祖先,并[猴子]使用@@options
var和set_option
方法对其进行修补。如果您没有决定为所有类提供自己的超类,那么让我们修补一下祖先(例如Kernel
模块):
module Kernel
def set_option name, value
(@@options ||= {})[name.to_sym] = value
end
end
现在任何类都可以包含set_option
“指令”以将选项放入共享选项哈希中(考虑使用实例变量@options
而不是@@options
来制作选项特定于实例,或使用Alex D的解决方案。)
如果您希望选项设置采用花哨的语法(包括默认值,现场检查器,褶皱和奢侈品),您可以在此处使用DSL。 this article中的第一个示例显示了如何使用DSL实现纯set_option
。进一步的调整只受你想象力的限制。
答案 2 :(得分:1)
如果您需要init实例选项,则应使用实例方法来执行此操作。
module OptionSetter
def set_option(key, value)
@options[key] = value
end
end
class Base
def initialize(options = {})
@options = {}
options.each do |key, value|
set_option key, value
end
end
end
class A < Base
include OptionSetter
def hello
puts @options[:name]
puts @options[:address]
end
end
class B < Base
include OptionSetter
def greeting
puts @options[:age]
end
end
A.new(name: "james", address: "some street").hello
B.new(age: 18).greeting
在ruby中使用attr_accessor
的
class Base
attr_accessor :options
def initialize(options = {})
@options = options
end
end
class A < Base
def hello
puts @options[:name]
puts @options[:address]
end
end
class B < Base
def greeting
puts @options[:age]
end
end
A.new(name: "james", address: "some street").hello
B.new(age: 18).greeting
# another approach
james = A.new
james.options[:name] = "james"
james.options[:address] = "some street"
james.hello