我有一个Rails应用程序,需要重复设置默认属性。有时,用户将提供将被尊重的属性的值,但在其他情况下,模型或用户可能希望使用默认值覆盖这些属性而忽略原始值。
我猜这个问题需要一个用于设置默认值的banged(!
)和非banged方法,允许用户和程序切换到适当的状态。非撞击的setter只会在它们不为nil时设置默认值,而banged版本将始终使用默认值覆盖属性。差别很小:
class BangDiBang
attr_accessor :value
def set_default
self.value ||= do_some_suff_to_determine_default_value
end
def set_default!
self.value = do_some_suff_to_determine_default_value
end
...
end
这段代码的问题是如果我要设置一堆变量,我最终会为每个变量重复两次相同的代码。
我的问题是如何分解这段代码?将逻辑保存在一个方法中,并使用两个方法set_value
和set_value!
使用不同的赋值运算符调用中央逻辑。
我想到了一个解决方案:将中央逻辑写为文本,从setter方法替换赋值操作并进行评估(但这感觉不对)。我怎么不重复自己?
答案 0 :(得分:0)
由于您正在调用set_default
但未指定哪个变量,因此您对此进行此操作的方式不适用于多个参数。理想情况下,您需要为每个变量定义行为。有些库可以处理这类事情,但你可以很容易地自己动手:
class Example
def self.default_param(name, default_value)
define_method("default_#{name}") { default_value }
define_method(name) do
instance_variable_get("@#{name}") || default_value
end
attr_writer name
end
default_param :foo, 'foo default'
end
ex = Example.new
ex.foo #=> "foo default"
ex.foo = 'bar'
ex.foo #=> "bar"
ex.default_foo #=> "foo default"
我已将set_default
和set_default!
重命名为更清晰:对于每个具有默认值的变量,都会创建三个方法(例如使用foo
作为变量名称):< / p>
foo
- 如果它是真实的,则返回@foo
的值,否则返回default_foo
foo=
- 设置@foo
default_foo
- 返回指定的默认值您可以进一步划分和干掉上面的一些代码,创建一个default_params
(复数)方法来获取哈希值,将类宏提取到关注点:
module DefaultParams
def default_param(name, default_value)
define_method("default_#{name}") { default_value }
define_method(name) do
instance_variable_get("@#{name}") || default_value
end
attr_writer name
end
def default_params(params)
params.each { |default| default_param(*default) }
end
end
class Example
extend DefaultParams
default_params foo: 'default foo', bar: 'my favorite bar'
end
答案 1 :(得分:0)
我已经实施了一个灵感来自coreyward的解决方案。我一开始并没有意识到,我需要将默认值分离为单个方法,而不是使用两种方法来设置默认值数组。这为应用程序的设计提供了极大的灵活性。非常感谢答案。
对于我已添加到application_record.rb
def set_attr_from_defaults
default_attrs.each do |atr|
eval("self.#{atr[0..atr.length-9]} ||= self.#{atr}")
end
end
def set_attr_from_defaults!
default_attrs.each do |atr|
eval("self.#{atr[0..atr.length-9]} = self.#{atr}")
end
end
def set_default_attr params
params.each { |key, value| self.define_singleton_method(key){value} }
end
def default_attrs
self.attributes.keys.map{|i| (i+'_default').to_sym} & self.methods
end
default_attrs
生成默认属性的符号列表。 set_default_attr
定义了单例方法,打算在像attrname_default: 'default_value' ...
这样的散列中使用解析。当属性具有set_attr_from_defaults
对时,var: var_default
会根据默认值设置属性。数字9
是_default
+ 1的长度。