mrb
C++ binder library for mruby
class Game
{
public:
Game() = default;
void run(int frames) {}
std::unordered_map<std::string, std::string> const user {
{"name", "sasq"},
{"pass", "secret"}
};
int score = 0;
};
You use the default mruby C creation function;
auto* ruby = mrb_open();
mrb::make_class<Game>(ruby, "Game");
mrb::add_method<&Game::run>(ruby, "run");
mrb_close(ruby);
Or you can use the provided mrb ruby class;
mrb::mruby ruby;
ruby.make_class<Game>("Game");
ruby.add_method<&Game::run>("run");
Either way, ruby usage is the same;
game = Game.new()
game.run(50)
You can expose fields with readers/writers
mrb::attr_reader<&Game::user>("user");
mrb::attr_accessor<&Game::score>("score");
print(game.user['name'])
game.score += 1
If you want to define your functions with the C api, you can use mrb::get_args()
to help with argument parsing;
mrb_define_module_function(
ruby, ruby->kernel_module, "test",
[](mrb_state* mrb, mrb_value) -> mrb_value {
auto [b, s, f] = mrb::get_args<bool, std::string, float>(mrb);
return mrb::to_value<std::string>(
std::to_string(b) + "/" + s + "/" + std::to_string(f), mrb);
},
MRB_ARGS_REQ(3));
if test(false, 'hello', 3.14) == 'false/hello/3.14'
print('Should get here!')
end
Supported data types
-
Basic arithmetic types convert to floats or fixnums.
-
std::string
convert to ruby strings -
std::array
andstd::vector
convert to arrays. -
std::map
andstd::unordered_map
will convert to and from hashes (note that symbols will be converted to strings.
All data is converted which means all methods can be seen as pass-by-value.
Memory Management
Objects passed to Ruby will be freed by ruby during garbage collection using
delete
. If you want to use another deleter (or make ruby not free it) you
can use
mrb::set_deleter<Game>(ruby, [](Game* self) { /* Do something */ }
Generic ruby objects passed into C can be captured using `mrb::Value`. This type is reference counted, so the value will not be garbage colleced as long as it is stored on the C side.
Building
mrb uses CMake and pulls in mruby as a git submodule.
You need rake
to build the ruby part.
Currently, there is a dependency issue that makes the very first build fail.
API
make_class
RClass* mrb::make_class<CLASS>(mrb_state* ruby, const char* name, RClass* parent = nullptr)
RClass* mrb::make_noinit_class<CLASS>(mrb_state* ruby, const char* name, RClass* parent = nullptr)
Expose a C++ class to ruby. First version must have a parameterless constructor. Second version can not be called with new
from ruby.
add_method
mrb::add_method<&Method>(mrb_state* ruby, const char* name);
mrb::add_method<Class>(mrb_state* ruby, const char* name, Function fn);
Expose a method in a registered class.
add_method<Game>(ruby, "add_score", [](Game* game, int score) {
game->score += score;
});
accessors
mrb::attr_accessor<&Field>(mrb_state* ruby, const char* name);
mrb::attr_reader<&Field>(mrb_state* ruby, const char* name);
mrb::attr_writer<&Field>(mrb_state* ruby, const char* name);
Expose a field in a registered class.
mrb::attr_reader<&Game::score>(ruby, "score");