Negative Indexing into InstancePath


#1

I noticed that you cannot index into an InstancePath using negative indices like you can for a normal array. Also I’ve noticed that using the leaf property of the InstancePath doesn’t yield anything if the last object in the InstancePath is a Group or ComponentInstance.

I’m not sure if these are expected behaviors and these should be feature requests or if they are bugs.


#2

The API states that entities are collections:

The entities class just happens to include the “[ ]” method to provide basic selection of individual objects, similar to arrays, but it is not a Ruby array object. To obtain a Ruby array that contains references to the entity objects, use:

entsarr = Sketchup.active_model.entities.to_a

Note: The array elements are references to entity objects at the time of instantiation. If the model’s entities are created or deleted after “to_a”, the separate array of references is static and not kept up to date.


#3

Expanding on what Bruce wrote, if a new Entity is added after the Array is created, no new element will be added in the Array to reference it. Conversely, if an Entity referenced by an element of the Array is erased, the element will continue to reference the now non-valid, deleted Entity. The latter will prevent the now-dead Entity from being garbage collected until the Array itself is destroyed.


#4

InstancePath - []

I’m assuming your logic also applies to InstancePath then and it is not intended for negative indices to work.

I do however still wonder if not returning Group or ComponentInstance objects is intentional for:

InstancePath - leaf


#5

Yeah, either the API documentation is wrong (it says the leaf may be any DrawingElement), or the implementation is bugged. It returns nil for an InstancePath that ends in a ComponentInstance or Group.


#6

This is noted in the following bug report …

The nil return for #leaf appears to be expected although the doc for the method doesn’t say so.

If you read the doc for the opposing #root method you’ll see it does specify that nil is returned when the root is not a group or component.

So these two methods have double duty as test methods. They were obviously designed this way, and not meant to be the same as the #first and #last method as in the Array class.


#7

I don’t think it was an intentional decision to not allow negative indicies. Would probably make sense to mimick array access better. This is one of these cases where Ruby have so many ways of doing things that it’s challenging to remember all the mutations.


#8

Especially because the docs for Sketchup::InstancePath#[] say …

The elements of an instance path can be accessed like an array.

In the tracker issue referenced below, I question that perhaps the phrase “can be accessed like an array.” might be removed, and readers directed to use #to_a instead when needing to use negative indices or slices.

Except we are discussing the Sketchup::InstancePath class here, not the entities collection.

But the idea of creating an array copy still holds true for any of the API collection classes that do not quite implement enumerable methods correctly.

# Where some_instance_path is a Sketchup::InstancePath object:
patharr = some_instance_path.to_a
# ... or ...
leaf = some_instance_path.to_a[-1]
leaf_parent = some_instance_path.to_a[-2]
first = some_instance_path.to_a.first

An example of walking the instance path in reverse order:

some_instance_path.to_a.reverse.each do |ent|
  if ent.is_a?(Sketchup::Group)
    # do this ...
  elsif ent.is_a?(Sketchup::ComponetInstance)
    # do that ...
  else
    # a leaf, do other - it's a primitive, cpoint, cline,
    # dimension, text callout, section plane, vertex, etc.
  end
end

The above may also be a good candidate task for a case block.


Issue logged (with this thread referenced)