C++だと似たようなコードを繰り返し書いていたので、コードの圧縮を考えてみる。
#include <string> #include <map> #include "hello.h" using std::string; using std::map; class MyMap : public DataWrapper<MyMap> { std::map<string, string> m; DEF(initialize, (0, ())) { return Qnil; } DEF(get, (1, (key))) { Check_Type(key, T_STRING); string k(RSTRING_PTR(key)); return rb_str_new2(m[k].c_str()); } DEF(set, (2, (key, val))) { Check_Type(key, T_STRING); string k(RSTRING_PTR(key)); string v(RSTRING_PTR(val)); m[k] = v; return Qnil; } public: static void Init() { VALUE clazz = define_class(); DEFINE_METHOD(clazz, initialize, 0); DEFINE_NAMED_METHOD(clazz, "[]", get, 1); DEFINE_NAMED_METHOD(clazz, "[]=", set, 2); } }; extern "C" __declspec(dllexport) void Init_hello() { MyMap::Init(); }
require 'hello' m = MyMap.new m["foo"] = "bar" puts m["foo"]
うーん、いまいち…。
ヘッダはこんな感じ。
#include <typeinfo> #include <ruby.h> #define __F(f) (reinterpret_cast<VALUE (__cdecl *)(...)>(f)) #define DEFINE_METHOD(clazz, name, n) \ rb_define_method((clazz), (#name), __F(&_##name), (n)) #define DEFINE_NAMED_METHOD(clazz, name, func, n) \ rb_define_method((clazz), (name), __F(&_##func), (n)) #define DEF(name, x) static VALUE _##name DEF_ARGS x { return data_get(self)->name DEF_VARGS x ; } VALUE name DEF_XARGS x #define DEF_ARGS(n, x) DEF_ARG##n x #define DEF_ARG0() (VALUE self) #define DEF_ARG1(arg1) (VALUE self, VALUE arg1) #define DEF_ARG2(arg1, arg2) (VALUE self, VALUE arg1, VALUE arg2) #define DEF_ARG3(arg1, arg2, arg3) (VALUE self, VALUE arg1, VALUE arg2, VALUE arg3) #define DEF_ARG4(arg1, arg2, arg3, arg4) (VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4) #define DEF_ARG5(arg1, arg2, arg3, arg4, arg5) (VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5) #define DEF_XARGS(n, x) DEF_XARG##n x #define DEF_XARG0() () #define DEF_XARG1(arg1) (VALUE arg1) #define DEF_XARG2(arg1, arg2) (VALUE arg1, VALUE arg2) #define DEF_XARG3(arg1, arg2, arg3) (VALUE arg1, VALUE arg2, VALUE arg3) #define DEF_XARG4(arg1, arg2, arg3, arg4) (VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4) #define DEF_XARG5(arg1, arg2, arg3, arg4, arg5) (VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5) #define DEF_VARGS(n, x) DEF_VARG##n x #define DEF_VARG0() () #define DEF_VARG1(arg1) (arg1) #define DEF_VARG2(arg1, arg2) (arg1, arg2) #define DEF_VARG3(arg1, arg2, arg3) (arg1, arg2, arg3) #define DEF_VARG4(arg1, arg2, arg3, arg4) (arg1, arg2, arg3, arg4) #define DEF_VARG5(arg1, arg2, arg3, arg4, arg5) (arg1, arg2, arg3, arg4, arg5) template <class T> class DataWrapper { protected: static void free(T *p) { delete p; } static VALUE alloc(VALUE klass) { T *p = new T; return Data_Wrap_Struct(klass, 0, &free, p); } static VALUE define_class(VALUE module = Qnil, VALUE super = rb_cObject) { char* name = const_cast<char *>(typeid(T).name()); for (; *name != ' '; name++); name++; VALUE clazz = NIL_P(module) ? rb_define_class(name, super) : rb_define_class_under(module, name, super); rb_define_alloc_func(clazz, &alloc); return clazz; } static T* data_get(VALUE self) { T *p; Data_Get_Struct(self, T, p); return p; } };
探せばもっとちゃんとしたライブラリがありそうだなー。