Berger, Daniel
3/11/2005 11:47:00 PM
Hi all,
Ruby 1.8.2
Solaris 9
I'm having problem with rb_block_given_p() in a C extension. It seems
to be evaluated by a constructor when it shouldn't be. Here's the C
code:
/* fab.c */
#include "ruby.h"
VALUE cFoo, cFab;
static VALUE foo_init(VALUE self){
if(rb_block_given_p())
rb_yield(self);
return self;
}
static VALUE fab_get_foos(VALUE klass, VALUE rbNum){
VALUE argv, rbFoo;
int i = 0;
int n = NUM2INT(rbNum);
for(i = 0; i < n; i++){
rbFoo = rb_class_new_instance(0,&argv,cFoo);
rb_iv_set(rbFoo,"@some_arg",INT2FIX(i));
if(rb_block_given_p()){
rb_yield(rbFoo);
}
}
return Qnil;
}
void Init_fab(){
cFab = rb_define_class("Fab",rb_cObject);
cFoo = rb_define_class("Foo",rb_cObject);
rb_define_method(cFoo, "initialize", foo_init, 0);
rb_define_attr(cFoo,"some_arg", 1, 1);
rb_define_singleton_method(cFab, "get_foos", fab_get_foos, 1);
}
Now, if I run a sample script, I get this as the result:
# test1.rb
require "fab"
Fab.get_foos(3){ |f| p f.some_arg }
# result
nil
0
nil
1
nil
2
Why am I getting the nil? It looks like it's evaluating the call to
rb_block_given_p() on the Foo constructor, i.e. in foo_init, even though
I'm not explicitly passing it there.
A pure Ruby version doesn't seem to have this problem:
# test2.rb
class Foo
attr_accessor :some_arg
def initialize
yield self if block_given?
end
end
class Fab
def self.get_foos(num)
0.upto(num){ |i|
f = Foo.new
f.some_arg = i
yield f if block_given?
}
end
end
if $0 == __FILE__
Fab.get_foos(5){ |f|
p f.some_arg
}
end
# result
0
1
2
What have I done wrong?
Regards,
Dan