class Karafka::Helpers::ClassMatcher

Class used to autodetect corresponding classes that are internally inside Karafka framework It is used among others to match:

consumer => responder

Constants

CONSTANT_REGEXP

Regexp used to remove any non classy like characters that might be in the consumer class name (if defined dynamically, etc)

Public Class Methods

new(klass, from:, to:) click to toggle source

@param klass [Class] class to which we want to find a corresponding class @param from [String] what type of object is it (based on postfix name part) @param to [String] what are we looking for (based on a postfix name part) @example Consumer that has a corresponding responder

matcher = Karafka::Helpers::ClassMatcher.new(SuperConsumer, 'Consumer', 'Responder')
matcher.match #=> SuperResponder

@example Consumer without a corresponding responder

matcher = Karafka::Helpers::ClassMatcher.new(Super2Consumer, 'Consumer', 'Responder')
matcher.match #=> nil
# File lib/karafka/helpers/class_matcher.rb, line 24
def initialize(klass, from:, to:)
  @klass = klass
  @from = from
  @to = to
end

Public Instance Methods

match() click to toggle source

@return [Class] matched class @return [nil] nil if we couldn't find matching class

# File lib/karafka/helpers/class_matcher.rb, line 32
def match
  return nil if name.empty?
  return nil unless scope.const_defined?(name)

  matching = scope.const_get(name)
  same_scope?(matching) ? matching : nil
end
name() click to toggle source

@return [String] name of a new class that we're looking for @note This method returns name of a class without a namespace @example From SuperConsumer matching responder

matcher.name #=> 'SuperResponder'

@example From Namespaced::Super2Consumer matching responder

matcher.name #=> Super2Responder
# File lib/karafka/helpers/class_matcher.rb, line 46
def name
  inflected = +@klass.to_s.split('::').last.to_s
  # We inject the from into the name just in case it is missing as in a situation like
  # that it would just sanitize the name without adding the "to" postfix.
  # It could create cases when we want to build for example a responder to a consumer
  # that does not have the "Consumer" postfix and would do nothing returning the same name.
  # That would be bad as the matching classes shouldn't be matched to themselves.
  inflected << @from unless inflected.include?(@from)
  inflected.gsub!(@from, @to)
  inflected.gsub!(CONSTANT_REGEXP, '')
  inflected
end
scope() click to toggle source

@return [Class, Module] class or module in which we're looking for a matching

# File lib/karafka/helpers/class_matcher.rb, line 60
def scope
  scope_of(@klass)
end

Private Instance Methods

same_scope?(matching) click to toggle source

@param matching [Class] class of which scope we want to check @return [Boolean] true if the scope of class is the same as scope of matching

# File lib/karafka/helpers/class_matcher.rb, line 83
def same_scope?(matching)
  scope == scope_of(matching)
end
scope_of(klass) click to toggle source

@param klass [Class] class for which we want to extract it's enclosing class/module @return [Class, Module] enclosing class/module @return [::Object] object if it was a root class

@example Non-namespaced class

scope_of(SuperClass) #=> Object

@example Namespaced class

scope_of(Abc::SuperClass) #=> Abc
# File lib/karafka/helpers/class_matcher.rb, line 74
def scope_of(klass)
  enclosing = klass.to_s.split('::')[0...-1]
  return ::Object if enclosing.empty?

  ::Object.const_get(enclosing.join('::'))
end