Converting class_for to a C extension

D

Daniel Berger

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 said:


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.
 
D

Daniel Berger

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;



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?


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))
);
}

Regards,

Dan
 
V

Vincent Fourmond

Daniel said:
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 said:


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.


You should ;-) 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
 
L

Lyle Johnson

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

<snip>

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

Eric Hodel

<snip>

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 :p
 
D

Daniel Berger

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
 
E

Eric Hodel

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.
 
D

Daniel Berger

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.


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
 
E

Eric Hodel

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top