The Plugin Framework (PF) attempts
to keep plugins from clashing with other Ruby namespaces
(eg, other plugins, Ruby, SketchUp, and PF itself),
while allowing intentional access to these namespaces.
For example, a plugin may need to invoke a related plugin,
call one of its methods, and/or share library code.
Consequently, PF handles modules, classes, methods,
and related items in a rather unusual manner.
For example, some classes are created dynamically,
while others are basically modules.
are the only "normal" classes
(ie, statically defined, treated like nouns).
A SketchUp user may have dozens of plugins,
most of which will not be invoked in a typical session.
The loading of these plugins consumes valuable resources
(eg, processor memory, startup time),
making SketchUp less responsive than it should be.
In order to minimize this unproductive resource usage,
PF implements a form of lazy loading
scans the SketchApps directory,
identifying, reading, and loading each SketchApps plugin.
During this initial loading process, each plugin:
- defines a class containing a
- tells PF which menu items (etc) it wants
When and if the plugin is invoked (eg, by a menu item or tool),
method is executed.
After causing the rest of the plugin's code
(including support libraries) to be loaded,
this method typically calls assorted setup routines
(eg, registering WebDialog callbacks) and exits.
As described in Plugin Loading
each PF plugin is loaded into an anonymous module.
So, class or module definitions made by the plugin
are sequestered (by default) into a separate namespace.
, which calls
to load the Framework library files.
In development mode, these are loaded from a common area:
In normal mode, these are loaded from the plugin set's own area, eg:
to evaluate each library file's code.
Plugin-specific libraries are loaded in the plugin's anonymous module.
External libraries (eg,
) load into the global namespace.
stores references to loaded classes
Typically, each plugin's
method extracts these references
and stores them in instance variables (eg,
The plugin can then call the needed methods (eg,
I'm considering reworking this mechanism to use native Ruby facilities, eg:
- Each library would have an explicit path.
- Plugins would define "constant aliases" (eg,
and use them in place of the current instance variables.
The source code for the Plugin Framework's classes and modules
is contained in several file trees.
bin and etc
are executable scripts, for use by developers.
are "miscellany", for use by the framework:
| | bd_proxy: class" BD_Proxy
| | court: class" Court
| | make_dev: class" Make_Dev
| | load_sketchapps.rb: module Load_SketchApps
| | ... class* Load_SketchApps::Loader
are Ruby libraries,
for use by applications and/or the framework:
| | pf_browser_dialog.rb: class PF_Browser_Dialog
| | pf_common.rb: module PF_Incl
| | pf_dialog.rb: class PF_Dialog
| | ... class* PF_Gen_Help
| | pf_erb_view.rb: class* PF_ERb_View
| | pf_gen_js.rb: class* PF_Gen_JS
| | pf_logger.rb: class* PF_Logger
| | ... class' << self
| | pf_main.rb: class* PF_Main
| | pf_model.rb: class* PF_Model
are Ruby libraries and scripts,
for use by developers to create archives, etc.
are Ruby scripts,
for use by Apple's PackageMaker (installer creation) tool.
| | ft_lib.rb: module FT_Lib
| | ft_pkg: class" FT_Pkg
| | ft_pkgs: class" FT_Pkgs
| | ft_ver: class" FT_Ver
| | pm_1_pre: class" PM_1_Pre
| | pm_2_post: class" PM_2_Post
Some of the layouts above require a bit of explanation:
class* - These classes should probably be modules, but we want to set up and maintain contextual instance variables.
class' - This class only exists to support a singleton method.
class" - These classes only exist to keep YARD happy.
This wiki page is maintained by Rich Morin
an independent consultant specializing in software design, development, and documentation.
Please feel free to email
comments, inquiries, suggestions, etc!