How to include other libraries in my plugin?

I need Flt lib in my plugin. I want to wrap the code with own module like this:

module MyCompany
  module MyProject

    module flt
      ...

There are many files in Flt lib. Do I need to wrap them all?

I run into a problem when wrapping class float:

module MyCompany
  module MyProject

class Float

  DECIMAL_DIG = (MANT_DIG*Math.log(RADIX)/Math.log(10)).ceil+1

  # Minimum normalized number == MAX_D.next
  MIN_N = Math.ldexp(0.5,Float::MIN_EXP) # == nxt(MAX_D) == Float::MIN

  # Maximum denormal number == MIN_N.prev
  MAX_D = Math.ldexp(Math.ldexp(1,Float::MANT_DIG-1)-1,Float::MIN_EXP-Float::MANT_DIG)

  # Minimum non zero positive denormal number == 0.0.next
  MIN_D = Math.ldexp(1,Float::MIN_EXP-Float::MANT_DIG);

  # Maximum significand == Math.ldexp(Math.ldexp(1,Float::MANT_DIG)-1,-Float::MANT_DIG)
  MAX_F = Math.frexp(Float::MAX)[0]

end

end
end

The constant MANT_DIG is not initiated.

I do not think my method to use other libraries is correct. What is the right way to include existing libraries in my plugin? Thanks.

@Henry12

Adding your own namepsace to this gem might involve some work. There are a few places where its code adds items to Ruby base classes.

Anyway, in the code you’ve shown above, several of the constants are namespaced, as in Float::MIN_EXP.

You probably need to do that with all the code you’ve shown. But, the gem’s code is adding items to Ruby’s Float class, and if the rest of the code uses the added constants, you’ll have more problems, because you’re adding your own namespace…

Ruby class and module namespace identifiers should be CamelCase (aka SnakeCase.)
Local variables are all lowercase in Ruby.

So the submodule needs to at least begin with a lowercase character, like Flt.

In fact the project README file states …

All types and functions are within a namespace called Flt.

module MyCompany
  module MyProject

    module Flt
      ...

If the module (or class) is a library to access a filetype or some thing universally known by a short acronym (such as a trademark) then it can be all uppercase. (Examples would be the CSV and JSON libraries for file types; or companies like IBM, ASUS, etc.; Operating systems ie: IOS, etc.; Interfaces: USB, MIDI, etc. I think you should get the idea.)

Again it’s Float not float.

And …

  • you cannot wrap Ruby Core base classes !
    They must remain defined in the toplevel Objectspace.

  • SketchUp’s Ruby process is a shared process.
    It is not permitted for SketchUp extensions to directly modify Ruby Core classes or modules.

So if you are thinking of using this library for a SketchUp extension that you will publish, then don’t.

You could use it only for yourself if you really had to, but as it changes several Ruby core classes if this interfered with any other SketchUp extension, this would violate any warranty implied by the affected extensions. Ie, don’t expect to get a refund if your use of this library breaks paid extensions.

There might be the possibility of rewriting this library as a Ruby refinement that only your extension uses. Or … rewriting the core class changes as refinements that only this library uses.


There is also the quirk that SketchUp’s Length class was previously a subclass of Float but is no longer for some quirky implementational reason.

My mention here is prompted by possible issues in converting objects between Length and Float.


Also, at the bottom of the "float.rb" file …

# Is Float('...') correctly rounded, even for subnormal numbers?
def Flt.float_correctly_rounded?
  # That doesn't seem to be the case for mswin32
  @float_correctly_rounded ||= RUBY_PLATFORM.match(/mswin32/).nil?
end

The test against the global RUBY_PLATFORM constant is unreliable as the platform substring has varied over the recent SketchUp versions.

Use the Sketchup::platform method for versions greater than 14.

EDIT: I’ll revise my thinking per my comments in a following post. (A platform only test may not be adequate.)

# Is Float('...') correctly rounded, even for subnormal numbers?
def Flt.float_correctly_rounded?
  # That doesn't seem to be the case for mswin32
  if Sketchup.respond_to?(:platform)
    @float_correctly_rounded ||= Sketchup.platform != :platform_win
  else
    @float_correctly_rounded ||= RUBY_PLATFORM.match(/mswin32/).nil?
  end
end

Also at the bottom of the "float.rb" file …

# Return a (limited) context object for Float.
# This eases the implementation of functions compatible with either Num or Float values.
def Float.context
  Flt::FloatContext.instance
end

… would need to qualify the method call with your wrapping namespaces …

def Float.context
  MyCompany::MyProject::Flt::FloatContext.instance
end

This necessary call qualification would also need to happen other places in the gem’s code.


I haven’t looked through all the files to know what other things need “adjustment”.

Old SU - mswin32 should be mingw32?

Maybe RUBY_PLATFORM.include? instead of ``RUBY_PLATFORM.match`

Some of the builds are like: "x64-mswin64_140" so the test should not assume 32bit.

It seems to me that this gem (first migrated from the old “ruby-decimal” gem) in 2014, may still be assuming that a rounding error occurs specifically on Windows 32bit platform, … Ie, 64bit Windows running 64 bit Ruby may not have the issue this gem is trying to detect.

Ie, see it’s closed issue Incorrectly rounded trigonometry results · Issue #3 · jgoizueta/flt · GitHub

So, my first idea of checking only the platform, may not be a good test.
But I still think that sniffing at the RUBY_PLATFORM string alone could be problematic.

Probably it would be better to run a test similar to the one the gem author ran in the issue #3 linked above. (There is a "test" folder included with the gem having quite a few test scenarios.)

I think all the Ruby builds that are mswin will be processed in the Sketchup.respond_to?(:platform) branch of the conditional?

So, only older SU versions will use the RUBY_PLATFORM based value?

All mingw Rubies RUBY_PLATFORM contain the text mingw32. Below are some Windows SU RUBY_DESCRIPTION values, RUBY_PLATFORM is the text enclosed in brackets at the end of the string:

SU    RUBY_DESCRIPTION
2015  ruby 2.0.0p247 (2013-06-27) [x64-mingw32]
2017  ruby 2.2.4p230 (2015-12-16 revision 53155) [x64-mingw32]
2019  ruby 2.5.5p157 (2019-03-15 revision 67260) [x64-mingw32]
2021  ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x64-mswin64_140]

All the above are 64bit builds, mingw 32bit builds have i386-mingw32 for the RUBY_PLATFORM string.

Lastly, starting with Ruby 3.1, publicly available Ruby builds are known as UCRT builds. SU’s Windows Ruby builds are now mswin builds (I think SU 2021 was the first). Below are RUBY_DESCRIPTION strings for mingw, ucrt, and mswin builds, note the difference in the RUBY_PLATFORM strings:

ruby 3.2.0dev (2022-10-12T04:30:25Z master 0360fca4ad) [x64-mingw32]
ruby 3.2.0dev (2022-10-12T04:30:25Z master 0360fca4ad) [x64-mingw-ucrt]
ruby 3.2.0dev (2022-10-12T04:30:25Z master 0360fca4ad) [x64-mswin64_140]

BTW, sometime ago I think I asked about ‘community based’ docs to be included in the API docs. Maybe one doc could be a table summarizing properties of the Ruby builds across SU versions & OS’s?

Interested? Could you contribute? I could start a GitHub repo, it would just be markdown docs.

Yes, if you want to use the Gem in the extension it needs to be wrapped in the extension’s namespace. If there are a lot of files you can maybe use scripting or a regex search and replace to add the wrapping namespace to all files.

Regarding modifying base classes, this is not allowed in SketchUp as it risks causing clashes between extensions. You may be able to sue refinements to make monkey patches that only apply within your own extension.

There seems to be an echo in here. :wink:

In the example above, they would, ie the pre-2014 versions all using Ruby 1.8.x.

However, as I noted, perhaps the constant sniffing alone is a poor way to determine if the condition exists.

I seem to recall that SketchUp vers 6, 7 and 8 (and perhaps 2013) used the pre-compiled Ruby interpreter DLL from the Windows Ruby Installer. I think back then the constant was “mswin” (but cannot remember exactly. The archived Windows installers back then could be checked.)

Ie, for Windows, SketchUp used the Ruby 1.8.0 initial release DLL up until ver 8. For SU v8, the pre-compiled Ruby 1.8.6-p287 DLL was used for the Windows edition. (On Mac SU used whatever native Ruby version was present, which was some patch level of v1.8.5 for the then current MacOS release.)

After Trimble bought SketchUp, they (which now included ThomThom) began compiling their own Ruby build at Ruby 2.0.0-p247 which was shipped with SketchUp 2014 for both Windows and Mac editions.

Bitness: SU 2015 was the first available 64bit SketchUp Windows build. SU 2016 was the last available 32bit SketchUp Windows build.

As I had said previously, I am suspecting that the condition the gem author was trying to detect might be a bitness (integer size?) issue and not so much a platform or compiler tool chain issue.

From what I have read in the past, it is supposed to be possible for one GitHub repo to include another. I’m not sure how this is done however.

Such a feature could be nice for holding the extra “Files” of the API documentation separate from the other YARD generated pages for the API objects and methods.

In my custom local API documentation pages, I had already separated out the Ruby Build Numbers list into it’s own page with nicely formatted HTML tables.

Additional Ruby properties might go on this page.

But, the whole point of adding the Sketchup::platform module method for 2014+ was to avoid the messiness of all the variant RUBY_PLATFORM strings.

I have been working on my own. It is taking just way too long for even simple errors in Trimble’s doc pages to be corrected. So I’ve begun correcting my own. And making some tweaks to the CSS styling, etc.

Engaging with SketchUp’s development processes can be an exercise in frustration. Everything takes 3 years or more. Even the simplest typo corrections.