## Artichoke is a Ruby Made with Rust 💎🦀🚀 [🎢 artichoke.github.io/rubyconf/2019](https://artichoke.github.io/rubyconf/2019) [🎡 artichoke.run](https://artichoke.run)

Artichoke Ruby

Why Build a Ruby? 🏗💎

### Goals - Build for WebAssembly 🎯 - Execute untrusted code 🔦🔍 - Package single-binary apps 🧳

#### WebAssembly - Sandboxed by default 🏖 - Multi-platform 👻👽👾🤖 - Ruby in the browser 🍭

#### Untrusted Code "Code execution as a service" 🎲🎰

#### Why Execute Untrusted Code? - [Mozilla Firefox](https://developer.mozilla.org/en-US/docs/WebAssembly) 🔥🦊 - [Godot scripting](https://docs.godotengine.org/en/3.1/getting_started/step_by_step/scripting.html) 🕹🎮 - [Shopify Scripts](https://github.com/Shopify/shopify-scripts) 🛍🛒 - [Redis `EVAL`](https://redis.io/commands/eval) 🧱💈

#### Single Binary Apps Dead simple, hermetic deployments 🍱 #### Single Binary Apps Apps are hard to package 📦 especially for the web 🐒 #### Single Binary Apps - Ruby, stdlib, gems load shared objects ❗️ - Stdlib, gems, apps load Ruby code 💔 - Apps load Ruby code, config, and assets 💥

### Goals - Build for WebAssembly 🎯 - Execute untrusted code 🔦🔍 - Package single-binary apps 🧳

### Artichoke 💎❤️🦀 Rust

#### WebAssembly Compilation Build on WebAssembly targets with a native compiler toolchain 🛠 #### Building WebAssembly ```shell rustup add target wasm32-unknown-emscripten cargo build --release --target wasm32-unknown-emscripten ```

Deep Web Integration

#### Static Linking Drop a single binary in `FROM scratch` Docker container and run a full Rails app 💎🐳 #### Static Linking Statically linked dependencies enable single binary app distributions 📻 #### Static Linking Statically linked libc enables single binary app distributions 🥔 `x86_64-unknown-linux-musl`

### From Rust to Ruby 🦀 ➡️ 💎

### Ruby Core ```ruby ENV['DRY_RUN'] = '0' ary = Array.new(1024, 'Artichoke Ruby') fixture = File.read( 'artichoke-frontend/ruby/fixtures/learnxinyminutes.txt' ) /function/.match(fixture) ```

### Ruby Core - Multiple implementations 😺😸😻 - Configurable at compile time 🏘

Untrusted ENV Access #### `ENV` - System backend ↔️ OS 🖥 - In-memory backend ↔️ `HashMap` 🎟 #### In-Memory `ENV` Build on WebAssembly targets that do not have a system environ 🔧 #### In-Memory `ENV` Run untrusted code by restricting system access ⛓

Capturable IO #### `IO` - Capturable `$stdout` and `$stderr` 🧤 - Optional `IO#popen` 🚪 - Optional `Kernel#open("|date")` 📅 #### Capturable `IO` Build on WebAssembly targets that do not have file descriptors 🔧 #### Disabled `IO` pipes Run untrusted code by disabling subprocess capabilities ⛓

Virtual Kernel#require #### `File` Access - System backend ↔️ OS 🗄📁 - In-memory backend ↔️ `HashMap` 🗃🗂

Pure Rust Regexp #### `Regexp` - Pure Rust engine for WebAssembly 💧 - Oniguruma engine for compatibility 🚗

### From Core to Fast 🏎💨 🏎🏎 Benchmarks run on AWS `c5.2xlarge` 🖥 🖥

### `String#scan` `String` pattern over 6.8MB of Unicode text 📚 ```ruby raise unless $fixture.scan('http://').length == 3539 raise unless $fixture.scan('https://').length == 1865 raise unless $fixture.scan('表达式').length == 120 raise unless $fixture.scan("\r

").empty? ``` String#scan

String#scan Artichoke 66 ms / iteration MRI 82 ms / iteration

### `String#scan` `Regexp` pattern over 6.8MB of Unicode text 📚 ```ruby raise unless $fixture.scan(%r{https?://}).length == 3539+1865 raise unless $fixture.scan(/表达式/).length == 120 raise unless $fixture.scan(/\r

/).empty? ``` String#scan

String#scan Artichoke 48 ms / iteration MRI 89 ms / iteration

### Sparse Array Allocation ```ruby a = [] a[1_000_000_000_000_000] = 'quadrillion' a.concat((0..1000).to_a) 100.times do |i| a.unshift(i) end b = a.reverse b[123_456_789, 500_000] = [Object.new, /Array/, 100.0] puts a.length # => 1000000000001102 puts b.length # => 999999999501105 ```

Sparse Array Allocation Artichoke 7 MB / iteration MRI failed to allocate memory ( NoMemoryError )