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.