RUBYLOVE  

cover-pic

  • This is part 2 of a multi-part series. Read part 1 here.

If you do not already know who Avdi Grimm is then please, go check out his Confident Ruby when you have time. It is an AMAZING read. If you know about Confident Ruby already then you get to see some examples here.

Essential this style of coding uses liberal casting to keep nils and conditionals out of your code. It is also a style of Ruby that adheres to the Tell, don’t ask principle. Because co-opting nils is evil, as is reaching into an object’s state in order to decide what it should do.

Let’s go back to our deck of cards. I put it into a repository for you this time so you can work along with me. Once that is forked, clone it down. You will find all the tests are there, just like I promised in part 1!

You can also compare that to the origin gist to see where I started from if you aren’t down to read part 1.

Step 1 - Change the Structs to an immutable object

Since we are going for a mostly functional approach here, I don’t want the option to mutate these cards. To get closer to accomplishing that, we need to replace the structs that Deck is composed of, Card and Suite, with Value objects from Tim Crayford’s library, Values

These are pretty much like structs, however they are immutable. I will point out here that there is a bug in the gem version that doesn’t seem to be in the github version. Because of that bug we will use the Class version instead of my preferred ‘struct block to const’ method.

Old
New

I made one more change here to be “Confident”. I cast rank to a string. That removes any chance of getting a nil value! I may get an empty string, but I wont get a nil. Then for style consistency I capitalize the first letter and lowercase the rest.

Now onto the Card struct where do similar work:

Old
New

Can you spot what I did here to make my code more confident?

In suit I get the value of @suit OR ‘naked’ in the case when @suit is nil, then again, for the sake of consistency in my formatting, I cast it to a symbol. We do something similar in to_s where I cast rank to a string, and I do for suit what I did for Rank#to_s.

We might get some ugly results if passed ugly data. But what it WONT do is barf all over you. It is also as the great Jim Weirich would say, “Polite Ruby”.

The origin Deck itself requires no modification here for swapping out those Structs for Values. That is a benefit of good design and the Single Responsibility principle. We needed to change some objects under the hood, yet we didn’t have to change the object that uses them.

That is it for this post. I will be back very soon to explain why the approach I took to Deck#build_deck and Deck#all_ranks is functional, and how it is superior to an typical imperative approach.

Stay tuned!