igor-starostenko/tune_spec

View on GitHub
lib/tune_spec/instances.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true

require_relative 'instances/groups'
require_relative 'instances/steps'
require_relative 'instances/page'

module TuneSpec
  # Maps instance variables of pages, steps and groups
  # to corresponding objects under framework directory
  module Instances
    # Creates an instance of Group or calls an existing
    #
    # @param name [Symbol, String] the prefix of the Groups object class
    # @param opts [Hash] optional arguments
    # @param args [Any] extra arguments
    # @param block [Block] that yields to self
    # @return [GroupObject]
    # @example
    #   groups(:login, {}, 'Main').complete
    def groups(name, opts = {}, *args, &block)
      instance_handler(name, Groups, opts, *args, block)
    end

    # Creates an instance of Step or calls an existing
    #
    # @param name [Symbol, String] the prefix of the Step object class
    # @param opts [Hash] optional arguments
    # @param args [Any] extra arguments
    # @param block [Block] that yields to self
    # @return [StepObject]
    # @example
    #   steps(:calculator, page: :demo).verify_result
    def steps(name, opts = {}, *args, &block)
      opts[:page] && opts[:page] = pages(opts.fetch(:page))
      instance_handler(name, Steps, opts, *args, block)
    end

    # Creates an instance of Page or calls an existing
    #
    # @param name [Symbol, String] the prefix of the Page object class
    # @param opts [Hash] optional arguments
    # @param args [Any] extra arguments
    # @param block [Block] that yields to self
    # @return [PageObject]
    # @example
    #   pages(:home).click_element
    def pages(name, opts = {}, *args, &block)
      instance_handler(name, Page, opts, *args, block)
    end

    private

    # @private
    def instance_handler(name, klass, opts, *args, block)
      method_name = klass.instance_method_name(name)
      instance_klass = klass.call_object(method_name)
      create_instance_method(method_name, klass, instance_klass)
      formatted_opts = klass.format_opts(opts, instance_klass)
      args << formatted_opts unless formatted_opts.empty?
      call_instance_method(method_name, *args, block)
    end

    # @private
    def create_instance_method(method_name, klass, instance_klass)
      return if respond_to?(method_name)

      define_singleton_method(method_name) do |*args|
        if instance_variable_defined?("@#{method_name}")
          instance_var = instance_variable_get("@#{method_name}")
          return instance_var if klass.rules_passed?(instance_var, args.first)
        end

        new_instance = create_instance(klass, instance_klass, *args)
        instance_variable_set("@#{method_name}", new_instance)
      end
    end

    # @private
    def create_instance(klass, instance_klass, *args)
      return instance_klass.new(*args) if klass.object_type == :common

      wait_opts = TuneSpec.calabash_wait_opts
      page(instance_klass, *args).await(wait_opts)
    end

    # @private
    def call_instance_method(method_name, *args, block)
      return __send__(method_name, *args) unless block

      __send__(method_name, *args).instance_eval(&block)
    end
  end
end