Refactor and document

This commit is contained in:
Jonas Nicklas 2013-03-17 15:48:04 +01:00
parent e5809138e1
commit 415e2db70d
4 changed files with 109 additions and 83 deletions

View File

@ -4,90 +4,117 @@ module Capybara
# @api private
module Helpers
class << self
##
#
# Normalizes whitespace space by stripping leading and trailing
# whitespace and replacing sequences of whitespace characters
# with a single space.
#
# @param [String] text Text to normalize
# @return [String] Normalized text
#
def normalize_whitespace(text)
text.to_s.gsub(/[[:space:]]+/, ' ').strip
end
extend self
##
#
# Escapes any characters that would have special meaning in a regexp
# if text is not a regexp
#
# @param [String] text Text to escape
# @return [String] Escaped text
#
def to_regexp(text)
text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)))
end
##
#
# Normalizes whitespace space by stripping leading and trailing
# whitespace and replacing sequences of whitespace characters
# with a single space.
#
# @param [String] text Text to normalize
# @return [String] Normalized text
#
def normalize_whitespace(text)
text.to_s.gsub(/[[:space:]]+/, ' ').strip
end
##
#
# Injects a `<base>` tag into the given HTML code, pointing to
# `Capybara.asset_host`.
#
# @param [String] html HTML code to inject into
# @param [String] The modified HTML code
#
def inject_asset_host(html)
if Capybara.asset_host
if Nokogiri::HTML(html).css("base").empty? and match = html.match(/<head[^<]*?>/)
html.clone.insert match.end(0), "<base href='#{Capybara.asset_host}' />"
end
else
html
##
#
# Escapes any characters that would have special meaning in a regexp
# if text is not a regexp
#
# @param [String] text Text to escape
# @return [String] Escaped text
#
def to_regexp(text)
text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)))
end
##
#
# Injects a `<base>` tag into the given HTML code, pointing to
# `Capybara.asset_host`.
#
# @param [String] html HTML code to inject into
# @param [String] The modified HTML code
#
def inject_asset_host(html)
if Capybara.asset_host
if Nokogiri::HTML(html).css("base").empty? and match = html.match(/<head[^<]*?>/)
html.clone.insert match.end(0), "<base href='#{Capybara.asset_host}' />"
end
else
html
end
end
end
# @api private
module CountHelpers
class << self
def matches_count?(count, options={})
case
when options[:between]
options[:between] === count
when options[:count]
Integer(options[:count]) == count
when options[:maximum]
Integer(options[:maximum]) >= count
when options[:minimum]
Integer(options[:minimum]) <= count
else
count > 0
end
##
#
# Checks if the given count matches the given count options. By default,
# when no options are given, count should be larger than zero.
#
# @param [Integer] count The actual number. Should be coercible via Integer()
# @option [Range] between Count must be within the given range
# @option [Integer] count Count must be exactly this
# @option [Integer] maximum Count must be smaller than or equal to this value
# @option [Integer] minimum Count must be larger than or equal to this value
#
def matches_count?(count, options={})
case
when options[:between]
options[:between] === count
when options[:count]
Integer(options[:count]) == count
when options[:maximum]
Integer(options[:maximum]) >= count
when options[:minimum]
Integer(options[:minimum]) <= count
else
count > 0
end
end
def failure_message(description, options={})
message = "expected to find #{description}"
if options[:count]
message << " #{options[:count]} #{declension('time', 'times', options[:count])}"
elsif options[:between]
message << " between #{options[:between].first} and #{options[:between].last} times"
elsif options[:maximum]
message << " at most #{options[:maximum]} #{declension('time', 'times', options[:maximum])}"
elsif options[:minimum]
message << " at least #{options[:minimum]} #{declension('time', 'times', options[:minimum])}"
end
message
##
#
# Generates a failure message given a description of the query and count
# options.
#
# @param [String] description Description of a query
# @option [Range] between Count should have been within the given range
# @option [Integer] count Count should have been exactly this
# @option [Integer] maximum Count should have been smaller than or equal to this value
# @option [Integer] minimum Count should have been larger than or equal to this value
#
def failure_message(description, options={})
message = "expected to find #{description}"
if options[:count]
message << " #{options[:count]} #{declension('time', 'times', options[:count])}"
elsif options[:between]
message << " between #{options[:between].first} and #{options[:between].last} times"
elsif options[:maximum]
message << " at most #{options[:maximum]} #{declension('time', 'times', options[:maximum])}"
elsif options[:minimum]
message << " at least #{options[:minimum]} #{declension('time', 'times', options[:minimum])}"
end
message
end
def declension(singular, plural, count)
if count == 1
singular
else
plural
end
##
#
# A poor man's `pluralize`. Given two declensions, one singular and one
# plural, as well as a count, this will pick the correct declension. This
# way we can generate gramatically correct error message.
#
# @param [String] singular The singular form of the word
# @param [String] plural The plural form of the word
# @param [Integer] count The number of items
#
def declension(singular, plural, count)
if count == 1
singular
else
plural
end
end
end

View File

@ -458,15 +458,14 @@ module Capybara
self.eql?(other) or (other.respond_to?(:base) and base == other.base)
end
private
private
def text_found?(*args)
type = args.shift if args.first.is_a?(Symbol) or args.first.nil?
content = args.shift
options = (args.first.is_a?(Hash))? args.first : {}
content, options = args
count = Capybara::Helpers.normalize_whitespace(text(type)).scan(Capybara::Helpers.to_regexp(content)).count
Capybara::CountHelpers.matches_count?(count, options)
Capybara::Helpers.matches_count?(count, options || {})
end
end
end

View File

@ -32,13 +32,13 @@ module Capybara
def_delegators :@result, :each, :[], :at, :size, :count, :length, :first, :last, :empty?
def matches_count?
Capybara::CountHelpers.matches_count?(@result.size, @query.options)
Capybara::Helpers.matches_count?(@result.size, @query.options)
end
def failure_message
message = Capybara::CountHelpers.failure_message(@query.description, @query.options)
message = Capybara::Helpers.failure_message(@query.description, @query.options)
if count > 0
message << ", found #{count} #{Capybara::CountHelpers.declension("match", "matches", count)}: " << @result.map(&:text).map(&:inspect).join(", ")
message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << @result.map(&:text).map(&:inspect).join(", ")
else
message << " but there were no matches"
end

View File

@ -52,7 +52,7 @@ module Capybara
end
def failure_message_for_should
message = Capybara::CountHelpers.failure_message(description, options)
message = Capybara::Helpers.failure_message(description, options)
message << " in #{format(@actual.text(type))}"
message
end