Ваши функции объявлены как static
в отдельных единицах компиляции, поэтому, конечно, rb_ary_some_fun
не может видеть rb_obj_is_number
.Сразу приходят на ум два варианта:
Один из вариантов - поместить реализацию C rb_obj_is_number
в строку, доступную для обоих вызовов builder.c
.Это даст вам две копии функции, но:
- Обе реализации будут
static
, поэтому у вас не будет проблем с пространством имен. - Реализация, вероятно, достаточно мала, чтобылишний раздув не будет проблемой.
- Обе реализации будут происходить из одной и той же строки, поэтому у вас не должно возникнуть проблем с их сохранением.
У вас есть что-товот так:
# In some library file...
module CUtil
IS_NUMBER = %q{
static VALUE rb_obj_is_number(void) { /*...*/ }
}
end
# When monkey patching Object...
class Object
require 'inline'
inline do |builder|
builder.c CUtil::IS_NUMBER
end
alias is_number rb_obj_is_number
end
# When monkey patching Array...
class Array
require 'inline'
inline do |builder|
builder.c <<-EOC
#{CUtil::IS_NUMBER}
static VALUE rb_ary_some_fun(void) { /*...*/ }
EOC
end
alias some_fun rb_ary_some_fun
end
Это большая куча клуджа, поэтому я бы не советовал.Вероятно, есть случаи, когда такой подход имеет смысл.
правильный способ сделать это - вызвать is_number
как метод Ruby из вашего C. Вызов is_number
как методпозволяет переопределять его, исправлять обезьяны и т. д., как и любой другой метод.Вы бы использовали rb_funcall
что-то вроде этого:
/* There's no need to call this over and over again inside a loop. */
ID is_number = rb_intern("is_number");
/* ... */
if(rb_funcall(c_arr[i], is_number, 0) == Qtrue) {
result += NUM2DBL(c_arr[i]);
}
Также я рекомендую использовать правильные сигнатуры функций (например, rb_obj_is_number(void)
), чтобы ваш компилятор не попадал в режим K & R.Вам также следует настроить флажки предупреждений вашего компилятора, чтобы он громко жаловался на подобные вещи.