Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

string to Class object

5 views
Skip to first unread message

R. Mark Volkmann

unread,
Jun 23, 2005, 9:26:51 PM6/23/05
to
How can I create a Class object from a String that contains the name of a class?
For example, after

clazz = Array

the variable clazz holds a Class object representing the class Array.
I want to start with a string like this.

name = 'Array'
clazz = ???

--
R. Mark Volkmann
Partner, Object Computing, Inc.


Austin Ziegler

unread,
Jun 23, 2005, 9:41:43 PM6/23/05
to
On 6/23/05, R. Mark Volkmann <ma...@ociweb.com> wrote:
> How can I create a Class object from a String that contains the name of a class?
> For example, after
>
> clazz = Array
>
> the variable clazz holds a Class object representing the class Array.
> I want to start with a string like this.
>
> name = 'Array'
> clazz = ???

For top-level objects, this is as simple as:

name = 'Array'
klass = Object.const_get(name)
p klass # => Array

For nested values, it's:

name = 'Transaction::Simple::Group'
klass = name.split(/::/).inject(Object) { |k, n| k.const_get(n) }
p klass # => Transaction::Simple::Group

-austin
--
Austin Ziegler * halos...@gmail.com
* Alternate: aus...@halostatue.ca


Devin Mullins

unread,
Jun 23, 2005, 9:38:56 PM6/23/05
to
Good question. A crappy way:

ObjectSpace.each_object {|obj|
break obj if Class === obj and obj.name == clazz
}

But I'm still young. There might be a non-crappy way.

Devin

James Edward Gray II

unread,
Jun 23, 2005, 9:44:31 PM6/23/05
to
On Jun 23, 2005, at 8:26 PM, R. Mark Volkmann wrote:

> How can I create a Class object from a String that contains the
> name of a class?
> For example, after
>
> clazz = Array
>
> the variable clazz holds a Class object representing the class Array.
> I want to start with a string like this.
>
> name = 'Array'
> clazz = ???

clazz = Object.const_get(name)

Hope that helps.

James Edward Gray II


Devin Mullins

unread,
Jun 23, 2005, 9:46:00 PM6/23/05
to
Well, slightly less:

ObjectSpace.each_object(Class) {|obj|
break obj if obj.name == clazz
}

Devin

Hal Fulton

unread,
Jun 23, 2005, 9:50:43 PM6/23/05
to
Austin Ziegler wrote:
>
> For top-level objects, this is as simple as:
>
> name = 'Array'
> klass = Object.const_get(name)
> p klass # => Array
>
> For nested values, it's:
>
> name = 'Transaction::Simple::Group'
> klass = name.split(/::/).inject(Object) { |k, n| k.const_get(n) }
> p klass # => Transaction::Simple::Group
>

Quite right. There is also the eval (evil?) method:

clazz = eval(name)


BTW, I've wondered why Object.const_get doesn't honor
the X::Y::Z form. It's unambiguous and I can't see a
good reason not to decipher it.


Hal


Austin Ziegler

unread,
Jun 23, 2005, 11:19:47 PM6/23/05
to
On 6/23/05, Hal Fulton <hal...@hypermetrics.com> wrote:

> Austin Ziegler wrote:
> > For nested values, it's:
> >
> > name = 'Transaction::Simple::Group'
> > klass = name.split(/::/).inject(Object) { |k, n| k.const_get(n) }
> > p klass # => Transaction::Simple::Group
> Quite right. There is also the eval (evil?) method:
>
> clazz = eval(name)

> BTW, I've wondered why Object.const_get doesn't honor
> the X::Y::Z form. It's unambiguous and I can't see a
> good reason not to decipher it.

RCR?

Mark Hubbart

unread,
Jun 24, 2005, 3:07:18 AM6/24/05
to
On 6/23/05, Hal Fulton <hal...@hypermetrics.com> wrote:

One possible reason: when you call Object#const_get, you're asking
Object to fetch a constant in its namespace. It might not be logical
to allow recursive decent. (I'm not convinced of this, though... it's
just a thought :)

What about adding a Kernel#const_get that does this? That might
separate things a little better; a global method that decodes any
class name, nested or not, based on current context.

cheers,
Mark


nobuyoshi nakada

unread,
Jun 24, 2005, 5:21:50 AM6/24/05
to
Hi,

At Fri, 24 Jun 2005 16:07:18 +0900,
Mark Hubbart wrote in [ruby-talk:146353]:


> What about adding a Kernel#const_get that does this? That might
> separate things a little better; a global method that decodes any
> class name, nested or not, based on current context.

Kernel also is one of modules.

$ ruby -e 'p Kernel.const_get("Object")'
Object


Index: object.c
===================================================================
RCS file: /cvs/ruby/src/ruby/object.c,v
retrieving revision 1.169
diff -U2 -p -r1.169 object.c
--- object.c 11 May 2005 07:00:32 -0000 1.169
+++ object.c 24 Jun 2005 04:37:33 -0000
@@ -1715,9 +1715,46 @@ rb_mod_attr_accessor(argc, argv, klass)
}

+static ID
+mod_const_id(namep)
+ volatile VALUE *namep;
+{
+ VALUE tmp, name = *namep;
+ ID id;
+
+ switch (TYPE(name)) {
+ case T_STRING:
+ break;
+ case T_FIXNUM:
+ rb_warn("do not use Fixnums as Symbols");
+ id = FIX2LONG(name);
+ if (!rb_id2name(id)) {
+ rb_raise(rb_eArgError, "%ld is not a symbol", id);
+ }
+ return id;
+ case T_SYMBOL:
+ return SYM2ID(name);
+ default:
+ tmp = rb_check_string_type(name);
+ if (NIL_P(tmp)) {
+ rb_raise(rb_eTypeError, "%s is not a symbol", RSTRING(rb_inspect(name))->ptr);
+ }
+ *namep = name = tmp;
+ }
+ if (RSTRING(name)->ptr && strchr(RSTRING(name)->ptr, ':'))
+ return 0;
+
+ id = str_to_id(name);
+ if (!rb_is_const_id(id)) {
+ rb_name_error(id, "wrong constant name %s", rb_id2name(id));
+ }
+
+ return id;
+}
+
/*
* call-seq:
* mod.const_get(sym) => obj
*
- * Returns the value of the named constant in <i>mod</i>.
+ * Returns the value of the named constant under <i>mod</i>.
*
* Math.const_get(:PI) #=> 3.14159265358979
@@ -1728,9 +1765,10 @@ rb_mod_const_get(mod, name)
VALUE mod, name;
{
- ID id = rb_to_id(name);
+ ID id = mod_const_id(&name);

- if (!rb_is_const_id(id)) {
- rb_name_error(id, "wrong constant name %s", rb_id2name(id));
+ if (!id) {
+ return rb_path2const(RSTRING(name)->ptr, mod, Qtrue);
}
+
return rb_const_get(mod, id);
}
Index: variable.c
===================================================================
RCS file: /cvs/ruby/src/ruby/variable.c,v
retrieving revision 1.121
diff -U2 -p -r1.121 variable.c
--- variable.c 13 May 2005 08:56:14 -0000 1.121
+++ variable.c 24 Jun 2005 04:17:48 -0000
@@ -234,11 +234,21 @@ rb_set_class_path(klass, under, name)

VALUE
-rb_path2class(path)
+rb_path2const(path, cbase, idcheck)
const char *path;
+ VALUE cbase;
+ int idcheck;
{
const char *pbeg, *p;
ID id;
- VALUE c = rb_cObject;
+ VALUE c = cbase;

+ switch (TYPE(cbase)) {
+ case T_MODULE:
+ case T_CLASS:
+ break;
+ default:
+ rb_raise(rb_eTypeError, "class or module required but %s given",
+ rb_obj_classname(cbase));
+ }
if (path[0] == '#') {
rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path);
@@ -249,6 +259,9 @@ rb_path2class(path)

while (*p && *p != ':') p++;
- str = rb_str_new(pbeg, p-pbeg);
+ *(volatile VALUE *)&str = rb_str_new(pbeg, p-pbeg);
id = rb_intern(RSTRING(str)->ptr);
+ if (idcheck && !rb_is_const_id(id)) {
+ rb_name_error(id, "wrong constant name %s", RSTRING(str)->ptr);
+ }
if (p[0] == ':') {
if (p[1] != ':') goto undefined_class;
@@ -258,7 +271,15 @@ rb_path2class(path)
if (!rb_const_defined(c, id)) {
undefined_class:
- rb_raise(rb_eArgError, "undefined class/module %.*s", p-path, path);
+ if (cbase == rb_cObject) {
+ rb_raise(rb_eArgError, "undefined class/module %s",
+ RSTRING(str)->ptr);
+ }
+ else {
+ rb_raise(rb_eArgError, "undefined class/module %s under %s",
+ RSTRING(str)->ptr, rb_class2name(c));
+ }
}
c = rb_const_get_at(c, id);
+ if (!*p) break;
switch (TYPE(c)) {
case T_MODULE:
@@ -273,4 +294,21 @@ rb_path2class(path)
}

+VALUE
+rb_path2class(path)
+ const char *path;
+{
+ VALUE c = rb_path2const(path, rb_cObject, Qfalse);
+
+ switch (TYPE(c)) {
+ case T_MODULE:
+ case T_CLASS:
+ break;
+ default:
+ rb_raise(rb_eTypeError, "%s does not refer class/module", path);
+ }
+
+ return c;
+}
+
void
rb_name_class(klass, id)
Index: intern.h
===================================================================
RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.170
diff -U2 -p -r1.170 intern.h
--- intern.h 12 Jun 2005 16:56:05 -0000 1.170
+++ intern.h 24 Jun 2005 03:57:26 -0000
@@ -504,6 +504,7 @@
VALUE rb_mod_name _((VALUE));
VALUE rb_class_path _((VALUE));
void rb_set_class_path _((VALUE, VALUE, const char*));
+VALUE rb_path2const _((const char*, VALUE, int));
VALUE rb_path2class _((const char*));
void rb_name_class _((VALUE, ID));
VALUE rb_class_name _((VALUE));

--
Nobu Nakada


Mark Hubbart

unread,
Jun 24, 2005, 12:50:32 PM6/24/05
to
On 6/24/05, nobuyoshi nakada <nobuyosh...@ge.com> wrote:
> Hi,
>
> At Fri, 24 Jun 2005 16:07:18 +0900,
> Mark Hubbart wrote in [ruby-talk:146353]:
> > What about adding a Kernel#const_get that does this? That might
> > separate things a little better; a global method that decodes any
> > class name, nested or not, based on current context.
>
> Kernel also is one of modules.
>
> $ ruby -e 'p Kernel.const_get("Object")'
> Object

I actually meant a private instance method defined in Kernel, like
Kernel#warn et al. I was thinking that it might make sense to call
either
SomeNamespace.const_get("SomeConst")
or a plain
const_get("Nifty::Nested::Namespaces")
which could be done from anywhere, and would use the current scope.

But differentiating between the two looks like it may be be more
confusing than it's worth (especially since the worth was dubious
anyway). I un-submit the idea.

cheers,
Mark


George Moschovitis

unread,
Jun 24, 2005, 2:40:03 PM6/24/05
to
checkout

lib/facet/object/constant.rb in the Facets gem.

-g.

R. Mark Volkmann

unread,
Jun 24, 2005, 5:01:45 PM6/24/05
to
Quoting George Moschovitis <george.mo...@gmail.com>:

> checkout
>
> lib/facet/object/constant.rb in the Facets gem.

Thanks! It looks like this will do what I want.

After running "gem install facets" I found that the file constant.rb was placed
in C:\Ruby\Ruby1.8.2-15\lib\ruby\gems\1.8\gems\facets-0.7.2\lib\facet\object.
Just thought I'd share this in case anyone had trouble finding it.

George Moschovitis

unread,
Jun 25, 2005, 9:36:26 AM6/25/05
to
>> lib/facet/object/constant.rb in the Facets gem.
> Thanks! It looks like this will do what I want.

there is an even better alternative too:

lib/facet/class/by_name.rb
or
lib/facet/module/by_name.rb

(dont't remember exactly)

this allows you to do:

clazz = Class.by_name('Namespace::MyClass')

regards,
George.

--
http://www.nitrohq.com

Ara.T.Howard

unread,
Oct 13, 2005, 10:57:27 PM10/13/05
to
On Fri, 14 Oct 2005, nobuyoshi nakada wrote:

> Hi,
>
> At Fri, 14 Oct 2005 01:21:55 +0900,
> Ara.T.Howard wrote in [ruby-talk:160438]:
>> you can 'fix' broken code by creating a wrapper that does
>>
>> #! /usr/bin/env ruby
>> STDOUT.sync = true
>> exec(ARGV.join(' '))
>
> IO#sync flag can't affect other processes.

sheesh. you're right of course... how does using a pty affect this?

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze. --Nagarjuna
===============================================================================

nobuyoshi nakada

unread,
Oct 14, 2005, 12:08:38 AM10/14/05
to
Hi,

At Fri, 14 Oct 2005 11:57:27 +0900,
Ara.T.Howard wrote in [ruby-talk:160549]:


> > IO#sync flag can't affect other processes.
>
> sheesh. you're right of course... how does using a pty affect this?

$ ruby -e 'IO.popen(%[ruby -e "p STDOUT.tty?"]) {|i| p i.read}'
"false\n"

$ ruby -rpty -e 'PTY.spawn(%[ruby -e "p STDOUT.tty?"]) {|i,o| p i.read}'
"true\r\n"

--
Nobu Nakada


0 new messages