[ruby/fiddle] Add `sym_defined?` methods to test if a symbol is defined (https://github.com/ruby/fiddle/pull/108)

I would like to check if a symbol is defined before trying to access it.
Some symbols aren't available on all platforms, so instead of raising an
exception, I want to check if it's defined first.

Today we have to do:

```ruby
begin
  addr = Fiddle::Handle.sym("something")
  # do something
rescue Fiddle::DLError
end
```

I want to write this:

```ruby
if Fiddle::Handle.sym_defined?("something")
  addr = Fiddle::Handle.sym("something")
  # do something
end
```

https://github.com/ruby/fiddle/commit/9d3371de13

Co-authored-by: Sutou Kouhei <kou@clear-code.com>
This commit is contained in:
Aaron Patterson 2022-09-13 08:27:59 -07:00 коммит произвёл Hiroshi SHIBATA
Родитель 755d99e878
Коммит 0097c7f388
2 изменённых файлов: 59 добавлений и 4 удалений

Просмотреть файл

@ -321,8 +321,10 @@ rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
return fiddle_handle_sym(RTLD_NEXT, sym);
}
static VALUE
fiddle_handle_sym(void *handle, VALUE symbol)
typedef void (*fiddle_void_func)(void);
static fiddle_void_func
fiddle_handle_find_func(void *handle, VALUE symbol)
{
#if defined(HAVE_DLERROR)
const char *err;
@ -330,13 +332,13 @@ fiddle_handle_sym(void *handle, VALUE symbol)
#else
# define CHECK_DLERROR
#endif
void (*func)();
fiddle_void_func func;
const char *name = StringValueCStr(symbol);
#ifdef HAVE_DLERROR
dlerror();
#endif
func = (void (*)())(VALUE)dlsym(handle, name);
func = (fiddle_void_func)(VALUE)dlsym(handle, name);
CHECK_DLERROR;
#if defined(FUNC_STDCALL)
if( !func ){
@ -379,6 +381,53 @@ fiddle_handle_sym(void *handle, VALUE symbol)
xfree(name_n);
}
#endif
return func;
}
static VALUE
rb_fiddle_handle_s_sym_defined(VALUE self, VALUE sym)
{
fiddle_void_func func;
func = fiddle_handle_find_func(RTLD_NEXT, sym);
if( func ) {
return PTR2NUM(func);
}
else {
return Qnil;
}
}
static VALUE
rb_fiddle_handle_sym_defined(VALUE self, VALUE sym)
{
struct dl_handle *fiddle_handle;
fiddle_void_func func;
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
if( ! fiddle_handle->open ){
rb_raise(rb_eFiddleDLError, "closed handle");
}
func = fiddle_handle_find_func(fiddle_handle->ptr, sym);
if( func ) {
return PTR2NUM(func);
}
else {
return Qnil;
}
}
static VALUE
fiddle_handle_sym(void *handle, VALUE symbol)
{
fiddle_void_func func;
func = fiddle_handle_find_func(handle, symbol);
if( !func ){
rb_raise(rb_eFiddleDLError, "unknown symbol \"%"PRIsVALUE"\"", symbol);
}
@ -468,6 +517,7 @@ Init_fiddle_handle(void)
rb_cHandle = rb_define_class_under(mFiddle, "Handle", rb_cObject);
rb_define_alloc_func(rb_cHandle, rb_fiddle_handle_s_allocate);
rb_define_singleton_method(rb_cHandle, "sym", rb_fiddle_handle_s_sym, 1);
rb_define_singleton_method(rb_cHandle, "sym_defined?", rb_fiddle_handle_s_sym_defined, 1);
rb_define_singleton_method(rb_cHandle, "[]", rb_fiddle_handle_s_sym, 1);
/* Document-const: NEXT
@ -526,6 +576,7 @@ Init_fiddle_handle(void)
rb_define_method(rb_cHandle, "close", rb_fiddle_handle_close, 0);
rb_define_method(rb_cHandle, "sym", rb_fiddle_handle_sym, 1);
rb_define_method(rb_cHandle, "[]", rb_fiddle_handle_sym, 1);
rb_define_method(rb_cHandle, "sym_defined?", rb_fiddle_handle_sym_defined, 1);
rb_define_method(rb_cHandle, "file_name", rb_fiddle_handle_file_name, 0);
rb_define_method(rb_cHandle, "disable_close", rb_fiddle_handle_disable_close, 0);
rb_define_method(rb_cHandle, "enable_close", rb_fiddle_handle_enable_close, 0);

Просмотреть файл

@ -22,12 +22,14 @@ module Fiddle
def test_static_sym_unknown
assert_raise(DLError) { Fiddle::Handle.sym('fooo') }
assert_raise(DLError) { Fiddle::Handle['fooo'] }
refute Fiddle::Handle.sym_defined?('fooo')
end
def test_static_sym
begin
# Linux / Darwin / FreeBSD
refute_nil Fiddle::Handle.sym('dlopen')
assert Fiddle::Handle.sym_defined?('dlopen')
assert_equal Fiddle::Handle.sym('dlopen'), Fiddle::Handle['dlopen']
return
rescue
@ -54,6 +56,7 @@ module Fiddle
handle = Fiddle::Handle.new(LIBC_SO)
assert_raise(DLError) { handle.sym('fooo') }
assert_raise(DLError) { handle['fooo'] }
refute handle.sym_defined?('fooo')
end
def test_sym_with_bad_args
@ -66,6 +69,7 @@ module Fiddle
handle = Handle.new(LIBC_SO)
refute_nil handle.sym('calloc')
refute_nil handle['calloc']
assert handle.sym_defined?('calloc')
end
def test_handle_close