Module: OnyxCord::Bot::Extensions

Included in:
OnyxCord::Bot
Defined in:
lib/onyxcord/cogs/extensions.rb

Overview

Extension management: load, unload, and reload cog modules from files.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#extensionsHash{String => Hash} (readonly)

Returns loaded extensions keyed by name.

Returns:

  • (Hash{String => Hash})

    loaded extensions keyed by name



8
9
10
# File 'lib/onyxcord/cogs/extensions.rb', line 8

def extensions
  @extensions
end

Instance Method Details

#load_extension(name, path: nil) ⇒ Array<Cog>

Load an extension from a file. The file must define a setup(bot) method that receives the bot and returns a cog instance (or an array of cog instances). Optionally, the file can define a teardown(bot) method for cleanup.

Parameters:

  • name (String, Symbol)

    The extension name (used as key and to resolve file path).

  • path (String, nil) (defaults to: nil)

    Optional explicit file path. When nil, resolves extensions/<name>.rb.

Returns:

  • (Array<Cog>)

    the cogs created by the extension.

Raises:

  • (ArgumentError)

    if the extension is already loaded.

  • (LoadError)

    if the file cannot be found or does not define setup.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/onyxcord/cogs/extensions.rb', line 19

def load_extension(name, path: nil)
  @extensions ||= {}
  name = name.to_s
  raise ArgumentError, "Extension '#{name}' is already loaded" if @extensions.key?(name)

  path ||= resolve_extension_path(name)
  raise LoadError, "Extension file not found: #{path}" unless File.exist?(path)

  mod = load_extension_module(path, name)

  raise LoadError, "Extension '#{name}' must define a self.setup(bot) method" unless mod.respond_to?(:setup)

  result = mod.setup(self)
  cogs = Array(result).select { |obj| obj.is_a?(Cog) }

  @extensions[name] = {
    path: path,
    module: mod,
    cogs: cogs.map { |c| c.respond_to?(:qualified_name) ? c.qualified_name : c.class.name }
  }

  cogs
end

#load_extensions(dir) ⇒ Array<Cog>

Load all .rb files from a directory as extensions.

Parameters:

  • dir (String)

    The directory path containing extension files.

Returns:

  • (Array<Cog>)

    all cogs created from the loaded extensions.

Raises:

  • (ArgumentError)


81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/onyxcord/cogs/extensions.rb', line 81

def load_extensions(dir)
  raise ArgumentError, "Extensions directory not found: #{dir}" unless Dir.exist?(dir)

  cogs = []
  Dir.glob(File.join(dir, '*.rb')).each do |file|
    name = File.basename(file, '.rb')
    cogs.concat(load_extension(name, path: file))
  rescue LoadError, StandardError => e
    OnyxCord::LOGGER.warn("Failed to load extension '#{name}': #{e.message}") if defined?(OnyxCord::LOGGER)
  end
  cogs
end

#reload_extension(name) ⇒ Array<Cog>

Reload an extension: unload then load.

Parameters:

  • name (String, Symbol)

    The extension name.

Returns:

  • (Array<Cog>)

    the cogs created by the reloaded extension.

Raises:

  • (ArgumentError)

    if the extension was not previously loaded.



66
67
68
69
70
71
72
73
74
75
# File 'lib/onyxcord/cogs/extensions.rb', line 66

def reload_extension(name)
  @extensions ||= {}
  name = name.to_s
  ext = @extensions[name]
  raise ArgumentError, "Extension '#{name}' is not loaded" unless ext

  path = ext[:path]
  unload_extension(name)
  load_extension(name, path: path)
end

#unload_extension(name) ⇒ true, false

Unload an extension by name. Calls teardown(bot) if defined.

Parameters:

  • name (String, Symbol)

    The extension name.

Returns:

  • (true, false)

    whether the extension was found and unloaded.



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/onyxcord/cogs/extensions.rb', line 47

def unload_extension(name) # rubocop:disable Naming/PredicateMethod
  @extensions ||= {}
  name = name.to_s
  ext = @extensions.delete(name)
  return false unless ext

  mod = ext[:module]
  mod.teardown(self) if mod.respond_to?(:teardown)

  ext[:cogs].each { |cog_name| remove_cog(cog_name) }

  true
end