Error - short_class_name method undefined, in parametric.rb

I’ve getting this error in the Ruby console when running a test plugin that uses the parametric.rb file (with module name changed) from another plugin from Sketchucation, and the same from a second (Grid) from the Extension Warehouse.

Error: #<NoMethodError: undefined method `short_class_name' for JWM::Flat:Module>
/Users/JohnWMcC/Library/Application Support/SketchUp 2020/SketchUp/Plugins/JWM_Flats/parametric.rb:407:in `block in <module:Flat>'

And while I don’t get the error in the su_grid plugin, freshly downloaded and installed from the Extension Warehouse, and after a restart of SU. It exhibits the behaviour this error causes. R-click on the grid and the context menu now says Edit::Sketchup::Samples::Grid::Grid.

It used to say just Edit Grid (using the short_class_name)


I can see the definition in the code, and it used to work fine in an earlier version of SU.

    # Generate a human friendly name of the class, omitting the ancestors.
    def short_class_name"::").last

What’s changed so this no longer works? The su_grid doesn’t trigger the error but looks as if it has a similar cause.

The output in the context menu comes from

        if Parametric.selection_parametric?
          menu.add_item("Edit #{short_class_name}") { Parametric.edit_selection }

Probably because you changed the module name or wrapped it inside another module:

I don’t know what file each of those bits of code are in so don’t know how you’d call the short_class_name method.

It’s hard to say what’s wrong without having the full code. Maybe prepending self. to the short_class_name works. Otherwise extend self.

I thought it might have been something I did, but it no longer works properly even in the SU grid plugin.
su_grid_111.rbz (6.9 KB)

That’s the version I installed, and even after a fresh download, deleting the old file and folder, then reinstalling and re-starting SU, the behaviour is still the same.

OOPS - the parametric file got left out of my .rbz.

Wrong version of the plugin altogether. That was a previous version without the parametric additions.

But it’s the same issue as in the Grid plugin. short_class_name is not defined, or at least isn’t working properly.

Will try to find my almost working test parametric version for Flats only

su_grid/grid.rb just has a string “Grid” for the menu name, it’s not using that above short_class_name method.

if (not $grid_loaded)
    add_separator_to_ ("Tools")"Tools").add_item("Grid") {
    $grid_loaded = true

The grid extension seems to work ok here, unless you think it’s a bug that it displays the full class name of the object selected in the context menu.
In su_grid/parametric.rb:

if (not $parametric_loaded)
    $parametric_loaded = true

    UI.add_context_menu_handler do |menu|
        klass = Parametric.selection_parametric?
        if( klass )
            menu.add_item("Edit #{klass}") { Parametric.edit_selection }

It’s using the method Parametric.parametric? which either returns false or the first item in the selection

def Parametric.selection_parametric?
    ss = Sketchup.active_model.selection
    false if ss.count != 1
    Parametric.parametric? ss.first

Maybe you modified that to include a short_class_name method?

Well, I think it’s ugly. And I thought it did have the reference to the short_class_name it it, but I’ve got several versions of parametric.rb now, and have been getting confused which is which. I see now that Grid doesn’t try to use it, but I thought an earlier version I had just showed Edit Grid. Rusty and perhaps faulty memory, then.

The Sketchucation plugin SU Draw Parametric Shapes, which i adapted from the original Sketchup team version on the Extension Warehouse, with ThomThom’s help, had an improved version of parametric.rb, which Steve Baumgartner adapted to keep the parameters in Edit in the original order, is the one I most recently started from.

That does work to use the short name.
Draw and Edit a Box and you get this:

I’ll have to study the code carefully to see why that works and mine doesn’t.

Maybe as @eneroth3 Christina suggests, that does use extend self? Will look and check.

[Just checked]
No, it doesn’t.

# If you use it in your own plugin, CHANGE THE MODULE NAME to replace JWM by your own initials and the name
# of your calling program instead of Shapes.

require 'sketchup.rb'

module JWM::Shapes

  # Abstract class which should be inherited by implementing class.
  class Parametric

    # TODO(thomthom): The arguments for this class needs documenting. It looks
    # like they are overloaded. But how many different mutations are there?
    # SLB: As supported here, the alternatives for args[0] are:
    #  - a Hash of key => value parameters for a new object (unknown here how they were obtained)
    #  - an Entity selected by the user (via right-click menu?)
    #  - nil/missing
    # @param [Hash] data
    # @param [Geom::Transformation] transformation for the instance being edited, nil/missing for new
    def initialize(*args)

jwm_shapes/parametric.rb uses a short_class_name method, but it also hides this with a local variable of the same name when setting the context menu

  unless file_loaded?(__FILE__)
    UI.add_context_menu_handler do |menu|
      # klass_name = Parametric.selection_parametric?
      # if klass_name
      ent = Sketchup.active_model.selection.first
      klass_path = Parametric.get_class(ent)
      unless klass_path.nil?
        short_class_name = klass_path.rpartition(/::/)[2]
        if Parametric.selection_parametric?
          menu.add_item("Edit #{short_class_name}") { Parametric.edit_selection }

Edit: it’s not actually inside the class but still a bit confusing that it uses the same name.

My Ruby skills aren’t up to much so I’ve missed that somewhere in my code. I AM trying to learn the basics better, but still a long way to go in the latest 2013 edition of the PickAxe book, which I only received last Sunday.

Will re-look and try to fix.

Many thanks for your help in pointing me in the right direction.

Edit: another thing I’d like to do is to be able to change parametric.rb to use a 4-parameter inputbox, to allow for passing a Combo pick list to a couple of my arguments.

I think, in a rather muddled way, I need to add a new method in the Parametric class which the calling program will override, but can’t yet see clearly how to approach that.

But let me try to get the simpler version using short_class_name working first, and understand why it doesn’t in the version I’m working on for Flats only, to get the parametric code to work without erroring.

where is it defined then, in the Shapes extension?

That text string occurs in six places in the Shapes parametric.rb file:

jwm_shapes/parametric.rb:50     model.start_operation(short_class_name(), true)
jwm_shapes/parametric.rb:83:    def short_class_name
jwm_shapes/parametric.rb:168:   title = "#{operation} #{short_class_name()}"
jwm_shapes/parametric.rb:230:   model.start_operation("Edit #{short_class_name()}")
jwm_shapes/parametric.rb:399:   short_class_name = klass_path.rpartition(/::/)[2]
jwm_shapes/parametric.rb:402:   menu.add_item("Edit #{short_class_name}") { Parametric.edit_selection }

Sorry, I wasn’t clear about what ‘it’ I was referring to.
The Parametric class has a short_class_name method.
Outside that class, but still inside the module JWM::Shapes is a local variable short_class_name.

Yes, I finally see that - the last occurrence but one, line 399: 'short_class_name = klass_path… etc.`

And as you say, that’s outside the Parametric class.

Still don’t understand the semantics or syntax of that line. Why doesn’t it use the previously defined method of the same name - 'short_class_name`?

Edit: and would it help not to use the same name here? Say call the variable short_name to distinguish it more clearly from the method?

That might help work out where my error is coming from.

The method in Parametric class would always return “Parametric”. It’s just used for the Undo menu and the title of the inputbox.

The local variable in the context menu handler gets the class of the selected entity via the Parametric.get_class(ent) method that gets it from attributes that the program added at some earlier time. It’s retreiving the name of the class of the selected entitity from the attributes dictionary.
This line

short_class_name = klass_path.rpartition(/::/)[2]

Takes the String e.g. "Sketchup::Face"
Converts to an array
[“Sketchup”, “::”, “Face”]’
and takes just the 3rd element:

Maybe. That’s a matter of opinion and programming style. I’d get confused if they were the same.

The NoMethodError generally means (if it is in fact defined,) it’s is not in the scope of where it is called from.

The main problem we all have with “Parametric.rb” is that it was never properly deployed as a community library. Instead it was “bundled” with a number of SketchUp example extensions, some of which revised the Parametric object code, and some have not. So there are a number of differing versions out there which are not being well controlled (ie, version management.)

I find it really silly that Trimble modified the code to wrap it in a Sketchup::Samples::Grid namespace and then left the global variables polluting the ObjectSpace.

Now I just looked at “su_grid” ver 1.1.1 code …

There is an issue with the Parametric class. It is defined in a common namespace module, ie:
Sketchup::Samples. It is not within the Sketchup::Samples::Grid extension module.
This means if there are differing versions of this class, published in several installed “sample” extensions, and they are loading, … then they are overwriting each other, potentially creating chaos.

Evidence that John’s version that he pasted into his own module, has comments by ThomThom which means it’s likely a newer version. The version of the Parametric class in the Grid v1.1.1 extension, is older and does not have these comments.

Anyway, … if the method is out of scope, you can always just extract the class name right in the context menu handler block …

    UI.add_context_menu_handler do |menu|
      if obj = Parametric.selection_parametric?
        obj_name = obj.respond_to?(:typename) ? obj.typename :'::').last
        menu.add_item("Edit #{obj_name}") { Parametric.edit_selection }

There are several ways to use library objects. Depends upon whether they are a module or a class.

For a module, it depends upon how it is written. It can be a mixin module which is used with include, or a library module which is used by making qualified calls (ie, Sketchup.version is an example of making a qualified call to a library module.)
Or it can be both (if written correctly,) and the module has both types of methods (module functions and mixin instance methods.)

For a class, it’s a bit easier. Normally you create a subclass …

require "su_parametric"

module JWM::Shapes

  class Parametric < Sketchup::Samples::Parametric

    def my_new_instance_method()
      # code here

    # ... etc. ...

  end # class

end # extension module

… but as said above, there is a clash going on with multiple versions being defined.

@DanRathbun, I’m sure I haven’t got the skill set (yet, at least - I’m trying to learn Ruby better from the ground up, but still have long way to go), but I wonder if you could confirm whether it would be possible in principle to do an improved version of parametric.rb that wouldn’t break backward compatibility, but that would allow not only a three parameter input box, but if the calling program implemented a method for a four parameter one, could detect that and allow combo/dropdown values too.

Then maybe get the SU team to make it a ‘proper’ Community version and maintain it as a common working version, with version control?

And see if plugin authors who have used it, would repackage it with their main program, so that at least only one version would need to be maintained for the future?

I currently have three slightly different versions in active use - one for the Sketchucatio SU Draw Parametric Shapes, one for Grid (su_grid|), and one for my attempt to make my Scenery plugin work parametrically. They (should) only differ in their Module names, but in fact at least the su_grid one differs in the way it implements the Context menu. And I think I’ve discovered a small typo difference betwee my Scenery and SU Draw Parametric Shapes versions.

All very confusing!

As to having multiple copies on one installation of SU, @slbaumgartner adapted the code that I packaged with SU Draw Parametric Shapes, so that it didn’t double up context menu Edit entries, if two or more plugins used different versions in their own extensions. (which earlier versions, including the Extension Warehouse Community SU Shapes extension and the su_grid did, and may still do for all I know).

Maybe @thomthom who has now joined the SU team could comment on this suggestion? When he did help me with extending and improving the SU shapes and its enclosed community version of parametric.rb, he hadn’t yet joined SU.

Yes I think we’ve talked about this before.

The first step is to identify the latest version of the Parametric class. I’d think it might be in the community Shapes extension.

ADD: I know “Shapes”, “Grid Tool”. “Onion Dome Creator” and “Window Maker” all use it. Others?

The next step is to compile a list of Trimble sample extensions and get them to use the community library class.

The 3rd step is to compile a list of 3rd party extensions and notify their authors how to use the library.

The whole point of a common library is that the code is maintained and loaded from one place, instead of “packaged up” within numerous extensions.

It certainly would help if we’d get a ExtensionLibrary subclass implemented of the SketchupExtension class.

I have test code in this regard, but haven’t played with it in years.

I don’t think I was aware of those discussions. If I took part, i don’t remember it.

@slbaumgartner has a later version in the SketchUcation SU Draw Parametric Shapes extension, which returns the parameters in the Edit inputbox in the same order as the original input, and tidied up a few other bits of the code…

I was interested to read in the PickAxe book that Hash is now supposed to remember the order that key/value pairs were entered, but that wasn’t my experience, and the Community version of SU Shapes didn’t do that.

That’s one of two principal differences between the Plugin Store and the Extension Store versions of SU Shapes. The other is that I added four new shapes: Sphere (adapted from Dome), Helix, Helical Ramp, and Helical Ramp with Sides.

I needed the latter two for a model I was building at the time, the Helix was a needed precursor of those, and I added the Sphere for completeness. Then published it on SketchUcation

@thomthom didn’t want to cloud the original SU Shapes with the latter three shapes, but I think included the Sphere. I haven’t used the Community/EW version of SU Shapes since shortly after finishing it with @thomthom’s help, after I added the other shapes.

So (in my rather limited experience) the SketchUcation version of parametric.rb is the latest version I know of. I don’t know about Window Maker. I know of it, but haven’t used it for years if at all. And I’d never even heard of Onion Dome Creator. Where is it to be found?

I will if I can try to find all the parametric.rb versions in those, and any others I can find, and do a file compare on them, to see how they differ other than in file save date.

Yeah, I remember reading this as well. But it’s #rehash method might mix up the order?

What Ruby version do you think this happened?

I also remember this. I was in Thomas’ camp. As the helical objects weren’t manifold. I thot they could be in a sister extension, and their command be on their own submenu.

But, hey … there is plenty of room in the world for different “flavors”.

They are all on the SketchUp Team store page in the EW.

I’m currently in the process of do this myself.

Grid Tool”, “Onion Dome” and “Window Maker” ALL use version “1.0” in the Sketchup::Samples module.

Have a look at the “Window Maker” extension code. It actually reloads the same Sketchup::Samples::Parametric class (as the other extensions,) but then in it’s own Sketchup::Samples::Windows extension module, it subclasses the shared Parametric class and then makes subclass overrides as it’s own Window class. Ie … it looks like …

require 'su_windows/parametric.rb'

module Sketchup::Samples::Windows

  # Define the main parametric window class

  class Window < Sketchup::Samples::Parametric

    # method overrides and extra method definitions ...

# etc...

EDIT (ADD): The “Onion Dome” extension does this same thing. Loads (or reloads) the common "parametric.rb" file, and then implements it’s own subclass of it.