Class: Avo::PluginManager
- Inherits:
-
Object
- Object
- Avo::PluginManager
- Defined in:
- lib/avo/plugin_manager.rb
Instance Attribute Summary collapse
-
#engines ⇒ Object
readonly
Returns the value of attribute engines.
-
#plugins ⇒ Object
(also: #all)
readonly
Returns the value of attribute plugins.
Instance Method Summary collapse
- #as_json(*arg) ⇒ Object
-
#begin_reload ⇒ Object
Starts a re-registration cycle without touching the currently published @plugins/@engines, so concurrent readers (e.g. mount_avo's route-drawing loop) keep seeing the complete pre-reload list until #commit_reload publishes the new one.
-
#commit_reload ⇒ Object
Publishes the registrations collected since #begin_reload.
-
#initialize ⇒ PluginManager
constructor
A new instance of PluginManager.
- #installed?(name) ⇒ Boolean
- #mount_engine(klass, **options) ⇒ Object
- #register(name, priority: 10) ⇒ Object
-
#register_configuration(name, klass) ⇒ Object
Register a plugin's configuration namespace on Avo::Configuration so host apps configure the plugin from config/initializers/avo.rb:.
- #register_field(method_name, klass) ⇒ Object
-
#register_menu_item(name, &block) ⇒ Object
Register a custom menu DSL method (e.g.
form) contributed by a plugin, so it can be used insideconfig.main_menuand friends. - #register_resource_tool ⇒ Object
- #register_tool ⇒ Object
- #register_view_type(name, component:, icon:, active_icon:, translation_key: nil) ⇒ Object
- #to_s ⇒ Object
Constructor Details
#initialize ⇒ PluginManager
Returns a new instance of PluginManager.
8 9 10 11 12 13 |
# File 'lib/avo/plugin_manager.rb', line 8 def initialize @plugins = [] @engines = [] @building_plugins = [] @building_engines = [] end |
Instance Attribute Details
#engines ⇒ Object (readonly)
Returns the value of attribute engines.
4 5 6 |
# File 'lib/avo/plugin_manager.rb', line 4 def engines @engines end |
#plugins ⇒ Object (readonly) Also known as: all
Returns the value of attribute plugins.
3 4 5 |
# File 'lib/avo/plugin_manager.rb', line 3 def plugins @plugins end |
Instance Method Details
#as_json(*arg) ⇒ Object
128 129 130 131 132 133 134 135 |
# File 'lib/avo/plugin_manager.rb', line 128 def as_json(*arg) plugins.map do |plugin| { klass: plugin.to_s, priority: plugin.priority, } end end |
#begin_reload ⇒ Object
Starts a re-registration cycle without touching the currently published @plugins/@engines, so concurrent readers (e.g. mount_avo's route-drawing loop) keep seeing the complete pre-reload list until #commit_reload publishes the new one. Called by Avo.boot inside its Mutex, so only one reload is ever building at a time.
20 21 22 23 |
# File 'lib/avo/plugin_manager.rb', line 20 def begin_reload @building_plugins = [] @building_engines = [] end |
#commit_reload ⇒ Object
Publishes the registrations collected since #begin_reload. Each of the two reassignments below is individually an atomic pointer swap, so a reader of .engines alone (or .plugins alone) always sees the complete old list or the complete new one, never a partially rebuilt one. The two fields are not published jointly -- a reader combining both in one operation could observe them from different reload generations. No current reader does that (mount_avo reads only .engines; installed? reads only .plugins).
33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/avo/plugin_manager.rb', line 33 def commit_reload @plugins = @building_plugins @engines = @building_engines # Reset to fresh arrays rather than nil: register/mount_engine must # stay callable even outside a begin_reload/commit_reload window -- # e.g. avo-permissions calls Avo.plugin_manager.register at Rails # initializer time, before Avo.boot ever runs. Such a call is simply # discarded by the next #begin_reload rather than raising, matching # the pre-atomic-publish behavior where register/mount_engine never # crashed regardless of timing. @building_plugins = [] @building_engines = [] end |
#installed?(name) ⇒ Boolean
145 146 147 148 149 |
# File 'lib/avo/plugin_manager.rb', line 145 def installed?(name) plugins.any? do |plugin| plugin.name.to_s == name.to_s end end |
#mount_engine(klass, **options) ⇒ Object
151 152 153 154 155 156 157 |
# File 'lib/avo/plugin_manager.rb', line 151 def mount_engine(klass, **) # Dedup by class so a plugin hook that (by bug) calls mount_engine # twice for the same engine within one boot can't leave a duplicate # entry for #commit_reload to publish. @building_engines.delete_if { |engine| engine[:klass] == klass } @building_engines << {klass:, options:} end |
#register(name, priority: 10) ⇒ Object
47 48 49 50 51 52 53 54 |
# File 'lib/avo/plugin_manager.rb', line 47 def register(name, priority: 10) # Capture the file that called `register` so the plugin can later resolve # the gem it actually ships in. Plugins register under nicknames # (e.g. `:rhino` for `avo-rhino_field`), so the name alone isn't enough. registered_from = caller_locations(1, 1)&.first&.path @building_plugins << Plugin.new(name:, priority: priority, registered_from: registered_from) end |
#register_configuration(name, klass) ⇒ Object
Register a plugin's configuration namespace on Avo::Configuration so host apps configure the plugin from config/initializers/avo.rb:
Avo.plugin_manager.register_configuration :intelligence, Avo::Intelligence::Configuration
Avo.configure do |config|
config.intelligence.thinking_effort = "medium"
end
Call it from an engine initializer ordered before: :load_config_initializers
(or at require time) — the host's avo.rb reads the accessor, so it must be
defined before config/initializers run. An :avo_boot hook is too late.
Instances are memoized per Configuration object, so replacing
Avo.configuration resets plugin configs along with everything else.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/avo/plugin_manager.rb', line 96 def register_configuration(name, klass) name = name.to_sym @configuration_namespaces ||= {} # Guard against a plugin silently shadowing a core option or another # plugin's namespace. Re-registering the same namespace with the same # class is fine — boot runs more than once. existing = @configuration_namespaces[name] if existing.nil? && Avo::Configuration.method_defined?(name) raise ArgumentError, "Avo::Configuration already defines ##{name}; pick a different configuration namespace." end if !existing.nil? && existing != klass raise ArgumentError, "Configuration namespace :#{name} is already registered with #{existing}; pick a different namespace." end @configuration_namespaces[name] = klass Avo::Configuration.define_method(name) do (@plugin_configurations ||= {})[name] ||= klass.new end Avo::Configuration.define_method(:"#{name}=") do |value| (@plugin_configurations ||= {})[name] = value end end |
#register_field(method_name, klass) ⇒ Object
60 61 62 63 64 65 66 67 68 |
# File 'lib/avo/plugin_manager.rb', line 60 def register_field(method_name, klass) # Avo.boot method is executed multiple times. # During the first run, it correctly loads descendants of Avo::Fields::Base. # Plugins are then loaded, introducing additional descendants to Avo::Fields::Base. # On subsequent runs, Avo::Fields::Base descendants now include these plugin fields. # This field_name_attribute assign forces the field name to retain the registered name instead of being computed dynamically from the field class. klass.field_name_attribute = method_name Avo.field_manager.load_field method_name, klass end |
#register_menu_item(name, &block) ⇒ Object
Register a custom menu DSL method (e.g. form) contributed by a plugin,
so it can be used inside config.main_menu and friends. Delegates to
avo-menu's builder when it's installed; a no-op otherwise, so plugins can
register unconditionally. The block is evaluated in the menu builder's
context, so it can call link, resource, etc. See
Avo::Menu::Builder.register_item.
76 77 78 79 80 |
# File 'lib/avo/plugin_manager.rb', line 76 def (name, &block) return unless defined?(Avo::Menu::Builder) Avo::Menu::Builder.register_item(name, &block) end |
#register_resource_tool ⇒ Object
122 123 |
# File 'lib/avo/plugin_manager.rb', line 122 def register_resource_tool end |
#register_tool ⇒ Object
125 126 |
# File 'lib/avo/plugin_manager.rb', line 125 def register_tool end |
#register_view_type(name, component:, icon:, active_icon:, translation_key: nil) ⇒ Object
56 57 58 |
# File 'lib/avo/plugin_manager.rb', line 56 def register_view_type(name, component:, icon:, active_icon:, translation_key: nil) Avo.view_type_manager.register(name, component:, icon:, active_icon:, translation_key:) end |
#to_s ⇒ Object
137 138 139 140 141 142 143 |
# File 'lib/avo/plugin_manager.rb', line 137 def to_s plugins.map do |plugin| plugin.to_s end.join(",") rescue "Failed to fetch plugins." end |