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!