$30 off During Our Annual Pro Sale. View Details »

Opal: The Journey from JavaScript to Ruby

Opal: The Journey from JavaScript to Ruby

Slide-deck from my presentation at RubyConf Kenya 2017.

Bozhidar Batsov

June 11, 2017
Tweet

More Decks by Bozhidar Batsov

Other Decks in Programming

Transcript

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

    View Slide

  2. Божидар

    View Slide

  3. Sofia, Bulgaria

    View Slide

  4. View Slide

  5. Bug

    View Slide

  6. Few important things
    you need to know
    about me

    View Slide

  7. View Slide

  8. I’m an Emacs fanatic

    View Slide

  9. View Slide

  10. bbatsov

    View Slide

  11. I love Ruby

    View Slide

  12. I don’t like
    JavaScript

    View Slide

  13. View Slide

  14. wtfjs.com

    View Slide

  15. Why am I here?

    View Slide

  16. 4%
    96%
    Web Development Other

    View Slide

  17. 10%
    90%
    Rails Other

    View Slide

  18. View Slide

  19. 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.

    View Slide

  20. 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.

    View Slide

  21. 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.

    View Slide

  22. 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.

    View Slide

  23. 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.

    View Slide

  24. 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.

    View Slide

  25. Nooooooo

    View Slide

  26. JRuby

    View Slide

  27. RubyMotion

    View Slide

  28. Rails, Rails, Rails

    View Slide

  29. And what about
    JavaScript?

    View Slide

  30. 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)

    View Slide

  31. The possibilities are
    infinite with
    JavaScript

    View Slide

  32. If only there was some
    nice alternative to
    JavaScript…

    View Slide

  33. CoffeeScript

    View Slide

  34. PureScript

    View Slide

  35. Dart

    View Slide

  36. Elm
    legit

    View Slide

  37. Scala.js

    View Slide

  38. ClojureScript
    legit

    View Slide

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

    View Slide

  40. Ruby also rocks!

    View Slide

  41. Ruby is better than
    JavaScript

    View Slide

  42. View Slide

  43. View Slide

  44. 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?

    View Slide

  45. Opal.rb
    http://opalrb.org/

    View Slide

  46. A brief history of time
    Opal

    View Slide

  47. • 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

    View Slide

  48. The Value Proposition

    View Slide

  49. Ruby to JavaScript
    source-to-source
    compiler

    View Slide

  50. Ruby
    Opal
    JavaScript

    View Slide

  51. No new VM

    View Slide

  52. No bytecode

    View Slide

  53. No translation layers

    View Slide

  54. An implementation of
    Ruby’s corelib and
    stdlib

    View Slide

  55. But we already have
    CoffeeScript!

    View Slide

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

    View Slide

  57. A basic example

    View Slide

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

    View Slide

  59. /* 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);

    View Slide

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

    View Slide

  61. The magic happens in
    Opal.compile

    View Slide

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

    View Slide

  63. "/* 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"

    View Slide

  64. /* 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);

    View Slide

  65. 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

    View Slide

  66. JavaScript interop

    View Slide

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

    View Slide

  68. class Array
    def length
    `this.length`
    end
    end

    View Slide

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

    View Slide

  70. 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!')

    View Slide

  71. Alternative JS interop
    (coming in Opal 0.9)

    View Slide

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

    View Slide

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

    View Slide

  74. # 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) }

    View Slide

  75. # 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

    View Slide

  76. 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)

    View Slide

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

    View Slide

  78. Ruby from
    JavaScript

    View Slide

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

    View Slide

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

    View Slide

  81. Is Opal any good?

    View Slide

  82. Very basic corelib
    No stdlib
    Semicolons
    Misc WTFs
    JavaScript Complexity

    View Slide

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

    View Slide

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

    View Slide

  85. Performance

    View Slide

  86. File Size

    View Slide

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

    View Slide

  88. Debugging

    View Slide

  89. It’s just JavaScript

    View Slide

  90. Opal has source
    maps

    View Slide

  91. View Slide

  92. View Slide

  93. Ruby Compatibility

    View Slide

  94. 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)

    View Slide

  95. 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

    View Slide

  96. Performance is key

    View Slide

  97. Performance
    Debugging
    Ruby Compatibility
    Ruby WTFs
    Opal Complexity

    View Slide

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

    View Slide

  99. Epic!!!

    View Slide

  100. Diving in

    View Slide

  101. opal-irb

    View Slide

  102. opal-rails

    View Slide

  103. opal-browser

    View Slide

  104. $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

    View Slide

  105. opal-jquery

    View Slide

  106. 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

    View Slide

  107. opal-react

    View Slide

  108. opal-native

    View Slide

  109. View Slide

  110. opal-
    activesupport

    View Slide

  111. Looking forward

    View Slide

  112. Implement the
    missing things

    View Slide

  113. Better
    documentation

    View Slide

  114. A book on Opal

    View Slide

  115. More Opal wrappers
    of popular JS libs

    View Slide

  116. WebAssembly

    View Slide

  117. Contribute to Opal!

    View Slide

  118. github.com/opalrb

    View Slide

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

    View Slide

  120. Felina

    View Slide