Extendig ruby: defining classes and creating objects from c

I can't manage to define a new class (actually an exception) and then
instantiating it from C.
I define the class with:
  xr_cException = rb_define_class_under(xr_module, "Exception",
rb_eRuntimeError);
  rb_define_method(xr_cException, "initialize",
xr_cException_initialize, 4);
...
static VALUE xr_cException_initialize(VALUE self, VALUE status, VALUE
lasterror, VALUE function, VALUE msg)
{
  rb_iv_set(self, "@status", status);
  rb_iv_set(self, "@lasterror", lasterror);
  rb_iv_set(self, "@function", function);
  rb_iv_set(self, "@msg", msg);
  return self;

At this point I can write a ruby test program like
a=MYMOD::Exception.new(1,2,3,4)
raise a, "Hello!"
and it works all right and I get output:
  Test.rb:5: Hello! (MYMOD::Exception)

However if I try to do the same thing from C with:
  VALUE oException, argv[4]={INT2FIX(1), INT2FIX(2), INT2FIX(3),
INT2FIX(4)};
  oException = rb_class_new_instance(4, argv, xr_cException);
  rb_raise(oException, "Hello!");
I put this piece of code inside a method named raiseit and call test
from a test ruby program. I get error:
Test.rb:9:in `raiseit': undefined method `new' for #<MYMOD::Exception:
MYMOD::Exception> (NoMethodError)

It seems that when I try to create an object of type MYMOD::Exception,
somehow ruby doesn't find the new method. I've tried to define also a
new method for this class, but I get the same error.
By the way, the function rb_call_new_instance seems to be quite
undocumented...

What is the correct way to create a new object of a given class from C?

Thanks
libit

···

--
Posted via http://www.ruby-forum.com/.

Hi,

At Sat, 20 Oct 2007 00:56:16 +0900,
An Onymous wrote in [ruby-talk:274836]:

  rb_raise(oException, "Hello!");

The first argument of rb_raise() is a class. Try:

    rb_exc_raise(oException);

···

--
Nobu Nakada

Oh, so ruby was looking for a "new" method not on the class but on the
instance.
This explains the problem, however how do I raise an exception from an
object?

    rb_exc_raise(oException);

rb_exc_raise is not defined in ruby.h. At least not in the latest
version 1.8.6
What is it? I see it defined in intern.h and called from everywhere but
I can't find where it is defined.

libit

···

--
Posted via http://www.ruby-forum.com/\.

Hi,

At Sat, 20 Oct 2007 04:33:33 +0900,
An Onymous wrote in [ruby-talk:274879]:

> rb_exc_raise(oException);

rb_exc_raise is not defined in ruby.h. At least not in the latest
version 1.8.6

It's declared in intern.h which is included by ruby.h.

What is it? I see it defined in intern.h and called from everywhere but
I can't find where it is defined.

In eval.c.

···

--
Nobu Nakada

Thank you. Now it works.
I ended up writing an updated version of rb_raise which behaves more
like the ruby "raise" global function. That is:
myrb_raise(Qnil,NULL) behaves like "raise"
myrb_raise(Qnil,fmt,...) behaves like "raise <string>" raising a
RuntimeError with the given message
myrb_raise(exc,NULL) behaves like "raise <exc>" where exc can be either
a class OR AN EXCEPTION OBJECT (if exc is an exception object, its
message is preserved)
and
myrb_raise(exc,fmt,...) behaves like "raise <exc>,<string>" that is like
the previous one but also setting the exception message.

Here it is:
VALUE myrb_raise(VALUE exc, const char *fmt, ...)
{
  if(!NIL_P(exc)) {
    ID exception = rb_intern("exception");
    if(!rb_respond_to(exc, exception)) rb_raise(rb_eTypeError,
"exception class/object expected");
  }
  if(fmt) {
    va_list args;
    char buf[BUFSIZ];
    VALUE msg;
    va_init_list(args,fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);
    msg=rb_str_new2(buf);
    if(NIL_P(exc)) exc = rb_class_new_instance(1, &msg,
rb_eRuntimeError);
    else exc = rb_funcall(exc, exception, 1, msg);
  }
  rb_exc_raise(exc);
}

···

--
Posted via http://www.ruby-forum.com/.

Actually the first few lines should read:
VALUE myrb_raise(VALUE exc, const char *fmt, ...)
{
  ID exception;
  if(!NIL_P(exc)) {
    exception = rb_intern("exception");
...

···

--
Posted via http://www.ruby-forum.com/.