1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
# frozen_string_literal: true
require 'set'
require 'thread'
module Seahorse
module Client
class PluginList
include Enumerable
# @param [Array, Set] plugins
# @option options [Mutex] :mutex
def initialize(plugins = [], options = {})
@mutex = options[:mutex] || Mutex.new
@plugins = Set.new
if plugins.is_a?(PluginList)
plugins.send(:each_plugin) { |plugin| _add(plugin) }
else
plugins.each { |plugin| _add(plugin) }
end
end
# Adds and returns the `plugin`.
# @param [Plugin] plugin
# @return [void]
def add(plugin)
@mutex.synchronize do
_add(plugin)
end
nil
end
# Removes and returns the `plugin`.
# @param [Plugin] plugin
# @return [void]
def remove(plugin)
@mutex.synchronize do
@plugins.delete(PluginWrapper.new(plugin))
end
nil
end
# Replaces the existing list of plugins.
# @param [Array<Plugin>] plugins
# @return [void]
def set(plugins)
@mutex.synchronize do
@plugins.clear
plugins.each do |plugin|
_add(plugin)
end
end
nil
end
# Enumerates the plugins.
# @return [Enumerator]
def each(&block)
each_plugin do |plugin_wrapper|
yield(plugin_wrapper.plugin)
end
end
private
# Not safe to call outside the mutex.
def _add(plugin)
@plugins << PluginWrapper.new(plugin)
end
# Yield each PluginDetail behind the mutex
def each_plugin(&block)
@mutex.synchronize do
@plugins.each(&block)
end
end
# A utility class that computes the canonical name for a plugin
# and defers requiring the plugin until the plugin class is
# required.
# @api private
class PluginWrapper
# @param [String, Symbol, Module, Class] plugin
def initialize(plugin)
case plugin
when Module
@canonical_name = plugin.name || plugin.object_id
@plugin = plugin
when Symbol, String
words = plugin.to_s.split('.')
@canonical_name = words.pop
@gem_name = words.empty? ? nil : words.join('.')
@plugin = nil
else
@canonical_name = plugin.object_id
@plugin = plugin
end
end
# @return [String]
attr_reader :canonical_name
# @return [Class<Plugin>]
def plugin
@plugin ||= require_plugin
end
# Returns the given plugin if it is already a PluginWrapper.
def self.new(plugin)
if plugin.is_a?(self)
plugin
else
super
end
end
# @return [Boolean]
# @api private
def eql? other
canonical_name == other.canonical_name
end
# @return [String]
# @api private
def hash
canonical_name.hash
end
private
# @return [Class<Plugin>]
def require_plugin
require(@gem_name) if @gem_name
plugin_class = Kernel
@canonical_name.split('::').each do |const_name|
plugin_class = plugin_class.const_get(const_name)
end
plugin_class
end
end
end
end
end
|