… to support construtor and method overloading. This PR is quite large, but it can be broken down into four key changes:
* First, update the NativeRegistry to be keyed on Ruby class and method id and to store a vector of Native instances (NativeFunction, NativeIterator, NativeAttributeGet, NativeAttributeSet). If a method is overridden, there will be more than one native stored.
* Second, create a base class Native for NativeFunction, NativeIterator, NativeAttributeGet and NativeAttributeSet. This allows the NativeRegistry to store unique_ptrs instead of std::any, which is hopefully a bit clearer and more importantly allows memory to be cleaned up via the use of std::unique_ptr (Natives are allocated on the heap but previously were never freed). It also reduces the amount of code by sharing it via the base Native class. Also NativeAttribute was split into NativeAttributeGet and NativeAttributeSet so they could share more code with Native. This should have probably been a different commit but I realized its benefits after doing all the other changes.
* Third, update From_Ruby#is_convertible's return type from bool to a new enum called Convertible which has three values - Exact, TypeCast or None. Exact means the Ruby type and C++ type are the same (example float), TypeCast means the Ruby type can be casted to the C++ type (example integer to float) and None means the Ruby and C++ types are not compatible. This is a backwards incompatible change for anyone who implemented their own version of From_Ruby#is_convertible but that seems fairly unlikely because it was previously used only for updating std::variants.
* Fourth, update Natives to resolve overloaded methods at runtime by comparing the types of Ruby VALUEs to the C++ types using From_Ruby#is_convertible as described above. Exact matches take precedence over TypeCast matches. If no matches are found an exception is thrown.