Simple Q: object creation to be determined by incoming data


#1

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?


#2

On Mon, May 21, 2007 at 08:38:02PM +0900, Todd B. 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©
}.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.


#3

Thanks guys, const_get is what I was looking for!


#4

Alle lunedì 21 maggio 2007, Todd B. 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