While working on our unit test framework, I wanted to write a function that checks if a given Ext JS windoid is opened. The function should accept a title argument. This was easily implemented as:
# title is a string with the exact windoid title def windoidDisplayed?(title) spans = $browser.spans t = $browser.length && $browser.detect {|i| \ i.class_name == 'x-window-header-text' \ && title == i.text \ } return t && t.visible? end
I then realized that users might not have the full title of the window, and might only want to check for a windoid with a title that matches some regular expression. A simple and naive way to do it is
# title can be a string or a regular expression def windoidDisplayed?(title) spans = $browser.spans t = $browser.length && $browser.detect {|i| \ i.class_name == 'x-window-header-text' \ && (title.kind_of?(String) \ ? (title == i.text) \ : (title =~ i.text)) \ } return t && t.visible? end
However, I didn’t want to check in every loop iteration if the passed title argument is regular expression. Although performance is really a non-issue in our unit tests, it just seemed to be a cumbersome and ugly code. I thought of using the dynamic nature of ruby to add a method (e.g. “match?”) to both string and regular expression classes, so I can call it in a polymorphic way without having to detect the type of title:
class String def match?(x) return self == x end end class Regexp def match?(x) return self.match(x) end end # title can be a string or a regular expression def windoidDisplayed?(title) spans = $browser.spans t = $browser.length && $browser.detect {|i| \ i.class_name == 'x-window-header-text' \ && title.match?(i.text) \ } return t && t.visible?
Before implementing it, I thought I’d check if a similar function already exists in Ruby’s Standard Library, and indeed, when I looked up the Ruby book for functions that are in both String and Regexp classes, I run into “===” (the Case Equality operator), which is meant exactly for this kind of things. Unlike JavaScript, where the === operator is meant for identity, in Ruby, the === method is usually called in case expressions to match the case target for each when clause. As said in the documentation, for the String class, === method tests for equality and is the same as ==, but for Regexp class, === method tests for matches, and is the same as =~. Exactly what I was looking for. So my little function can simply be implemented like:
# title can be a string or a regular expression def windoidDisplayed?(title) spans = $browser.spans t = $browser.length && $browser.detect {|i| \ i.class_name == 'x-window-header-text' \ && title === i.text \ } return t && t.visible? end
BTW, while searching for that, I took a look at Watir‘s sources, hoping to learn from the experts as I’m new to Ruby.
I found that Watir source (watir.rb, lines 50-70) does a similar trick to what I initially thought to do – define a new “matches” method (and not “match?” like the ruby convention that is also used in Watir in methods like “exists?” and “visible?“), and don’t use the === method.
In addition, in several places in the code there are still explicit tests for String class, such as the verify_contains method in input_elements.rb and navigate_to_link_with_id and navigate_to_link_with_url methods in watir_simple.rb.