newbie Q: conditional object creation

Discussion in 'Ruby' started by Paul Van Delst, Jul 5, 2006.

  1. Hello,

    The subject line may be confusing as I don't know the correct terminology, so apologies in
    advance.

    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?

    Thanks for any help. (I have about 4 days of Ruby experience so please be kind... :eek:)

    cheers,

    paulv

    --
    Paul van Delst Ride lots.
    CIMSS @ NOAA/NCEP/EMC Eddy Merckx
     
    Paul Van Delst, Jul 5, 2006
    #1
    1. Advertising

  2. Paul Van Delst wrote:
    > Hello,
    >
    > The subject line may be confusing as I don't know the correct
    > terminology, so apologies in advance.
    >
    > 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


    just:

    @name,@value=name,value if VALID_NAMES.index(name)

    > 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?
    >


    any not initialized instance variable will return null, so just don't
    bother ;D

    lopex
     
    Marcin Mielżyński, Jul 5, 2006
    #2
    1. Advertising

  3. Marcin Mielżyński wrote:
    > Paul Van Delst wrote:
    >
    >> Hello,
    >>
    >> The subject line may be confusing as I don't know the correct
    >> terminology, so apologies in advance.
    >>
    >> 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

    >
    > just:
    >
    > @name,@value=name,value if VALID_NAMES.index(name)


    Excellent! Thanks very much.

    cheers,

    paulv

    --
    Paul van Delst Ride lots.
    CIMSS @ NOAA/NCEP/EMC Eddy Merckx
     
    Paul Van Delst, Jul 5, 2006
    #3
  4. 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, Jul 6, 2006
    #4
  5. 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, Jul 6, 2006
    #5
  6. 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
     
    Paul Van Delst, Jul 6, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alec S.
    Replies:
    10
    Views:
    10,239
    Alec S.
    Apr 16, 2005
  2. tommalia
    Replies:
    1
    Views:
    1,910
    Dimitre Novatchev
    Jul 15, 2006
  3. jon wayne
    Replies:
    9
    Views:
    723
    Jim Langston
    Sep 22, 2005
  4. Sol Linderstein
    Replies:
    3
    Views:
    109
    kaeli
    Jun 3, 2004
  5. Replies:
    44
    Views:
    363
    John G Harris
    May 25, 2006
Loading...

Share This Page