Need more help with Ruby and C

Hello all,

So I have something like the following in my C file:

static VALUE rb_cBar;

static VALUE foo_new() {
VALUE new_foo;

return new_foo;
}

static VALUE execute(VALUE foos) {
VALUE foo = rb_ary_entry(foos, 0);
printf(“Foo Value: %i\n”, rb_iv_get(foo, “@value”);
}

void Init_bar() {
rb_cBar = rb_define_class(“Bar”, rb_cObject);
rb_define_method(rb_cBar, “new_foo”, foo_new, 0);
rb_define_method(rb_cBar, “execute”, execute, 1);
}

and in my Ruby file I do the following:

require ‘bar’

b = Bar.new
a = Array.new
a << b.new_foo
b.execute(a)

My question is with the execute method. It outputs 0.00 when it should
output 1.01 (there’s a foo_init method called that I didn’t include here
that sets the value variable of the foo struct to 1.01). I assume this
doesn’t work because I’m passing the execute method an array created in
Ruby code and not an array created using the C functions. Is there some
way I can do it the way I’m trying to above?


Thanks!
Bryan

On May 4, 2008, at 20:13 , Bryan R. wrote:

Hello all,

So I have something like the following in my C file:

static VALUE rb_cBar;

static VALUE foo_new() {
VALUE new_foo;

^^^ problem exists here. can’t help any further.

On Monday 05 May 2008 05:13:49 Bryan R. wrote:

static VALUE foo_new() {

static VALUE execute(VALUE foos) {

ruby passes ‘self’ (current context) as the first argument of any C
defined
method, so you have to define it as:

static VALUE foo_new(VALUE self) {

static VALUE execute(VALUE self, VALUE foos) {

Jan

On Monday 05 May 2008 15:44:03 Bryan R. wrote:

Hi Jan,

Alright, that makes sense, thanks for the information. However, that
doesn’t help me to understand how I can pass a Ruby array of objects to the
execute method. Am I missing something here? Can you help me with this?

The array is just an object (everything in ruby is object) which you can
manipulate from C with rb_ary_* functions. You wrote the code yourself:

VALUE foo = rb_ary_entry(foos, 0); // this will return the first
element of
the array

now, rb_* functions operate on (and returns) ruby objects (VALUE), if
you want
to direclty use POD data types in C, you have to convert them, e.g. :

VALUE val = rb_iv_get(foo,"@value");
printf(“Foo Value: %i\n”, NUM2INT(val));

or alternatively

printf(“Foo Value: %i\n”, NUM2INT(rb_iv_get(foo, “@value”));

For integral types there are general macros INT2NUM (c to ruby) and
NUM2INT
(ruby to C), and their variants (FIX2INT,INT2FIX,…), for floats/doubles
there is NUM2DBL (ruby to c) and rb_float_new() (C to ruby).

Also, every method in ruby must return value, so if your function does
not
return anything, you have to explicitly return ‘nil’ with

return Qnil;

Jan

Jan,

Awesome… this now works perfectly! Also, thanks for the heads-up on
having to return a value and using Qnil. I was getting a segmentation
fault
in irb that I wasn’t sure about and it was because I wasn’t returning
anything.

One side question… why is it called ‘Qnil’? What is the ‘Q’ for?


Thanks again!
Bryan

Hi Jan,

Alright, that makes sense, thanks for the information. However, that
doesn’t help me to understand how I can pass a Ruby array of objects to
the
execute method. Am I missing something here? Can you help me with
this?


Thanks!
Bryan

Okay, new question… still in line with what I’ve been asking already.
Say
I have the following:

typedef struct {
char* name;
} Foo;

static VALUE rb_cBar;
static VALUE rb_cTest;

static VALUE foo_new(VALUE self) {
Foo* f;
VALUE info;
info = Data_Make_Struct(rb_cTest, Foo, 0, free, f);
rb_obj_call_init(info, 0, 0);
return info;
}

static VALUE foo_init(VALUE self) {
VALUE str;
char* name = “Bryan”;
str = rb_str_new2(name);
rb_iv_set(self, “@name”, str);
return self;
}

static VALUE test(VALUE self, VALUE arg) {
Foo* f;
Data_Get_Struct(arg, Foo, f);
printf(“Name: %s\n”, f->name);
return Qnil;
}

void Init_power_flow() {
rb_cBar = rb_define_class(“Bar”, rb_cObject);
rb_cTest = rb_define_class(“Test”, rb_cObject);
rb_define_method(rb_cBar, “test”, test, 1);
rb_define_method(rb_cBar, “new_foo”, foo_new, 0);
rb_defien_method(rb_cTest, “initialize”, foo_init, 0);
}

If I do the following, everything works perfectly and I see my name
printed
on the screen:

b = Bar.new
f = b.new_foo
b.test(f) // prints “Bryan”

However, say I change the foo_new method to be the following:

static VALUE foo_new(VALUE self) {
Foo* f;
VALUE info;
f = ALLOC(Foo);
f->name = “Bryan”;
info = Data_Wrap_Struct(self, 0, free, f);
return info;
}

and I change the method declaration in Init to be the following:

rb_define_method(rb_cTest, “initialize”, foo_new, 0);

Now, when I do what I did before, I get an error:

b = Bar.new
f = Test.new
b.test(f) // TypeError: wrong argument type Test (expected Data)

Any idea why trying to define a constructor rather than a ‘factory’
method
is causing me issues?


Thanks in advance!
Bryan