module Taipo::Utilities

Utility methods for Taipo

@since 1.4.0 @api private

Public Class Methods

extract_variable(name:, object:, context:) click to toggle source

Return a named variable from either an object or a binding

@param name [String] the name of the variable @param object [Object] the object in which the variable may exist @param context [Binding] the binding in which the variable may exist

@return [Object] the variable

@raise [Taipo::NameError] if no variable with name exists

@since 1.5.0 @api private

# File lib/taipo/utilities.rb, line 24
def self.extract_variable(name:, object:, context:)
  if name[0] == '@' && object.instance_variable_defined?(name)
    object.instance_variable_get name
  elsif name[0] != '@' && context.local_variable_defined?(name)
    context.local_variable_get name
  else
    msg = "Argument '#{name}' is not defined."
    raise Taipo::NameError, msg
  end
end
instance_method?(str) click to toggle source

Check if a string is the name of an instance method

@note All this does is check whether the given string begins with a hash

symbol.

@param str [String] the string to check

@return [Boolean] the result

@since 1.4.0 @api private

# File lib/taipo/utilities.rb, line 46
def self.instance_method?(str)
  str[0] == '#'
end
match?(object:, definition:) click to toggle source

Check if an object matches a given type definition

@param object [Object] the object to check @param definition [String] the type definiton to check against

@return [Boolean] the result

@raise [::TypeError] if definition is not a String @raise [Taipo::SyntaxError] if the type definitions in checks are

invalid

@since 1.5.0 @api private

# File lib/taipo/utilities.rb, line 63
def self.match?(object:, definition:)
  msg = "The 'definition' argument must be of type String."
  raise ::TypeError, msg unless definition.is_a? String

  types = Taipo::Parser.parse definition
  types.any? { |t| t.match? object }
end
object_to_type_def(obj) click to toggle source

Return the type definition for an object

@note This assume that each element returned by Enumerator#each has the same

number of components.

@param obj [Object] the object

@return [String] a type definition of the object

@since 1.4.0 @api private

# File lib/taipo/utilities.rb, line 82
def self.object_to_type_def(obj)
  return obj.class.name unless obj.is_a? Enumerable

  if obj.is_a? Array
    element_types = Hash.new
    obj.each { |o| element_types[self.object_to_type_def(o)] = true }
    if element_types.empty?
      obj.class.name
    else
      obj.class.name + '<' + element_types.keys.join('|') + '>'
    end
  else
    element_types = Array.new
    obj.each.with_index do |element,index_e|
      element.each.with_index do |component,index_c|
        element_types[index_c] = Hash.new if index_e == 0
        c_type = self.object_to_type_def(component)
        element_types[index_c][c_type] = true
      end
    end
    inner = element_types.reduce('') do |memo,e|
      e_type = e.keys.join('|')
      (memo == '') ? e_type : memo + ',' + e_type
    end
    if element_types.empty?
      obj.class.name
    else
      obj.class.name + '<' + inner + '>'
    end
  end
end
symbol?(str) click to toggle source

Check if a string is the name of a symbol

@note All this does is check whether the given string begins with a colon.

@param str [String] the string to check

@return [Boolean] the result

@since 1.4.0 @api private

# File lib/taipo/utilities.rb, line 124
def self.symbol?(str)
  str[0] == ':'
end
throw_error(object:, name:, definition:, result: false) click to toggle source

Throw an error with an appropriate message for a given object not matching a given type definition

@param object [Object] the object that does not match definition @param name [String] the name of the object (with the code that originally

called the #check method)

@param definition [String] the type definition that does not match object @param result [Boolean] whether this is being called in respect of a

return value (such as by {Taipo::Result::ClassMethods#result})

@raise [Taipo::TypeError] the error

@since 1.5.0 @api private

# File lib/taipo/utilities.rb, line 142
def self.throw_error(object:, name:, definition:, result: false)
  subject = (result) ? "The return value of #{name}" : "Object '#{name}'"

  if Taipo::Utilities.instance_method? definition
    msg = "#{subject} does not respond to #{definition}."
  elsif Taipo::Utilities.symbol? definition
    msg = "#{subject} is not equal to #{definition}."
  elsif object.is_a? Enumerable
    type_def = Taipo::Utilities.object_to_type_def object
    msg = "#{subject} is #{type_def} but expected #{definition}."
  else
    class_name = object.class.name
    msg = "#{subject} is #{class_name} but expected #{definition}."
  end

  raise Taipo::TypeError, msg
end