You can use C code to prepare methods for mruby scripts.
The steps are:
- Defining a method
- Getting argument values
- Adding the method to the
mrb_state
Defining a Method
To define a Ruby function, make a C function that:
- accepts two arguments, a
mrb_state
and amrb_value
- returns a
mrb_value
.
Here’s a minimal method definition:
mrb_value
ruby_method(mrb_state *mrb, mrb_value self)
{
return mrb_nil_value();
}
The arguments are:
mrb_state
, the current mruby VM instancemrb_value
, the currentself
(caller of this method)
Notice that you don’t define the Ruby arguments here. You’ll handle those later by getting them from the mrb_state
.
The return type must be mrb_value
. If it’s not, your program will crash (Segmentation Fault
:( ) when the return value is accessed (no compile-time error). If your method shouldn’t return anything, use return mrb_nil_value();
mruby implements a lot of the built-in classes’ instance methods this way, for example: String#capitalize!
(src).
Getting Arguments
You might have noticed that your C function definition didn’t define any arguments. Instead, you get your arguments by extracting them from mrb_state
.
mrb_value
ruby_method(mrb_state *mrb, mrb_value self)
{
// Initialize a variable
mrb_int some_integer;
// Extract a value
mrb_get_args(mrb, "i", &mrb_int);
return mrb_nil_value();
}
mrb_get_args
takes a string whose letters say what kind of arguments and how many arguments to extract. The mrb_get_args
source documents the different possibilities.
Notably, anything after a |
is optional.
For a default value, assign a value to the variable and make the argument optional. In this example, inherit
defaults to TRUE
:
mrb_bool inherit = TRUE;
mrb_get_args(mrb, "|b", &inherit);
That’s from C implementation of Module#constants
. Another nice example is the String#[]
source.
Adding Methods to mruby State
To add a method to the mruby state, you must attach it to some object. To make a method global, you can define it on Object
. Let’s do that.
We’ll use mrb_define_method
, which accepts five arguments:
mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec)
mrb_state *mrb
: the open mruby VM instancestruct RClass *c
: the mruby class to attach the method toconst char *name
: the Ruby name for this methodmrb_func_t func
: the C function to execute for this Ruby methodmrb_aspec aspec
: the number & types of arguments for this method
In fact, specifying arguments is not currently used (github issue). To pass some value here, you can use some convenient macros from mruby.h
.
So, let’s add a global method, greet!
. Here’s the method:
static mrb_value
mrb_greet(mrb_state *mrb, mrb_value self) {
printf("Hello, mruby!\n");
return mrb_nil_value();
}
Then, attach it to Object
, which will make it global:
mrb_define_method(mrb, mrb->object_class, "greet!", mrb_greet, MRB_ARGS_NONE());
Now, you can run in your Ruby script:
greet!