Opal

Ruby is the Best JavaScript

Ruby is the Best JavaScript

by Kevin Kuchta

In his talk titled 'Ruby is the Best JavaScript' at RubyConf 2018, Kevin Kuchta explores the intriguing concept of using Ruby and JavaScript interchangeably. He begins by highlighting the misconception that distinguishes these two programming languages, arguing that Ruby’s syntax and metaprogramming capabilities can mimic JavaScript functionality. Throughout the presentation, he demonstrates various methods to combine Ruby and JavaScript, emphasizing the importance of creative coding techniques. Key takeaways from the talk include:

  • Tool Overview: Kuchta introduces tools such as Opal, which compiles Ruby to JavaScript, and the Ruby Racer gem, which allows JavaScript to be embedded into Ruby applications, showcasing reputable methods for integrating the two languages.
  • Syntax Manipulation: He cleverly demonstrates how to craft Ruby code that appears to be JavaScript by bending standard conventions. For instance, he creates a 'var' method that behaves like JavaScript's variable declaration and illustrates how to implement 'console.log' functionality using Ruby syntax.
  • Metaprogramming Techniques: Kuchta discusses how Ruby's metaprogramming features can be leveraged to create lightweight objects that mimic JavaScript objects, allowing users to write more syntactically pleasing and less convoluted code.
  • Anonymous Functions: He explains how to define anonymous functions while maintaining the structure of JavaScript’s syntax by utilizing Ruby’s Proc objects and adapting JavaScript-style functions within Ruby.
  • Creative Coding: Throughout the talk, Kuchta emphasizes the flexibility of Ruby's syntax to create code that effectively mirrors JavaScript without compromising Ruby’s inherent capabilities.

Kuchta concludes by reaffirming the rich possibilities presented when engaging the unique features of both languages. His experimentation in blending Ruby and JavaScript offers valuable insights for developers seeking to expand their programming techniques. He invites the audience to explore these methods while acknowledging the chaos generated through the process, humorously apologizing for the unconventional approach taken during the presentation.

00:00:15.890 Hello everyone, this is Ruby. If you think I've lost it and this is clearly JavaScript, don't worry, we'll come back to that. This is Ruby, and if you're still convinced I've lost it, hold on, because the title of this talk is 'Ruby is the Best JavaScript.' My name is Kevin Kuchta, and I work at a mental health startup called Joyful and Agile. I am a full-stack developer.
00:00:27.480 What I would like to demonstrate over the course of this talk is that it is possible to work with both languages at the same time. However, before diving into that, I must mention a few good ways of combining Ruby and JavaScript. So, let’s say you have a pile of Ruby, and for some reason, you'd prefer to have a pile of JavaScript. There's a tool called Opal that will compile Ruby to JavaScript, allowing you to run it in a browser or any JavaScript environment.
00:00:58.649 Conversely, if you have a pile of JavaScript that you want to run inside your Ruby application, there are several tools for that, one of which is the gem called Ruby Racer. This gem allows you to embed JavaScript in Ruby, which is pretty cool. These approaches are both reasonable and mature methods of combining Ruby and JavaScript. They stand in stark contrast to the monstrous affront to good taste that will comprise the rest of this talk.
00:01:44.040 In that vein, this slide is the inspiration for this talk. It’s an image that circulated on the internet a few years ago. If you can’t quite tell, this is Java code that has been bent out of all recognition to look like a whitespace-sensitive language. They pushed all the semicolons and curly braces to the far right-hand side of the screen. I don’t know the story behind this image, but I like to imagine it was a Python programmer being forced to write Java code against their will, and they were not going to go quietly.
00:02:08.039 Many people saw this and thought it was a terrible idea. I saw it and thought, 'Wow, I bet I can do worse.' So, here is the unholy abomination I came up with. It does exactly what it looks like in both languages; it’s both functional Ruby and functional JavaScript. It defines a couple of variables, creates an anonymous function, evaluates that function, and prints out the result. In my opinion, this is a testament to the great and terrible things that Ruby allows us to do.
00:02:49.000 I would like to walk you through how this was accomplished including the cool metaprogramming techniques and the clever syntax tricks. Starting with the latter, let’s look at how 'var' was accomplished. If you don't know, 'var' is how you define variables in JavaScript. There are, of course, newer and shinier ways to do this in the latest version of JavaScript, but we’re going to stick with classic JavaScript for this talk.
00:03:59.580 In Ruby, we can mimic this by defining a 'var' method that takes one argument and does absolutely nothing with it. This works because in Ruby, assignment is an expression. For example, 'x = 3' returns the value of 3, and thus 3 gets passed to 'var' without any positive outcome, but the assignment still goes through. In Ruby, we can also drop the parentheses on a method call, adding a semicolon at the end to make it look even more like JavaScript. So, we've created a variable declaration that works in Ruby but appears as though it’s JavaScript.
00:04:59.580 Next, let’s consider 'console.log'. If you’re not aware, 'console.log' is how you print to standard output in JavaScript, while in Ruby, you would use 'puts'. You might already have some ideas on how to go about it: let's create a 'console' class. We can then make an instance of this class that includes a 'log' method, which takes some input and prints it out.
00:05:58.150 However, two problems arise. First, we have this 'console' class floating around that we don't really need; we only need the 'console' object with a lowercase 'c.' It would be great if we could simply have the object without defining a class first. Secondly, our 'console.log' only takes one argument, while the real 'console.log' can take multiple arguments.
00:06:24.800 This can easily be rectified by using the splat operator, although it has an amusing name despite being an asterisk. You can stick it before a parameter in a method declaration, enabling that method to accept any number of arguments. For instance, I can create a log function that takes a variable number of arguments, joins them together like we would for any array of strings, and prints the result.
00:06:50.430 So when I call 'log' with two strings, it works perfectly. That's one problem solved! Now let’s tackle the other problem: we have an extra class that we really don’t need. To dig into Ruby classes, here is your standard class definition, using the 'class' keyword and giving it a name, then sketching the components. When I create a new instance of it, it's quite traditional.
00:07:21.370 In Ruby, everything is an object, and classes themselves are also objects. For our purposes, we can simply call 'class.new' and give it a block. What you put in this block is essentially the same as what you would normally define in a class definition. However, unlike the 'class' keyword, 'class.new' doesn’t create a floating class in the current scope—it returns a class object. We can use this property to avoid having an intermediate 'foo' variable.
00:08:28.440 Instead, we can just say 'class.new' and immediately call 'new' on that. That way, we never end up with an extra class floating around in the current scope. Even better, we can create a new object in Ruby using 'Object.new', which gives us a very bare-bones object. If we want to add anything interesting to this object, we can add methods by simply defining them directly on the object.
00:09:49.920 For example, let’s say we need a mock object; we can create a new lightweight object and define methods on it to return hard-coded values, and then use this lightweight object for whatever method we’re testing. Getting back to our JavaScript techniques, we can create that lightweight 'console' object without needing an entire class floating around.
00:10:33.270 So far, we’ve made a 'console.log' that takes a variable number of arguments, works like the real 'console.log', and prints them out—without adding a whole class to the scope. Now, we’ve dealt with variable declarations and console logging, but the heart and soul of JavaScript lies in functions. For our next task, let’s create an anonymous function.
00:11:37.450 You might recall that in JavaScript, you define an anonymous function using the 'function' keyword. While there are newer methods with arrow functions that we won’t use here, let’s stick with classic JavaScript for the time being. You’ll give the function a name, parameters, and curly braces, validating the structure as you would do it in JavaScript.
00:12:02.780 The equivalent in Ruby is creating a Proc object, which is how we define anonymous functions in Ruby. We can provide it a block, and what we want to do now is write some Ruby code that resembles the JavaScript syntax but performs Ruby tasks. To achieve this, we will start getting creative.
00:12:59.410 Let’s rethink the JavaScript syntax. If instead of using the keyword 'function' we use a simple function call, then we can pass arguments, as well as adapt Ruby-style information into this. For a moment, let’s conceive of what it would look like if we defied those conventions and eventually get to a point of insanity.
00:14:22.660 To get serious, while defining methods and passing blocks in Ruby style involves some unique hurdles, our next task is to show how we can get around those. So, let's check how we can practically define functions in Ruby that look somewhat like JavaScript does.
00:15:35.180 What we'll do is take our function 'function', which takes several arguments and a block and returns a Proc. This Proc will handle our logic and define our methodology. Given the right structure and conditions, we'll demonstrate how these methods can all work harmoniously.
00:16:58.150 And to do this efficiently, we’ll have our JavaScript-style function, which also handles actual computations. For instance, as part of our function, we can define some methods that accept a block. With the right design, we can achieve highly syntactically pleasing declarations.
00:17:46.710 As we venture deeper into Ruby, we’ll navigate through the language's flexible syntax features. While investigating, we'll also benefit from understanding some metaprogramming tricks that further enrich our capabilities. In conclusion, this experimentation and inquiry will serve as a creative framework, allowing us to adapt functions proficiently.
00:19:09.170 At the close of our exploration, let’s review the steps we’ve covered in maintaining our clarity while challenging syntax expectations. What you’ve witnessed throughout is a practical guide that leverages Ruby’s flexibility and features to bring functions in line with prevailing JavaScript practices.
00:20:09.019 To summarize the remarkably convoluted outcome we’ve achieved, both Ruby and JavaScript provide us with fascinating tools, and engaging in this practice brings to light the power beneath their respective surfaces. What I've shared today embodies a fantastic realm of possibilities, proving the ingenuity of our craft, even when it begs all sense of decorum.
00:21:33.350 In light of this, if you have further comments or questions about the encounters we shared, I’m available for dialogue after this session. My name is Kevin Kuchta, and I sincerely apologize for the chaos we've engaged in today. Thank you for your attention!