Hi,
I used to wrap C libraries in Ruby using the ffi gem[1], but I recently
learned that Ruby has already gained bindings to libffi in its stdlib,
named fiddle[2]. fiddle's API looks a little more raw than ffi's, but it
makes me wonder whether ffi will be around for a long time still once
fiddle's API gets a little love.
Anyway, I decided to give fiddle a try to eliminate the dependency on
ffi, but was stumped when I wanted to wrap a function using enums. I
know I can just tell fiddle the enum argument is an int and everything
ought to work fine, but when calling the function I'd rather not use the
raw numbers, but symbolic values. What is the proper way to do this with
fiddle?
Here's an example. A C header may contain this:
enum something {
FOO = 1,
BAR,
BAZ
};
void func(enum something flag);
Now I can probably do the following with fiddle:
require "fiddle/import"
module MyLib
extend Fiddle::Importer
dlload "mylib.so"
extern "void func(int)"
end
MyLib.func(2)
That does probably work, but it will allow any integer values for
func(), and not just 1-3. Also, it forces me to use the numeric values,
which is not ideal. So the next step would be to wrap it in a cleaner
function, like this:
module MyLib
SOMETHING = {:foo => 1, :bar => 2, :baz => 3}
def wrapped_func(arg)
arg = SOMETHING[arg] || raise(ArgumentError, "Unknown flag: #{arg}")
func(arg)
end
end
MyLib.wrapped_func(:bar)
But now the function in Ruby is named #wrapped_func instead of #func,
and I have to write useless boilerplate, perhaps for quite a number of
functions (for each one that uses an enum). To resolve the first
problem, I could revert to the old alias trick, but I still regard that
one as hacky, and it does not address the boilerplate problem:
module MyLib
alias old_func func
def func(arg)
arg = SOMETHING[arg] || raise(ArgumentError, "Unknown flag: #{arg}")
old_func(arg)
end
end
MyLib.func(:bar)
Is there a way to declare the "something" enum from the above example
with fiddle and have the #func method check that the provided argument
is valid in its context, without having me to write that all by hand
using a hacky alias trick?
Greetings
Marvin
[1]: https://rubygems.org/gems/ffi
[2]: http://ruby-doc.org/stdlib-2.4.0/libdoc/fiddle/rdoc/Fiddle.html
···
--
Blog: http://www.guelkerdev.de
PGP/GPG ID: F1D8799FBCC8BC4F