JSON Parser for MRuby or how to define classes and exceptions in C

mruby, Ruby Leave a comment

MRuby is progressing quite rapidly, it is now possible to implement a real REPL, see github. So, it is time to continue my efforts to integrate MRuby into ArangoDB. ArangoDB currently uses JavaScript to implement transactions and enrich the database with small Actionlets, i. e. functions that take a HTTP request and produce a HTTP response. Additionally, there is a shell, which allows you to administrate the server.

I want to be able to also use MRuby for these jobs. These easiest part is the interactive shell. It requires the following components:

  • a JSON parser and stringifier
  • a HTTP client
  • a REPL

MRuby now comes with a simple REPL. However, there are still some issues with parsing and readline support, so for the time being I stick to the approach described in my last post.

In principle the JSON parser can be implemented in Ruby itself using one of the known json packages. As ArangoDB comes with a parser, I will be using the built-in parser. The same is presumable true for the HTTP client.

In this blog post I want to describe what I’ve done to integrate the JSON parser into MRuby. I hope that will help others to write C/C++ extensions.

The last post describes how to integrate C code into MRuby. Let me go into more details.

I need a class ArangoJson with a method parse which takes a string as argument, parses the JSON structures and returns a Ruby hash.

mrb_define_class defines a new class called ArangoJson which is a sub-class of Object. mrb_define_class_method defines a new C method in this class which takes 1 argument (but see below).

mrb_get_args extracts a string argument from the argument list and stores the result in s. As far as I can see, you do not need to free the returned string.

Everything works as expected

Stragely, if you pass a number instead of a string, the program crashs

Similarly, passing no argument does not raise an exception. So, I not sure what the meaning the ARGS_REQ parameter is. I hope the MRuby team can shed some light on it.

The conversion function MR_ObjectJson is straight forward and shows how to use the various data types in MRuby.

This leaves the error handling. I wanted my own exception. Luckily it is quite easy to define:

The only problem is, where to store the defined class. mrb_state has no custom data pointer – at least I did not find any. So I used the following trick: Instead of using a mrb_state as returned by mrb_open, I use a slightly large data structure with my extensions at the end.

So, creating an exception with two custom instance variables @error_num and @error_message

Because Ruby has no closed, but an open class definition, one can now use a Ruby definition for the getter extending the class defined in C.

What remains to do to finish the MRuby shell is

  • implement the “require” function to load Ruby files
  • add a wrapper to the HTTP client
Tweet about this on TwitterShare on Google+Share on RedditShare on LinkedInBuffer this page

About Frank Celler

Frank is both entrepreneur and backend developer, developing mostly memory databases for two decades. He is the lead developer of ArangoDB and co-founder of triAGENS. Try to challenge Frank asking him questions on C, C++ and MRuby. Besides Frank organizes Cologne’s nosql group & nosql conferences.