Pure functional plugin registry backed by ETS for fast concurrent lookups.
Separates plugin registration/discovery from lifecycle management. All read operations are direct ETS lookups - no process serialization.
Design
Following Rich Hickey's principle of separating data from coordination:
- Registry is data (what plugins exist, their metadata)
- Lifecycle is coordination (loading, enabling, state management)
Usage
# Initialize registry (usually in application start)
PluginRegistry.init()
# Register a plugin
PluginRegistry.register(:my_plugin, MyPlugin, %{version: "1.0"})
# Fast lookups (direct ETS, no GenServer)
PluginRegistry.get(:my_plugin)
PluginRegistry.list()
PluginRegistry.find_by_command(:help)
# Check if registered
PluginRegistry.registered?(:my_plugin)
Summary
Functions
Returns the count of registered plugins.
Filters plugins by metadata criteria.
Finds plugins that provide a specific command.
Finds plugins by metadata key-value match.
Gets a plugin entry by ID. Direct ETS lookup.
Gets all commands provided by a plugin.
Gets a plugin module by ID.
Initializes the plugin registry ETS tables.
Checks if the registry has been initialized.
Lists all registered plugins.
Lists all registered commands with their provider plugins.
Registers a plugin in the registry.
Checks if a plugin is registered.
Unregisters a plugin from the registry.
Updates a plugin's metadata.
Types
@type metadata() :: map()
@type plugin_entry() :: %{ id: plugin_id(), module: plugin_module(), metadata: metadata(), registered_at: DateTime.t() }
@type plugin_module() :: module()
Functions
@spec count() :: non_neg_integer()
Returns the count of registered plugins.
@spec filter((plugin_entry() -> boolean())) :: [plugin_entry()]
Filters plugins by metadata criteria.
Examples
# Find all plugins with version "1.0"
PluginRegistry.filter(fn entry ->
entry.metadata[:version] == "1.0"
end)
Finds plugins that provide a specific command.
Examples
PluginRegistry.find_by_command(:help)
# => [:help_plugin, :docs_plugin]
@spec find_by_metadata(atom(), term()) :: [plugin_entry()]
Finds plugins by metadata key-value match.
Examples
PluginRegistry.find_by_metadata(:category, :ui)
@spec get(plugin_id()) :: {:ok, plugin_entry()} | :error
Gets a plugin entry by ID. Direct ETS lookup.
Examples
case PluginRegistry.get(:clipboard) do
{:ok, entry} -> entry.module
:error -> nil
end
Gets all commands provided by a plugin.
Gets a plugin module by ID.
@spec init() :: :ok
Initializes the plugin registry ETS tables.
Call this once during application startup.
@spec initialized?() :: boolean()
Checks if the registry has been initialized.
@spec list(keyword()) :: [plugin_entry()] | [plugin_id()]
Lists all registered plugins.
Options
:ids_only- Return only plugin IDs (default: false)
Lists all registered commands with their provider plugins.
@spec register(plugin_id(), plugin_module(), metadata()) :: :ok | {:error, :already_registered}
Registers a plugin in the registry.
Examples
PluginRegistry.register(:clipboard, Raxol.Plugins.Clipboard, %{
version: "1.0.0",
description: "Clipboard integration"
})
Checks if a plugin is registered.
@spec unregister(plugin_id()) :: :ok
Unregisters a plugin from the registry.
Updates a plugin's metadata.