Converting class_for to a C extension

Hi all,

I found this snippet posted to handle doing const_get for nested
classes/modules:

def class_for(class_name)
names = class_name.split("::")
result = Object
names.each { |n|
result = result.const_get(n)
}
result
rescue NameError
nil
end

I’m trying to convert this to a C extension, but I’m having some
trouble:

static VALUE class_for(VALUE klass_name){
VALUE v_names, v_result;
ID id_split = rb_intern(“split”);
int i;

v_names = rb_funcall(klass_name, id_split, 1, rb_str_new2("::"));
v_result = rb_cObject;

for(i = 0; i < RARRAY(v_names)->len; i++)
v_result = rb_const_get(RBASIC(v_result)->klass, RARRAY(v_names)-

ptr[i]);

return v_result;
}

With this code I get “uninitialized constant Class::(null)
(NameError)”.

It appears to be a problem with the first argument to rb_const_get().
I’m not sure what that value should be, but I also tried
TYPE(v_result) - which caused a segfault - and just v_result - which
resulted in a similar “uninitialized constant (null) (NameError)”
error.

What am I doing wrong here?

Thanks,

Dan

PS - Yes, I realize I’m not doing error handling in the C extension -
I’m not worried about that for now.

On Feb 13, 3:26 pm, “Daniel B.” [email protected] wrote:

}
ID id_split = rb_intern(“split”);
return v_result;
error.

What am I doing wrong here?

Naturally I saw my mistake 2 minutes later:

It should be:

for(i = 0; i < RARRAY(v_names)->len; i++){
v_result = rb_const_get(
v_result,
rb_intern(StringValuePtr(RARRAY(v_names)->ptr[i]))
);
}

Regards,

Dan

Daniel B. wrote:

}
ID id_split = rb_intern(“split”);
}
What am I doing wrong here?

Thanks,

Dan

PS - Yes, I realize I’m not doing error handling in the C extension -
I’m not worried about that for now.

You should :wink: the (null) stuff is a sign that you’re using a NULL
pointer somewhere, though I can’t get where. The segfault is another
indication. So one thing here is returning false or NULL…

The problem, in my opinion, is here:

RBASIC(v_result)->klass

Why do you need to use ->klass ?? All objects you’re getting are
classes or modules already. You end up looking for constants in the
Class class, and that is not where they are defined.

Cheers,

Vince

On 2/13/07, Daniel B. [email protected] wrote:

I found this snippet posted to handle doing const_get for nested
classes/modules:

I know this doesn’t directly answer the question you asked, but why
not just use rb_path2class()?

On Feb 13, 3:40 pm, “Lyle J.” [email protected] wrote:

On 2/13/07, Daniel B. [email protected] wrote:

I found this snippet posted to handle doing const_get for nested
classes/modules:

I know this doesn’t directly answer the question you asked, but why
not just use rb_path2class()?

SLAPS FOREHEAD

Thanks Lyle.

Dan

On Feb 13, 2007, at 14:40, Lyle J. wrote:

On 2/13/07, Daniel B. [email protected] wrote:

I found this snippet posted to handle doing const_get for nested
classes/modules:

I know this doesn’t directly answer the question you asked, but why
not just use rb_path2class()?

One of these days I’m going to write a patch to expose this to Ruby :stuck_out_tongue:

On 2/14/07, Eric H. [email protected] wrote:

One of these days I’m going to write a patch to expose this to Ruby :stuck_out_tongue:

Expose what to Ruby?

On 2/14/07, Daniel B. [email protected] wrote:

I think he just means that there’s no direct equivalent in plain Ruby
(right?).

SLAPS FOREHEAD

Oh, yeah. :wink:

On Feb 14, 12:50 pm, “Lyle J.” [email protected] wrote:

On 2/14/07, Eric H. [email protected] wrote:

One of these days I’m going to write a patch to expose this to Ruby :stuck_out_tongue:

Expose what to Ruby?

I think he just means that there’s no direct equivalent in plain Ruby
(right?).

I think just patching const_get to handle “::” would suffice.

Dan

On Feb 14, 2007, at 12:05, Daniel B. wrote:

On Feb 14, 12:50 pm, “Lyle J.” [email protected] wrote:

On 2/14/07, Eric H. [email protected] wrote:

One of these days I’m going to write a patch to expose this to
Ruby :stuck_out_tongue:

Expose what to Ruby?

I think he just means that there’s no direct equivalent in plain Ruby
(right?).

Yup. I’ve reimplemented rb_path2class() numerous times in ruby, and
there’s a perfectly good C method lying around that needs only a one-
line patch to be accessible.

I think just patching const_get to handle “::” would suffice.

Possibly.

On Feb 14, 1:44 pm, Eric H. [email protected] wrote:

I think he just means that there’s no direct equivalent in plain Ruby
(right?).

Yup. I’ve reimplemented rb_path2class() numerous times in ruby, and
there’s a perfectly good C method lying around that needs only a one-
line patch to be accessible.

I think just patching const_get to handle “::” would suffice.

Possibly.

I tried messing with object.c yesterday, but I couldn’t make it work.
Any ideas for a patch? It would be nice to get one in for 1.8.6 if
possible.

Dan

On Feb 15, 2007, at 07:50, Daniel B. wrote:

I tried messing with object.c yesterday, but I couldn’t make it work.
Any ideas for a patch? It would be nice to get one in for 1.8.6 if
possible.

Oh, I was mistaken, its VALUE rb_path2class(const char *) not VALUE
rb_path2class(VALUE), so a wrapper function needs to be written (so
more than one line). I don’t know if Object::path2class is a good
name, since the C implementation can only have Object as its root.

I got this far:

Index: intern.h

— intern.h (revision 11758)
+++ intern.h (working copy)
@@ -453,6 +453,7 @@ VALUE rb_mod_name _((VALUE));
VALUE rb_class_path _((VALUE));
void rb_set_class_path _((VALUE, VALUE, const char*));
VALUE rb_path2class _((const char*));
+VALUE rb_obj_path2class _((VALUE));
void rb_name_class _((VALUE, ID));
VALUE rb_class_name _((VALUE));
void rb_autoload _((VALUE, ID, const char*));
Index: variable.c

— variable.c (revision 11758)
+++ variable.c (working copy)
@@ -274,6 +274,13 @@ rb_path2class(path)
return c;
}
+VALUE
+rb_obj_path2class(path)

  • VALUE path;
    +{
  • return rb_path2class(StringValueCStr(path));
    +}

void
rb_name_class(klass, id)
VALUE klass;
Index: object.c

— object.c (revision 11758)
+++ object.c (working copy)
@@ -2646,7 +2646,7 @@ Init_Object()
rb_define_private_method(rb_cModule, “method_added”,
rb_obj_dummy, 1);
rb_define_private_method(rb_cModule, “method_removed”,
rb_obj_dummy, 1);
rb_define_private_method(rb_cModule, “method_undefined”,
rb_obj_dummy, 1);

  • rb_define_singleton_method(rb_cObject, “path2class”,
    rb_obj_path2class, 1);
    rb_define_method(rb_mKernel, “nil?”, rb_false, 0);
    rb_define_method(rb_mKernel, “==”, rb_obj_equal, 1);

$ ./ruby186 -e ‘p Object.path2class(“Struct”)’
-e:1:in `path2class’: can’t convert Class into String (TypeError)
from -e:1