Ruby中的DRY'er对象初始化

问题描述:

在ruby中有更多'干'的方法来做以下事情吗?Ruby中的DRY'er对象初始化

#!/usr/bin/env ruby 

class Volume 
    attr_accessor :name, :size, :type, :owner, :date_created, :date_modified, :iscsi_target, :iscsi_portal 

    SYSTEM = 0 
    DATA = 1 

    def initialize(args={:type => SYSTEM}) 
     @name = args[:name] 
     @size = args[:size] 
     @type = args[:type] 
     @owner = args[:owner] 
     @iscsi_target = args[:iscsi_target] 
     @iscsi_portal = args[:iscsi_portal] 
    end 

    def inspect 
     return {:name => @name, 
       :size => @size, 
       :type => @type, 
       :owner => @owner, 
       :date_created => @date_created, 
       :date_modified => @date_modified, 
       :iscsi_target => @iscsi_target, 
       :iscsi_portal => @iscsi_portal } 
    end 

    def to_json 
     self.inspect.to_json 
    end 

+0

OpenStruct会有所需的功能吗? – 2011-06-26 05:28:18

+0

这应该在codereview.stackexchange.com – 2012-01-31 00:36:36

每当你看到的东西像一个长长的清单,通常你可以把它卷都成一个单一的阵列:

class Volume 
    ATTRIBUTES = [ 
    :name, :size, :type, :owner, :date_created, :date_modified, 
    :iscsi_target, :iscsi_portal 
    ].freeze 

    ATTRIBUTES.each do |attr| 
    attr_accessor attr 
    end 

    SYSTEM = 0 
    DATA = 1 

    DEFAULTS = { 
    :type => SYSTEM 
    }.freeze 

    def initialize(args = nil) 
    # EDIT 
    # args = args ? DEFAULTS : DEFAULTS.merge(args) # Original 
    args = args ? DEFAULTS.merge(args) : DEFAULTS 

    ATTRIBUTES.each do |attr| 
     if (args.key?(attr)) 
     instance_variable_set("@#{attr}", args[attr]) 
     end 
    end 
    end 

    def inspect 
    ATTRIBUTES.inject({ }) do |h, attr| 
     h[attr] = instance_variable_get("@#{attr}") 
     h 
    end 
    end 

    def to_json 
    self.inspect.to_json 
    end 
end 

操纵实例变量是以后很简单。

+0

太棒了!我必须在初始化函数中更改一行 args = args? DEFAULTS:DEFAULTS.merge(args) 变成 args =(args == nil)?默认值:DEFAULTS.merge(args) 否则它将返回DEFAULTS并且不会设置任何内容。 – 2009-06-11 19:46:58

class Volume 

    FIELDS = %w(name size type owner iscsi_target iscsi_portal date_create date_modified) 
    SYSTEM = 0 
    DATA = 1 
    attr_accessor *FIELDS 

    def initialize(args= { :type => SYSTEM }) 
    args.each_pair do | key, value | 
     self.send("#{key}=", value) if self.respond_to?("#{key}=") 
    end 
    end 

    def inspect 
    FIELDS.inject({}) do | hash, field | 
     hash.merge(field.to_sym => self.send(field)) 
    end.inspect 
    end 

end 

Riffing关闭tadman的的answer

我会#inspect返回一个字符串(最喜欢的#inspect方法),也许因素 出你转换成散列法成#to_hash方法来代替。

args.merge(DEFAULTS).merge(args)废话让args覆盖的DEFAULTS,但 防止任何默认行为args(比方说,如果args == Hash.new(3)args == Hash.new { |h,k| h[k] = h.to_s.length }

class Volume 
    ATTRIBUTES = %w{ 
    name size type owner date_created date_modified 
    iscsi_target iscsi_portal 
    }.map! { |s| s.to_sym }.freeze 

    attr_accessor *ATTRIBUTES 

    SYSTEM = 0 
    DATA = 1 

    DEFAULTS = { :type => SYSTEM }.freeze 

    def initialize(args = nil) 
    args = args ? args.merge(DEFAULTS).merge(args) : DEFAULTS 

    ATTRIBUTES.each do |attr| 
     instance_variable_set("@#{attr}", args[attr]) 
    end 
    end 

    def to_hash 
    Hash[ *ATTRIBUTES.map { |attr| [ attr, instance_variable_get("@#{attr}") ] }.flatten ] 
    end 

    def inspect 
    to_hash.inspect 
    end 

    def to_json 
    self.to_hash.to_json 
    end 
end 

这里有答案稍有不同的旋转通过tadman:

class Volume 
    ATTRIBUTES = [ 
    :name, :size, :type, :owner, :date_created, :date_modified, 
    :iscsi_target, :iscsi_portal 
    ].freeze 

    ATTRIBUTES.each do |attr| 
    attr_accessor attr 
    end 

    SYSTEM = 0 
    DATA = 1 

    DEFAULTS = { 
    :type => SYSTEM 
    }.freeze 

    def initialize(&block) 
    ATTRIBUTES.each do |attr| 
     self.__send__ "#{attr}=", DEFAULTS[attr] 
    end 
    yield(self) 
    end 

    def inspect 
    ATTRIBUTES.inject({}) { |h,attr| h[attr] = self.__send__ attr; h } 
    end 
    def to_json 
    self.inspect.to_json 
    end 
end 

这允许这样做:

vol = Volume.new do |v| 
    v.name = 'myVolume' 
end 

我喜欢这个,因为如果有人在属性上输入错误,它就会立即给出错误。

此外,不同于他的回答,它会在未提供默认值时初始化默认值。

,或者如果你最终做了很多,真正需要干:

module Attributable 
    @@ATTRIBUTES = [] 
    @@DEFAULTS = {} 

    def initialize(&block) 
    @@ATTRIBUTES.each do |attr| 
     self.class.__send__ :attr_accessor, attr 
     self.__send__ "#{attr}=", @@DEFAULTS[attr] 
    end 
    yield(self) 
    end 
end 

class Volume 
    include Attributable 
    @@ATTRIBUTES = [ :name, :size, :type, :owner ] 
    @@DEFAULTS = { :type => 0 } 
end 

无法工作,如何与常量做,所以我用类变量,而不是做到了。