Make Query a first class citizen

This commit is contained in:
Jonas Nicklas 2012-01-02 18:11:07 +01:00
parent 33692b258c
commit 4083ed1afa
4 changed files with 58 additions and 59 deletions

View File

@ -302,6 +302,7 @@ module Capybara
autoload :Server, 'capybara/server'
autoload :Session, 'capybara/session'
autoload :Selector, 'capybara/selector'
autoload :Query, 'capybara/query'
autoload :VERSION, 'capybara/version'
module Node

View File

@ -109,10 +109,10 @@ module Capybara
# @return [Array[Capybara::Element]] The found elements
#
def all(*args)
selector = Capybara::Selector.normalize(*args)
selector.xpaths.
map { |path| find_in_base(selector, path) }.flatten.
select { |node| selector.matches_filters?(node) }
query = Capybara::Query.new(*args)
query.xpaths.
map { |path| find_in_base(query, path) }.flatten.
select { |node| query.matches_filters?(node) }
end
##
@ -138,13 +138,13 @@ module Capybara
protected
def raise_find_error(*args)
normalized = Capybara::Selector.normalize(*args)
raise Capybara::ElementNotFound, normalized.failure_message(self)
query = Capybara::Query.new(*args)
raise Capybara::ElementNotFound, query.failure_message(self)
end
def find_in_base(selector, xpath)
def find_in_base(query, xpath)
base.find(xpath).map do |node|
Capybara::Node::Element.new(session, node, self, selector)
Capybara::Node::Element.new(session, node, self, query)
end
end

49
lib/capybara/query.rb Normal file
View File

@ -0,0 +1,49 @@
module Capybara
class Query
attr_accessor :selector, :locator, :options, :xpaths
def initialize(*args)
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
if text = options[:text]
@options[:text] = Regexp.escape(text) unless text.kind_of?(Regexp)
end
unless options.has_key?(:visible)
@options[:visible] = Capybara.ignore_hidden_elements
end
if args[1]
@selector = Selector.all[args[0]]
@locator = args[1]
else
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
@locator = args[0]
end
@selector ||= Selector.all[Capybara.default_selector]
xpath = @selector.call(@locator)
if xpath.respond_to?(:to_xpaths)
@xpaths = xpath.to_xpaths
else
@xpaths = [xpath.to_s].flatten
end
end
def failure_message(node)
message = selector.failure_message.call(node, self) if selector.failure_message
message ||= options[:message]
message ||= "Unable to find #{name} #{locator.inspect}"
message
end
def name; selector.name; end
def matches_filters?(node)
return false if options[:text] and not node.text.match(options[:text])
return false if options[:visible] and not node.visible?
selector.custom_filters.each do |name, block|
return false if options.has_key?(name) and not block.call(node, options[name])
end
true
end
end
end

View File

@ -2,53 +2,6 @@ module Capybara
class Selector
attr_reader :name, :custom_filters
class Normalized
attr_accessor :selector, :locator, :options, :xpaths
def initialize(*args)
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
if text = options[:text]
@options[:text] = Regexp.escape(text) unless text.kind_of?(Regexp)
end
unless options.has_key?(:visible)
@options[:visible] = Capybara.ignore_hidden_elements
end
if args[1]
@selector = Selector.all[args[0]]
@locator = args[1]
else
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
@locator = args[0]
end
@selector ||= Selector.all[Capybara.default_selector]
xpath = @selector.call(@locator)
if xpath.respond_to?(:to_xpaths)
@xpaths = xpath.to_xpaths
else
@xpaths = [xpath.to_s].flatten
end
end
def failure_message(node)
message = selector.failure_message.call(node, self) if selector.failure_message
message ||= options[:message]
message ||= "Unable to find #{name} #{locator.inspect}"
message
end
def name; selector.name; end
def matches_filters?(node)
return false if options[:text] and not node.text.match(options[:text])
return false if options[:visible] and not node.visible?
selector.custom_filters.each do |name, block|
return false if options.has_key?(name) and not block.call(node, options[name])
end
true
end
end
class << self
def all
@ -62,10 +15,6 @@ module Capybara
def remove(name)
all.delete(name.to_sym)
end
def normalize(*args)
Normalized.new(*args)
end
end
def initialize(name, &block)