This one was a bit of a wildcard. I worked on and solved (or so I thought) this challenge months ago, so when I went back to review it, I expected it to work, and that maybe there would be some funky code, but that it would all basically work. I was wrong. I’m not sure what happened to make me publish code that was neither intuitive or understandable, but that is what happened. I’ll walk through what my old, smelly code said, and then go through how I rewrote it to make it better.
The challenge description asks the developer to make a program that asks for a quote and an author, and then display both in a string:
[author] says “[quote]”.
A follow-up challenge is to save the quotes to a data structure so that you can display all the quotes at once.
The basic challenge of the code is to display a quote within a string, which can be tricky because double quotes (ie: “”) usually denote a string, but we also need it to indicate something an author said. The most straightforward solution in my opinion, is to use double quotes for your string, as usual, and then use the escape character [\] to keep the double quotes in the string. It looks something like this:
puts “#{author} says \”#{quote}\””
Because the challenge specifically says to do so, I used string concatenation, but it feels a little clunky. This was my first attempt:
puts author + ‘ says “‘ + quote + ‘“.’
I changed it up on the second run through with:
puts author_and_quote[1] + " says " + "\"" + author_and_quote[0] + "\""
In Ruby, you can use single or double quotes to indicate a string, and if you use the other inside, it shows up like any character would. I’m not a big fan of the plus signs and everything like that; interpolation just seems to read better than concatenation. The challenge does specifically ask you to use concatenation, which I did in both.I wanted to use the escape character, so there’s minimal difference, but I did change it up a little.
The hot mess that was my first attempt featured two while loops with nested conditional blocks, and a do loop. I can see what I was trying to do: I’ve got a block that enforces a positive integer and asks for the number of quotes the user would like to add. It serves the same basic function as my getInteger(prompt) method, but it’s less self-contained, so I replaced it with my newer code. The main difference in utility of the old block and the new one is that the new one allows you to put 0 as an entry, and it asks for zero quotes. My previous one couldn’t do that, because it was asking for a string and converting it to an integer, and checking to see if it was less than or equal to 0. Ruby converts strings of non-numeric characters to 0 when using the to_i method, so if someone typed “one” or “-1” into the prompt, it would return 0 and -1. So there is some improved accuracy with the new method.
The second block I used was to get the quote and the author. I took the approach the first time around to use a hash with author-quote key-value pairs. It potentially set me up to have a search function where you could look by name, but it didn’t really work when I went back and tried it, so I opted for simplicity: I defined a method that would get a quote and who said it, and return an array.
The last change I made was to get the number of quotes to be added, push them into an array to keep track of them, and then iterate through each element in the array, using the following statement to generate the correct output:
puts author_and_quote[1] + " says " + "\"" + author_and_quote[0] + "\""
And that’s day 5 of 57! As always, you can see the code at https://github.com/corbettbw/exercises-for-programmers!