DRY'er Inicializace objektů v Ruby

hlasů
14

Je tam víc ‚suché‘ způsob, jak udělat následující ruby?

#!/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

konec

Položena 11/06/2009 v 19:34
zdroj uživatelem
V jiných jazycích...                            


4 odpovědí

hlasů
12

Kdykoliv uvidíte dlouhý seznam věcí, jako je to, že obvykle můžete vrátit to všechno až do singulární Array:

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

Manipulaci proměnných instance je po tom velice jednoduché.

Odpovězeno 11/06/2009 v 19:41
zdroj uživatelem

hlasů
9
 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
Odpovězeno 11/06/2009 v 20:46
zdroj uživatelem

hlasů
1

Zde je trochu jiný rotace na odpověď ze strany 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

To umožňuje, jak to udělat:

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

Líbí se mi to, protože to má tu výhodu, že dává chyby hned, pokud má někdo udělal překlep na příznaku.

Také, na rozdíl od své odpovědi, že inicializuje výchozí když nejsou součástí dodávky.

nebo pokud jste skončili dělat to hodně a opravdu potřebují suchá:

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

nemohl vymyslet, jak to udělat s konstantami, tak jsem to udělal s třídními proměnnými místo.

Odpovězeno 11/06/2010 v 07:50
zdroj uživatelem

hlasů
1

Riffy pryč tadman ‚s odpovědí

Budu muset #inspectvrátit řetězec (jako většina #inspectmetod), a možná vytknout konverze na metodu hash na #to_hashmetodu místo.

args.merge(DEFAULTS).merge(args)Nesmysl nechává argspřepsat DEFAULTS, ale pořád žádný výchozí chování pro args(řekněme, pokud args == Hash.new(3)neboargs == 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
Odpovězeno 12/06/2009 v 02:11
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more