[Example] An extension registrar file that checks for and loads Dynamic Components

[Example] An extension registrar file that checks for and loads Dynamic Components.

This is a dummy example extension (has no functions) other than to check for and attempt to load the Dynamic Components extension before it loads it’s own extension code.

This might be needed if the extension references any Ruby objects defined by the DC extension.

If the DC extension cannot be found or loaded, this extension will not load itself, output console messages and display a popup notification in the lower-right corner.

The registrar file without the dummy "main.rb" and icon file:

# encoding: UTF-8

# An sample extension registrar file that requires Dynamic Components. If the
# user has switched off the Dynamic Components extension, then this registrar
# file will reenable it and make it load.
#
# Assumes this registrar file name is: "SomeCompany_ExtensionNeedsDC.rb" and
# that the extension subfolder is named: "SomeCompany_ExtensionNeedsDC" and
# contains a loader file named "main.rb" (or "main.rbe" if encrypted.)
#
# In practice, the programmer will change the top-level namespace module name
# and the extension submodule name as necessary, then enter valid properties
# for the EXTENSION data object.

# DEPENDANCY - Allow the DC extension registrar script to be evaluated first:
load_error = nil
begin
  require 'su_dynamiccomponents'
rescue LoadError => load_error
  puts load_error.inspect
end

module SomeCompany
  module ExtensionNeedsDC

    VERSION ||= "1.0.0"
    KEY ||= Module.nesting[0].name # A key for saving defaults, options, etc.

    @notice = nil


    # Instantiate a SketchupExtension data object:
    EXTENSION ||= SketchupExtension.new(
      KEY.gsub('::','_'), # <--<<< The extension name for the Extension Manager
      "#{KEY.gsub('::','_')}/main"
    )
    # Set the extension data properties:
    EXTENSION.instance_eval {
      self.version = VERSION
      self.creator = "Author at SomeCompany"
      self.copyright = "©2025, SomeCompany, LLC"
      self.description = "An extension does nifty things for SketchUp modeling."
    }

    # Checks if the DC extension is already loaded, if not attempts to load it.
    # @return [nil] If the DC extension could not be found.
    # @return [Boolean] If the DC is loaded, false if it is not loaded.
    def self.is_dc_extension_loaded?
      # Make sure that the DC extension is loaded:
      if defined?($dc_extension)
        dc_name = $dc_extension.name
        dc_extn = $dc_extension
      else
        if defined?($dc_strings)
          dc_name = $dc_strings["Dynamic Components"]
        else
          text = LanguageHandler.new("dynamiccomponents.strings")
          # If text.strings is empty the file could not be found so, the
          # lookup hash is empty and text[] returns the argument unchanged.
          dc_name = text["Dynamic Components"]
        end
        dc_extn = Sketchup.extensions[dc_name]
      end
      if dc_extn # nil if not found
        # If not loaded, then check it to load it:
        if dc_extn.loaded?
          puts "#{KEY}: The #{dc_name} extension is loaded. All is good."
          return true
        else
          puts "#{KEY}: Attempting to load the #{dc_name} extension ..."
          dc_extn.check # loads the extension's files
          if dc_extn.loaded? # true | false
            puts "#{KEY}: The #{dc_name} extension is now loaded. All is good."
            return true
          else
            return false # message will be output in load_conditionally()
          end
        end
      else
        return nil
      end
      #
    end ### is_dc_extension_loaded?()

    # Loads the EXTENSION upon the condition that the Dynamic Components
    # extension is loaded. If not, display console messages and a popup
    # notification to the user in SketchUp's bottom right corner.
    def self.load_conditionally
      # If this EXTENSION's extension code references any of the DC modules
      # or classes, then make sure that the DC extension is loaded before this
      # EXTENSION is registered because it will then load and likley produce
      # a NameError exception, etc.
      success = self.is_dc_extension_loaded?
      if success
        Sketchup.register_extension(EXTENSION, true)
      else
        # If EXTENSION was registered in a previous session & the user had it
        # switched on in Extension Manager, then it will still load & override a
        # false load arg in:
        # `Sketchup.register_extension(EXTENSION, false)`, so we skip registration.
        #
        # Notify the user that the DC extension is required:
        if success.nil?
          action = 'found'
        elsif success == false
          action = 'loaded'
        end
        message = "#{KEY}: The Dynamic Components extension could not be #{action}.\n\n"
        puts message
        EXTENSION.define_singleton_method(:error) { message }
        # Show a popup UI::Notification informing the user:
        preamble = %["#{EXTENSION.name}" requires the \r\n] +
          %[ Dynamic Components extension, but it could \r\n]
        message = preamble + " not be #{action}!\r\n"
        @notice = UI::Notification.new(EXTENSION, message)
        icon = File.join(__dir__, KEY.gsub('::','_'), 'warning48.png')
        #puts icon
        #puts "exist: #{File.exist?(icon)}"
        @notice.icon_name = icon
        @notice.show # for 10 seconds max 2021.1+
      end
    end ### load_conditionally()

    # Later cleanup:
    UI.start_timer(120.0, false) {
      puts "#{KEY}: Cleaning up ..."
      @notice = nil if @notice
      remove_instance_variable :@notice
      singleton_class.undef_method :is_dc_extension_loaded?
      singleton_class.undef_method :load_conditionally
    }

    # Attempt to load EXTENSION:
    self.load_conditionally

  end # extension submodule
end # top-level namepsace module

raise(load_error) if load_error
2 Likes