class Marta::BlackMagic::MagicFinder

Element searching class.

@note It is believed that no user will use it

Public Class Methods

new(meth, tolerancy, name, requestor) click to toggle source
Calls superclass method
# File lib/marta/black_magic.rb, line 34
def initialize(meth, tolerancy, name, requestor)
  @tolerancy = tolerancy
  @engine = requestor.engine
  @name = name
  @requestor = requestor
  super(meth, requestor)
end

Public Instance Methods

actual_searching(result) click to toggle source

The core of Black Magic Algorithm

# File lib/marta/black_magic.rb, line 187
def actual_searching(result)
  granny, pappy, i = true, true, 1
  while !result.exists?
    array_of_xpaths = form_complex_xpath(i, granny, pappy)
    if XPathFactory.new(@meth, @requestor).analyze(i, @tolerancy)[0] < i
      # One more step.
      # We will try to exclude grandparent element data at first.
      # Then we will try to exclude parent.
      # Finally we will try to exclude all the parents.
      # If they are already excluded and Marta is out of tolerancy...
      granny, pappy, i = granny_pappy_manage(granny, pappy) + [1]
      array_of_xpaths = form_complex_xpath(i, granny, pappy)
    end
    array_of_elements,
      array_of_els_xpaths = candidates_arrays_creation(array_of_xpaths)
    i += 1
    result =
        get_search_result(result, array_of_elements, array_of_els_xpaths)
  end
  return result
end
candidates_arrays_creation(array_of_xpaths) click to toggle source

We are forming arrays of candidates

# File lib/marta/black_magic.rb, line 137
def candidates_arrays_creation(array_of_xpaths)
  array_of_elements, array_of_els_xpaths = Array.new, Array.new
  something = nil
  array_of_xpaths.each do |xpath|
    something = @engine.elements(xpath: xpath)
    if something.to_a.length > 0
      array_of_elements += something.to_a
      something.to_a.length.times {array_of_els_xpaths.push xpath}
    end
  end
  return array_of_elements, array_of_els_xpaths
end
find() click to toggle source

Main method. It finds an element

Calls superclass method
# File lib/marta/black_magic.rb, line 84
def find
  if !forced_xpath?
    element = prefind_with_waiting
    if !element.exists?
      warn_and_search element
      if collection?
        return_collection
      else
        return_element
      end
    end
  end
  super
end
form_complex_xpath(unknowns, granny=true, pappy=true) click to toggle source

Marta can form special xpath guess for element finding attempt

# File lib/marta/black_magic.rb, line 112
def form_complex_xpath(unknowns, granny=true, pappy=true)
  xpath_factory = XPathFactory.new(@meth, @requestor)
  xpath_factory.granny = granny
  xpath_factory.pappy = pappy
  if xpath_factory.array_of_hashes.count <= unknowns
    raise "Marta did her best. But she found nothing"
  else
    xpath_factory.generate_xpaths(unknowns, @tolerancy)
  end
end
get_result_inputs(array_of_elements) click to toggle source

Getting indexes of the most common element in the array of suggested elements

# File lib/marta/black_magic.rb, line 164
def get_result_inputs(array_of_elements)
  result = array_of_elements.group_by(&:itself).
           values.max_by(&:size).first
  array_of_elements.each_index.
                          select{|i| array_of_elements[i] == result}
end
get_search_result(result, array_of_elements, array_of_els_xpaths) click to toggle source

Selecting the most common element in the array.

# File lib/marta/black_magic.rb, line 151
def get_search_result(result, array_of_elements, array_of_els_xpaths)
  something = result
  if array_of_elements.size > 0
    inputs = get_result_inputs(array_of_elements)
    most_uniq_xpath_by_inputs(array_of_els_xpaths, inputs)
    array_of_elements[array_of_els_xpaths.index(@xpath)]
  else
    something
  end
end
granny_pappy_manage(granny, pappy) click to toggle source

We should manage granny, pappy and i values for additional steps

# File lib/marta/black_magic.rb, line 124
def granny_pappy_manage(granny, pappy)
  if !(granny or pappy)
    raise "Marta did her best. But she found nothing"
  end
  if (granny and pappy) or (granny and !pappy)
    granny = false
  else
    granny, pappy = true, false
  end
  return granny, pappy
end
most_uniq_xpath_by_inputs(array_of_els_xpaths, inputs) click to toggle source

Getting the most specific xpath for the most common element in order to locate it only

# File lib/marta/black_magic.rb, line 173
def most_uniq_xpath_by_inputs(array_of_els_xpaths, inputs)
  xpaths = Array.new
  array_of_els_xpaths.
         each_with_index{|e, i| xpaths.push e if inputs.include?(i)}
  @xpath = xpaths[0]
  xpaths.each do |x|
    current_count = array_of_els_xpaths.count(x)
    proposed_count = array_of_els_xpaths.count(@xpath)
    @xpath = x if current_count < proposed_count
  end
  @xpath
end
prefind_with_waiting() click to toggle source

We can prefind an element and wait for it.

# File lib/marta/black_magic.rb, line 43
def prefind_with_waiting
  begin
    prefind.wait_until_present(timeout: SettingMaster.cold_timeout)
  rescue
    # found nothing
    prefind
  end
end
return_collection() click to toggle source

When black magic is finding some collection it is not only returning it. It is silently generating changes to a json file

# File lib/marta/black_magic.rb, line 54
def return_collection
  result = prefind_collection
  to_save = @meth
  result.each do |item|
    meth_data = method_structure true
    meth_data['positive'] = get_attributes item, @requestor
    to_save = make_collection(to_save, meth_data)
  end
  file_name  = @requestor.instance_variable_get("@class_name").to_s
  file_data = @requestor.instance_variable_get("@data")
  file_data['meths'][@name] = to_save
  file_write(file_name, file_data)
  result
end
return_element() click to toggle source

When black magic is finding some element it is not only returning it. It is silently writing actual data about the element to json

# File lib/marta/black_magic.rb, line 71
def return_element
  result = prefind
  meth_data = method_structure
  meth_data['positive'] = get_attributes result, @requestor
  to_save = forget_unstable(@meth, meth_data)
  file_name  = @requestor.instance_variable_get("@class_name").to_s
  file_data = @requestor.instance_variable_get("@data")
  file_data['meths'][@name] = to_save
  file_write(file_name, file_data)
  subtype_of prefind
end