00:00:08.679
Okay, we are starting off our technical program right now and our first speaker is my fellow Ruby rogue, Avdi Grimm. He lives in Pennsylvania and did a really great ebook last year called "Exceptional Ruby." He gave some talks on that topic last year. I saw him presenting at RubyConf and decided I wanted him to speak here because he has a unique way of presenting. This morning, he will be showing you the ins and outs of Ruby with a talk entitled "Code to Joy." So, welcome!
00:00:49.360
Good morning! Who all got out on the dance floor last night? Great! I want to talk to you about some things that make me happy. My job right now is working with awesome people. They schedule appointments with me, and I do remote pair programming sessions with them. Sometimes, I get to pair up multiple times a day with people at various levels of experience, each facing different challenges. It’s a privilege to hear what they are working on and to help them. Ruby makes me happy.
00:02:01.119
Ruby is designed as a programming language to make programmers happy, and after all these years of using it, it still finds ways to make me smile. There’s something else that makes me happy: postcards! I’m currently writing a book titled "The Confident Ruby," and I decided to do something a little different this year. You could pay me $25 for the book or send me a postcard instead. I now have postcards from all over the world, and I love it! The content people write on them floors me. So, postcards also make me very happy.
00:02:51.760
Here’s the plan for the next 28 minutes: I thought we’d take a random walk through the Ruby language and its standard libraries, discussing some idioms and tools that bring a smile to my face. Since I’m not great at coming up with illustrations for talks, I decided to include some of the postcards that people have sent me.
00:03:10.599
Let’s start with Splats, the Splat operator. It's the asterisk (*) in Ruby. If you have a method that returns multiple values, like `Process.wait`, which returns both the process ID and the process status, you can use the Splat operator to destructure those into separate variables. It’s incredibly convenient, almost like having multiple return values. Ruby also has implicit splatting in some cases, meaning it can often recognize when you want to Splat out a return value without needing to put the asterisk there explicitly.
For example, if we have a method called `send_request`, which returns both a status code and a message, we can satisfy both clients wishing to use it. One client might want to destructure the return value into separate variables right away, while another client prefers to use it as an object to pass around. This is achievable by first creating a `Struct` for those return values and then simply returning the appropriate object. This setup allows both patterns to work seamlessly, which is very satisfying.
00:04:55.600
Now, let’s talk about `YAML::Store`. Who here knows about it? Raise your hand! Great! I'm excited to introduce many of you to this library today. `YAML::Store` is part of the standard library in Ruby and serves as a simple, file-based persistence mechanism. You instantiate a repository with a file name and open up a transaction block. Inside that block, you use the repository like a hash with keys and values. For instance, let’s say I have some blog post objects. I can create a `post` key and append an array of posts into the repository. The data that gets generated in the resulting YAML file is very readable and reflects the structure of the objects we input.
00:07:38.760
Now, let’s introduce a slightly more complex object structure by adding a category to these blog posts. For instance, we might have two blog posts under the food category. When we look at the generated output, we can see that it handles references smartly. The first post contains a category object nested underneath it, complete with its ID and information. In the second post, the category reference utilizes the previously defined category object without repeating the content. This efficiency is quite impressive!
00:09:00.880
However, using `YAML::Store` can be slow, as it reads and writes the YAML format frequently. To counter performance issues, there is another library called `PStore`. Interestingly, `YAML::Store` is based on `PStore`, which uses Ruby’s binary marshaling format. If you experience slow performance with `YAML::Store`, consider using `PStore`. While you sacrifice human-readable output, you gain significant performance improvements. This is not something for web servers but rather local command-line applications, providing a straightforward hash persistence mechanism.
00:10:58.839
Let’s talk about enumerators. They allow you to convert a regular method into something iterable. For instance, let’s say we have a simple method that yields a series of names one after another, without any loops. By calling `to_enum` on this method, we receive an Enumerator, which transforms our yielding method into an iterable object.
I once had a problem where I wanted my program to treat config files like `Rake` treats its config files, so I needed it to search the current directory and then its parent directory, searching for specific files. The standard library provided a method called `ascend` that yields for the current directory and each ancestor up to the root. I turned the `ascend` method into an enumerator, allowing me to iterate through ancestor paths. I collected files I found along the way into an array, ultimately making the process efficient and straightforward.
00:12:58.639
Now let’s discuss the `break` keyword in Ruby. The `break` keyword can break out of a loop or, in our case, out of a method yielding values. If we pass a block that breaks after two names, we can see how it exits early, returning two names and stopping execution of the method without needing a return statement. However, this might raise concerns about whether any critical cleanup code in the method would be executed. Fortunately, using an `ensure` block can ensure that any cleanup operations will still be executed even when a break occurs.
00:14:54.480
In an interesting twist, Ruby allows you to pass a value directly to the `break` statement, which not only exits the method but also sets the return value. For instance, if we're searching through lines in a file for a particular string, we can also find a maximum number of lines to search through at once. If we exceed that limit, we can specify a break value to return if we don't find the expected result within those 100 lines, streamlining the logic overall.
00:17:55.480
Next, let's explore subclassing modules. Let's consider a basic role-playing game with characters. Each character has a class and a race, and we want a human wizard character. We set up a class and a race and assign them attributes accordingly. However, what if we want to delegate attributes not defined in the character class to either the race or the class? Using `Forwardable`, we could delegate attributes to either race or class. But adding new attributes later could require updating the character class. Every time we add a new attribute to either category, we would end up repeating work.
00:20:14.559
Instead, we can solve this by creating a new module subclass that delegates messages based on a constructor parameter. By subclassing the module class, we can define a custom initialization method to save the delegation target attribute. This way, we utilize the `method_missing` approach, allowing Ruby to check where a method call should be delegated. With this setup, we can make calling attributes more efficient, looking first at the origin or, if not found, delegating the search to the appropriate target.
00:22:22.159
Ultimately, we create an effective delegation mechanism that integrates seamlessly with Ruby's messaging system without the need for constant updates with every attribute change. This flexibility makes Ruby very powerful and shows its capabilities for elegant code.
00:24:05.840
My favorite idiom in Ruby is quite simply: code is nice. But sometimes we face challenges—like technical debt or community drama—that can sour our perceptions of coding. During these times, it’s essential to practice joyful coding. The only way to generate joyful code is by sharing it with someone else. If you want to refresh your perspective, I encourage you to find someone who knows a bit less than you in some area, then wow them with something amazing, and you’ll feel uplifted too!
00:25:12.000
Thank you for allowing me to share these joyous aspects of Ruby with you. I hope to have inspired you to turn and spread that joy to others as well! Thank you very much.
00:27:29.960
Thank you for the great talk! I have a question: when you return a value with the `break` keyword and also have a rescue block, which value is returned? Will the value from the `break` override anything in the rescue block? Well, the `break` value takes precedence unless you raise an exception that the rescue block catches. This is because the action of breaking does not trigger rescue; it simply overrides with the specified value. If you were to use an explicit return in your ensure clause, that could lead to unintended side effects.