Webruby – Now you can write your favorite Ruby code for the browser!



Webruby – Now you can write your favorite Ruby code for the browser!

0 1


rubykaigi2013-talk


On Github xxuejie / rubykaigi2013-talk

Webruby

Now you can write your favorite Ruby code for the browser!

Xuejie "Rafael" Xiao / @defmacro

What is webruby?

  • Ruby implementation that runs in the browser
  • Based on mruby
  • Calling JavaScript directly from Ruby

Demos

IRB(by Joshua Nussbaum)

WebGL

How webruby works?

mruby

  • Matz's embeddable minimal implementation of Ruby language
  • Written in C99
  • Minimal, Embeddable, Modular, Configurable
  • Targeting Mobile device/Robots/Digital appliances/Games

What about the Web?

emscripten

  • LLVM-to-JavaScript compiler
  • Generated JS code runs very fast, and gets faster every day
  • asm.js: subset of JavaScript used as low-level, efficient compiler target

Combine them together

mruby source

Running with node.js

Loading mode

run() load bytecode packed in generated JS file run_bytecode(bytecode) load bytecode run_source(src) parse and load Ruby source code on-the-fly

If we do not need run_source(src), we may be able to get rid of all the parsing code!

Load source on-the-fly

$(document).ready(function() {
  var src = "5.times { puts 'Ruby is awesome!' }";
  var w = WEBRUBY();

  w.run_source(src);
  w.close();
});

Running in the browser

mruby test cases

Actually it may not be that slow because of JIT!

Okay, I can run Ruby in the browser.

But how can I access DOM/my fancy JavaScript library?

mruby-js

  • Grouped as a mruby gem
  • DOM access
  • Type conversion between Ruby and JavaScript
  • JavaScript method invoking
  • Callback handling(JavaScript functions and Ruby procs)

Example to use

# gets window object
window = MrubyJs.window

# gets jQuery selected object, this is a function call!
# you can also use jQuery.invoke("#container")
container = window.jQuery["#container"]

# appends new tag
# another way of writing this: container.append["content"]
container.append("<p>This is inserted using run_source()!</p>")
Demo

DOM access

DOM is a tree!

Type conversion

Ruby type Direction JavaScript type 42 ←→ 42 3.14 ←→ 3.14 true ←→ true nil ←→ undefined "String" ←→ "String" :symbol → "symbol" Proc.new { ... } → function() { ... } [ ... ] → [ ... ] { ... } → { ... }

Object encapsulation

Method calling

Wrap using instance_eval

MrubyJs.window.instance_eval do
 if confirm("continue?")
    console.log "you chose continue"
    food = prompt("What's your favourite food?")
    alert "Really?? #{food}?\nThat's gross."
    jQuery('body').prepend("<h1>Likes #{food}</h1>")
 else
    console.log "you chose not to coninue"
 end
end

mruby-js limitations

JavaScript Ruby foo.bar() foo.bar.invoke or foo.bar[] new bar("foo") bar.invoke_new("foo") var a = bar; a(2); a = window.bar; a[2]

When should I use webruby?

Drawbacks

  • Giant webruby.js file Version Raw gzip -1 non-asm.js 3.2M 691K asm.js 2.2M 661K
  • Slow startup time
  • Double GC(maybe asm.js can help with this?)

Places webruby might fit

  • Cross-platform games
    • Common game logic in Ruby
    • Web, iOS, Android, PlayStation...
    • OpenGL ES 2 as rendering API
  • Web apps
    • Business logic in Ruby
    • Interactions with jQuery, three.js, Backbone.js, Meteor...

Thank you!

Questions?