how to create an object of a class you don't know yet

Discussion in 'Ruby' started by Bradley, Todd, Dec 3, 2004.

  1. Hi, I'm just now getting into Ruby's OO-ness, and could use some advice.
    I'm trying to create an object, but which specific class needs to be
    determined at runtime. I figured out how to do this by creating a
    string and executing it using the "eval" command, but I know there must
    be an easier way. My first guess was to do something like #{answer}.new
    but that didn't work.


    Here's my code:


    class Foo
    def method1
    end
    end

    class Bar
    def method2
    end
    end

    # Pretend this was determined at runtime
    answer = "Foo"


    # There must be a better way of doing this:

    myobj = Object.new # Needs to exist in this scope
    mystring = "myobj = #{answer}.new"

    eval mystring

    puts "I just created a #{myobj.class} object."




    Any advice is appreciated. Thanks in advance!


    Todd.
     
    Bradley, Todd, Dec 3, 2004
    #1
    1. Advertising

  2. Bradley, Todd

    Eric Hodel Guest

    On 03 Dec 2004, at 10:44, Bradley, Todd wrote:

    > Hi, I'm just now getting into Ruby's OO-ness, and could use some
    > advice.
    > I'm trying to create an object, but which specific class needs to be
    > determined at runtime. I figured out how to do this by creating a
    > string and executing it using the "eval" command, but I know there must
    > be an easier way. My first guess was to do something like
    > #{answer}.new
    > but that didn't work.
    >
    >
    > Here's my code:
    >
    >
    > class Foo
    > def method1
    > end
    > end
    >
    > class Bar
    > def method2
    > end
    > end
    >
    > # Pretend this was determined at runtime
    > answer = "Foo"
    >
    >
    > # There must be a better way of doing this:
    >
    > myobj = Object.new # Needs to exist in this scope
    > mystring = "myobj = #{answer}.new"
    >
    > eval mystring
    >
    > puts "I just created a #{myobj.class} object."


    klass = answer.split('::').inject(Object) { |klass,const|
    klass.const_get const }

    myobj = klass.new

    In longer terms:

    answer.split('::') # for Foo::Bar::Baz nested classes/modules

    answer.split('::').inject(Object) do |klass, const| # namespaces start
    from Object
    klass.const_get const # #inject passes the value of this expression in
    # as the first arg to the block, so use that namespace
    # to find the next part of the namespace
    end

    klass = answer.split [...] # #inject returns the last result, which will
    # be a class, provided answer references a class

    myobj = klass.new # instantiate an instance of the class

    You can also do things like this:

    KLASSES = { 'html' => HTMLWriter, 'pdf' => PDFWriter, 'plain-text' =>
    TextWriter }

    output = ARGV.shift

    raise "invalid output type" unless KLASSES.include? output

    writer = KLASSES[output].new
     
    Eric Hodel, Dec 3, 2004
    #2
    1. Advertising

  3. "new" is just a class method, and you can call class methods on classes
    that aren't bound at the time of interpretation. For example:

    instance = MyClass.new

    is the same as

    a_class = MyClass
    instance = a_class.new

    So you can do things like:

    irb(main):001:0> classes = [ String, Hash, Array ]
    => [String, Hash, Array]
    irb(main):002:0> grab_bag = classes.collect { |a_class| a_class.new }
    => ["", {}, []]



    On Dec 3, 2004, at 1:44 PM, Bradley, Todd wrote:

    > Hi, I'm just now getting into Ruby's OO-ness, and could use some
    > advice.
    > I'm trying to create an object, but which specific class needs to be
    > determined at runtime. I figured out how to do this by creating a
    > string and executing it using the "eval" command, but I know there must
    > be an easier way. My first guess was to do something like
    > #{answer}.new
    > but that didn't work.
    >
    >
    > Here's my code:
    >
    >
    > class Foo
    > def method1
    > end
    > end
    >
    > class Bar
    > def method2
    > end
    > end
    >
    > # Pretend this was determined at runtime
    > answer = "Foo"
    >
    >
    > # There must be a better way of doing this:
    >
    > myobj = Object.new # Needs to exist in this scope
    > mystring = "myobj = #{answer}.new"
    >
    > eval mystring
    >
    > puts "I just created a #{myobj.class} object."
    >
    >
    >
    >
    > Any advice is appreciated. Thanks in advance!
    >
    >
    > Todd.
    >
    >


    Francis Hwang
    http://fhwang.net/
     
    Francis Hwang, Dec 3, 2004
    #3
  4. Bradley, Todd wrote:
    > Hi, I'm just now getting into Ruby's OO-ness, and could use some advice.
    > I'm trying to create an object, but which specific class needs to be
    > determined at runtime. I figured out how to do this by creating a
    > string and executing it using the "eval" command, but I know there must
    > be an easier way. My first guess was to do something like #{answer}.new
    > but that didn't work.
    >
    >
    > Here's my code:
    >
    >
    > class Foo
    > def method1
    > end
    > end
    >
    > class Bar
    > def method2
    > end
    > end
    >
    > # Pretend this was determined at runtime
    > answer = "Foo"
    >
    >
    > # There must be a better way of doing this:
    >
    > myobj = Object.new # Needs to exist in this scope
    > mystring = "myobj = #{answer}.new"
    >
    > eval mystring
    >
    > puts "I just created a #{myobj.class} object."
    >
    >
    >
    >
    > Any advice is appreciated. Thanks in advance!
    >
    >
    > Todd.
    >
    >
    >

    class GMClassManager
    @@classHash = { 'CLASS_ROOM_DEFAULT' => GMRoom,
    'CLASS_ROOM_LOGIN' => GMLoginRoom,
    }

    def GMClassManager.getRoomObject( valueClassId )
    tmpClass = @@classHash[ valueClassId ]
    if not tmpClass == nil
    tmpClass.new
    else
    nil
    end
    end
    end


    This works for me
     
    Daneel van Tonder, Dec 4, 2004
    #4
  5. Daneel van Tonder wrote:

    > class GMClassManager
    > @@classHash = { 'CLASS_ROOM_DEFAULT' => GMRoom,
    > 'CLASS_ROOM_LOGIN' => GMLoginRoom,
    > }


    Using a constant instead would be nicer, I think.
     
    Florian Gross, Dec 4, 2004
    #5
    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. DP
    Replies:
    0
    Views:
    1,178
  2. Berehem
    Replies:
    4
    Views:
    591
    Lawrence Kirby
    Apr 28, 2005
  3. Jason
    Replies:
    0
    Views:
    227
    Jason
    Jul 6, 2004
  4. Andries

    I know, I know, I don't know

    Andries, Apr 23, 2004, in forum: Perl Misc
    Replies:
    3
    Views:
    276
    Gregory Toomey
    Apr 23, 2004
  5. Andrew Poulos
    Replies:
    1
    Views:
    94
    Bjoern Hoehrmann
    Sep 1, 2008
Loading...

Share This Page