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
--
Posted via http://www.ruby-forum.com/.

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 May 4, 2008, at 20:13 , Bryan Richardson wrote:

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

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 05:13:49 Bryan Richardson 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?

···

--
Thanks!
Bryan

On Mon, May 5, 2008 at 6:31 AM, Jan Dvorak <jan.dvorak@kraxnet.cz> wrote:

On Monday 05 May 2008 05:13:49 Bryan Richardson 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

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

···

On Monday 05 May 2008 15:44:03 Bryan Richardson 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?

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

On Mon, May 5, 2008 at 10:38 AM, Jan Dvorak <jan.dvorak@kraxnet.cz> wrote:

On Monday 05 May 2008 15:44:03 Bryan Richardson 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

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

On Mon, May 5, 2008 at 12:48 PM, Bryan Richardson <btricha@gmail.com> wrote:

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

On Mon, May 5, 2008 at 10:38 AM, Jan Dvorak <jan.dvorak@kraxnet.cz> wrote:

> On Monday 05 May 2008 15:44:03 Bryan Richardson 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
>
>