当我有一个initialize
方法看起来像这样的时候有很多例子:
class Foo
def initialize bar, buz, ...
@bar, @buz, ... = bar, buz, ...
end
end
有没有办法通过简单的命令来执行此操作,如:
class Foo
attr_constructor :bar, :buz, ...
end
其中符号表示实例变量的名称(具有attr_accessor
,attr_reader
,attr_writer
的精神/风味?)
我想知道是否有内置方式或更优雅的方式做这样的事情:
class Class
def attr_constructor *vars
define_method("initialize") do |*vals|
vars.zip(vals){|var, val| instance_variable_set("@#{var}", val)}
end
end
end
所以我可以像这样使用它:
class Foo
attr_constructor :foo, :bar, :buz
end
p Foo.new('a', 'b', 'c') # => #<Foo:0x93f3e4c @foo="a", @bar="b", @buz="c">
p Foo.new('a', 'b', 'c', 'd') # => #<Foo:0x93f3e4d @foo="a", @bar="b", @buz="c">
p Foo.new('a', 'b') # => #<Foo:0x93f3e4e @foo="a", @bar="b", @buz=nil>
答案 0 :(得分:2)
这对你有用吗?
class Foo
def initialize(hash)
hash.each { |k,v| instance_variable_set("@#{k}", v) }
end
end
答案 1 :(得分:2)
我使用OpenStruct
:
require 'ostruct'
class Foo < OpenStruct
end
f = Foo.new(:bar => "baz")
f.bar
#=> "baz"
编辑:好的,抱歉误解了你。怎么样:
class Foo
def initialize(*args)
@baz, @buz = args
end
end
答案 2 :(得分:2)
有趣的问题。一个小的元编程应该照顾它。
module Attrs
def self.included(base)
base.extend ClassMethods
base.class_eval do
class << self
attr_accessor :attrs
end
end
end
module ClassMethods
# Define the attributes that each instance of the class should have
def has_attrs(*attrs)
self.attrs = attrs
attr_accessor *attrs
end
end
def initialize(*args)
raise ArgumentError, "You passed too many arguments!" if args.size > self.class.attrs.size
# Loop through each arg, assigning it to the appropriate attribute (based on the order)
args.each_with_index do |val, i|
attr = self.class.attrs[i]
instance_variable_set "@#{attr}", val
end
end
end
class Foo
include Attrs
has_attrs :bar, :buz
end
f = Foo.new('One', 'Two')
puts f.bar
puts f.buz
当然,缺点是缺乏灵活性 - 您必须按特定顺序传递构造函数参数。当然,大多数编程语言都是如此。 Rails人们可能会争辩说你应该做
f = Foo.new(:bar => 'One', :baz => 'Two')
这将允许您以任何顺序传入attrs,以及剥离大部分元编程。但输入的内容要多得多。