Slide 1

Slide 1 text

Opal: The Journey from JavaScript to Ruby by Bozhidar I. Batsov (@bbatsov)

Slide 2

Slide 2 text

Божидар

Slide 3

Slide 3 text

Sofia, Bulgaria

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Bug

Slide 6

Slide 6 text

Few important things you need to know about me

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

I’m an Emacs fanatic

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

bbatsov

Slide 11

Slide 11 text

I love Ruby

Slide 12

Slide 12 text

I don’t like JavaScript

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

wtfjs.com

Slide 15

Slide 15 text

Why am I here?

Slide 16

Slide 16 text

4% 96% Web Development Other

Slide 17

Slide 17 text

10% 90% Rails Other

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Ruby 2.2 includes many new features and improvements for the increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.

Slide 20

Slide 20 text

Ruby 2.2 includes many new features and improvements for the increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.

Slide 21

Slide 21 text

Ruby 2.2 includes many new features and improvements for the increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.

Slide 22

Slide 22 text

Ruby 2.2 includes many new features and improvements for the increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.

Slide 23

Slide 23 text

Ruby 2.2 includes many new features and improvements for the increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.

Slide 24

Slide 24 text

Ruby 2.2 includes many new features and improvements for the increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.

Slide 25

Slide 25 text

Nooooooo

Slide 26

Slide 26 text

JRuby

Slide 27

Slide 27 text

RubyMotion

Slide 28

Slide 28 text

Rails, Rails, Rails

Slide 29

Slide 29 text

And what about JavaScript?

Slide 30

Slide 30 text

Things people are doing with JavaScript • Client-side apps • Server-side apps - Node.js (& io.js) • iOS & Android apps (using React Native) • Windows Phone apps • Desktop app (e.g. for Windows & GNOME)

Slide 31

Slide 31 text

The possibilities are infinite with JavaScript

Slide 32

Slide 32 text

If only there was some nice alternative to JavaScript…

Slide 33

Slide 33 text

CoffeeScript

Slide 34

Slide 34 text

PureScript

Slide 35

Slide 35 text

Dart

Slide 36

Slide 36 text

Elm legit

Slide 37

Slide 37 text

Scala.js

Slide 38

Slide 38 text

ClojureScript legit

Slide 39

Slide 39 text

Why are we doing this (ClojureScript)? Because Clojure rocks, and JavaScript reaches… — Rich Hickey (creator of Clojure)

Slide 40

Slide 40 text

Ruby also rocks!

Slide 41

Slide 41 text

Ruby is better than JavaScript

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

Ruby’s advantages • Doesn’t have this • Sane boolean semantics • No need for a book called “Ruby: The Good Parts” • No wtfruby.com • Solid core library • Extensive standard library • Do you really need more?

Slide 45

Slide 45 text

Opal.rb http://opalrb.org/

Slide 46

Slide 46 text

A brief history of time Opal

Slide 47

Slide 47 text

• Initial release - 22.01.2010 • Used in production by 2013 • Popularity spikes in 2014 after the launch of the Volt web framework • Latest version (0.8.0) was released on 16.07.2015

Slide 48

Slide 48 text

The Value Proposition

Slide 49

Slide 49 text

Ruby to JavaScript source-to-source compiler

Slide 50

Slide 50 text

Ruby Opal JavaScript

Slide 51

Slide 51 text

No new VM

Slide 52

Slide 52 text

No bytecode

Slide 53

Slide 53 text

No translation layers

Slide 54

Slide 54 text

An implementation of Ruby’s corelib and stdlib

Slide 55

Slide 55 text

But we already have CoffeeScript!

Slide 56

Slide 56 text

CoffeeScript’s shortfalls • Same (spartan) core library • No standard library • It’s not Ruby

Slide 57

Slide 57 text

A basic example

Slide 58

Slide 58 text

def hello(name) puts "Hello, #{name.capitalize}!" end hello("bruce")

Slide 59

Slide 59 text

/* Generated by Opal 0.7.0 */ (function(Opal) { Opal.dynamic_require_severity = "error"; var self = Opal.top, $scope = Opal, nil = Opal.nil, $breaker = Opal.breaker, $slice = Opal.slice; Opal.add_stubs(['$puts', '$capitalize', '$hello']); Opal.Object.$$proto.$hello = function(name) { var self = this; return self.$puts("Hello, " + (name.$capitalize()) + "!"); }; return self.$hello("bruce"); })(Opal);

Slide 60

Slide 60 text

Opal.Object.$$proto.$hello = function(name) { var self = this; return self.$puts("Hello, " + (name.$capitalize()) + "!"); }; return self.$hello("bruce");

Slide 61

Slide 61 text

The magic happens in Opal.compile

Slide 62

Slide 62 text

Opal.compile( "puts 'Hi, eurucamp!’" )

Slide 63

Slide 63 text

"/* Generated by Opal 0.7.2 */ \n(function(Opal) {\n Opal.dynamic_require_severity = \"error\";\n var self = Opal.top, $scope = Opal, nil = Opal.nil, $breaker = Opal.breaker, $slice = Opal.slice;\n\n Opal.add_stubs(['$puts']);\n return self.$puts(\"Hi, eurucamp!\")\n}) (Opal);\n"

Slide 64

Slide 64 text

/* Generated by Opal 0.7.2 */ (function(Opal) { Opal.dynamic_require_severity = "error"; var self = Opal.top, $scope = Opal, nil = Opal.nil, $breaker = Opal.breaker, $slice = Opal.slice; Opal.add_stubs(['$puts']); return self.$puts("Hi, eurucamp!") })(Opal);

Slide 65

Slide 65 text

Ruby to JS mapping • self -> this (mostly) • Ruby method/block -> JS function • Ruby string -> JS string • Ruby number -> JS number • Ruby array -> JS array • Ruby hash -> custom JS type

Slide 66

Slide 66 text

JavaScript interop

Slide 67

Slide 67 text

>> `"bozhidar".toUpperCase()` => "BOZHIDAR"

Slide 68

Slide 68 text

class Array def length `this.length` end end

Slide 69

Slide 69 text

`window.title` # => "Opal: Ruby to JavaScript compiler" %x{ console.log("Opal version is:"); console.log(#{RUBY_ENGINE_VERSION}); } # => Opal version is: # => 0.8.0

Slide 70

Slide 70 text

require 'native' window = Native(`window`) window[:location][:href] # => “http://opalrb.org/docs/“ window[:location][:href] = "http://opalrb.org/" # will bring you to opalrb.org window.alert('Hey campers!')

Slide 71

Slide 71 text

Alternative JS interop (coming in Opal 0.9)

Slide 72

Slide 72 text

# JavaScript: foo.bar(1, "a") foo.JS.bar(1, :a) foo.JS.bar 1, :a

Slide 73

Slide 73 text

# JavaScript: # ($a = foo) # .bar # .apply($a, [1].concat([2, 3])) foo.JS.bar(1, *[2, 3]) foo.JS.bar 1, *[2, 3]

Slide 74

Slide 74 text

# JavaScript: # ($a = (TMP_1 = function(arg){ # var self = TMP_1.$$s || this; # if (arg == null) arg = nil; # return "" + (arg.method()) + " " + (self.$baz(3)) # }, # TMP_1.$$s = self, TMP_1), # foo.bar)(1, 2, $a); foo.JS.bar(1, 2) { |arg| arg.JS.method + baz(3) }

Slide 75

Slide 75 text

# JavaScript: foo["bar"] foo.JS[:bar] # JavaScript: foo[2] foo.JS[2] # JavaScript: foo["bar"] = 1 foo.JS[:bar] = 1 # JavaScript: foo[2] = "a" foo.JS[2] = :a

Slide 76

Slide 76 text

require 'js' # new foo(bar) JS.new(foo, bar) # delete foo["bar"] JS.delete(foo, :bar) # "bar" in foo JS.in(:bar, foo) # foo instanceof bar JS.instanceof(foo, bar) # typeof foo JS.typeof(foo)

Slide 77

Slide 77 text

require 'js' # parseFloat("1.1") JS.call(:parseFloat, '1.1') JS.parseFloat('1.1')

Slide 78

Slide 78 text

Ruby from JavaScript

Slide 79

Slide 79 text

class Foo def bar puts 'Called Foo#bar' end end

Slide 80

Slide 80 text

Opal.Foo.$new().$bar(); // => “Called Foo#bar”

Slide 81

Slide 81 text

Is Opal any good?

Slide 82

Slide 82 text

Very basic corelib No stdlib Semicolons Misc WTFs JavaScript Complexity

Slide 83

Slide 83 text

Performance Debugging Ruby Compatibility Ruby WTFs Opal’s Perceived Complexity File Size

Slide 84

Slide 84 text

Very basic corelib No stdlib Semicolons Misc WTFs JavaScript Performance Debugging Ruby Compatibility Ruby WTFs Opal File Size

Slide 85

Slide 85 text

Performance

Slide 86

Slide 86 text

File Size

Slide 87

Slide 87 text

opal.min.js =~ 259 kb opal.min.js.gz =~ 49 kb

Slide 88

Slide 88 text

Debugging

Slide 89

Slide 89 text

It’s just JavaScript

Slide 90

Slide 90 text

Opal has source maps

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

Ruby Compatibility

Slide 94

Slide 94 text

Ruby compatibility • Mostly compatible with Ruby 2.0 • Tested against RubySpec • Implements most of the Ruby corelib • Implements some of the stdlib (e.g. Set)

Slide 95

Slide 95 text

Notable differences • true and false are translated to JavaScript’s booleans • All numbers are JavaScript floats • Strings are immutable • Symbols are strings • No dynamic requires • No threads • No frozen objects • All methods are public

Slide 96

Slide 96 text

Performance is key

Slide 97

Slide 97 text

Performance Debugging Ruby Compatibility Ruby WTFs Opal Complexity

Slide 98

Slide 98 text

Very basic corelib No stdlib Semicolons Misc WTFs JavaScript Complexity Performance Debugging Ruby Compatibility Ruby WTFs Opal Complexity

Slide 99

Slide 99 text

Epic!!!

Slide 100

Slide 100 text

Diving in

Slide 101

Slide 101 text

opal-irb

Slide 102

Slide 102 text

opal-rails

Slide 103

Slide 103 text

opal-browser

Slide 104

Slide 104 text

$document.ready do alert 'yo folks, I'm all loaded up in here' end $document.body.style.apply { background color: 'black' color 'white' font family: 'Verdana' } Browser::HTTP.get '/something.json' do on :success do |res| alert res.json.inspect end end

Slide 105

Slide 105 text

opal-jquery

Slide 106

Slide 106 text

Element.find('#header') Element.find('#navigation li:last') Document.ready? do alert 'document is ready to go!' end Element.find('#header').on :click do puts 'The header was clicked!' end

Slide 107

Slide 107 text

opal-react

Slide 108

Slide 108 text

opal-native

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

opal- activesupport

Slide 111

Slide 111 text

Looking forward

Slide 112

Slide 112 text

Implement the missing things

Slide 113

Slide 113 text

Better documentation

Slide 114

Slide 114 text

A book on Opal

Slide 115

Slide 115 text

More Opal wrappers of popular JS libs

Slide 116

Slide 116 text

WebAssembly

Slide 117

Slide 117 text

Contribute to Opal!

Slide 118

Slide 118 text

github.com/opalrb

Slide 119

Slide 119 text

Opal Resources • http://opalrb.org/docs/ • http://opalrb.org/try/ • https://opalist.curated.co/ • http://datamelon.io/blog/ • http://fkchang.github.io/opal-playground/

Slide 120

Slide 120 text

Felina