The Pretzel Colon in Ruby

Chris Jones
3 min readJan 18, 2019

--

I’d like to introduce you to a method in Ruby called the pretzel colon. If you’re unfamiliar or have yet to come across it, I’m talking about this guy:(&:symbol). The pretzel colon has helped to make my own code much simpler. So, what does it do? Let’s say you want to collect some values from a series of objects in an array. We can iterate over that object and collect a certain attribute and return the updated array. Say, something like this.

array = ["a", "ab", "abc"]
array.map {|string| string.length}
=> [1, 2, 3]

So, in this instance, we have an array that we’re operating on with three different strings. We want to collect the length of each string and then return the array with those lengths. We iterate over each string in the array and ask for the length attribute, which is then passed into our return array. We can do exactly the same thing with the pretzel colon.

array.map(&:length)
=> [1, 2, 3]

Not only does this shorten our code, but it’s much less repetitious. In the original method, you can see that we reference the object we’re iterating over twice. With the pretzel colon, we eliminate that reiteration. How does this actually work? The code above is not actually ‘&’, ‘:’, then ‘length’. We’re passing in length as the symbol ‘:length’. The symbol class has a nifty method called Symbol#to_proc, which sends the objects in the array through to the block with the method, our symbol, that we call on it. In essence, we’re saying take each object in the array ‘&’ perform the given ‘:method’ on that object.

array.map {|string| string.length}
array.map(&:length.to_proc) # passes array objects with length method called
array.map(&:length)
=> [1, 2, 3] #same return for all three methods

Let’s wrap this up with how much nicer our code can look by implementing this with some actual methods. In a recent lab, we had three object classes; customer, review, and restaurant. The review class held our information about the customer and restaurant, serving to link them. This method, #longest_review, searches the written reviews for restaurant that calls the method. It then returns the longest review. Here’s my original solution.

def longest_review
longest = self.reviews.map {|review| review.content}
longest2 = longest.sort_by {|content| content.length}
longest2.last
end

Alright… so, this works, but it’s not really clean and we have to use a few intermediate variables before we get to our result. When I reformatted, I took two steps; I used the pretzel colon to reduce my code, then I chained my methods together to get a much cleaner result.

def longest_review
self.reviews.map(&:content).sort_by(&:length).last
end

Nice. This is much cleaner and coherent than my original solution. I got rid of the intermediate variables and through chaining was able to accomplish everything in a single line.

Now, the pretzel colon is slick, but it only works under certain conditions. Specifically, when we’re iterating and calling an attribute of the objects being passed through. It does not work for the .find or .select methods where we would be iterating and searching for equivalence. Still, it’s a great tool to have your arsenal to make your code shorter, more readable, and easier to type out.

--

--

No responses yet