Pro Yearly is on sale from $80 to $50! »

Opal: The Journey from JavaScript to Ruby

Opal: The Journey from JavaScript to Ruby

Slides from my eurucamp 2015 talk.

1be785d1d788b82929e55fc83a9f0aaa?s=128

Bozhidar Batsov

August 04, 2015
Tweet

Transcript

  1. Opal: The Journey from JavaScript to Ruby by Bozhidar I.

    Batsov (@bbatsov)
  2. Божидар

  3. Sofia, Bulgaria

  4. None
  5. Bug

  6. Few important things you need to know about me

  7. None
  8. I’m an Emacs fanatic

  9. None
  10. bbatsov

  11. I love Ruby

  12. I don’t like JavaScript

  13. None
  14. wtfjs.com

  15. Why am I here?

  16. 4% 96% Web Development Other

  17. 10% 90% Rails Other

  18. None
  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.
  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.
  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.
  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.
  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.
  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.
  25. Nooooooo

  26. JRuby

  27. RubyMotion

  28. Rails, Rails, Rails

  29. And what about JavaScript?

  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)
  31. The possibilities are infinite with JavaScript

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

  33. CoffeeScript

  34. PureScript

  35. Dart

  36. Elm legit

  37. Scala.js

  38. ClojureScript legit

  39. Why are we doing this (ClojureScript)? Because Clojure rocks, and

    JavaScript reaches… — Rich Hickey (creator of Clojure)
  40. Ruby also rocks!

  41. Ruby is better than JavaScript

  42. None
  43. None
  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?
  45. Opal.rb http://opalrb.org/

  46. A brief history of time Opal

  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
  48. The Value Proposition

  49. Ruby to JavaScript source-to-source compiler

  50. Ruby Opal JavaScript

  51. No new VM

  52. No bytecode

  53. No translation layers

  54. An implementation of Ruby’s corelib and stdlib

  55. But we already have CoffeeScript!

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

    library • It’s not Ruby
  57. A basic example

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

  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);
  60. Opal.Object.$$proto.$hello = function(name) { var self = this; return self.$puts("Hello,

    " + (name.$capitalize()) + "!"); }; return self.$hello("bruce");
  61. The magic happens in Opal.compile

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

  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"
  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);
  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
  66. JavaScript interop

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

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

  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
  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!')
  71. Alternative JS interop (coming in Opal 0.9)

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

  73. # JavaScript: # ($a = foo) # .bar # .apply($a,

    [1].concat([2, 3])) foo.JS.bar(1, *[2, 3]) foo.JS.bar 1, *[2, 3]
  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) }
  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
  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)
  77. require 'js' # parseFloat("1.1") JS.call(:parseFloat, '1.1') JS.parseFloat('1.1')

  78. Ruby from JavaScript

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

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

  81. Is Opal any good?

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

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

    Size
  84. Very basic corelib No stdlib Semicolons Misc WTFs JavaScript Performance

    Debugging Ruby Compatibility Ruby WTFs Opal File Size
  85. Performance

  86. File Size

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

  88. Debugging

  89. It’s just JavaScript

  90. Opal has source maps

  91. None
  92. None
  93. Ruby Compatibility

  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)
  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
  96. Performance is key

  97. Performance Debugging Ruby Compatibility Ruby WTFs Opal Complexity

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

    Performance Debugging Ruby Compatibility Ruby WTFs Opal Complexity
  99. Epic!!!

  100. Diving in

  101. opal-irb

  102. opal-rails

  103. opal-browser

  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
  105. opal-jquery

  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
  107. opal-react

  108. opal-native

  109. None
  110. opal- activesupport

  111. Looking forward

  112. Implement the missing things

  113. Better documentation

  114. A book on Opal

  115. More Opal wrappers of popular JS libs

  116. WebAssembly

  117. Contribute to Opal!

  118. github.com/opalrb

  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/
  120. Felina