SWIG: ruby proc->c function pointer

Sorry for the slightly off-topic question. I am starting to use swig
to wrap some C++ library for ruby for the first time.
In the process of doing so, I realize I will need to pass proc objects
from ruby and turn them into function pointers in C, so as to provide a
callback mechanism.
I understand this can potentially be done with typemaps, but I am not
sure exactly how. I only need to have a single callback per class, so
I was thinking of storing the ruby callback within the class itself and
then have a common C wrap function that would map the C callback to the
appropiate ruby callbacks (ie. proc object) based on what was stored in
the class. I was also unsure if SWIG already provides some auxiliary
functions for doing something similar.
Does anyone have any pointers?
I'm already familiar with how ruby-fltk handles this, for example, and
I want to basically emulate something akin within the SWIG
meta-language. I'm looking at FXRuby but the code is a tad too complex
for a SWIG newbie.

Hi,

I'm writing bindings to Subversion by SWIG. This has some
callback codes.

In <1106936665.034711.322390@z14g2000cwz.googlegroups.com>
  "SWIG: ruby proc->c function pointer" on Sat, 29 Jan 2005 03:25:52 +0900,

In the process of doing so, I realize I will need to pass proc objects
from ruby and turn them into function pointers in C, so as to provide a
callback mechanism.

Here is an example:

--- callback.h
#ifndef CALLBACK_H
#define CALLBACK_H

typedef void (*callback_t) (void *user_data, const char *other_data);

void invoke(callback_t callback, void *user_data, const char *other_data);

#endif

···

"gga" <GGarramuno@aol.com> wrote:
---

--- callback.c
#include "callback.h"

void
invoke(callback_t callback, void *user_data, const char *other_data)
{
  callback(user_data, other_data);
}
---

--- callback.i
%module callback

%{
void
wrap_callback(void *user_data, const char *other_data)
{
  VALUE proc = (VALUE)user_data;
  rb_funcall(proc, rb_intern("call"), 1, rb_str_new2(other_data));
}
%}

%typemap(in) (callback_t callback, void *user_data)
{
  $1 = wrap_callback;
  $2 = (void *)$input;
}

%include callback.h
%{
#include "callback.h"
%}
---

--- Makefile.swig
# -*- Makefile -*-

MODULE = callback
FEATURE = $(MODULE)
INTERFACE = $(MODULE).i

RUBY = ruby
SWIG = swig

SWIGOPT = -I/usr/local/include -I/usr/include -ruby -feature $(FEATURE)
WRAPPER = $(FEATURE)_wrap.c

swigall: $(WRAPPER) Makefile

$(WRAPPER): $(INTERFACE)
  $(SWIG) $(SWIGOPT) -o $@ $(INTERFACE)

Makefile: extconf.rb
  $(RUBY) extconf.rb
  @if [ -f Makefile ] ; then\
    echo "include Makefile.swig" >> Makefile;\
  fi

swigclean:
  @if [ -f Makefile ] ; then\
    make -f Makefile clean;\
  fi
  rm -f Makefile $(WRAPPER)
---

--- extconf.rb
require 'mkmf'
create_makefile("callback")
---

--- to build
% make -f Makefile.swig
% make
---

--- sample usage
% irb -r callback
irb(main):001:0> Callback.invoke(Proc.new{|str| p str}, "abc")
"abc"
=> nil
---

--
kou

I finally got around to trying this. Thanks.
Unfortunately, the latest SWIG (v1.3.22) seems to choke on it, with:

irb(main):005:0> Callback.invoke(Proc.new{|str| p str}, "abc")
TypeError: cannot convert nil into String
        from (irb):5:in `invoke'
        from (irb):5

Looking at the code, SWIG fails in the StringValuePtr() conversion
here.

/* Get type mangle from class name */
SWIGRUNTIME(char *)
SWIG_Ruby_MangleStr(VALUE obj)
{
  VALUE stype = rb_iv_get(obj, "__swigtype__");
  return StringValuePtr(stype);
}