A question about how file_loaded? works

I’ve changed my implementation and now I have separate loader file.
The 1st file is fms_Temp.rb

Sketchup.require 'sketchup.rb'
Sketchup.require 'extensions.rb'

	# Sketchup's Extension class provides a user interface in Sketchup for installing and removing plugins (now called extensions). 
	module FMS_Temp_module
		#Register the FMS_Temp_module Tools with SU's extension manager
		loader = File.join(File.dirname(__FILE__), "fms_Temp", "Temp.rb")
		tempExtension = SketchupExtension.new("Temp", loader)
    
		#extension details
		tempExtension.description="Adds TempWhatsitThingumy to the Extensions menu for creating TempWhatsitThingumies."
		tempExtension.version = "1.0"
		tempExtension.creator = "Francis Mc Shane"
		tempExtension.copyright = "2018"
		
		Sketchup.register_extension(tempExtension, true) # show on 1st install 

	end # module FMS_Temp_module

the 2nd file is the loader file called Temp.rb

module FMS_Temp_module

  require File.join(File.dirname(__FILE__), "Temp1.rb")
  
  require File.join(File.dirname(__FILE__), "Temp2.rb")
  
  unless @loaded
    @loaded = true
    extensions_menu = UI.menu("Extensions")
    extensions_menu.add_item("TempWhatsitThingumy") {
      stuff=UI.inputbox(["Input whatsit","Input thingumy"], ["Car", "James"], "Input 2 items.")
      obj = FMS_Temp_module::Temp_class2.new(stuff[0], stuff[1])
      obj.method_temp_class2
      }
  end
  puts("In file Temp.rb and module variable @loaded is #{@loaded}.")
end # of module FMS_Temp_module

the 3rd file defines a class and is called Temp1.rb

module FMS_Temp_module

  class Temp_class1

    def initialize(whatsit)
      @whatsit = whatsit
    end
    def method_temp_class1
    
      puts"In method_temp_class1 of class Temp_class1 and @whatsit is #{@whatsit}. Change this flowery text to show a change to this method's output message."
    
    end
    
  end # of class Temp_class1
  
end # of module FMS_Temp_module

and the 4th file defines another class dependant on the first class and is called Temp2.rb

module FMS_Temp_module

  class Temp_class2 < FMS_Temp_module::Temp_class1

    def initialize(whatsit="Car", thingumy="James")
      super(whatsit)
      @thingumy = thingumy
    end
    def method_temp_class2
    
      puts"In method_temp_class2 of class method_temp_class2 and @whatsit is #{@whatsit}. Change this text to show a change to this method's first message."
      puts"In method_temp_class2 of class Temp_class2 and @thingumy is #{@thingumy}. Change this text to show a change to this method's 2nd message."
    
    end
    
  end # of class Temp_class2
  
end # of module FMS_Temp_module

Hoping this is good. I’ve also tried it with eneroth3’s @loaded instead of @@loaded and that works fine too.

Thank you for much appreciated help.

Now Temp1.rb and Temp.rb are unnecessarily interconnected. @@loaded is defined as false in one and then referenced in the other. If you reload the one defining @@loaded as false, and then the other, the code that was only supposed to run once still runs twice.

By using an @instance_var, and not define as false anywhere, you get around both this issues.

Naturally you are correct! Somehow I missed the fact that I had defined @@loaded in a previously loaded file (I had to define it somewhere!) but that, as you rightly point out, resets what it should be (true) to false when I edit and reload that file. It could possibly be located in a file of its own but your solution is the most elegant.

So delete the @@loaded assignment in Temp.rb and use @loaded in the conditional.

I’ll edit my posted code to your suggestion.

1 Like

It does not matter if it still is within the same module. In his example all the files are connected because they modify the same plugin module. There is nothing wrong with this. Modules are broken up into multiple files for easier maintainability.

I have a current project with the main plugin module broken into at least 10 files. And there is likely to be more before it’s done.

Which is why (when we use class or module variables,) we use conditional declarations.

Ie for non-boolean references such as strings, hashes or arrays …

@@thingy_title ||= "Nifty Thing"
@@options ||= { autosave => false }
# ... etc.

But for boolean references we cannot use the ||= operator, we must do this …

@@auto_widget = false unless defined?(@@auto_widget)

This way reloading will not redefine these references.


What I do is first define the @@loaded reference then use it immediately as the conditional expression for a block that defines all the extension’s constants and module vars …

module Author::SomePlugin

  @@loaded = false unless defined?(@@loaded)
  unless @@loaded
    # define constants
    # define module vars
  end

end

I also see you are using the core Ruby require() method.

If you end up scrambling / encrypting your code, you’ll need to use Sketchup::require() instead.

I like the conditional assignation idea.

I need to thoroughly check out the difference between load and require.

I found this to be a really helpful discussion.
Thank you.

Sketchup::require() and Sketchup::load() are the SAME method. One just aliases the other. (They should NOT be this way. This was one of the worst decisions ever made in the SketchUp API implementation.)

Kernel::require() and Kernel::load() are quite distinct from one another.

1 Like

While the Ruby interpreter doesn’t care very much about files I’d avoid having a file structure that doesn’t match the architectrue of the program. If a module can be divided into logical chunks, each defined by its own file, it can most likely be divided into separate classes/modules too.

Sometimes this might work out. Other times not. This is not some hard and fast rule.

When I have major nested classes or sub-modules I’ll often have their code files in a sub-directory because they often have multiple files as well.

I’ll look hard at all of these methods.