8.4 Green
Now that we have RED tests to capture the enhanced behavior of our palindrome detector, it’s time to make them GREEN. Part of the philosophy of TDD is to get them passing without worrying too much at first about the quality of the implementation. Once the test suite is GREEN, we can polish it up without introducing regressions (Box 8.1).
The main challenge is implementing letters(), which returns a string of the letters (but not any other characters) making up the content of the Phrase. In other words, we need to select the characters that match a certain pattern. This sounds like a job for regular expressions (Section 4.3).
At times like these, using an online regex matcher with a regex reference like the one shown in Figure 4.5 is an excellent idea. Indeed, sometimes they make things a little too easy, such as when the reference has the exact regex you need (Figure 8.8).
Figure 8.8 The exact regex we need.
Let’s test it in the console to make sure it satisfies our criteria (using the re.search() method introduced in Section 4.3):7
$ source venv/bin/activate (venv) $ python3 >>> import re >>> re.search(r"[a-zA-Z]", "M") <re.Match object; span=(0, 1), match='M'> >>> bool(re.search(r"[a-zA-Z]", "M")) True >>> bool(re.search(r"[a-zA-Z]", "d")) True >>> bool(re.search(r"[a-zA-Z]", ",")) False
Lookin’ good!
We’re now in a position to build up an array of characters that matches upper- or lowercase letters. The most straightforward way to do this is with the for loop method we first saw in Section 2.6. We’ll start with an array for the letters, and then iterate through the content string, pushing each character onto the array (Section 3.4.3) if it matches the letter regex:
# Works but not Pythonic the_letters = [] for character in self.content: if re.search(r"[a-zA-Z]", character): the_letters.append(character)
At this point, the_letters is an array of letters, which can be joined to form a string of the letters in the original string:
"".join(the_letters)
Putting everything together gives the letters() method in Listing 8.30 (with a highlight added to indicate the beginning of the new method).
Listing 8.30: A working letters() method (but with full suite still RED).
src/palindrome/phrase.py
Although the full test suite is still RED, our letters() test should now be GREEN, as indicated by the number of failing tests changing from 2 to 1:
Listing 8.31: RED
We can get the final RED test to pass by replacing self.content with self.letters() in the processed_content() method. The result appears in Listing 8.32.
Listing 8.32: A working ispalindrome() method. GREEN
src/palindrome/phrase.py
The result of Listing 8.32 is a GREEN test suite (Figure 8.98):
Figure 8.9 Our detector finally understands Adam’s palindromic nature.
Listing 8.33: GREEN
It may not be the prettiest code in the world, but this GREEN test suite means our code is working!
8.4.1 Exercise
Using the same code shown in Listing 8.16, import the Phrase class into the Python REPL and confirm directly that ispalindrome() can successfully detect palindromes of the form “Madam, I’m Adam.”