Plugin folder structure - Is it a good habit to extend search path?

plugin
extension

#1

Hi,

My plugin folder is now organized based on the SU guidelines for extensions.

I have noticed that some authors extend the search path for Ruby with something like

basedir = File.dirname(__FILE__)
$:.push(File.join(basedir, 'plugin_folder_name'))

This allows to require files without specifying the path.

I was wondering whether this is actually a good idea. If two authors create a file with the same name, then only the first file would be loaded from require and this is not necessarily the right one. Am I understanding it correctly?

I was thinking to a way to make the plugin independent from the main plugin file in the Plugin folder and I thought that the following approach should work. I first define three constants:

PLUGIN_NAME      = File.basename( __FILE__, ".*").freeze
PLUGIN_PATH_ROOT = File.dirname( __FILE__ ).freeze
PLUGIN_PATH      = File.join( PLUGIN_PATH_ROOT, PLUGIN_NAME ).freeze

I would then replace all the requires in my code with

require File.join(PLUGIN_PATH, 'file_required')

In this way, if I want to change the plugin name (and I need to do that in the future) I can simply change the main rb file and the corresponding folder name

Is this the recommended approach?

Corollary question about require: would it make sense to put all the requires in the loader file within the respective plugin folder?

Thanks


#2

You understand correctly. There is no good reason to add paths to Ruby’s search path.


#3

you can achieves the same with

require_relative   'file_required'

IMHO, too many plugins overload Ruby with occasional use methods…

To ensure none get loaded before the user actually wants to use them,
I tend to use the menu file to load the ‘loaders’ needed for my plugins…
it will add the menu items, toolbars and occasionally relevant observers, then only when called, they load the required logic…

command1 = UI::Command.new("Add This Now"){
                          load( File.join(File.dirname(__FILE__), "Add_This_Now_logic.rb"))}

This also ensures my logic has precedence…

john


#4

Yes, this is how most of us do it. Also some of this path creation has been built into the SketchupExtension class (in later versions.)
Read “Tools/extensions.rb


#5

I am trying to use this technique with my plugin but the problem is that after the menu item runs once it will not fire again.
Here is a snippet of the Medeek_Load.rb file :

module Medeek_Engineering_Inc_Extensions

	module MedeekTrussPluginModuleLoader

	# Show the Ruby Console at startup so we can
	# see any programming errors we may make.
	# SKETCHUP_CONSOLE.show

	# First we pull in the standard API hooks.


	this_dir=File.dirname(__FILE__)
	# Fix for ruby 2.0
	if this_dir.respond_to?(:force_encoding)
		this_dir=this_dir.dup.force_encoding("UTF-8")
	end
	PATH=this_dir
	entries=Dir.entries(this_dir)
	ext=".rbs"


	# Add a toolbar item to launch our plugin.

	toolbar = UI::Toolbar.new "Medeek Truss"

cmd = UI::Command.new("Draw Roof Truss") {

		Sketchup.load(File.join(this_dir,"MEDEEK_ROOF_TRUSS.rbs"))
}
	cmd.small_icon = "images/mdkplg_tool_icon16_2.png"
	cmd.large_icon = "images/mdkplg_tool_icon24_2.png"
	cmd.tooltip = "Medeek Truss"
	cmd.status_bar_text = "Draw Roof Truss"
	cmd.menu_text = "Roof Truss"
	toolbar = toolbar.add_item cmd
	# toolbar.show

	cmd2 = UI::Command.new("Draw Floor Truss") {

	Sketchup.load(File.join(this_dir,"MEDEEK_FLOOR_TRUSS.rbs"))
}
	cmd2.small_icon = "images/mdkplg_tool_icon16_3.png"
	cmd2.large_icon = "images/mdkplg_tool_icon24_3.png"
	cmd2.tooltip = "Medeek Truss"
	cmd2.status_bar_text = "Draw Floor Truss"
	cmd2.menu_text = "Floor Truss"
	toolbar = toolbar.add_item cmd2
	# toolbar.show

	cmd3 = UI::Command.new("Draw Truss Set") {

	Sketchup.load(File.join(this_dir,"MEDEEK_TRUSS_SET.rbs"))
}
	cmd3.small_icon = "images/mdkplg_tool_icon16_4.png"
	cmd3.large_icon = "images/mdkplg_tool_icon24_4.png"
	cmd3.tooltip = "Medeek Truss"
	cmd3.status_bar_text = "Draw Truss Set"
	cmd3.menu_text = "Truss Set"
	toolbar = toolbar.add_item cmd3
	toolbar.show

	cmd4 = UI::Command.new("Draw Roof Rafters") {

	Sketchup.load(File.join(this_dir,"MEDEEK_ROOF_RAFTERS.rbs"))
}
	cmd4.small_icon = "images/mdkplg_tool_icon16_5.png"
	cmd4.large_icon = "images/mdkplg_tool_icon24_5.png"
	cmd4.tooltip = "Medeek Truss"
	cmd4.status_bar_text = "Draw Roof Rafters"
	cmd4.menu_text = "Roof Rafters"
	toolbar = toolbar.add_item cmd4
	toolbar.show


	# Add a menu item to launch our plugin.

	submenu = UI.menu("Plugins").add_submenu("Medeek Truss")
	submenu.add_item("Roof Truss") { Sketchup.load(File.join(this_dir,"MEDEEK_ROOF_TRUSS.rbs")) }
	submenu.add_item("Floor Truss") { Sketchup.load(File.join(this_dir,"MEDEEK_FLOOR_TRUSS.rbs")) }
	submenu.add_item("Truss Set") { Sketchup.load(File.join(this_dir,"MEDEEK_TRUSS_SET.rbs")) }
	submenu.add_item("Roof Rafters") { Sketchup.load(File.join(this_dir,"MEDEEK_ROOF_RAFTERS.rbs")) }
	


	end
end

#6

It depends if you have a call as the last line in the file, or as part of the command…
in this example I call JcB::TransL8.get_text from the command2…

      if @dev_mode

        transL8_menu = UI.menu('Help',(TRANSL8["Add Translation to Plugin"]))

        command2 = UI::Command.new((TRANSL8["Add Translation to Plugin"])){
                                load( File.join(File.dirname(__FILE__), 'transL8_process.rb'))
                                JcB::TransL8.get_text 
}

        transL8_menu.add_item(command2)

      end

once you have a command you can reuse it for both menu and toolbar…
for a .rbs you may need to use Sketchup.require…
for your toolbar it is better to use restore for people who want it ‘off’…

john


#7

For the first item I call up the file “MEDEEK_ROOF_TRUSS.rbs”, the code in this file in very condensed form looks like:

require 'sketchup.rb'
require 'extensions.rb'
require 'langhandler.rb'

module Medeek_Engineering_Inc_Extensions

	module MedeekTrussPlugin


##############################
#
# Class Methods of Plugin
#
##############################

class MedeekMethods
  	class << self

include Math

def some method name

{

}

def another method name

{

}

end # << self
end # MedeekMethods Class

###########################
#
# Main Entry into Program
#
###########################

MedeekMethods.roof_truss_family_menu


end # MedeekTrussPlugin

end # Medeek Module


#8

I guess I’m not fully understanding how to make this work. I will study your example above and see if I can implement it.

My original code was all contained within one file and now it has become rather lengthy and unmanageable. The idea is to break it into four separate files and only that portion of the code that pertains is loaded when a user clicks on a menu item or toolbar icon.

I am very new to Ruby programming so I apologize for my ignorance.


#9

not a problem…

each file still needs a command, with plain .rb files this can be either the last line, or in the menu cmd…

with .rbs that may need to be in the menu cmd…

if it is there, you can use require rather than load…

for your example it’s something like…
Medeek_Engineering_Inc_Extensions::MedeekTrussPlugin::MedeekMethods.roof_truss_family_menu

john


#10

This revised code seems to work:

module Medeek_Engineering_Inc_Extensions

module MedeekTrussPluginModuleLoader


require 'sketchup.rb'
require 'extensions.rb'
require 'langhandler.rb'

# Show the Ruby Console at startup so we can
# see any programming errors we may make.
# SKETCHUP_CONSOLE.show




this_dir=File.dirname(__FILE__)
# Fix for ruby 2.0
if this_dir.respond_to?(:force_encoding)
	this_dir=this_dir.dup.force_encoding("UTF-8")
end
PATH=this_dir
entries=Dir.entries(this_dir)
ext=".rbs"


# Add a toolbar item to launch our plugin.

toolbar = UI::Toolbar.new "Medeek Truss"
 	
 	cmd = UI::Command.new("Draw Roof Truss") {

	Sketchup.load(File.join(this_dir,"MEDEEK_ROOF_TRUSS.rbs"))
	Medeek_Engineering_Inc_Extensions::MedeekTrussPlugin::MedeekMethods.roof_truss_family_menu
 	}
		cmd.small_icon = "images/mdkplg_tool_icon16_2.png"
 		cmd.large_icon = "images/mdkplg_tool_icon24_2.png"
 		cmd.tooltip = "Medeek Truss"
		cmd.status_bar_text = "Draw Roof Truss"
		cmd.menu_text = "Roof Truss"
 		toolbar = toolbar.add_item cmd
 		# toolbar.show

cmd2 = UI::Command.new("Draw Floor Truss") {

   		Sketchup.load(File.join(this_dir,"MEDEEK_FLOOR_TRUSS.rbs"))
	Medeek_Engineering_Inc_Extensions::MedeekTrussPlugin::FloorTruss::MedeekMethods.floor_truss_family_menu
 	}
		cmd2.small_icon = "images/mdkplg_tool_icon16_3.png"
 		cmd2.large_icon = "images/mdkplg_tool_icon24_3.png"
 		cmd2.tooltip = "Medeek Truss"
		cmd2.status_bar_text = "Draw Floor Truss"
		cmd2.menu_text = "Floor Truss"
 		toolbar = toolbar.add_item cmd2
 		# toolbar.show

cmd3 = UI::Command.new("Draw Truss Set") {

   		Sketchup.load(File.join(this_dir,"MEDEEK_TRUSS_SET.rbs"))
	Medeek_Engineering_Inc_Extensions::MedeekTrussPlugin::TrussSet::MedeekMethods.truss_set_family_menu
 	}
		cmd3.small_icon = "images/mdkplg_tool_icon16_4.png"
 		cmd3.large_icon = "images/mdkplg_tool_icon24_4.png"
 		cmd3.tooltip = "Medeek Truss"
		cmd3.status_bar_text = "Draw Truss Set"
		cmd3.menu_text = "Truss Set"
 		toolbar = toolbar.add_item cmd3
 		# toolbar.show

cmd4 = UI::Command.new("Draw Roof Rafters") {

   		Sketchup.load(File.join(this_dir,"MEDEEK_ROOF_RAFTERS.rbs"))
	Medeek_Engineering_Inc_Extensions::MedeekTrussPlugin::RoofRafters::MedeekMethods.roof_rafters_family_menu
 	}
		cmd4.small_icon = "images/mdkplg_tool_icon16_5.png"
 		cmd4.large_icon = "images/mdkplg_tool_icon24_5.png"
 		cmd4.tooltip = "Medeek Truss"
		cmd4.status_bar_text = "Draw Roof Rafters"
		cmd4.menu_text = "Roof Rafters"
 		toolbar = toolbar.add_item cmd4
 		toolbar.show


# Add a menu item to launch our plugin.

submenu = UI.menu("Plugins").add_submenu("Medeek Truss")
submenu.add_item(cmd)
submenu.add_item(cmd2)
submenu.add_item(cmd3)
submenu.add_item(cmd4)



end

end

Thank-you for the assistance. A simple fix but it had me stumped for a few hours.