On Fri, Apr 12, 2002 at 01:06:34AM +0900, Ian Macdonald wrote:
> I'm pretty new to Ruby, so if there's a better way to do this, please
> let me know.

Not all instance variables begin with an "@", so this doesn't quite work
(try it with Exception, and you will discover that it doesn't work,
since it uses mesg and not @mesg).

I recently needed to do get access to all the instance variables (not
just the ones that begin with @), so I wrote a small extension:

  #include <ruby.h>
  #include <intern.h>

  VALUE ruby_each_instance_variable(VALUE self) {
      int j;
      VALUE instance_vars = rb_obj_instance_variables(self);
      VALUE yield_value = rb_ary_new2(2);
      struct RArray * instance_vars_ary = RARRAY(instance_vars);
      struct RArray * yield_value_ary = RARRAY(yield_value);
      ID id;
      yield_value_ary->len = 2;

      for(j = 0; j < instance_vars_ary->len; ++j) {
          id = rb_intern(STR2CSTR(instance_vars_ary->ptr[j]));
          yield_value_ary->ptr[0] = ID2SYM(id);
          yield_value_ary->ptr[1] = rb_ivar_get(self, id);
          rb_yield(yield_value);
      }

      return Qnil;
  }

  void Init_each_instance_variable(void) {
      rb_define_private_method(rb_cObject, "each_instance_variable", ruby_each_instance_variable, 0);
  }

Not a perfect solution, but it works.  An alternative would be to write
an extension to interface with rb_ivar_get, and do the iteration in
Ruby.  I chose to not do this, because I wanted to discourage using
the extension to access arbitrary instance variables.

Paul