Why do you want to use webruby over opal?

Published on:

Oops, time flies!

It's been a long time since I last wrote about webruby. 2014 is a really busy year for me, mostly busy in places other than programming :) Anyway, I'm back here, and I'm confident to say that webruby is not dead. In fact, I've recently upgraded webruby to the latest version of mruby with emscripten SDK. This solves a lot of existing bugs in mruby, and will also give us better experience in the better.

Okay, back to the topic of this thread. I will probably write about this upgrades, but let's leave that to a future thread. I've been wanting to write this for a while: someone posted a comment on my webruby tutorial asking:

why not using opal?

I've answered this question once when I was doing Q&A for RubyConf China 2013, but at that time, I know so little about Opal that I didn't even know Opal can do bootstrapping!

I've thought about this question for a while, and here's my conclusion: I think Opal and webruby are 2 quite different way of running Ruby on the web: while Opal translates Ruby directly to JS, webruby compiles the whole mruby VM(written in C) to JS, and runs mruby bytecode directly. Both implementations can parse Ruby code right in the browser now without a question, the targets used are different: JS for Opal, and bytecode for mruby.

I won't go that far to say this is definitely advantage for webruby, since I believe at one time the legendary Mike Pall recommended language creators target Lua directly, not luajit bytecode. But it's worth pointing out this is a difference. Depending on the exact application you are building, one might be more appealing than the other one.

Below is a few points I want to make about webruby, I won't classify them as benefits over Opal, I just like to call them as interesting behaviours of webruby:

  1. Webruby shares the same parsing as mruby, so if there're any parsing changes at mruby side, all we need to do is updating mruby code. There's no need to implement the special parsing code again. Webruby will always(well, the exact answer is mostly, since the underlying C compiler might have different semantics) have the same syntax and semantics as the official mruby implementation.
  2. With the advancements of JavaScript VM, there's potential that we can reach near-native, predictable performance in the C layer. As a result, the performance of webruby will mostly depend on the performance of mruby VM. See this for more details. This eases the efforts taken in profiling and reasoning about webruby performance, which might or might not be hard for Opal(NOTE: I'm not that familiar with Opal, so my knowledge of this might be wrong). While opal generates a lot of function calls, inlining operators is already possible. What's more, advancements in static analyzing may help Opal a lot. So this is really an interesting area to see :)
  3. In webruby, C-interoperability is possible via emscripten. Existing C code can be brought to the web, either due to performance reasons, or legacy reasons. Certain wrapper code is needed for interop between Ruby and C, of course, but it still saves a lot of efforts IMHO.
  4. Portability is an area that I think webruby certainly has an advantage: if you have a mruby codebase already running in other environments such as embedded boards, Android or iOS, porting to the web via webruby might not be a hard task. See this for one example on this, those awesome developers use webruby to build a Web IDE for their mobile payment system. What's also worth mentioning is that by portability, I'm not talking about Ruby alone! For those embedded systems, I consider both Ruby part and C part as a single codebase. Code written in both Ruby and C can be ported to webruby with certain efforts.

As the creator of webruby, I definitely know more about webruby than Opal, and I'm sure Opal developers can also craft a list of points showing that Opal is better or more interesting than webruby. These days, I'm more into this idea: while certain similarities can be found, webruby and Opal are really just for different use cases: Opal is more generally suitable for replacing JavaScript in modern websites, while webruby is mainly targeted at building native web apps.

Webruby is now a gem!

Published on:

It's been quite some time since I wrote my last post. I've been pretty busy with my work these days, I've also been to Japan for my RubyKaigi 2013 talk. But I managed to finish one feature for webruby, of which I've been dreaming for quite a long long time. Ladies and gentleman, from this time, you can install webruby using the following command:

$ gem install webruby

No more boring git commands, it is just that simple, webruby is now a gem!

Well, the sad truth is: it is actually not that simple. We need python2, ruby, node.js for this, but I believe you awesome guys or ladies already have these installed, right? The only tricky part is that LLVM 3.2 is needed to run emscripten, with LLVM 3.3 already released, this can be a little troublesome. What I suggest is that you can go to here, download the binary files for your favourite OS, extract it and define an environment variable LLVM containing the bin folder of the extracted files. This will be enough to let emscripten find LLVM 3.2.

With LLVM and webruby installed, we can use the following command to create a new project:

$ webruby new MyFirstWebrubyProject

Webruby will create a folder named MyFirstWebrubyProject with files you need:

$ tree MyFirstWebrubyProject

├── Rakefile
└── app
    └── app.rb

1 directory, 2 files

In Rakefile, you can do all the customization for webruby: whether you want to add new mrbgem, whether you want to build as release mode or debug mode, or whether you want to change the entrypoint file. By default, the entrypoint will be app/app.rb, mrubymix is used here to solve the difficult require part. I know you guys don't like this, but this is the closest solution I could think of. I will keep an eye on thoughts on the Internet, and if I found a nicer way, I will bring your favourite require back.

Building is as simple as running rake. But keep in mind that if you are running emscripten for the first time on your machine, you may find this:

$ rake
WARNING: We found out that you have never run emscripten before, since
emscripten needs a little configuration, we will run emcc here once and
exit. Please follow the instructions given by emcc. When it is finished,
please re-run rake.

Welcome to Emscripten!

This is the first time any of the Emscripten tools has been run.

A settings file has been copied to ~/.emscripten, at absolute path: /Users/rafael/.emscripten

It contains our best guesses for the important paths, which are:

  LLVM_ROOT       = /usr/local/bin
  PYTHON          = /usr/local/bin/python2
  NODE_JS         = /usr/local/bin/node
  EMSCRIPTEN_ROOT = /Users/rafael/.rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/webruby-0.1.1/modules/emscripten

Please edit the file if any of those are incorrect.

This command will now exit. When you are done editing those paths, re-run it.

In most cases, emscripten will figure everything out, and you can simple type rake again to build your project. I only did this to keep you away from wired behaviours like one of you files are not built correctly.

I feel excited that we can finally avoid the annoying git staging areas, what do you guys think?

Happy birthday Ruby! Let's get lost in the JavaScript world!

Published on:

Happy birthday Ruby! It's 24th in the US now, while it is still 24th in Japan. So it is neither too early nor to late:) It is also a perfect chance(and a happy coincidence, I didn't plan to release on this day, it just happens) to show you some of my latest work. The result looks like this:

A live demo is at here. This is the WebGL geometries example at here provided in the three.js repository. While the original example is written in JavaScript, I took some time(actualy less than an hour) to port it to Ruby. The Ruby source code and original JavaScript source code are at here. However, feel free to dig into your favourite developer tools for the demo listed above, since the Ruby code is stored in a separate file, fetched using Ajax and parsed on the fly.

From a comparison of the two versions of source code you can see that a lot of things can be achieved purely in the Ruby side:

  • Fetch the fields of a JavaScript object using both '.' syntax and '[]' syntax
  • Call a JavaScript function using either normal method or new call
  • Pass Ruby strings, arrays and hashes as arguments to the JavaScript functions
  • Use either JavaScript functions or Ruby Procs as callback functions

Basically most of the things you normally do in JavaScript can be done entirely in Ruby. However, there're still some syntax differences:

  • While you can use console.log("Log message!") to call a JavaScript function, if you want to invoke a function with no arguments, you either need to use console.log.invoke or console.log[]. This is because Ruby does not distinguish between console.log and console.log()
  • For new call, instead of new bar(), we need to use bar.invoke_new, since I haven't found a good way to implement new function. Maybe I need to check rspec for inspiration-_-
  • You can create a variable that caches a function: such as:
object_create_func = $three.SceneUtils.createMultiMaterialObject

However, to invoke this function, you need to use following syntax:

object = object_create_func[$three.CubeGeometry.invoke_new(100, 100, 100, 4, 4, 4), materials]

This is now only a temporarily solution, I may find a way to work around this.

  • Suppose you want to call a set function on an object foo, you cannot directly do a foo.set(1), since set is already used in Ruby side, what you can do here is one of the following solutions:
foo.call(:set, 1)
# or

  • When adding Ruby Procs as callback functions, you can either directly create a proc:
p = Proc.new {
 puts "Resize occurs!"
$window.addEventListener('resize', p, false)

You can also use existing functions as callbacks, but do remember you need to use the following syntax:

def onResize
 puts "Resize occurs!"
$window.addEventListener('resize', :onResize.to_proc, false)

While we still use a symbol to represent a function, to_proc must be invoked to tell webruby that we want to use the actual function, not the onResize string.

  • Do remember that in current implementation of webruby, you only have the precision of float, not double. So the range that can be expressed in a number is a little limited. I will check later if we can work this around.

And there's one more TODO task: currently you cannot pass arguments to a callback function using a Ruby proc. For example, if you add arguments to window.setInterval, they are not passed back to your Ruby Proc. I will work on this in the next few days(but not today, I have some stupid homework to finish today-_-).

Although we have a few limitations or rules to keep in mind, I do think we now have a almost complete JavaScript calling interface:) Now we have a whole lot of existing JavaScript libraries that we can take advantage of, including three.js, the yet-to-release famo.us engine and WebAudio.js, etc. We may even take advantage of the WebWorker API for multi-threading! I must admit that I'm a little behind schedule for my OpenGL ES binding project, but since we have three.js now, we can already create awesome Web projects:) Anyway, I will come back to create a complete OpenGL ES binding implemention.

Ruby: will you love your new JavaScript house in the next 20 years? I do wish you enjoy it!

Introducing mrubymix: static require for mruby

Published on:

I've been considering a lot about the "require" problem in Webruby. We know that mruby will not have an official require function. While it is not so hard to write one, we still may not be able to get a consistent API, since all the mrbgems are directly adding modules or classes without needing a require. Personally, I think this makes require useless. What's more, when targeting an embedded system, is it possible that we will always have a dynamic library loading mechanism? I just don't have the answer.

However, we still need a way to organize the source code. Nowadays we cannot assume that anyone is interested in putting all the source code in one file! One way of solving this is to use cat to concatenate all the source files just as what we would do when compiling mruby unit tests. However, there's still one problem: you need to maintain the order of concatanation. A simple cat *.rb > rbcode.rb will not solve the problem since the order may not be what you want, just imagine if you have a zlib library named zlib.rb and many other source files depend on it.

So what we really need here is a utility that can:

  1. Combine multiple Ruby source files into one giant file.
  2. Maintain a dependency or an order of different files.

I'm not an enthusiast of Rails, but what came to my mind first is the Rails asset pipeline. It solves exactly the same problem, but on JavaScript or CSS files. So can we borrow the ideas from Rails and use it on Webruby, or even mruby?

Here I created a gem(Ruby gem, not mrbgem) called mrubymix. It reads a root source file, or an entrypoint file, then parses and includes all the other source files required by the entrypoint. mrubymix will automatically records the dependency of each file, and only include one source file once, even if it is required by many other file.

Here is an example, supports we have the following entrypoint file, named app.rb:

#= require aaa

#= require ./foo/bar

puts "This is app.rb!"

You may notice that the syntax here we use is the same as Rails asset pipeline. This app.rb file has two depencencies: aaa.rb and ./foo/bar.js. Two simple rules are used here:

  • The suffix .rb can be omitted.
  • The path of required file is relative to the path of current file

To demostrate how mrubymix resolves multiple dependencies of the same file, suppose aaa.rb contains the following content:

#= require ./foo/bar

puts "This is aaa.rb!"

And this is the content of ./foo/bar.rb:

puts "This is foo/bar.rb!"

We can run the following command to process app.rb:

$ mrubymix app.rb out.rb

The first argument to mrubymix is the path of the entrypoint file, while the second argument is the path of output file. After running this command, the content of out.rb should be:

# File: /Users/rafael/develop/tmp/post/foo/bar.rb

puts "This is foo/bar.rb!"

# File: /Users/rafael/develop/tmp/post/aaa.rb

puts "This is aaa.rb!"

# File: /Users/rafael/develop/tmp/post/app.rb

puts "This is app.rb!"

For each file, mrubymix will first write the full path of the file included as a Ruby comment, then the actual content of the file will be appended. Notice here that all the require lines are removed. What's more, even though the file foo/bar.rb has been required twice, only one is actually inserted, the inserted location is also the earliest one, which is ahead of all depending source files.

For now, this gem is just reinventing wheels of sprockets, which only deals with JavaScript, CoffeeScript and CSS. One idea would be change this gem to use the parsing part of sprockets, this could bring new features such as require_tree, or require_directory, etc. But for now, I can live with this simple implementation.

The build process of Webruby has also been changed to use this small library. Considering the simplicity of building process and the small size of this gem, I just added as a git submodule instead of requiring this gem to be available on your machine. This may provide another reason of maintaining an independent library instead of using sprockets.

I believe this gem is not only helpful for Webruby. Whenever you are using mruby, you need to solve the code organization problem, and this gem can provide an alternative to the regular require way:)

Webruby updates: the new optimization mode and minor API changes

Published on:

Now here's some exciting news(at least exciting for me): with all the optimizations from emscripten and closure compiler, now the generated JavaScript file is only ~800k with ruby parser code, or ~400k without parser code!

This means that with only a JavaScript of ~400k, you can have a full-fledged Ruby running in the browser! Personally I think this really brings webruby to a usable state, what do you think?

To enable this optimization, instead of running rake, you can simple run the following command:

$ OPT=1 rake

On my machine, the generated JavaScript file here is only 821k. Or if you do not need the parser code, you can further strip the file size with:


My test shows that the file size has been further reduced to only 401k!

Notice that now the linking time is longer than the normal case, so I suggest you only use optimization mode only when releasing your code, and continue with the non-optimization option when developing.

There's also a small API changes from what I described in the tutorial. Now the HTMl skeleton for invoking webruby looks like following:

<!DOCTYPE html>
    <title>Webruby tutorial</title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="webruby.js"></script>
    <h1>This is a skeleton for Webruby tutorial!</h1>
    <div id="container"></div>
      $(document).ready(function() {
        var src = "MrubyJs.get_root_object.call('$', '#container')" +
          ".call('append', '<p>This is inserted in Webruby using " +

        var w = WEBRUBY();

        /* Runs embedded source code in mruby.js file. */

        /* Parses and executes Ruby source code on the fly. */

        /* Closes this webruby instance and frees all resources,
         * this may be optional, but it will help reduce memory
         * usage if you have multiple webruby instances in your
         * page.

Now WEBRUBY serves as a function instead of an object. With each run of WEBRUBY(), you can have a separate webruby instance for running Ruby code. The mruby state, mrb, is now encapsulated in the returned object of WEBRUBY(). You do not need to specify it manually now.

Personally, I think this new API is a little simpler. However, if you have other opinions, please feel free to leave a comment here:)

Finally it's here: Webruby 1-2-3 tutorial

Published on:

Update: I've changed the API a little bit. Please check this post for the latest API. I decided to keep this post unchanged so you can see both versions. Feel free to leave a comment if you belive the old one is better:)

Lately some people have been asking me to write a tutorial on how to use Webruby. Sorry, guys. I was having a lot of fun writing this stuff but I forgot to bring these fun to you. Now the tutorial on Webruby is finally here:)

The final result of this tutorial looks like this:

You can also find a live demo at here. The demo page uses jQuery to insert <p> tags from Ruby side. This is a boring and pretty stupid demo, but it at least shows how to execute Ruby code and how to call JavaScript code from Ruby side, so I wish you wouldn't feel too bored. Well, let's get started:)

First question: where do I put my Ruby source code?

Before everything starts, we need a place to keep and load our Ruby source code. Webruby now supports 3 kinds of source code loading methods:

  • All the source code in app folder of Webruby will be compiled and attached in the mruby.js file automatically. Then we can use WEBRUBY#run to load this part of source code.

  • You can pre-compile the Ruby source code, pass the generated mruby bytecodes to the browser side either by attached JavaScript file or XMLHttpRequest, and use WEBRUBY#run_bytecode to execute the bytecode directly. With this method, you can get the flexibility of loading code on the fly, while avoiding parsing Ruby source code at the browser side(and the whole parsing part can be avoided in mruby.js file).

  • And of course, you can use WEBRUBY#run_source to parse and execute Ruby code directly.

Webruby allows you to specify the loading modes you will use when compiling, this can help reduce the size of mruby.js file: if you do not need to parse Ruby source code on the fly, you wouldn't need all the parsing code in the generated mruby.js file, and if you only execute source code from app folder, modern optimizers may take advantage of that to further reduce the file size. Please refer to rakelib/functions.rb for how to specify supported loading modes. In this tutorial, we will use the default loading modes, which will support all 3 kinds of loading methods. And we will show how to load Ruby source code using WEBRUBY#run and WEBRUBY#run_source. The second method describes above is a little bit of complicated(since mruby has multiple versions of bytecode), I will describe it in another post(maybe with specialized bytecode generation tools) later.

Okay, I got that. But how to run this stuff exactly?

Now we've got all the backgrounds needed, let's walk through the developing process step by step.

Environment setup

I assure you that this is easy to do. Just clone the [project](https://github.com/xxuejie/webruby] from Github and setup submodules:

$ git clone git://github.com/xxuejie/webruby.git
$ git submodule init && git submodule update

And do remember one thing: webruby uses emscripten, and emscripten uses LLVM internally. So you may also need to install LLVM:

$ brew install llvm --with-clang

Note this is the Mac-with-homebrew way of installing LLVM. If you know how to install LLVM 3.2 on Linux/Windows, I will really appreciate it if you can comment below, I will update this post accordingly.

Update: Thanks to Reed for pointing out, actually you can just go to http://llvm.org/releases/download.html, download and extract the pre-compiled binary for your platform, change the value of LLVM_ROOT in your ~/.emscripten file to match the bin directory of your LLVM installation. You are then good to go!

This is almost it! I guess I may assume that most of you have Ruby and node.js installed already. But if you are not so convinced, you can run the mruby unit tests in webruby environment:

# in mruby folder

$ rake mrbtest
# building output omitted

node /Users/rafael/develop/webruby/build/mrbtest.js
mrbtest - Embeddable Ruby Test

This is a very early version, please test and report errors.
Thanks :)

Total: 510
OK: 510
KO: 0
Crash: 0
Time: 9.389 seconds

If you can see this, everything is fine:)

GEM setup

Webruby is designed in a way that the core project just contains build scripts and a very small yet required driver code. The rest parts are in separate projects(organized as mrbgems). The idea here is that your final mruby.js file does not to contain the part that you will not use. So the default build only contains a mruby runtime. In this demo we will need JavaScript calling support, which is provided by mruby-js.

The latest mruby supports using mrbgem directly from a git repository, so all you need to do here is uncomment Line #32 in build_config.rb. And make it look like this:

# JavaScript calling interface

conf.gem :git => 'git://github.com/xxuejie/mruby-js.git', :branch => 'master' # This is the line to uncomment!

Notice that if you have run mrbtest before uncommenting this line, you need to run rake clean to cleanup everything and do a full rebuild. This is due to that the gem settings have changed.

Writing Webruby code

Now we can actually start writing Ruby code. First we will try the first loading method: all the source code in app folder of webruby will be compiled and then attached in the mruby.js file. So feel free to add or change any file in the folder, but please do remember to add .rb suffix.

A special file named app.rb will be compiled at last, it serves as the entrypoint(or so-called "main" file). For our simplest demo, we will just code in this file. Now you can bring out your favourite code editor and change the content of this file to:

# This is the entrypoint file for webruby

# get window object

root_object = MrubyJs.get_root_object

# get jQuery selected object

container = root_object.call("$", "#container")

# appends <p> tag

container.call("append", "<p>This is inserted in Webruby using WEBRUBY#run()!</p>")

There is only one method in module MrubyJS: get_root_object. It would return the window object for a browser environment, or the global object when running in node.js. The returned object is of class JsObject, it is a wrapper over the actual object at JavaScript side. With its call function, you can make a call to a JavaScript function, the first argument is the function name, while the rest arguments are all passed to the JavaScript function.

JsObject also comes with call_constructor function for making a new call, and get for getting a field value from an object. Note that mruby-js is still under development, function and array passing support is still lacking, and the APIs are subject to change. I will try my best to keep here updated, but please always use the source code as the answer if you find a disagreement.

Now you can compile webruby using rake, if everything works well(it should), you can find a mruby.js file in build folder.

HTML skeleton

Node.js is great for debugging, but I believe most of you want to use webruby in a browser enviroment. We also need an HTML skeleton for loading our generated JS file.

Here's a sample skeleton: note that this only serves as a sample, and I believe all of you can write a much better skeleton within seconds. But for now, please bear with this dumb one:

<!DOCTYPE html>
    <title>Webruby tutorial</title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="webruby.js"></script>
    <h1>This is a skeleton for Webruby tutorial!</h1>
    <div id="container"></div>
      $(document).ready(function() {
        var mrb = WEBRUBY();

        /* Runs embedded source code in mruby.js file. */


Put this html file in the same folder with mruby.js file and open it with a modern browser, you can see an initial result:)

Loading Ruby source code on the fly

By changing the value of environment variable LOADING_MODE, you can actual customize the loading methods you want to support. For example, the following line can be used to only allow for running attached Ruby code compiled from app folder:


If you have been following this post, then your mruby.js must have already contained parsing code. Otherwise you may want to use following command to rebuild the JS file:


The Ruby code can thus be put in a JavaScript string, which may comes from other JavaScript file or XMLHttpRequest. In our demo we just hardcoded it in a string for simplicity:

<!DOCTYPE html>
    <title>Webruby tutorial</title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="webruby.js"></script>
    <h1>This is a skeleton for Webruby tutorial!</h1>
    <div id="container"></div>
      /* Inline source code, in practice you may want to get this from
       * an XMLHttpRequest.
      var src = "MrubyJs.get_root_object.call('$', '#container')" +
        ".call('append', '<p>This is inserted in Webruby using " +

      $(document).ready(function() {
        var mrb = WEBRUBY();

        /* Runs embedded source code in mruby.js file. */

        /* Parses and executes Ruby code on the fly. */


Now it looks just like what is shown in the demo. You can also use Closure Compiler to strip the size of generated JS file if you like, but please keep in mind that only simple optimization works for now, the advanced option still needs a little tweaking. On my machine, with a simple optimization the size of the JS file can be reduced from 4.2MB to 1.5MB.


It really feels nice to finally have something for everyone to use:) I've had a lot of fun and I will be continue maintaining this. Of course this is not fit for everyone's project, even after optimization there's a 1.5MB JS file to load. For now I guess the most suitable use case will be Web games or single page apps. This is why I'm also working on an OpenGL ES 2.0 binding. Anyway, I wish all of you had fun playing with webruby, just like I had fun developing this:)

mruby to JavaScript? Well, maybe this is not a working path as I thought

Published on:

Merry Christmas everyone! Honestly Christmas is not so important for me but it may be very important for you guys:) Also wish everyone of you a Happy New Year!

I said in my last post that I had a nice idea on a calling interface from mruby to JavaScript. But after some time's investigation, I start to wonder if I was being too optimistic. Anyway, here's my original idea:

Ruby is a dynamic language, so is JavaScript. The only thing that caught us is the C layer in between(being a pathetic C99 lover, I just prefer to ignore C++). However, all we need to do here is to figure out what function we want to call as well as all the arguments(from Ruby side) and pass all them through the C layer to the JavaScript side. We do not need to do any execution in the C layer.

Here's the point: suppose we have a Ruby object, which represents the document object in DOM. We can use method_missing to capture the function we want to call and all the arguments, pass them through the C layer and invoke it in the JavaScript side. Now comes the tricky part: while the function is represented by a string(or a symbol in Ruby side), we cannot refer to the actual function in the C side, but neither do we need to do this. We can just pass the string over to the JavaScript side and use method_missing.function_name to get this function. Problem solved.

Did you see my mistake? What I miss here is that getting the function is only one side of the stories. We still have all the arguments to process. At mruby side we have mrb_value that tells us the type of the argument, but when passing through the C layer, we need to resolve to the va_list mechanism(similar, but it is not called this in emscripten) for passing variable numbers of arguments. How are we going to preserve the types here? How can we distinguish a string from a number in JavaScript?

I could build a mrb_value-like type to use in va_list-like structure when handling control to JavaScript, but struct passing seems difficult, if not impossible, to process in emscripten. What's more, This may bring more performance cost, while running mruby on top of JavaScript already makes execution slower than pure JavaScript.

Or maybe I can also pass in an array of strings to the JavaScript side specifying the types of each arguments. While this array could be generated automatically, the question is still there: does it worth the cost?

Maybe my original plan on an OpenGL ES 2.0 API is right-_- Anyway, I will update here if I have more results.

Update: Well, I manage to succeed in building an interface using neither of the methods above! I just pass the pointer(array) of values to the JS side, and then let the JS code call "back" to the C code to process the arguments one-by-one. The cost should not be more than simply looping through the arguments. The internal structure of mruby calling stack helps a lot in this implementation! If you are interested, feel free to check out the code, specifically this commit.