Metaprogramming
Stupid Ruby Tricks
Summarized using AI

Stupid Ruby Tricks

by Mike Moore

In the talk "Stupid Ruby Tricks," Mike Moore explores various straightforward yet clever Ruby programming techniques that can enhance code efficiency and readability. Delivered at the Ruby on Ales 2015 event, this session is humorously framed, encouraging developers to experiment with Ruby's features without overthinking. Moore introduces the talk by referencing the personal challenges of writing it at the last minute while promoting a casual atmosphere among attendees. Key points from the discussion include:

  • File Operations: The talk highlights the simplicity of file operations in Ruby, demonstrating how methods like file.write and file.read eliminate the need for prior opening or closing files, making code cleaner.
  • Optional Parentheses: Moore emphasizes that Ruby supports optional parentheses, allowing developers to write cleaner code by removing unnecessary parentheses.
  • Default Hash Values: He provides an in-depth look at setting default values for hashes and the implications of sharing mutable objects as default values. By using a block to generate a new array or hash, developers can avoid unintended side effects.
  • Module Method Organization: The talk delves into the nuances of method inclusion and precedence using include and prepend, stressing the importance of managing method calls effectively through the use of super.
  • Using __END__: Moore introduces the __END__ keyword to manage constants and lengthy data in a tidy way, allowing developers to keep their code organized by moving extensive data structures outside the main class body.
  • Persistence with PStore: He also covers the Ruby pstore library for managing data storage, demonstrating how to create a transactional database that supports concurrent access.

Throughout the presentation, Moore’s humorous delivery and relatable anecdotes, such as his journey in Ruby programming and anecdotes about conference experiences, keep the audience engaged. The main takeaway is that programmers should comfortably explore Ruby’s features and keep their coding techniques simple and effective while enjoying the process. Moore concludes by providing resources for further exploration of Ruby programming and acknowledges the organizers for the opportunity to present.

00:00:29.599 This is Mike Moore. Has anyone heard of Mike Blomage on the internet? Yeah, Mike Blomage. I didn't actually know how to pronounce it correctly; I'm not French enough to say it that way. Blomage is someone who has spoken at Ruby conferences before. I don't know if you've seen him around, primarily focusing on pony content, a lot of ponies and bronies. Mike likes to speak and also organizes events; he organized Mountain West JS last week right on top of Amberconf.
00:00:40.559 He's primarily known for organizing conferences, and then he flew here and wrote a talk, which he will give at this conference. After that, he will fly home for Mountain West. I assume some number of you are also going to Mountain West. Who's going to Mountain West? Yeah, Mountain West train! Alright, I mean, we're way better and stuff, but you're okay too. Please welcome Mike Moore with a round of applause.
00:01:31.840 I love Ruby on Ales. I think this is my third time being here, and I just can't get enough. Thank you all for staying, and I can't wait to have a good time with you. I'm curious about the makeup of the audience. Who here is attending Ruby on Ales for the first time? Wow, that's at least half, if not more. Who here has been coding for less than a year? That's good! Wow, great job!
00:01:55.600 Tender Love is kind of known for asking himself, 'What would Freddie Mercury do?' when he's not sure what to do. I don't do that, but today I was thinking, 'What would Corey, the frontman for Slipknot, do?' I know that, although I don't look it, I'm a moderate Slipknot fan. I had this live album where they decided to play a song off their first album that they've never played live before. Corey said, 'It could be a train wreck, but we're going to do it anyway.' That's kind of how I feel about this talk.
00:02:16.000 This could be a train wreck. I literally wrote it last night and this morning, so we'll see where it goes. The title is 'Stupid Ruby Tricks.' There are three things you could focus on in that title. You could focus on Ruby itself, on the tricks, or what it's really about, which is stupid. So this is a stupid talk, and I hope to lower your expectations, and in doing so, we'll just be fine.
00:03:11.360 As John said, my name is Mike Moore. This is kind of the picture I'm usually known for. It's not my Twitter avatar; I probably should have changed it back, but I didn’t. I go by Blomage, but everyone says it sounds like 'mirage' or 'fromage.' When you say 'Blow mage,' everyone thinks I'm a medieval sex worker, but that’s not me. I’m okay with blemish; I will answer to it as well. I loved all of the talks I’ve seen so far.
00:03:48.560 I want you to know that I also have a GitHub profile, which is full of all sorts of really wonderful things. One thing I’d like to point out is that I have a URL up there—which is not long, so you can probably commit it to memory—but just think about that. It’s not too many bits that fit in the old brain there. Not only that, but my name is on the profile; I think that's important. I also have my username on there, so that's my special title.
00:04:07.120 I'm from Cedar Hills, Utah. There’s a Utah contingent here of at least two people, right? Who's from Utah? Yay, we’ve got three, four—including me! Cedar Hills, Utah, is a beautiful place; the mountains are awesome; the people are friendly. There's a wonderful Ruby conference there that starts in two days. If you want to keep this party going, absolutely come on down to Utah and join us at Mountain West RubyConf!
00:04:32.080 My company name is Humane Code LLC, and I think Ernie Miller should expect a cease and desist letter from my lawyers pretty soon. It’s such a clever idea that he thought of it before anyone else did. I’ve actually made some contributions too, as you can see from my repos. The thing I’m most notable for is MiniTest Rails, which is a really fun little project I run now.
00:04:50.720 MiniTest ships with Rails, and this doesn’t really do anything at all; it has no value. And that's my most starred gem! The other thing that’s somewhat embarrassing on my video profile is that it shows you your contribution calendar. If you look at this section right in the middle, can anybody guess what was going on in my life at this point? Was it a vacation? Alcoholism? Yes, I will get to the alcoholism later. I was at a startup during this time and considered this my 'trough of disillusionment' period; this was after the peak of inflated expectations and before the slope of enlightenment began.
00:05:37.680 Unfortunately, they didn't continue, so in late October, I moved somewhere else and started contributing again. The last thing I want to point out is that both Akira and I have GitHub profiles, and we’re both really close to a thousand followers. So anyways, I guess what I’m trying to say is that I’m kind of a big deal, really, if you think about it.
00:06:08.960 So, who was here for my pony talk two or three years ago? Okay, yeah, this is going to be worse, just letting you know. Again, it's about stupid. This talk is all about stupid. I do feel a little bad, though. Before the conference, I was supposed to talk yesterday morning; I literally did not start until last night. Considering that, I asked Josh if we could move me to later in the conference, so I’d actually have something. Josh, being a super nice guy, said, 'No problem, we’ll move you to Thursday.'
00:06:35.040 And we’ll just move Terrence up.
00:07:01.000 But when we got here, Taryn showed up and said, 'Guys, Friday Hug is my thing!' I was like, 'Oh, well, we’ll bring you up and you can do Friday Hug.' But then Ernie shows up and totally takes over the Friday Hug. Seriously!
00:07:34.560 Those who know me know that I'm not a big beer drinker. I’m a lot like Ryan Davis; I think of him as a mentor. I also prefer scotch on the rocks. I think I should apologize; I feel like I’m starting to lose control a little bit now.
00:08:01.679 The difference is that Tender Love has 'What would Freddie Mercury do?' and Bloomage has 'What would Corey, the frontman of Slipknot, do?' Totally different, very different. I know a lot of you are thinking, 'Is this going to go on much longer?' because you think it’s full of puns. I got a space picture in; I am on theme, right? Today’s theme, I’m moving it forward—you’ll see! The purpose of my talk is stupid.
00:08:58.960 Let's talk about a stupid Ruby trick—something that requires no brains at all. Specifically, let’s talk about file.write and file.read. I've been using Ruby since 2004, and when I came to it, this is how you open and read from a file: you open the file, and then inside the block, you read from it. The file takes care of closing it for you. For writing, you do the same type of thing using the open block, and you have to pass the 'w' flag to write to the file.
00:09:39.840 Instead, you can just call file.write as of Ruby 1.9. Only a few of you have used file.write, so I guess it's still good advice. The same thing for reading: you can read straight from a file without having to open it first. It's stupid, right? Yay, stupid tricks!
00:10:13.920 Here's another awesome stupid trick: optional parentheses. Does anyone know that Ruby has optional parentheses? Here is some code that we wrote, with all the parentheses highlighted. You can remove all these parentheses because none of them are required. You can come up with something like this, which I actually think is a huge improvement.
00:10:41.760 The thing that bothers people who like parentheses the most could be file reads. How does this work, right? The last line means you have 'puts' receiving 'file.read'—but what’s the priority? Without parentheses, you don’t know. So, the first piece of advice is this: don’t overload lines. If you can't remove all the parentheses on a line, you’re doing too much stuff on that line. Just add another line.
00:11:17.920 If you're in a place where you have to keep all your methods under 10 lines of code, don't just jam all that logic into one line. Avoid using ternaries and respect the absence of parentheses! Keep it simple. I imagine all of you knew this already, so what am I doing here presenting these tips to a self-selecting crowd that knows everything?
00:11:51.040 However, I do have the necessary qualifications to present. I’ve been programming professionally for 20 years and working with Ruby for a decade. You may think that my qualifications are irrelevant, but they are not. Don’t worry, this will be over soon enough! Now, let’s talk about default hash values. Let’s imagine we have a hash with key='foo' and value='bar'. If we ask this hash for 'baz' and it’s not in there, it returns nil, which is the default value when there’s no key.
00:12:22.080 We would really like to have 'baz' returned. One way to do this is to call fetch and provide a default value. If the key isn’t found, instead of nil, it will give us the default value instead. For example, if we put 'troll face' in this hash and ask for 'troll face', we will get the actual value back even with a default value of 'baz'.
00:12:59.440 When creating a new hash, you can’t do this with curly braces, but you can with the new method. You can pass in an object that will serve as the default value. This ensures that you do not have to call fetch every time; you can use the square bracket accessors. In this case, we have a new hash list—it’s completely empty—but when we access a nonexistent key, we expect to receive an empty array. You can add items to this array, such as 'x', 'y', and 'z', and they appear in the result.
00:13:23.680 The problem arises when we access the same value multiple times, and we find that the object we gave for the default value is being manipulated every time we access the hash. Each time you access it, you yield the same array, which can cause issues if you're modifying it. Rather than passing the original object, we can pass a block that will create a new array, ensuring we don’t manipulate the current default value.
00:13:49.760 In this case, we would create a new hash; when we ask for a default value, this proc will execute to create a new array every time there’s an access request. This way, we won’t share arrays, and if we ask for a nonexistent key, we’ll get an empty array, which is what we want.
00:14:22.080 We can do the exact same thing with another hash. Instead of a list, we want some sort of nested hash structure, similar to a PHP dictionary. We utilize the same constructor block and define that if there’s no value, we’re going to use a brand new hash. If we ask for 'x', we’ll receive an empty hash. But if we go for 'x.y' and 'x.y.z', we encounter nil or a no method error since 'y' is nonexistent.
00:15:11.040 To make this better, we can reference the original parent hash's default proc and apply that to each newly instantiated hash. This means when we call 'x', we get a hash back; when we call 'x.y', we also receive a hash; but if we call 'x.y.z', we get nil, as the hash only conforms to the first level. It’s a simple yet effective way to set up these defaults!
00:15:49.440 Let’s take it a step further and create a 'Frankenstein' hash. We can start with list behavior, adding keys 'x', 'y', and 'z' to it, along with a method for 'x.y' that holds our structure. Modifying the default proc afterward allows us to switch it to a recursive hash proc for 'xyz'. So when we call our new hash after modification, it’ll seamlessly conduct the recursion we set up.
00:16:03.440 Let’s shift gears and talk about include, prepend, and using super. This is one of the things I truly appreciate about modern Ruby. For example, we have a module 'foo' that does a thing. We want to include 'foo' into 'me', as I also do a thing. When I invoke 'me.new.do_a_thing', it only outputs 'me' as we don’t call super to allow 'foo' to execute its portion.
00:17:03.960 To remedy this, we need to call super. After implementing that, when I invoke 'me.new.do_a_thing', it’s great; I do my thing first before 'foo' runs its process. Prepend signifies that this module will draw up its methods in the inheritance chain before the rest. By switching from include to prepend, let’s see what happens!
00:17:56.400 Now, when we use do_a_thing, 'foo' appears first in the call chain and operates as indicated. But since 'foo' doesn’t invoke super, my method no longer runs, which is disappointing. It’s beneficial to have 'foo' call super, yet it can generate errors when 'super' is not defined. A better approach is to establish a check for whether super is defined before invoking it. This lets 'foo' call super if present.
00:18:38.080 If it can't find super, it skips the call. Thus, we can wrap up, ensuring both 'foo' and 'me' still operate without requiring excessive alterations to include or prepend behaviors. It’s neat how subtle changes in structure can refine flow without disrupting primary function.
00:19:05.600 So here, a nice illustration wraps it all up to highlight my points. I apologize for the shockingly bad puns you’ve encountered throughout, but they serve to keep this engaging, right? I love conference t-shirts and stickers; they're a highlight of every event I attend. I even had a wacky dream last night about wearing a t-shirt instead of a pressed white dress shirt.
00:19:32.480 Finally, let’s discuss Stupid Trick Number Five: Data and 'END.' How many of you have extensive constants with lots of data, similar to lengthy strings or numerous values? Here’s a neat trick: the '__END__' keyword. Anything occurring after '__END__' will be lumped into DATA. This is an IO-like object, so you can funnel values to the end of a file without terribly cluttering your code! You can split it as needed once you hit that endpoint.
00:20:02.720 Here’s a presentation tip: you can format data as YAML or JSON under the end declaration for better structure. This technique is tidy and allows you to keep your constants at the top of your class declaration.
00:20:39.040 Next, let's discuss 'pstore.' Who here has used or is aware of pstore? It’s a neat little database within Ruby’s standard library that permits concurrent access! You only need to require pstore and designate a path for it to operate, thus creating a transactional binary file that accommodates multiple processes. Using 'pstore' allows you to read and write objects seamlessly using key-value pairing.
00:21:12.160 As you can see from my earlier examples, you can work with simple data structures, then write them back out and read them in a stored format. This method allows you to maintain interaction without needing to establish another service. You can increment and read back, tallying 'infinity puns' even as we progress. You can also utilize an 'OpenStruct' for added complexity, storing relevant object information in an easily retrievable format.
00:21:48.560 Additionally, you can swap out pstore for yaml store in your code, allowing for identical implementation. It’s all seamlessly handled through Ruby’s syntax as you shift between both formats while still retaining usability.
00:22:12.640 I understand that you might wish for more tips, but that was my last one! However, fear not, everything will be alright! I appreciate everyone for letting me speak today. A huge thank you to the organizers for having me back. If you’d like useful Ruby information, there are a couple of resources online, including a video by James Edward Gray that includes 101 useful Ruby tips and a recent cool blog by Aja. Thank you very much!
00:22:59.200 You!
Explore all talks recorded at Ruby on Ales 2015
+5