Newbie Q: conditional object creation

Paul Van Delst wrote:

I'm want to be able to create objects, but I want the object creation to only proceed if the values passed to the init method are in a valid list. E.g.:

class MyObj
  VALID_NAMES=['bananas','dog','water']
  attr_reader :name, :value
  def initialize(name,value)
    i=VALID_NAMES.index(name)
    if i then
      @name,@value=name,value
    else
      @name,@value=nil
    end
  end
end

This sorta does what I want, but looks clunky, ugly and quite un-ruby-ish. Is there a better way (idiom?) to achieve this sort of thing? I.e. is there a way to make the init method not create even an "empty" object (as happens above) based on the valid names list?

   class MyObj
     VALID_NAMES = %w{bananas dog water} # array of strings

     # go into the metaclass
     class << self
       alias_method :__new__, :new

       def new(name, value)
         raise unless VALID_NAMES.include? name
         __new__(name, value)
       end
     end

     def initialize(name, value)
       @name, @value = name, value
     end
   end

This will raise an exception when MyObj.new is called with an invalid name. You should read up on metaclasses if you haven't already[1].

If you just want MyObj.new to return nil when supplied with an invalid argument, this will do the trick:

   def new(name, value)
     __new__(name, value) if VALID_NAMES.include? name
   end

Cheers,
Daniel

[1] http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

Daniel Schierbeck wrote:

Paul Van Delst wrote:

I'm want to be able to create objects, but I want the object creation to only proceed if the values passed to the init method are in a valid list. E.g.:

class MyObj
  VALID_NAMES=['bananas','dog','water']
  attr_reader :name, :value
  def initialize(name,value)
    i=VALID_NAMES.index(name)
    if i then
      @name,@value=name,value
    else
      @name,@value=nil
    end
  end
end

This sorta does what I want, but looks clunky, ugly and quite un-ruby-ish. Is there a better way (idiom?) to achieve this sort of thing? I.e. is there a way to make the init method not create even an "empty" object (as happens above) based on the valid names list?

  class MyObj
    VALID_NAMES = %w{bananas dog water} # array of strings

    # go into the metaclass
    class << self
      alias_method :__new__, :new

      def new(name, value)
        raise unless VALID_NAMES.include? name
        __new__(name, value)
      end
    end

    def initialize(name, value)
      @name, @value = name, value
    end
  end

This will raise an exception when MyObj.new is called with an invalid name. You should read up on metaclasses if you haven't already[1].

If you just want MyObj.new to return nil when supplied with an invalid argument, this will do the trick:

  def new(name, value)
    __new__(name, value) if VALID_NAMES.include? name
  end

Cheers,
Daniel

[1] http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

The same effect can be achieved in two other way that do not involve meta classes:

1. make initialize throw an exception. Although the instance will be created, nobody ever gets to see it (unless initialize stores self somewhere).

class MyClass
   VALID_NAMES=['bananas','dog','water']

   attr_reader :name, :value

   def initialize(name, value)
     raise ArgumentError, "Invalid name: #{name}" unless
        VALID_NAMES.include? name
     @name = name
     @value = value
   end
end

2. add a class method instead of aliasing new.

class MyClass
   VALID_NAMES=['bananas','dog','water']

   attr_reader :name, :value

   def self.create(name, value)
     raise ArgumentError, "Invalid name: #{name}" unless
        VALID_NAMES.include? name
     new name, value
   end

   def initialize(name, value)
     @name = name
     @value = value
   end
end

I'd probably favor approach 1 as it is more robust (you cannot forget to call "create" as in the second approach).

Kind regards

  robert

Robert Klemme wrote:

Daniel Schierbeck wrote:

[excellent code examples elided]

Beautiful. Thanks much to both posters. Especially for the exception handling examples. Much appreicated.

cheers,

paulv

···

--
Paul van Delst Ride lots.
CIMSS @ NOAA/NCEP/EMC Eddy Merckx