Modules, etc.

Overview

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. In fact, PF_Browser_Dialog and PF_Dialog are the only "normal" classes (ie, statically defined, treated like nouns).

Lazy Loading

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. Specifically, load_sketchapps.rb scans the SketchApps directory, identifying, reading, and loading each SketchApps plugin.

Basics

During this initial loading process, each plugin:

  • defines a class containing a main() method

  • tells PF which menu items (etc) it wants

When and if the plugin is invoked (eg, by a menu item or tool), its main() 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.

Details (Loading)

main() calls setup_libs(), which calls setup_lib() to load the Framework library files. In development mode, these are loaded from a common area:

.../SketchApps_dev/_Libraries/_Framework/...

In normal mode, these are loaded from the plugin set's own area, eg:

.../SketchApps/CFCL/_Libraries/_Framework/...

setup_lib() uses Kernel.load() to evaluate each library file's code. Plugin-specific libraries are loaded in the plugin's anonymous module. External libraries (eg, ERB.rb) load into the global namespace.

Details (Usage)

Currently, load_sketchapps.rb stores references to loaded classes in the $sketchapps_refs hash. Typically, each plugin's setup() method extracts these references and stores them in instance variables (eg, @ev, @md, @pf). The plugin can then call the needed methods (eg, @pf.log.debug).

Note: I'm considering reworking this mechanism to use native Ruby facilities, eg:

  • Each library would have an explicit path.
    (eg, SketchApps::Framework::ERb_View)

  • Plugins would define "constant aliases" (eg, EV),
    and use them in place of the current instance variables.

Source Code

The source code for the Plugin Framework's classes and modules is contained in several file trees.

bin and etc

Files in bin are executable scripts, for use by developers. Files in etc are "miscellany", for use by the framework:

  SketchApps/CFCL/_Framework/Common/Code/
  | bin/
  | | bd_proxy:                 class"  BD_Proxy
  | | court:                    class"  Court
  | | make_dev:                 class"  Make_Dev

  | etc/Ruby/
  | | load_sketchapps.rb:       module  Load_SketchApps
  | | ...                       class*  Load_SketchApps::Loader

lib/Ruby

Files in lib/Ruby are Ruby libraries, for use by applications and/or the framework:

  | lib/Ruby/
  | | 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

Packaging

Files in bin are Ruby libraries and scripts, for use by developers to create archives, etc. Files in PackageMaker are Ruby scripts, for use by Apple's PackageMaker (installer creation) tool.

  SketchApps/CFCL/_Framework/Packaging/
  | bin/
  | | ft_lib.rb:                module  FT_Lib
  | | ft_pkg:                   class"  FT_Pkg
  | | ft_pkgs:                  class"  FT_Pkgs
  | | ft_ver:                   class"  FT_Ver
  | PackageMaker/
  | | pm_1_pre:                 class"  PM_1_Pre
  | | pm_2_post:                class"  PM_2_Post

Legend

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!

Topic revision: r4 - 22 Oct 2012, RichMorin
This site is powered by Foswiki Copyright © by the contributing authors. All material on this wiki is the property of the contributing authors.
Foswiki version v2.1.6, Release Foswiki-2.1.6, Plugin API version 2.4
Ideas, requests, problems regarding CFCL Wiki? Send us email