From: Tim Hunter Date: 2004-07-26T03:31:54+09:00 Subject: Re: [NUBY] Iteration in extensions Fredrik Jagenheim wrote: > On Sun, 25 Jul 2004 13:36:54 +0900, daz wrote: >> >> You don't show how you defined 'add_values' or how you're calling it >> from Ruby, but I think your initial array is in 'self' ... > > Here is a more complete example of what I'm trying to do. > >> Here's an example from enum.c (Enumerable#reject) >> with some printf() statements added. > > I'm afraid I didn't understand how to translate your example into mine. > > This is basically what I'm trying to do: > > -------8<------ Bitmask.c > #include "ruby.h" > > static VALUE > bm_new(VALUE class) > { > long* bitmask; > bitmask = ALLOC(long); > *bitmask = 0; > VALUE data = Data_Wrap_Struct(class, 0, free, bitmask); > return data; > } > > static VALUE > bm_add_bit(VALUE self, VALUE bit) > { > long* bitmask; > int int_bit = NUM2INT(bit); > printf("in to add_bit: %s %s\n", > RSTRING(rb_inspect(self))->ptr, > RSTRING(rb_inspect(bit))->ptr); > Data_Get_Struct(self, long, bitmask); > *bitmask |= 1 << int_bit; > return self; > } > > static VALUE > bm_add_bits(VALUE self, VALUE bits) > { > printf("in to add_bits: %s\n", RSTRING(rb_inspect(bits))->ptr); > rb_iterate(rb_each, bits, bm_add_bit, 1); > return self; > } > > static VALUE > bm_value(VALUE self) > { > long* bitmask; > Data_Get_Struct(self, long, bitmask); > return INT2NUM(*bitmask); > } > > VALUE cBitmask; > > void Init_Bitmask() { > cBitmask = rb_define_class("Bitmask", rb_cObject); > rb_define_singleton_method(cBitmask, "new", bm_new, 0); > rb_define_method(cBitmask, "add_bit", bm_add_bit, 1); > rb_define_method(cBitmask, "add_bits", bm_add_bits, 1); > rb_define_method(cBitmask, "value", bm_value, 0); > } > > > -------8<------ test_Bitmask.rb > > require 'Bitmask' > > bm = Bitmask.new > bm.add_bit(2) > bm.add_bit(4) > puts bm.value > > bm = Bitmask.new > bm.add_bits([2, 4]) > puts bm.value Hmmm...the Pickaxe says this about rb_iterate: - VALUE rb_iterate(VALUE (*method)(), VALUE args, VALUE (*block)(), VALUE arg2); Invokes `method' with argument `args' and block `block'. A yield from that method will invoke `block' with the argument given to yield, and a second argument `arg2'. I understand that rb_iterate invokes `method' using the current self, that is, the self that gets add_bits. Since you're passing rb_each, your class needs to define an each method. That each method must yield and pass an argument, which (normally) is the next member in some collection. Lastly, the fourth arg, which becomes the 2nd argument to the block, must be a Ruby VALUE. An integer 1 probably isn't what you want. Overall it looks like rb_iterate isn't what you need. You want to call add_bit for each element in the array, so I'd do something like this: for (x = 0; x < RARRAY(bits)->len; x++) { VALUE bit = rb_ary_entry(bits, x); (void) bm_add_bit(self, bit); } Or, if you want to allow for somebody subclassing your class and overriding add_bit, replace the direct call to bm_add_bit with: (void) rb_funcall(self, rb_intern("add_bit"), 1, bit);