构造函数中许多attr_reader的简写

时间:2015-08-15 07:09:03

标签: ruby

我发现自己在课堂上初始化了很多变量,我想知道是否有更简单的方法可以做到这一点。一旦你获得了20个变量,就会变得有点多余。

class Car
  attr_reader :make, 
    :model, 
    :year, 
    :id

  def initialize(args)
    @make = args["make"]
    @model = args["model"]
    @year = args["year"]
    @id = args["id"]
  end
end

谢谢!

4 个答案:

答案 0 :(得分:1)

如果您特别关注immutable_struct,有一个名为attr_reader的宝石 https://github.com/iconara/immutable_struct

class Spaceship < ImmutableStruct.new(:name, :max_speed)
end

ship = Spaceship.new('Enterprise', 'Warp 9')

puts ship.max_speed # => Warp 9

ship.max_speed = '299792458 m/s' # raises NoMethodError

但如果你对attr_accessor没事,普通的Struct应该这样做。

答案 1 :(得分:1)

您也可以这样做:

class Car
  def initialize(args)
    args.each do |key, value|
      instance_variable_set("@#{key}", value)
    end
  end
end

car = Car.new({name: 'My car', make: 'BMW'})
p car #<Car:0x007fe80c8875d8 @name="My car", @make="BMW">

答案 2 :(得分:1)

您可以使用一些动态技术,使您的代码具有灵活的外观示例:

class Car
  def initialize(args = {})
    args.each do |ar|
      instance_variable_set(:"@#{ar.first}", ar.last)
    end
  end

  def method_missing(m, *args, &blk)
    if instance_variables.include? :"@#{m}"
      instance_variable_get("@#{m}")
    else
      super
    end
  end
end    
c = Car.new(foo: 1, bar: '132', baz: 'foo')    
puts c.foo
puts c.baz
puts c.bar    
puts c.barfoo

在irb中运行:

$ irb -r ./example.rb
#> 1
#> foo
#> 132
#> example.rb:14:in `method_missing': undefined method `barfoo' for #<Car:0x000000015bc740 @foo=1, @bar="132", @baz="foo"> (NoMethodError)

正如您所看到的,您可以根据需要将具有任意数量的对键值的散列作为参数传递,但是当属性不可用时它也会引发错误

instance_variablesinstance_variable_setinstance_variable_getmethod_missing

这是使用class_eval方法的另一个技巧:

class Car
  def initialize(args = {})
    args.each_pair do |k, v|
      self.class.class_eval do
        attr_reader k
      end
      instance_variable_set(:"@#{k}", v)
    end
  end
end
c = Car.new(foo: 1, bar: '132', baz: 'foo')
puts c.foo
puts c.baz
puts c.bar
puts c.inspect

在irb中运行:

#> 1
#> foo
#> 132
#> #<Car:0x00000002dc1fc0 @foo=1, @bar="132", @baz="foo">

再次在运行时为给定的密钥添加attr_reader并使用该密钥的值设置实例变量。

答案 3 :(得分:0)

我无法帮助自己写一个宝石来帮助我,因为我自己经常遇到同样的烦恼。它被称为&#34; attr_args_shorthand&#34;。

基本上你可以在gem的帮助下这样做:

class User
  def initialize(args)
    AttrArgsShorthand.set(self, args)
  end
end

然后你可以这样做:

user = User.new(name: "Kasper")
user.name #=> "Kasper"
user.name = "Christina"
user.name #=> "Christina"
user.instance_variable_get(:@name) #=> "Christina"

https://github.com/kaspernj/attr_args_shorthand