Instance_eval from C ext

I’m stumped… how do I call instance_eval from a C extension?

I have an object and a proc:

VALUE obj, pr;

and I want to eval pr with obj as self.

Currently, I do something like this, which works, but it’s inefficient:

rb_funcall(obj, rb_intern(“insteval_proc”), 1, pr);

and I have the following defined in ruby:

class Object
def insteval_proc pr
instance_eval &pr
end
end

I’d rather avoid the extra method call.

It doesn’t seem like I can use rb_obj_instance_eval(), because that
takes string arguments, not block arguments. Of course, if you have a
block accompanying the method call, it will instance_eval that, but I
don’t know how to set that up in C. That’s why I do "instance_eval &pr"
in my little hack.

And I can’t see how to use rb_iterate(). This is what I tried:

static VALUE my_instance_eval(VALUE obj)
{
return rb_obj_instance_eval(0, 0, obj);
}

static VALUE call_block(VALUE arg1, VALUE block)
{
return rb_funcall(block, ID_call, 0);
}

//…
rb_iterate(my_instance_eval, obj, call_block, pr);

but I get “block not supplied (ArgumentError)”, so I guess it’s not
being propagted into the rb_funcall.

Is there a simple way to emulate “&block” in C?

Even better, is there a way to rebind the proc’s self to my object, so I
only have to do it once, and can just call the block instead of using
instance eval?

Any ideas, anyone? Is this something you can do in ruby, but not using
the C API directly?

Joel VanderWerf wrote:

···

I’m stumped… how do I call instance_eval from a C extension?

I have an object and a proc:

VALUE obj, pr;

and I want to eval pr with obj as self.

Currently, I do something like this, which works, but it’s inefficient:

rb_funcall(obj, rb_intern(“insteval_proc”), 1, pr);

and I have the following defined in ruby:

class Object
def insteval_proc pr
instance_eval &pr
end
end

I’d rather avoid the extra method call.

It doesn’t seem like I can use rb_obj_instance_eval(), because that
takes string arguments, not block arguments. Of course, if you have a
block accompanying the method call, it will instance_eval that, but I
don’t know how to set that up in C. That’s why I do “instance_eval &pr”
in my little hack.

And I can’t see how to use rb_iterate(). This is what I tried:

static VALUE my_instance_eval(VALUE obj)
{
return rb_obj_instance_eval(0, 0, obj);
}

static VALUE call_block(VALUE arg1, VALUE block)
{
return rb_funcall(block, ID_call, 0);
}

//…
rb_iterate(my_instance_eval, obj, call_block, pr);

but I get “block not supplied (ArgumentError)”, so I guess it’s not
being propagted into the rb_funcall.

Take a look at
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/86105

you might find it useful.

···

On Mon, May 03, 2004 at 03:10:24AM +0900, Joel VanderWerf wrote:

Any ideas, anyone? Is this something you can do in ruby, but not using
the C API directly?

Joel VanderWerf wrote:

I’m stumped… how do I call instance_eval from a C extension?


Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Windows without the X is like making love without a partner.
– MaDsen Wikholm, mwikholm@at8.abo.fi

Mauricio Fernández wrote:

Any ideas, anyone? Is this something you can do in ruby, but not using
the C API directly?

Joel VanderWerf wrote:

I’m stumped… how do I call instance_eval from a C extension?

Take a look at
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/86105

you might find it useful.

Well, rb_iterate() is what I was trying before, but apparently it does
not arrange for rb_block_given_p() to be true, and so
rb_obj_instance_eval() bails out. I’ve adapted your example to show how
that is the case in both your code and mine.

The output (ruby-1.9.0 snapshot) is:

foo2, block given = 0
call_gsub, block given = 0
block2, block given = 0
Inside block, with string: h.
block2, block given = 0
Inside block, with string: e.
block2, block given = 0
Inside block, with string: l.
block2, block given = 0
Inside block, with string: l.
block2, block given = 0
Inside block, with string: l.
“HELLo, worLd!”
instance_eval_proc, block given = 0
my_instance_eval, block given = 0
example.rb:11:in `instance_eval_proc’: block not supplied (ArgumentError)
from example.rb:11

So I’m still looking for a solution to my problem, which is: how to
execute a Proc in the context of a given self object, from C code.

In other words, given the following working ruby code:

class Object
def instance_eval_proc(pr)
instance_eval(&pr)
end
end

obj = [1,2,3]
pr = proc { reverse }

p obj.instance_eval_proc(pr) # ==> [3, 2, 1]

how would you rewrite #instance_eval_proc in C?

== extconf.rb ==

require “mkmf”

create_makefile(“example”)

== example.rb ==

require “example.so”

b = “hello, world!”
CTest.foo2(b, /[ehl]/)
p b

obj = [1,2,3]
pr = proc { reverse }

p obj.instance_eval_proc(pr)

== example.c ==

#include <ruby.h>
#include <stdio.h>

VALUE mCTest;

static
VALUE
block2(VALUE str)
{
printf(“block2, block given = %d\n”, rb_block_given_p());
Check_Type(str, T_STRING);
printf(“Inside block, with string: %s.\n”, RSTRING(str)->ptr);
return rb_funcall(str, rb_intern(“upcase”), 0);
}

static
VALUE
call_gsub(VALUE args)
{
VALUE str, re;
printf(“call_gsub, block given = %d\n”, rb_block_given_p());
str = rb_ary_entry(args, 0);
re = rb_ary_entry(args, 1);

return rb_funcall(str, rb_intern(“gsub!”), 1, re);
}

static
VALUE
foo2(VALUE self, VALUE str, VALUE re)
{
VALUE args;
printf(“foo2, block given = %d\n”, rb_block_given_p());
args = rb_ary_new();
rb_ary_push(args, str);
rb_ary_push(args, re);

return rb_iterate(call_gsub, args, block2, str);
}

static VALUE my_instance_eval(VALUE obj)
{
printf(“my_instance_eval, block given = %d\n”, rb_block_given_p());
return rb_obj_instance_eval(0, 0, obj);
}

static VALUE call_block(VALUE arg1, VALUE block)
{
printf(“call_block, block given = %d\n”, rb_block_given_p());
return rb_funcall(block, rb_intern(“call”), 0);
}

static VALUE instance_eval_proc(VALUE self, VALUE pr)
{
printf(“instance_eval_proc, block given = %d\n”, rb_block_given_p());
return rb_iterate(my_instance_eval, self, call_block, pr);
}

void
Init_example()
{
mCTest = rb_define_module(“CTest”);
rb_define_singleton_method(mCTest, “foo2”, foo2, 2);
rb_define_method(rb_cObject, “instance_eval_proc”, instance_eval_proc, 1);
}

···

On Mon, May 03, 2004 at 03:10:24AM +0900, Joel VanderWerf wrote: