Module: RUtilAnts::Plugins::PluginsInterface

Included in:
PluginsManager
Defined in:
lib/rUtilAnts/Plugins.rb

Instance Method Summary collapse

Instance Method Details

#access_plugin(iCategoryName, iPluginName, iParameters = {}) ⇒ Object

Give access to a plugin. An exception is thrown if the plugin does not exist.

Parameters
  • iCategoryName (String): Category of the plugin to access

  • iPluginName (String): Name of the plugin to access

  • iParameters (map<Symbol,Object>): Additional parameters:

    • OnlyIfExtDepsResolved (Boolean): Do we return the plugin only if there is no need to install external dependencies ? [optional = false]

    • RDIInstaller (RDI::Installer): The RDI installer if available, or nil otherwise [optional = nil]

    • RDIContextModifiers (map<String,list< [String,Object] >>): The map of context modifiers to be filled by the RDI installer if specified, or nil if ignored [optional = nil]

  • CodeBlock: The code called when the plugin is found:

    • ioPlugin (Object): The corresponding plugin



295
296
297
298
299
300
301
302
# File 'lib/rUtilAnts/Plugins.rb', line 295

def access_plugin(iCategoryName, iPluginName, iParameters = {})
  lPlugin, lError = get_plugin_instance(iCategoryName, iPluginName, iParameters)
  if (lPlugin == nil)
    raise lError
  else
    yield(lPlugin)
  end
end

#clearPluginsObject

Clear the registered plugins



305
306
307
# File 'lib/rUtilAnts/Plugins.rb', line 305

def clearPlugins
  @Plugins = {}
end

#get_plugin_description(iCategory, iPluginName) ⇒ Object

Get the named plugin description

Parameters
  • iCategory (Object): Category those plugins will belong to

  • iPluginName (String): Plugin name

Return
  • map<Symbol,Object>: The corresponding description



268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/rUtilAnts/Plugins.rb', line 268

def get_plugin_description(iCategory, iPluginName)
  rDesc = nil

  if (@Plugins[iCategory] == nil)
    raise UnknownCategoryError.new("Unknown plugins category #{iCategory}.")
  else
    rDesc = @Plugins[iCategory][iPluginName]
    if (rDesc == nil)
      raise UnknownPluginError.new("Unknown plugin #{iPluginName} in category #{iCategory}.")
    end
  end

  return rDesc
end

#get_plugin_instance(iCategory, iPluginName, iParameters = {}) ⇒ Object

Get the named plugin instance. Uses RDI if given in parameters or if Main RDI Installer defined to resolve Plugins’ dependencies.

Parameters
  • iCategory (Object): Category those plugins will belong to

  • iPluginName (String): Plugin name

  • iParameters (map<Symbol,Object>): Additional parameters:

    • OnlyIfExtDepsResolved (Boolean): Do we return the plugin only if there is no need to install external dependencies ? [optional = false]

    • RDIInstaller (RDI::Installer): The RDI installer if available, or nil otherwise [optional = nil]

    • RDIContextModifiers (map<String,list< [String,Object] >>): The map of context modifiers to be filled by the RDI installer if specified, or nil if ignored [optional = nil]

Return
  • Object: The corresponding plugin, or nil in case of failure

  • Exception: The error, or nil in case of success



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/rUtilAnts/Plugins.rb', line 155

def get_plugin_instance(iCategory, iPluginName, iParameters = {})
  rPlugin = nil
  rError = nil

  lOnlyIfExtDepsResolved = iParameters[:OnlyIfExtDepsResolved]
  if (lOnlyIfExtDepsResolved == nil)
    lOnlyIfExtDepsResolved = false
  end
  lRDIInstaller = iParameters[:RDIInstaller]
  lRDIContextModifiers = iParameters[:RDIContextModifiers]
  if (@Plugins[iCategory] == nil)
    rError = UnknownCategoryError.new("Unknown plugins category #{iCategory}.")
  else
    lDesc = @Plugins[iCategory][iPluginName]
    if (lDesc == nil)
      rError = UnknownPluginError.new("Unknown plugin #{iPluginName} in category #{iCategory}.")
    elsif (lDesc[:Enabled] == false)
      rError = DisabledPluginError.new("Plugin #{iPluginName} in category #{iCategory} is disabled.")
    else
      if (lDesc[:PluginInstance] == nil)
        lSuccess = true
        # If RDI is present, call it to get dependencies first if needed
        if (lDesc[:Dependencies] != nil)
          # If it is not given as parameter, try getting the singleton
          if ((lRDIInstaller == nil) and
              (defined?(RDI::Installer) != nil))
            lRDIInstaller = RDI::Installer.get_main_instance
          end
          if (lRDIInstaller != nil)
            if (lOnlyIfExtDepsResolved)
              # Test that each dependency is accessible
              lSuccess = true
              lDesc[:Dependencies].each do |iDepDesc|
                lSuccess = lRDIInstaller.test_dependency(iDepDesc)
                if (!lSuccess)
                  # It is useless to continue
                  break
                end
              end
            else
              # Load other dependencies
              lError, lContextModifiers, lIgnored, lUnresolved = lRDIInstaller.ensure_dependencies(lDesc[:Dependencies])
              if (lRDIContextModifiers != nil)
                lRDIContextModifiers.merge!(lContextModifiers)
              end
              lSuccess = ((lError == nil) and
                          (lIgnored.empty?) and
                          (lUnresolved.empty?))
              if (!lSuccess)
                if (!lIgnored.empty?)
                  rError = PluginDependenciesIgnoredError.new("Unable to load plugin #{iPluginName} without its dependencies (ignored #{lIgnored.size} dependencies).")
                elsif (!lUnresolved.empty?)
                  rError = PluginDependenciesUnresolvedError.new("Unable to load plugin #{iPluginName} without its dependencies (couldn't load #{lUnresolved.size} dependencies):\n#{lError}")
                else
                  rError = PluginDependenciesError.new("Could not load dependencies for plugin #{iPluginName}: #{lError}")
                end
              end
            end
          end
        end
        if (lSuccess)
          if (lDesc[:PluginsDependencies] != nil)
            # Load other plugins
            lDesc[:PluginsDependencies].each do |iPluginInfo|
              iPluginCategory, iPluginName = iPluginInfo
              _, lError = get_plugin_instance(iPluginCategory, iPluginName, iParameters)
              lSuccess = (lError == nil)
              if (!lSuccess)
                # Don't try further
                rError = PluginDependenciesError.new("Could not load plugins dependencies for plugin #{iPluginName}: #{lError}.")
                break
              end
            end
          end
          if (lSuccess)
            # Load the plugin
            begin
              # If the file name is to be required, do it now
              if (lDesc[:PluginFileName] != nil)
                require lDesc[:PluginFileName]
              end
              lPlugin = eval("#{lDesc[:PluginClassName]}.new")
              # Add a reference to the description in the instantiated object
              lPlugin.instance_variable_set(:@rUtilAnts_Desc, lDesc)
              def lPlugin.pluginDescription
                return @rUtilAnts_Desc
              end
              # Register this instance
              lDesc[:PluginInstance] = lPlugin
              # If needed, execute the init code
              if (lDesc[:PluginInitCode] != nil)
                lDesc[:PluginInitCode].call(lPlugin)
              end
            rescue Exception
              rError = FailedPluginError.new("Error while loading file #{lDesc[:PluginFileName]} and instantiating #{lDesc[:PluginClassName]}: #{$!}. Ignoring this plugin.")
            end
          end
        end
      end
      rPlugin = lDesc[:PluginInstance]
    end
  end

  return rPlugin, rError
end

#get_plugins_descriptions(iCategoryName, iParameters = {}) ⇒ Object

Get the map of plugins descriptions, indexed with plugin names

Parameters
  • iCategoryName (String): The category for which we want the plugin names list

  • iParameters (map<Symbol,Object>): Additional parameters:

    • IncludeDisabled (Boolean): Do we include disabled plugins ? [optional = false]

Return
  • map<String,map<Symbol,Object>>: The map of plugin descriptions per plugin name



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/rUtilAnts/Plugins.rb', line 344

def get_plugins_descriptions(iCategoryName, iParameters = {})
  rPlugins = {}

  lIncludeDisabled = iParameters[:IncludeDisabled]
  if (lIncludeDisabled == nil)
    lIncludeDisabled = false
  end
  if (@Plugins[iCategoryName] != nil)
    if (lIncludeDisabled)
      rPlugins = @Plugins[iCategoryName]
    else
      @Plugins[iCategoryName].each do |iPluginName, iPluginDesc|
        if (iPluginDesc[:Enabled] != false)
          rPlugins[iPluginName] = iPluginDesc
        end
      end
    end
  end

  return rPlugins
end

#get_plugins_names(iCategoryName, iParameters = {}) ⇒ Object

Get the list of plugin names of a given category

Parameters
  • iCategoryName (String): The category for which we want the plugin names list

  • iParameters (map<Symbol,Object>): Additional parameters:

    • IncludeDisabled (Boolean): Do we include disabled plugins ? [optional = false]

Return
  • list<String>: The list of plugin names in this category



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/rUtilAnts/Plugins.rb', line 317

def get_plugins_names(iCategoryName, iParameters = {})
  rPlugins = []

  lIncludeDisabled = iParameters[:IncludeDisabled]
  if (lIncludeDisabled == nil)
    lIncludeDisabled = false
  end
  if (@Plugins[iCategoryName] != nil)
    @Plugins[iCategoryName].each do |iPluginName, iPluginDesc|
      if ((lIncludeDisabled) or
          (iPluginDesc[:Enabled] != false))
        rPlugins << iPluginName
      end
    end
  end

  return rPlugins
end

#init_pluginsObject

Constructor



54
55
56
57
58
# File 'lib/rUtilAnts/Plugins.rb', line 54

def init_plugins
  # Map of plugins, per category
  # map< String, map< String, map< Symbol, Object > > >
  @Plugins = {}
end

#parse_plugins_from_dir(iCategory, iDir, iBaseClassNames, &iInitCodeBlock) ⇒ Object

Parse plugins from a given directory

Parameters
  • iCategory (Object): Category those plugins will belong to

  • iDir (String): Directory to parse for plugins

  • iBaseClassNames (String): The base class name of plugins to be instantiated

  • iInitCodeBlock (CodeBlock): Code to be executed first time the plugin will be instantiated (can be ommitted):

    • ioPlugin (Object): Plugin instance



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
# File 'lib/rUtilAnts/Plugins.rb', line 98

def parse_plugins_from_dir(iCategory, iDir, iBaseClassNames, &iInitCodeBlock)
  # Gather descriptions
  # map< String, map >
  lDescriptions = {}
  lDescFiles = Dir.glob("#{iDir}/*.desc.rb")
  lDescFiles.each do |iFileName|
    lPluginName = File.basename(iFileName)[0..-9]
    # Load the description file
    begin
      File.open(iFileName) do |iFile|
        lDesc = eval(iFile.read, nil, iFileName)
        if (lDesc.is_a?(Hash))
          lDescriptions[lPluginName] = lDesc
        else
          log_bug "Plugin description #{iFileName} is incorrect. The file should just describe a simple hash map."
        end
      end
    rescue Exception
      log_exc $!, "Error while loading file #{iFileName}. Ignoring this description."
    end
  end
  # Now, parse the plugins themselves
  if (@Plugins[iCategory] == nil)
    @Plugins[iCategory] = {}
  end
  (Dir.glob("#{iDir}/*.rb") - lDescFiles).each do |iFileName|
    lPluginName = File.basename(iFileName)[0..-4]
    # Don't load it now, but store it along with its description if it exists
    if (@Plugins[iCategory][lPluginName] == nil)
      # Check if we have a description
      register_new_plugin(
        iCategory,
        lPluginName,
        iFileName,
        lDescriptions[lPluginName],
        "#{iBaseClassNames}::#{lPluginName}",
        iInitCodeBlock
      )
    else
      log_warn "Plugin named #{lPluginName} in category #{iCategory} already exists. Please name it differently. Ignoring it from #{iFileName}."
    end
  end
end

#register_new_plugin(iCategoryName, iPluginName, iFileName, iDesc, iClassName, iInitCodeBlock) ⇒ Object

Register a new plugin

Parameters
  • iCategoryName (String): Category this plugin belongs to

  • iPluginName (String): Plugin name

  • iFileName (String): File name containing the plugin (can be nil)

  • iDesc (map<Symbol,Object>): Plugin’s description (can be nil)

  • iClassName (String): Name of the plugin class

  • iInitCodeBlock (Proc): Code block to call when initializing the real instance (can be nil)



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/rUtilAnts/Plugins.rb', line 69

def register_new_plugin(iCategoryName, iPluginName, iFileName, iDesc, iClassName, iInitCodeBlock)
  # Complete the description with some metadata
  if (@Plugins[iCategoryName] == nil)
    @Plugins[iCategoryName] = {}
  end
  lDesc = nil
  if (iDesc == nil)
    lDesc = {}
  else
    lDesc = iDesc.clone
  end
  lDesc[:PluginFileName] = iFileName
  lDesc[:PluginInstance] = nil
  lDesc[:PluginClassName] = iClassName
  lDesc[:PluginInitCode] = iInitCodeBlock
  lDesc[:PluginIndex] = @Plugins[iCategoryName].size
  lDesc[:PluginName] = iPluginName
  lDesc[:PluginCategoryName] = iCategoryName
  @Plugins[iCategoryName][iPluginName] = lDesc
end