# typed: false # frozen_string_literal: true module Setsuzoku # The module to include into a class to give it plugin functionality. module Pluggable extend Forwardable extend T::Sig extend T::Helpers abstract! attr_accessor :plugin def_delegators :@plugin, :plugin_service, :plugin_request_class def self.included(klass) klass.extend(ClassMethods) klass.class_eval do if klass.respond_to?(:after_initialize) after_initialize :assign_plugin else # Initialize the pluggable instance and associate its plugin. # # @param _args [Array] array of args passed into new. #unused # @param _block [Proc] the block passed into new. #unused # # @return [Class] the instance of the class that is pluggable. def initialize(*_args, &_block) super self.assign_plugin self end end end end module ClassMethods extend T::Sig def plugin_context @plugin_context end def plugin_context=(val) @plugin_context = val end def plugin_class @plugin_class end def plugin_class=(val) @plugin_class = val end def default_options { plugin_class: self } end # Upon class load (or whenever you call this) register the core configuration # for the pluggable class. # # param options [Any] a list of keyword options to be passed in to customize registration. # # @return [Void] sig(:final) { params(options: T.untyped).void } def register_plugin(**options) options[:plugin_class].config_context[:required_instance_methods].each do |req_method| next if options[:required_instance_methods].key?(req_method) raise Setsuzoku::Exception::UndefinedRequiredMethod.new( registering_instance: self, plugin_class: options[:plugin_class], method_name: req_method ) end self.plugin_context = self.default_options.merge(options) end end def assign_plugin(*_args, &block) self.plugin = self.class.plugin_context[:plugin_class].new(registering_instance: self, **self.class.plugin_context.except(:plugin_class)) end # Define the Plugin that this class should use for its plugin interface. # # @return [Class] any class in Setsuzoku::Plugin sig { abstract.returns(T.untyped) } def plugin_class; end end end