mruby

Who I am

  • Full stack Developer
  • Working for Pilot.co
  • Traveling 
  • Cycling in free time

@michalkozminski

Michał Koźmiński

What is mruby?

  • CRuby subset
  • Lua alternative
  • no need for POSIX
  • Could be embedded
  • mostly compatible with CRuby 2.1

Lets start

mruby toolset

mirb

mrbc

Compiles *.rb to *.mrb which is bytecode for RiteVM

cat test.rb
puts "ok"

./mrbc --verbose -g test.rb
00001 NODE_SCOPE:
00001   NODE_BEGIN:
00001     NODE_CALL:
00001       NODE_SELF
00001       method='puts' (218)
00001       args:
00001         NODE_STR "ok" len 2
irep 0x7fef0340d720 nregs=4 nlocals=1 pools=1 syms=1 reps=0
file: test.rb
    1 000 OP_LOADSELF	R1
    1 001 OP_STRING	R2	L(0)	; "ok"
    1 002 OP_SEND	R1	:puts	1
    1 003 OP_STOP

cat test1.rb
puts 1+2

./mrbc --verbose -g test1.rb
00001 NODE_SCOPE:
00001   NODE_BEGIN:
00001     NODE_CALL:
00001       NODE_SELF
00001       method='puts' (218)
00001       args:
00001         NODE_CALL:
00001           NODE_INT 1 base 10
00001           method='+' (117)
00001           args:
00001             NODE_INT 2 base 10
irep 0x7f98a1c0d730 nregs=5 nlocals=1 pools=0 syms=2 reps=0
file: test1.rb
    1 000 OP_LOADSELF	R1
    1 001 OP_LOADI	R2	1
    1 002 OP_ADDI	R2	:+	2
    1 003 OP_SEND	R1	:puts	1
    1 004 OP_STOP

mrdb

mruby debugger

mruby

Differences

  • no require file
  • no threads
    • there ise mruby-thread gem
  • no native support of Kernel#sleep

Embedded usage

Ruby in C/C++

mruby in C

#include <mruby.h>
#include <mruby/compile.h>

int main(void) {
  mrb_state *mrb = mrb_open();
  mrb_load_string(mrb, "puts \"hello world! #{1+1}\"");
  mrb_close(mrb);
  return 0;
}

-----------------------

gcc -Iinclude hello.c build/host/lib/libmruby.a -lm -o hello.out

./hello.out
hello world! 2

Bytecode in C

./mrbc -Btest_string test.rb

-----------

test_string[] = {
0x45,0x54,0x49,0x52,0x30,0x30,0x30,0x33,0x02,0x60,0x00,0x00,0x01,0x9f,0x4d,0x41,
0x54,0x5a,0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x01,0x54,0x30,0x30,
0x30,0x30,0x00,0x00,0x00,0xae,0x00,0x04,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x13,
0x3d,0x00,0x80,0x00,0x11,0x00,0x00,0x02,0x01,0x40,0x80,0x02,0x40,0x01,0x00,0x03,
0xa1,0x40,0x00,0x02,0x01,0x00,0x01,0x01,0x20,0x80,0x00,0x02,0x01,0x00,0x81,0x01,
0x06,0x00,0x00,0x02,0xbd,0x00,0x80,0x02,0x01,0x40,0x00,0x03,0x3e,0x80,0x81,0x02,
0xa0,0xc0,0x00,0x02,0x06,0x00,0x00,0x02,0xbd,0x01,0x80,0x02,0x01,0xc0,0x00,0x03,
0x3e,0x80,0x81,0x02,0xa0,0xc0,0x00,0x02,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x04,
0x00,0x00,0x03,0x66,0x6f,0x6f,0x00,0x00,0x0e,0x69,0x6e,0x20,0x6d,0x61,0x69,0x6e,
0x3a,0x20,0x76,0x20,0x69,0x73,0x20,0x00,0x00,0x00,0x00,0x00,0x0e,0x69,0x6e,0x20,
0x6d,0x61,0x69,0x6e,0x3a,0x20,0x72,0x20,0x69,0x73,0x20,0x00,0x00,0x00,0x04,0x00,
0x06,0x54,0x68,0x72,0x65,0x61,0x64,0x00,0x00,0x03,0x6e,0x65,0x77,0x00,0x00,0x04,
0x6a,0x6f,0x69,0x6e,0x00,0x00,0x04,0x70,0x75,0x74,0x73,0x00,0x00,0x00,0x00,0xa0,
0x00,0x03,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x26,0x00,0x00,0x02,
0x06,0x00,0x80,0x01,0x3d,0x00,0x00,0x02,0x01,0x40,0x80,0x02,0x3e,0x40,0x01,0x02,
0xa0,0x00,0x80,0x01,0x06,0x00,0x80,0x01,0x3d,0x01,0x00,0x02,0x15,0x40,0x80,0x02,
0x20,0x40,0x80,0x02,0x3e,0x40,0x01,0x02,0xa0,0x00,0x80,0x01,0xbd,0x01,0x80,0x01,
0x16,0x40,0x80,0x01,0x3d,0x02,0x80,0x01,0x29,0x00,0x80,0x01,0x00,0x00,0x00,0x05,
0x00,0x00,0x10,0x69,0x6e,0x20,0x74,0x68,0x72,0x65,0x61,0x64,0x3a,0x20,0x78,0x20,
0x69,0x73,0x20,0x00,0x00,0x00,0x00,0x00,0x10,0x69,0x6e,0x20,0x74,0x68,0x72,0x65,
0x61,0x64,0x3a,0x20,0x76,0x20,0x69,0x73,0x20,0x00,0x00,0x03,0x62,0x61,0x72,0x00,
0x00,0x03,0x62,0x61,0x7a,0x00,0x00,0x00,0x02,0x00,0x04,0x70,0x75,0x74,0x73,0x00,
0x00,0x07,0x69,0x6e,0x73,0x70,0x65,0x63,0x74,0x00,0x4c,0x56,0x41,0x52,0x00,0x00,
0x00,0x2d,0x00,0x00,0x00,0x04,0x00,0x01,0x76,0x00,0x02,0x74,0x68,0x00,0x01,0x72,
0x00,0x01,0x78,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x00,
0x03,0x00,0x01,0xff,0xff,0x00,0x00,0x45,0x4e,0x44,0x00,0x00,0x00,0x00,0x08,
};


#include <mruby.h>
#include <mruby/irep.h>
#include <mruby/proc.h>


int main(void)
{
  mrb_state *mrb = mrb_open();

  int n = mrb_read_irep(mrb, test_symbol);
  mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb));

  mrb_close(mrb);

  return 0;
}

-------
gcc -Iinclude test_string.c build/host/lib/libmruby.a -lm -o test_string.out

extending mruby

mrbgem.rake

MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
  spec.license = 'MIT'
  spec.author  = 'mruby developers'
  spec.summary = 'Example mrbgem using C and ruby'

  # Example dependency
  spec.add_dependency('mruby-parser', '>= 1.0.0', '<= 1.5.2')
end

mrblib

module CRubyExtension
  def CRubyExtension.ruby_method
    puts "A Ruby Extension"
  end
end

src

#include <mruby.h>
#include <stdio.h>

static mrb_value mrb_c_method(mrb_state *mrb, mrb_value self)
{
  puts("A C Extension");
  return self;
}

void mrb_c_and_ruby_extension_example_gem_init(mrb_state* mrb) {
  struct RClass *class_cextension = mrb_define_module(mrb, "CRubyExtension");
  mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE());
}

void mrb_c_and_ruby_extension_example_gem_final(mrb_state* mrb) {
  /* finalizer */
}

Examples of use

mruby web irb

mruby arduino

unless Object.const_defined? :Serial
	Serial = Serial2
end

class Blinker
	include Arduino
	attr_accessor :interval ,:pin
	
	def initialize(pin, interval_ms)
		Serial.println("Blinker initialized")
		@pin = pin
		@interval = interval_ms
		pinMode(@pin, OUTPUT)
	end

	def run
		Serial.println("blink!")

		digitalWrite(@pin, HIGH)
		delay(@interval)
		digitalWrite(@pin, LOW)
		delay(@interval)
	end
end

MobiRuby

Thanks, Bye

mruby

By Michał Koźmiński