module InstDataShipper module Hooks extend ActiveSupport::Concern class_methods do def define_hook(name) @hooks ||= {} @hooks[name] ||= [] end def hook(name, prepend: false, &block) _assert_hook_defined(name) @hooks ||= {} @hooks[name] ||= [] hooks = @hooks[name] prepend ? hooks.unshift(block) : hooks << block end def _assert_hook_defined(name) return true if @hooks&.key?(name) return if superclass.respond_to?(:_assert_hook_defined) && superclass._assert_hook_defined(name) raise ArgumentError, "Hook #{name} is not defined" end def _list_hooks(name) list = [] list.push(*superclass._list_hooks(name)) if superclass.respond_to?(:_list_hooks) list.push(*@hooks[name]) if (@hooks || {})[name] list end end def run_hook(name, *args, **kwargs) self.class._list_hooks(name).each do |blk| instance_exec(*args, **kwargs, &blk) end end def run_hook_safe(name, *args, **kwargs) self.class._list_hooks(name).each do |blk| instance_exec(*args, **kwargs, &blk) rescue StandardError end end end end