有没有一种干净的方法可以删除常见的 ruby 对象初始化代码?
Is there a clean way to remove the common ruby object initialization code?
是否有一种简洁的方法来遍历 attr_reader 属性并设置它们?
class Foo
attr_reader :bar, :baz, ...
def initialize attrs
@bar = attrs[:bar]
@baz = attrs[:baz]
.
.
.
如果你想让散列键匹配属性名,一种可能是继承一个结构:
class Foo < Struct.new(:bar, :baz, keyword_init: true) # Note the "keyword_init" parameter
end
puts Foo.new(bar: 42, baz: :foo).bar
# => 42
Struct 也会创建 public writers,所以如果你不想让它们成为 public 你必须将它们设置为 private
FOO_ATTRS = [:bar, :baz]
class Foo < Struct.new(*FOO_ATTRS, keyword_init: true) # Note the "keyword_init" parameter
# Make method 'my_attribute=' private if needed
private *FOO_ATTRS.map { |attr| "#{attr}=" }
end
puts Foo.new(bar: 42, baz: :foo).bar
如果您想为不同的属性名称重命名散列键:
class Foo
INITIAL_ATTRS = {
foo: :@bar,
bar: :@baz
}
attr_reader *(INITIAL_ATTRS.values.map { |k| k.to_s.delete('@').to_sym })
def initialize attrs
attrs.slice(*INITIAL_ATTRS.keys).each do |var, value|
instance_variable_set(INITIAL_ATTRS[var], value)
end
end
end
编辑
另一种可能性是使用 private attr_writer 这样你就不必处理 @ tricks
class Foo
INITIAL_ATTRS = {
foo: :bar,
bar: :baz
}
attr_reader *(INITIAL_ATTRS.values)
def initialize attrs
attrs.slice(*INITIAL_ATTRS.keys).each do |var, value|
send("#{INITIAL_ATTRS[var]}=", value)
end
end
private
attr_writer *(INITIAL_ATTRS.values)
end
请注意,如果您不想将 foo 转换为 bar,您可以使用数组而不是 INITIAL_ATTRS 的散列。这将通过删除 .values
和 .keys
来简化代码
class Foo
INITIAL_ATTRS = [:foo, :bar]
attr_reader *INITIAL_ATTRS
def initialize attrs
attrs.slice(*INITIAL_ATTRS).each do |var, value|
send("#{var}=", value)
end
end
private
attr_writer *INITIAL_ATTRS
end
是否有一种简洁的方法来遍历 attr_reader 属性并设置它们?
class Foo
attr_reader :bar, :baz, ...
def initialize attrs
@bar = attrs[:bar]
@baz = attrs[:baz]
.
.
.
如果你想让散列键匹配属性名,一种可能是继承一个结构:
class Foo < Struct.new(:bar, :baz, keyword_init: true) # Note the "keyword_init" parameter
end
puts Foo.new(bar: 42, baz: :foo).bar
# => 42
Struct 也会创建 public writers,所以如果你不想让它们成为 public 你必须将它们设置为 private
FOO_ATTRS = [:bar, :baz]
class Foo < Struct.new(*FOO_ATTRS, keyword_init: true) # Note the "keyword_init" parameter
# Make method 'my_attribute=' private if needed
private *FOO_ATTRS.map { |attr| "#{attr}=" }
end
puts Foo.new(bar: 42, baz: :foo).bar
如果您想为不同的属性名称重命名散列键:
class Foo
INITIAL_ATTRS = {
foo: :@bar,
bar: :@baz
}
attr_reader *(INITIAL_ATTRS.values.map { |k| k.to_s.delete('@').to_sym })
def initialize attrs
attrs.slice(*INITIAL_ATTRS.keys).each do |var, value|
instance_variable_set(INITIAL_ATTRS[var], value)
end
end
end
编辑
另一种可能性是使用 private attr_writer 这样你就不必处理 @ tricks
class Foo
INITIAL_ATTRS = {
foo: :bar,
bar: :baz
}
attr_reader *(INITIAL_ATTRS.values)
def initialize attrs
attrs.slice(*INITIAL_ATTRS.keys).each do |var, value|
send("#{INITIAL_ATTRS[var]}=", value)
end
end
private
attr_writer *(INITIAL_ATTRS.values)
end
请注意,如果您不想将 foo 转换为 bar,您可以使用数组而不是 INITIAL_ATTRS 的散列。这将通过删除 .values
和 .keys
class Foo
INITIAL_ATTRS = [:foo, :bar]
attr_reader *INITIAL_ATTRS
def initialize attrs
attrs.slice(*INITIAL_ATTRS).each do |var, value|
send("#{var}=", value)
end
end
private
attr_writer *INITIAL_ATTRS
end