module Unobtainium::MultiFind::DriverModule

Driver module implementing multi find functionality.

Constants

DEFAULT_OPTIONS

Default options. This hash is also used to detect if any of the Hashes passed to multifind is an options Hash; it is considered one if it contains any of the keys specified here.

Attributes

multifind_options[RW]

Current options for multifind

Public Class Methods

matches?(impl) click to toggle source

Returns true if the implementation has `#find_element`, false otherwise.

# File lib/unobtainium-multifind/multifind.rb, line 49
def matches?(impl)
  return impl.respond_to?(:find_element)
end

Public Instance Methods

find(*args)
Alias for: multifind
multifind(*args) click to toggle source

Find multiple elements. Each argument is a Hash of selector options that are passed to options. If one argument contains keys from the DEFAULT_OPTIONS Hash, it is instead treated as an options Hash for the multifind method. @return Array of found elements or nil entries if no matching element

was found.
# File lib/unobtainium-multifind/multifind.rb, line 66
def multifind(*args)
  # Parse options
  options, selectors = multifind_parse_options(*args)

  # Now find elements
  results = []
  selectors.each do |selector|
    begin
      results << send(options[:find_method], selector)
    rescue ::Selenium::WebDriver::Error::NoSuchElementError => err
      if options[:raise_on_error]
        raise
      end
      if options[:return_errors]
        results << err
        next
      end
      results << nil
    end
  end

  # Filter results, if necessary
  return multifind_filter_results(options, results)
end
Also aliased as: find

Private Instance Methods

apply_filter(elem, options) click to toggle source

Applies the :check_element filter

# File lib/unobtainium-multifind/multifind.rb, line 204
def apply_filter(elem, options)
  if elem.nil?
    return elem
  end

  if elem.is_a?(::Selenium::WebDriver::Error::NoSuchElementError)
    return elem
  end

  if elem.send(options[:check_element])
    return elem
  end
  return nil
end
multifind_collapse_results(options, results) click to toggle source

Collapses results to only return what's specified by :find.

# File lib/unobtainium-multifind/multifind.rb, line 174
def multifind_collapse_results(options, results)
  # That was easy!
  if options[:find] == :all
    return results
  end

  # Filtering :first and :last is identical, except we go backwards
  # through the results array for :last.
  if options[:find] == :last
    results.reverse!
  end

  # We now return the first non-nil, non-error result
  results.each do |result|
    if result.nil?
      next
    end
    if result.is_a?(::Selenium::WebDriver::Error::NoSuchElementError)
      next
    end
    return [result]
  end

  # If we're here then we have no results, but want :first
  # or :last. An empty result is appropriate.
  return []
end
multifind_filter_results(options, results) click to toggle source

Filters results from multifind; this largely means honouring the :find option.

# File lib/unobtainium-multifind/multifind.rb, line 151
def multifind_filter_results(options, results)
  results = multifind_collapse_results(options, results)

  # If we're only checking for existence, we're done here.
  if options[:check_element] == :exists?
    return results
  end

  # Filter all results according to the :check_element option
  filtered = results.map do |result|
    if result.is_a? Array
      next result.map do |inner|
        next apply_filter(inner, options)
      end
    end
    next apply_filter(result, options)
  end

  return filtered
end
multifind_parse_options(*args) click to toggle source

Distinguishes between option hashes and selectors by detecting Hash arguments with keys from DEFAULT_OPTIONS. Those are considered to be options, and merged with any preceding option hashes, where latter occurrences overwrite earlier ones.

# File lib/unobtainium-multifind/multifind.rb, line 100
def multifind_parse_options(*args)
  # Sanity
  if @multifind_options.nil?
    @multifind_options = DEFAULT_OPTIONS
  end

  # Distinguish between options and selectors
  options = {}
  selectors = []
  args.each do |arg|
    # Let the underlying API handle all non-Hashes
    if not arg.is_a?(Hash)
      selectors << arg
      next
    end

    # See if it contains any of the keys we care about
    option_keys = DEFAULT_OPTIONS.keys
    diff = option_keys - arg.keys
    if diff != option_keys
      options.merge!(arg)
      next
    end

    selectors << arg
  end
  options = @multifind_options.merge(options)
  options = DEFAULT_OPTIONS.merge(options)

  # Ensure that the 'find' option contains correct
  # values only.
  if not [:all, :first, :last].include?(options[:find])
    raise ArgumentError, ":find option must be one of :all, :first or "\
      ":last, but is: #{options[:find]}"
  end

  # Ensure that 'check_element' contains only valid options.
  elem_klass = ::Selenium::WebDriver::Element
  if options[:check_element] != :exists? and
     not elem_klass.instance_methods.include?(options[:check_element])
    raise ArgumentError, ":check_element must either be :exists? or "\
      "a boolean method that ::Selenium::WebDriver::Element responds to, "\
      "but got: #{options[:check_element]}"
  end

  return options, selectors
end