RailsConf 2013

Dissecting Ruby with Ruby

Dissecting Ruby with Ruby

by Richard Schneeman

In the talk "Dissecting Ruby with Ruby" at Rails Conf 2013, Richard Schneeman explores the intricacies of Ruby libraries and provides programmers with the tools needed to effectively navigate and troubleshoot their code. He emphasizes how crucial it is to understand the inner workings of the libraries we use, enabling developers to tackle bugs and contribute to the Ruby community. The main points of the presentation include:

  • Introduction to Ruby Tools: Richard opens with his journey and introduces simple Ruby tools for inspecting libraries, urging attendees to keep their laptops open for hands-on learning.
  • Accessing Libraries: He explains how to open gems using Bundler, allowing developers to browse library source codes. This includes setting up their editor for code inspection.
  • Debugging Techniques: Richard advocates for using basic Ruby debugging methods like puts and kernel.caller, instead of relying solely on advanced debuggers. He shares a military analogy about tracer rounds to illustrate how Ruby provides insight into code execution paths.
  • Finding Method Definitions: He explains how to locate method definitions using method and method.source_location. This allows for understanding where in the library a particular method is defined.
  • Case Study: He outlines a real-world example involving an issue with the Rails method link_to. Richard details how to trace the problem's origin using the methods discussed, showcasing the process from identifying an issue to debugging it effectively.
  • Contributing to Ruby: The talk emphasizes the importance of not only fixing bugs but also engaging with the community by reporting issues and submitting pull requests, highlighting how this interaction can enhance both personal and community knowledge.
  • Conclusion: Richard encourages developers to leverage their newfound skills to contribute to the Ruby ecosystem actively. He reinforces that debugging is an essential part of development, which can lead to deeper insights into coding practices.

Overall, the session aims to empower developers to transform from bug reporters to bug fixers, enriching their understanding of Ruby while encouraging contributions to open-source projects.

00:00:16.320 Hello everyone, can you all hear me in the back? Okay, who attended the last talk? That's a good number of you. Thank you very much for coming today. My name is Richard Schneeman, or at least you can call me Schneems. It’s pronounced like 'schnauzer' or 'schnapps.' Some people have problems with that pronunciation. Some people say that I am married to Ruby; I've been programming in Ruby for a long time. In fact, this past weekend I made that dream a reality and actually got married to Ruby!
00:00:50.160 Thank you! After that, I took the opportunity to immediately come to RailsConf. Just a little bit more about me: I have a dog named Hans Peter von Wolfe. It's a long name because he's a long dog. I've written some gems you might have heard of. I've got the Sextant gem and the Wicked gem for turning your Rails controllers into step-by-step wizards. My most recent project is Code Triage, which is a platform where you can sign up to triage Rails issues or any kind of open-source issues you want.
00:01:41.040 The way it works is by sending you one new issue in your inbox per day. It's a great way to get started with open source if you haven't checked it out already—codetriage.com. I'm also an adjunct professor. The main reason I did that is so I could say, 'Good news, everyone!' They actually give you a card that says you have permission to say it. If you know anyone learning Rails, I have a bunch of material on schneems.com/rails. I also happen to work for Heroku, where we focus on optimizing developer happiness; you can git push and deploy three million apps and all that jazz.
00:02:26.959 I work for the Ruby Task Force, and of course, the best part of that is the Ruby Task Force meetings. And the second best part is that Matt is one of my coworkers. I would like to invite you all to please close your laptops if you have them open. I'm not an unreasonable professor or pseudo doctor, but if you are commenting on Rails issues or subscribing to codetriage.com, then you're more than welcome to keep your laptops out.
00:03:05.920 You know, we’ve all been there, looking at a library or talking to a library author who says, 'Oh yeah, you know that comment? Don’t look at that comment.' Or your coworkers might say, 'I have no idea how this library works. I mean, I know how to use it,' or they might suggest, 'Just look at the source code! Ruby is self-documenting—who needs docs?' So this talk is all about how to get into a library you’re not familiar with. It can sometimes be small or huge, and the objective is to gather information and navigate around, ultimately making the changes we want.
00:03:45.680 First, we need to get into our libraries. We can do this with Bundler by running 'bundle open' followed by the name of the gem you're looking to explore. For example, by running 'bundle open wicked,' you'll have the code right at your fingertips! Of course, in order to do this, you need to set your editor in your bashrc file. You might use macvim or Sublime; you just need to add a little ‘-w’ to your setup and you’re good to go. This is a handy little trick if you haven’t done it before.
00:04:22.400 Once you’re in, the next step is to extract information from our system. In this talk, we’re going to forget fancy debuggers. I know there are awesome Pry t-shirts and RubyMine is here, as well as other tools. However, for the rest of this talk, all you need is 'puts.' Before diving into that, I want to touch on military history. The military figured out that people struggle with aiming, given the complicated process of rise over run and other factors. At one point, they decided instead of having soldiers aim, why not let them know where their last shot was fired? This led to the concept of tracer rounds, which leave a visual trail, making it easier for someone to adjust their aim.
00:05:42.560 In Ruby, whether you know it or not, we also have something similar to a tracer round. I’ll be demonstrating that with a specific piece of equipment. Can anyone see it? I put a little line in there. Look at it now—there's something to be said about being able to automatically recognize and pull out these things. A quick note on notation: I know some of us are experienced Ruby developers married to Ruby, so I will be using this notation throughout this talk. The first element will always be capitalized and is either a class or a module; the last element will always be a method name.
00:06:43.440 If the middle part is a dot, it means it’s a class method; if there’s no dot, it indicates it’s not a class method, which could also be referred to as an instance method. Let’s have a show of hands: who uses Ruby 2.0? What about 1.93? Here’s the truth: Ruby 1.8.7 is going to be end of life in June, meaning no more security announcements or support. In this talk, we’re going to use Ruby code that's actually cross-interpreter, which works with JRuby, Rubinius, and MRI. I encourage all of you still using Ruby 1.8.7 to try Ruby 2.0 or JRuby on Heroku.
00:07:31.280 Furthermore, we are in our library with our little tool belt. Let’s take a look at some Ruby. You might encounter a problem where you know what a method does, but have no idea who is actually using this method. To find instances of the method being called, you can use Kernel.caller. All of these resources are available at rubydoc.org, but sometimes you can look at the documentation and feel completely lost. Kernel.caller will give you a backtrace of events leading to that point; if you’ve raised an exception, you’ve likely seen line after line in the backtrace.
00:08:48.160 You can get the same output without raising an exception. You can put 'caller.print' and you’ll see output that appears complex at first, but it's very useful. It shows you the file, exactly where to look, the line number, and the method name; Ruby is pretty smart. You can use ‘Kernel.caller’ for pinpointing the origin of specific problems in your code.
00:09:14.240 So, this might help you understand where a method was called from. But let’s say you don’t know where that method is defined, especially in a large library. To navigate this, my super secret favorite class is the Method class in Ruby. It may sound complicated at first because you have to call the method on the Method class to understand it better. But you'll soon see how useful it is.
00:09:52.160 For example, if we have a string, we can call .method on it and pass in the method name as a symbol or string. This will return a pure method. Once we have that method, we can call .source_location on it, which is my favorite feature. If you have a file like user.rb and a method called github_url, this will tell you exactly where Ruby is going to call that method. If there are multiple definitions or overloads, it doesn’t matter; this will pinpoint the exact line number and file name.
00:10:40.000 So, let’s look at a real case scenario I encountered in Rails with a wonderful method called link_to. In email templates, you need to set a host for the URLs, meaning it has to go to a full URL like example.com/myawesomepath. If you only pass in myawesomepath, the email won't know where it came from. If you incorrectly set the host with 'http://' in front, Rails will mishandle the URL generation. When things go wrong, you push them to production without realizing it until someone points it out, and I wanted to fix this.
00:11:57.920 To address this, we want to remove the protocol automatically, but first, we need to track where link_to is defined in the code. By pulling out the source location and looking into the action pack gem, we see where the code is being executed. You’ll notice if the URL generation is handled correctly, there is a line that starts with 'href' and we need to explore this further.
00:12:23.840 When we analyze this code and see the method call for url_for, it’s naturally confusing, as it's pulling options. Although it calls super, which means it’s checking the ancestors of the current class to see if any of them respond to the same method, we can investigate further by using self.class.ancestors to see the list of those ancestors. This allows us to determine where 'url_for' originates and what options it has taken into account.
00:12:55.680 This method of calling the ancestors will guide us through understanding the flow of the code better. If we check the output while confirming that url_for is indeed a method of one of these classes we’re examining, we can also see which methods are defined. This can greatly assist in troubleshooting what is actually being done here.
00:13:29.679 Now, let’s assume we’ve identified which of the url_for methods we need to hone in on. Many of us feel challenged by how extensive Rails might be when we pursue modifications. While maintaining accuracy is vital, tracing through these methods can yield excellent insights that explain the complexities of the situation as we isolate changes.
00:14:09.799 Somewhere along the way, we may seek to simplify or improve our code. We can pull out the ancestors and refine our focus, examining each to discern how they handle the method definition. Keeping this method extraction process organized greatly helps developers like us synthesize adjustments without feeling overwhelmed by unnecessary detail.
00:14:46.559 Sometimes, finding incorrect method calls or checking how things logically connect can lead to surprising revelations! Examining tighter method connections inside of Rails, we could potentially discover new fixes or alternative design patterns for resolving our programming issues, which brings excitement alongside clarity.
00:15:23.280 As we dig deeper into these libraries and frameworks, anticipating our functioning code to misbehave is often the worst case scenario. Reflecting on design choices can often illuminate how alignment with Ruby conventions and Ruby’s object-oriented nature plays a role in efficiency. Developers should strive for a balance between minimizing complexity and making sensible architecting choices.
00:15:44.000 Now that we have traced where to make necessary modifications—or if we have drafted up our edits for the issues we encountered—working on realizing our changes and testing them extensively can yield reinforcement concerning our places for improvement. Though it may seem complicated, continuous exploration and the circulating knowledge that comes with contributing can ultimately reinforce how we experience software development.
00:16:12.000 You will need to discover a case that reproduces a specific problem so you can address it adequately. Whether directly fixing the issue or documenting it—your choice matters the most for its ultimate progression. Raising awareness through discussions, issue reporting, and collaborative efforts can successfully open avenues for performance optimization in far-reaching inclusivity for future developers.
00:17:30.360 Here we have an opportunity to submit pull requests that will see their paths soar as changes cascade into the core library, connecting your contributions to the helpfulnings of the larger Rails community. Ultimately, diving into Ruby code fosters a thought-provoking environment where developers inspire one another and elevate the level of coding logic! You must trust the journey while remaining diligent; troubleshooting effectively creates a dynamic avenue for learning and personal improvement.
00:18:17.760 As we bend the curves around deeper understandings, leveraging various debugging techniques—not just the tools—encourages learning not only about Ruby but also about the ecosystem from which your projects are framed. The glowing light of insights will empower you to navigate codebases far more gracefully, while motivating thoughtful structures within your own scripts or libraries. Taking time to refine your work showcases responsibility as a coder, which rewards you with newly sourced empowerment in learning Ruby through deep interactions.
00:19:24.880 In completion, subscriptions like codetriage.com can open a portal for hands-on learning; it is crucial to reach for every resource available on iterating towards becoming creators of exemplary coding and thoughtful design patterns. I encourage you to please let me know if you have any questions; I may or may not have some Heroku credits I can share in exchange for good questions! Thank you all for your time!