Forum: Ruby Simple Q: object creation to be determined by incoming data

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
289cf19aa581c445915c072bf45c5e25?d=identicon&s=25 Todd Benson (Guest)
on 2007-05-21 13:38
(Received via mailing list)
I'm almost embarrassed to ask this, because I'm bound to be pointed to
some
code that I've almost certainly read already, but here goes my ruby
newbie
question:

I have an incoming stream of data in separated chunks, each having a
beginning word that defines that chunk's place in the world (how it will
respond to #to_s, etc).  Currently, I model each chunk as an object;
each
has its own class.  Basically, I'm unserializing object data, but I
provide
the object functionality.  I want to do off-the-stream object creation,
and
so I've went and done something like:

instance_eval( "#{class_name_from_stream_chunk}.new(
data_from_stream_chunk
)" )

Is this the only way to do this (by "way", I mean the code and also the
manner), and if not, the best way?
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-05-21 14:02
(Received via mailing list)
On Mon, May 21, 2007 at 08:38:02PM +0900, Todd Benson wrote:
> I want to do off-the-stream object creation, and
> so I've went and done something like:
>
> instance_eval( "#{class_name_from_stream_chunk}.new( data_from_stream_chunk
> )" )
>
> Is this the only way to do this (by "way", I mean the code and also the
> manner), and if not, the best way?

If the class names are all top-level, e.g. "Foo", then

  obj = Object.const_get(classname).new(*args)

If the class names are all under one module, e.g. the string "Foo"
really
means Bar::Foo, then

  obj = Bar.const_get(classname).new(*args)

(I'd recommend this form, as it prevents your stream creating objects
except
those directly under a 'safe' module)

If the class names are arbitary nested modules, e.g. they could be
"Bar::Foo", then

  obj = classname.split('::').inject(Object) { |k,c| k.const_get(c)
}.new(*args)

This assumes that your data_from_stream_chunk has been split into an
array
called 'args' (the 'shellwords' modules is useful for this). And also
you
have to make everything the correct type, e.g. if your object expects
an integer constructor then you'll have to call to_i.

HTH,

Brian.
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2007-05-21 14:03
(Received via mailing list)
Alle lunedì 21 maggio 2007, Todd Benson ha scritto:
>
> instance_eval( "#{class_name_from_stream_chunk}.new( data_from_stream_chunk
> )" )
>
> Is this the only way to do this (by "way", I mean the code and also the
> manner), and if not, the best way?

I'm not sure I understand correctly your question. I think you don't
need to
use instance eval. If class_name_from_stream_chunk is a string/symbol
and the
class is defined in the module M (if it is defined top level, substitute
M
with Kernel), you can do:

M.const_get(class_name_from_stream_chunk).new(data_from_stream_chunk)

You can also define a method which wraps this in a simpler interface:

def M.new_from_chunk name, data
  const_get(name).new(data)
end

and use it this way:

res = M.new(class_name_from_stream_chunk, data_from_stream_chunk)

I hope this helps

Stefano
289cf19aa581c445915c072bf45c5e25?d=identicon&s=25 Todd Benson (Guest)
on 2007-05-21 14:40
(Received via mailing list)
Thanks guys, const_get is what I was looking for!
This topic is locked and can not be replied to.