Is That a Ruby In Your Browsers?

An Introduction To Opal

PSA for Examples

Ruby code is compiled and run live, and the JavaScript is verbose!


As such, they are best viewed in a browser


So if you are reading a static slide, go here:

bspaulding.github.io/ruby-in-your-browsers

What Is Opal?

Ruby to JavaScript Transpiler

AKA a "source to source" compiler

puts "Hello, World"

What Is Opal?

JavaScript bridge

Browser APIs, NodeJS Support

puts %x{document.title}
%x{
  console.log(#{ RUBY_ENGINE_VERSION })
}

What Is Opal?

JavaScript bridge

require 'native'
win = Native(`window`)
puts win.location.href
# win.alert('+1 for native bridging!')

What Is Opal?

"a gemstone consisting of hydrated silica, typically semitransparent and showing varying colors against a pale or dark background"

New Oxford American Dictionary

What Is Opal?

National Gemstone of Australia

Wikipedia

http://www.patrickmclaurin.com/wordpress/wp-content/uploads/2013/06/get_on_with_it.png
http://www.patrickmclaurin.com/wordpress/wp-content/uploads/2013/06/get_on_with_it.png

Example: Fibonacci

def fib(n)
  n <= 1 ? 1 : fib(n - 1) + fib(n - 2)
end

puts (1..10).
  map {|n| fib n }.
  map(&:to_s).
  join(", ")

Example: Hamming Distance

def hamming(a,b)
    a.split("").
    zip(b.split("")).
    select {|(a,b)| a != b }.
    length
end

puts hamming("rubyist", "opalist")
puts hamming("happy", "yappy")
puts hamming("goose", "geese")

Example: Classes

class Greeter
  def initialize(name = "Opal")
    @name = name
  end

  def say_hello
    puts greeting
  end

  def greeting
    "Hello, #{@name}!"
  end
end

class LoudGreeter < Greeter
  def greeting
    super.upcase
  end
end

greeter = Greeter.new
greeter.say_hello

Example: Modules

class Array
  def all?
    each {|n| return false unless n }
  end
end

module Validatable
  def self.included(base)
    base.extend(ClassMethods)
  end

  def valid?
    self.class.validations.
      map {|attribute, block|
        block.call(self.send(attribute))
      }.all?
  end

  module ClassMethods
    def validate(attribute, &block)
      validations[attribute] = block
    end

    def validations
      @validations ||= {}
    end
  end
end

class Person
  include Validatable

  attr_accessor :name

  validate(:name) {|value|
    !value.to_s.empty?
  }
end

brad = Person.new
puts brad.valid?
brad.name = "Bradley"
puts brad.valid?

How Ruby is it?

RubySpec

Version Date Examples
0.5.5 2013-11 2,715*
0.6.3 2014-11 3,070
0.7.0.beta1 2014-10 3,445
0.7.0.beta2 2014-11 3,601
0.7.0.beta3 2014-11 3,603

* not all passing (for me!)

For context, ~20k rubyspecs total

How Ruby is it?

Missing A Few Things:

  • Mutable Strings / Symbols
    • no #<< or #gsub!
  • Encodings
  • Threads
  • Frozen Objects
  • method_added/method_removed
    • considered a bug, will be fixed
  • private/protected
  • C Extensions
  • File/Network IO
    • coming in 0.7 for Node.js
  • method_missing

Debugging

Testing

RSpec via opal-rspec


Adds async support:

async 'HTTP requests should work' do
  HTTP.get('/users/1.json') do |res|
    run_async {
      expect(res).to be_ok
    }
  end
end

Notable Libraries

opal-browser

Browser API wrapper:

DOM, CSS, AJAX, WebSockets, SSE, History, Storage, SQL

$document.ready do
  DOM {
    div.info {
      span.red "I'm all cooked up."
    }
  }.append_to($document.body)
end

Notable Libraries

opal-jquery

"toll-free" bridge to JQuery

foos = Element.find('.foo')
# => [<div class="foo">, ...]

foos.class
# => JQuery

foos.on(:click) do
  alert "element was clicked"
end

Notable Libraries

Templating

support for erb and haml

require 'template'

template = Template['user']
context  = User.new('Ford Prefect')

puts template.render(context)
# => "<div>...</div>"

Template.paths
# => [#<Template: 'views/user'>, #<Template: 'login'>]

Notable Libraries

Promise

require 'promise'
first = get_json '/users/1.json'
second = get_json '/users/2.json'

Promise.when(first, second).then do |user1, user2|
  puts "got users: #{user1}, #{user2}"
end.fail do
  alert "Something bad happened"
end

Frameworks

  • Vienna
    • client side
    • MVC
  • Lissio
    • client side
    • Component centric
  • Volt
    • full stack, similar to meteor
    • hybrid mvc / component structure
    • reactive view bindings
    • persistence
    • messaging

Resources

Thanks!

github/bspaulding

twitter/bradspaulding