RubyConf 2015

Analizando cómo se ejecutan por dentro los métodos Ruby

Jay McGavren  · 




Extracto de la transcripción automática del vídeo realizada por YouTube.

- Alright, I wanna make time for questions so I'll move at a brisk pace. If I'm overwhelming you, just raise a hand, I'll slow it down a little bit. So, how y'all doing? I'm Jay McGavren, I wrote this thing, and this is Messenger: the (Complete) Story of Method Lookup in Ruby.

This talk's gonna take place in two major parts, the first is all about methods defined on classes, including some places you might not expect them to be. The second part's all about modules. So, classes part. We're gonna start in a slightly unusual place, singleton methods.

Those are methods that are defined on only a single object, if you've ever stubbed methods out for a test, you've used singleton methods. So, for example, we've got a WebSpider class here, it sends out an actual http get request across the network and returns whatever html it gets back from the remote server, you probably don't want that in your test, though, so this test right here, you can see it creates a new WebSpider object, it calls get, and that sends an actual network request.

You don't want your test to have to wait for that and you don't want whatever random response you get back from the remote server. You want it quick and you want it predictable. That's a good alternative for writing a singleton method to override it. So here's a quick singleton method, we create a WebSpider object and we define a new get method that just always returns a static html string.

It's fast, it's predictable. Now, let's take a look at how method lookup works with those. So, to create a singleton method, we need an object, for starters. And before we can create an object, we're gonna need a class, so, here's MyClass. I'm gonna wanna create an instance in MyClass behind the scenes, Ruby will create a singleton class specific to that object.

And you can access any object's singleton class via the singleton_class method. So, there's the output you'll see if you call singleton class on our new object. Now why does Ruby do this? Chief reason is consistency. The same logic that lets you call methods on an object's class also lets you call methods on its singleton class.

When we define singleton methods on an object, they're added to its singleton class and that class makes the methods available exclusively to that object. So we define a singleton method here. And it'll live on a singleton class. When you call a method on an object, Ruby dispatches a message to that object, looking for that particular method.

Ruby's first stop in its search for a method is always gonna be the object's singleton class cause that's what the object refers to first. And as soon as Ruby finds a method with a matching name, it'll invoke it. Now, what would happen if we got rid of that singleton method, and defined it- defined a method by the same name on the class instead? If we call my_method on the object, Ruby will look on the singleton class first, but there's no method by that name there.

Well, where can the method be found? Each class maintains a pointer to the next class that Ruby should look on for methods. So, the ancestors method, that's your cheat sheet for understanding the places that Ruby's going to look for a given method. And you can access that list of classes that Ruby's going to look on via that ancestors method.

So, here we create an instance of MyClass. Call singleton class on that to get the singleton class and call the ancestors method on that and we get this array in response. Our singleton class is up first, and it's followed by MyClass. That's the place that Ruby's going to look next when it doesn't find that method on the singleton class.

So, when Ruby fails to find my method on the singleton class, it gets directed to the next class on the chain, MyClass. Goes there, invokes the method, and we're good to go. Now, supposed we were to move my method again to a super class of MyClass. So we define my method up there on MySuperclass and say that MyClass is a subclass of that.

We can create an instance of MyClass which will get us a singleton class. If we call ancestors on that singleton class again, we can see all the places that Ruby will look for my method. It starts, of course, with the singleton class, proceeds to MyClass as before, and the new addition here is MySuperclass.

So, we've got our output from the ancestors method up there, and you can see it exactly mirrors the places that Ruby looks for the method, it starts with the singleton class, moves onto MyClass, moves onto MySuperclass where it finds my method and invokes it.

Now what happens if a method appears in more than one place in the lookup chain? For example, if we defined it on MySuperclass and then defined it on MyClass as well. If a method- or, if a subclass method has the same name as a superclass method, it'll override that superclass method.

[ ... ]

Nota: se han omitido las otras 2.326 palabras de la transcripción completa para cumplir con las normas de «uso razonable» de YouTube.