Skip to content

objects.scad

Jon Gilbert edited this page Apr 17, 2024 · 2 revisions

LibFile: objects.scad

Functions for creating and accessing object-like lists.

Note: throughout this LibFile, we refer to things as Objects. I wish they were real, blessed, official capital-O Objects, and they're not. See this project's HOWTO wiki for a quick-start, minimum number of steps to get this into your OpenSCAD modules.

To use, add the following lines to the beginning of your file:

include <openscad_objects/objects.scad>

File Contents

  1. Section: Base Object Functions & Usage

  2. Section: Object Accessors

  3. Section: Managing Lists of Objects

  4. Section: Object Attribute Data Types

Section: Base Object Functions & Usage

These functions assist the creating and usage of object-like lists: "Objects".

Objects have two basic parts: a list of attributes, their types, and default values; and, a list of values for those attributes.

object = [
   TOC,
   value_1,
   value_N
   ];

The list of attributes, their data types, and their default values are all stored in the first element in the Object list: this is the table-of-contents (or "TOC"). The TOC is itself a list, and each element in the TOC list is an attribute defintion. After the TOC, each element in the Object list is the value of the attributes listed in the definition.

The functions in this section deal with creating the Object, and with its validity.

Function: Object()

Synopsis: Create a generic Object

See Also: obj_debug_obj(), ATTRIBUTE_DATA_TYPES

Usage:

  • object = Object(name, attrs);
  • object = Object(name, attrs, <vlist=vlist>, <mutate=object>);

Description:

Given an Object name as a string name, a list of attributes attrs, optionally a list of variable-listed values vlist, and optionally an existing Object to model against mutate, create and return an Object-like list object. This Object will be a list that is len(attrs) + 1 elements long: the first element will be a table-of-contents element containing the names and data types of each attribute; the remaining elements will be the values assigned to those attributes.

Defining what attributes the Object has with attrs: The attrs argument is a list of attribute names, and optionally data types and defaults, upon which the Object will be modeled. Each element in attrs is either a string or a list. In string form, the attribute's defining format is: name[=data_type[=default]], where name is the name of the attribute; and, data_type is one of the supported data types listed below in ATTRIBUTE_DATA_TYPES; and, default is a default value for that attribute.

Object_Attributes = [
   "a1=s",            // defines "a1", a string attribute
   "a2=i=10"          // defines "a2", an integer attribute, with a default of 10
];

When using the list form to define attributes, the attribute's defining format is a three-element list: [name, data_type, default]. The three elements directly map to those in the string format. Using a list format is required when the default is not easily represented in a simple string (such as when the default is a list itself, or an object, or a pre-defined constant such as PI or CENTER).

Object_Attributes = [
   ["a1", "s"],             // defines "a1", a string attribute
   ["a2", "i", 10],         // defines "a2", an integer attribute, with a default of 10
   ["a3", "l", [1, 2, 3]],  // defines "a3", a list attribute, with a default list
];

Pre-populating Objects with values with vlist: The vlist listing argument to Object() is a variable list of [attribute, value] lists. Attribute pairs given in vlist can be in any order. Attribute pairs may not be repeated. Unspecified attributes will be set to undef.

Modelling Objects from other Objects with mutate: Optionally, an existing, similar Object can be provided via the mutate argument: that existing Object list will be used as the original set of Object attribute values, with any new values provided in vlist taking precedence.

Arguments:

By Position What it does
name The "name" of the object (think "classname"). No default.
attrs The list of known attributes, and optionally their type and default for this object. No default.
By Name What it does
vlist Variable list of attributes and values: [ ["a1", 10], ["a2", "none"] ]; or, a list of running attribute value pairing: ["a1", 10, "a2", "none"]. Default: [] (which will produce an Object with no values).
mutate An existing Object of a similar name type on which to pre-set values. Default: []

Object() returns a list that should be treated as an opaque object: reading values directly from the object list, or modifying them manually into a new list, is not entirely safe.

Example 1: empty object creation: this is an empty object that has no values assigned to its attributes:

include <openscad_objects/objects.scad>
obj = Object("Obj", ["attr1=i", "attr2=s", "attr3=b=true"]);
echo(obj);
// emits: ECHO: [["Obj", ["attr1", "i", undef], ["attr2", "s", undef], ["attr3", "b", true]], undef, undef, undef]



Example 2: same empty object creation, but with the object shown with obj_debug_obj(). Note that while attr3 has a default value set, all of the attributes are still undefined:

include <openscad_objects/objects.scad>
obj = Object("Obj", ["attr1=i", "attr2=s", "attr3=b=true"]);
echo(obj_debug_obj(obj));
// emits: ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): undef
// 2: attr2 (s: undef): undef
// 3: attr3 (b: true): undef"



Example 3: pre-populating object attributes at creation. Note the values set for attr2 and attr3:

include <openscad_objects/objects.scad>
o = Object("Obj", ["attr1=i", "attr2=s", "attr3=b=true"], [["attr2", "hello"], ["attr3", false]]);
echo(obj_debug_obj(o));
// emits: ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): undef
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"



Example 4: pre-populating just as above, with the same attributes and values, but with a simpler vlist:

include <openscad_objects/objects.scad>
o = Object("Obj", ["attr1=i", "attr2=s", "attr3=b=true"], ["attr2", "hello", "attr3", false]);
echo(obj_debug_obj(o));
// emits: ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): undef
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"



Example 5: using mutate will carry values from a previous Object into a new one, with vlist values taking precedence:

include <openscad_objects/objects.scad>
O_attrs = ["attr1=i", "attr2=s", "attr3=b=true"];
o = Object("Obj", O_attrs, [["attr2", "hello"], ["attr3", false]]);
echo(obj_debug_obj(o));
o2 = Object("Obj", O_attrs, vlist=["attr1", 12], mutate=o);
echo(obj_debug_obj(o2));
// emits:
// ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): undef
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"
// ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): 12
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"



Example 6: when using mutate, you can specify an empty attrs list: the attributes will be carried over from the mutated Object:

include <openscad_objects/objects.scad>
O_attrs = ["attr1=i", "attr2=s", "attr3=b=true"];
o = Object("Obj", O_attrs, [["attr2", "hello"], ["attr3", false]]);
echo(obj_debug_obj(o));
o2 = Object("Obj", [], vlist=["attr1", 12], mutate=o);       // <-- an empty `attrs` list specified
echo(obj_debug_obj(o2));
// emits:
// ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): undef
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"
// ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): 12
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"




Function: obj_is_obj()

Synopsis: Test to see if a given value could be an Object

Usage:

  • bool = obj_is_obj(obj);

Description:

Given a thing, possibly an Object, returns true if that thing can be considered an Object, of any type.

To be considered an Object, a thing must: be a list; have a zeroth element defined; have a length that is the same length as its zeroth element; and, whose sub-list elements under its zeroth element have the same depth and count.

If the thing matches those requirements, obj_is_obj() returns true; otherwise, it will return false.

Arguments:

By Position What it does
obj An Object list (potentially). No default.

It is not an error to test for an object and have it return false.

Example 1: a positive test for an Object with obj_is_obj():

include <openscad_objects/objects.scad>
obj = Object("Obj", ["attr=i"]);
echo(obj_is_obj(obj));
// emits: ECHO: true



Example 2: a false test for an Object:

include <openscad_objects/objects.scad>
echo(obj_is_obj(1));
// emits: ECHO: false




Function: obj_is_valid()

Synopsis: Deeply test an Object to ensure its data types are consistent

Usage:

  • bool = obj_is_valid(obj);

Description:

Given an object obj, returns true if the object is "valid", and false otherwise. "Valid" in this context means the object is an object (as per obj_is_obj()); and, has at least one attribute element; whose attributes all have a valid type assigned; and, whose attributes with values all match their specified types.

Arguments:

By Position What it does
obj An Object list. No default.

It is not an error to test for an object and have it return false.


Function: obj_debug_obj()

Synopsis: Given an Object, return a single string that describes the Object

Usage:

  • string = obj_debug_obj(obj);
  • string = obj_debug_obj(obj, <show_defaults=true>, <sub_defaults=false>);

Description:

Given an object obj, return a string string of debug layout information of the object. Nested objects within the object will also be expanded with a visual indent.

Arguments:

By Position What it does
obj An Object list. No default.
By Name What it does
show_defaults If enabled, then TOC-provided defaults will be shown alongside the attribute data types. Default: true
sub_defaults If enabled, then TOC-provided defaults will be shown as the attribute's value, if the value is not set. Default: false

obj_debug_obj() does not output this debugging information anywhere: it's up to the caller to do this.

Example 1:

include <openscad_objects/objects.scad>
O_attrs = ["attr1=i", "attr2=s", "attr3=b=true"];
o = Object("Obj", O_attrs, [["attr2", "hello"], ["attr3", false]]);
echo(obj_debug_obj(o));
// emits:
// ECHO: "0: _toc_: Obj
// 1: attr1 (i: undef): undef
// 2: attr2 (s: undef): hello
// 3: attr3 (b: true): false"




Function: obj_has()

Synopsis: Test to see if an Object has a particular attribute

Usage:

  • bool = obj_has(obj, name);

Description:

Given an object obj and an accessor name name, return true if the object "can" access that name, or false otherwise. An object need not have a specified value for the given name, only the ability to access and refer to it; in other words, if the name exists in the Object's TOC, then obj_has() will return true.

Essentially, this is a thinly wrapped obj_toc_get_attr_names().

This might seem similar way to perl5's can() or python's callable(), but this is inaccurate: obj_has() cannot test if the object is able to execute or call the given name; it can only tell if the object has the given name as an attribute. The perl5 exists() or python hasattr() functions would be more analagous to obj_has().

Arguments:

By Position What it does
obj An Object list. No default.
name A string that may exist as an attribute for the Object. No default.

Example 1:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i=10", "a2=i", "a3=i=13"], ["a1", 10, "a2", 12, "a3", 23]);
b = obj_has(obj, "a1");
// b == true



Example 2:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i=10", "a2=i", "a3=i=13"], ["a1", 10, "a2", 12, "a3", 23]);
b = obj_has(obj, "radius");
// b == false




Function: obj_has_value()

Synopsis: Test to see if an Object has any data in it

Usage:

  • bool = obj_has_value(obj);

Description:

Given an object obj, return true if any one of its attributes are defined. If no attributes have a value defined, obj_has_value() returns false.

obj_has_value() does not evaluate the values of an object using any accessors, there is no conditional evaluation of the values done: objects that provide accessors with defaults won't use those accessors here, and unset attribute values will be considered undefined.

Arguments:

By Position What it does
obj An Object list. No default.

Example 1:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i=10", "a2=i", "a3=i=13"], ["a1", 10, "a2", 12, "a3", 23]);
retr = obj_has_value(obj);
// retr == `true`



Example 2:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i=10", "a2=i", "a3=i=13"]);
retr = obj_has_value(obj);
// retr == `false`




Function: obj_get_names()

Synopsis: Get a list of all the attribute names in the Object

Usage:

  • names = obj_get_names(obj);

Description:

Given an object obj, return the names of the attributes listed in its TOC as a list names. Names are returned in the order in which they are stored in the Object.

obj_get_names() does not return the Object's TOC.

Arguments:

By Position What it does
obj An Object list. No default.

Example 1:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i", "a3=i"], ["a1", 10, "a2", 12, "a3", 23]);
names = obj_get_names(obj);
// names == ["a1", "a2", "a3"];




Function: obj_get_values()

Synopsis: Get a list of all the values in the Object

Usage:

  • values = obj_get_values(obj);

Description:

Given an object obj, return the values of the attributes listed in its TOC as a list values. This is functionally the same as doing [for (i=[1:len(obj[0])-1]) obj[i]]. Values are returned in the order in which they are stored in the object.

obj_get_values() does not return the object's TOC, so len(object) > len(obj_get_values(object)).

obj_get_values() does not return values via the built-in accessor obj_accessor(), and no value defaults or type checking is done on the values before they're returned.

Arguments:

By Position What it does
obj An Object list. No default.

Example 1:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i", "a3=i"], ["a1", 10, "a2", 12, "a3", 23]);
values = obj_get_values(obj);
// values == [10, 12, 23];




Function: obj_get_values_by_attrs()

Synopsis: Get a list of values from the Object in arbitrary order

Usage:

  • values = obj_get_values_by_attrs(obj, names);

Description:

Given an object obj and a list of attribute names names, return the values for those attributes as a list values. Values are returned in the order in which they are specified in names. If the attributes have no value set, and there is a list of optional defaults defaults, returns the value at the same position as the attribute appears in names.

Arguments:

By Position What it does
obj An Object list. No default.
names A list of attribute names. No default.
By Name What it does
defaults A list of default values that positionally map to the attributes in names. No default.

It is not an error to specify an attribute name multiple times. A defaults list that isn't as long as a names list will be padded to be the same length with undef elements; however, a defaults list that is longer than a names list will have its extraneous elements ignored.

There is no type comparison for the defaults list given to obj_get_values_by_attrs() against the attributes in obj.

Example 1: calling obj_get_values_by_attrs(). Note the order of the names differs from the Object's order:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["attr1=i", "attr2=i"], ["attr1", 5, "attr2", 10]);
values = obj_get_values_by_attrs(obj, ["attr2", "attr1"]);
// values == [10, 5]



Example 2: only one attribute is specified in names, and only one value is returned in values:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["attr1=i", "attr2=i"], ["attr1", 5, "attr2", 10]);
values = obj_get_values_by_attrs(obj, ["attr2"]);
// values == [10]



Example 3: with no values set in the object, undef is returned for the attributes:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["attr1=i", "attr2=i"]);
values = obj_get_values_by_attrs(obj, ["attr1", "attr2"]);
// values == [undef, undef]



Example 4: with no value set in the object for "attr2" and no attribute defaults set in the Object, the value from defaults is returned instead:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["attr1=i, "attr2=i"], ["attr1", 3]);
values = obj_get_values_by_attrs(obj, ["attr1", "attr2"], [4, 4]);
// values == [3, 4]




Function: obj_get_defaults()

Synopsis: Get a list of all the attribute defaults in the Object

Usage:

  • defaults = obj_get_defaults(obj);

Description:

Given an Object obj, return the defaults values of the attributes listed in its TOC as a list defaults. Defaults are returned in the order in which they are stored in the Object. If an attribute has no default set, its position in the defaults list will be undef.

Arguments:

By Position What it does
obj An Object list. No default.

Example 1:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i=10", "a2=i", "a3=i=13"], ["a1", 10, "a2", 12, "a3", 23]);
defaults = obj_get_names(obj);
// defaults == [10, undef, 13];




Section: Object Accessors

These are the Object attribute accessors; functions that "get" and "set" the attribute values in the Object.

"Getting" an attribute's value from Object is pretty easy: take the attribute name, look it up in the TOC to get its index, and use that index to get the entry from the Object. If there's no value within the Object and a default is available, return that instead. Works pretty much like every other OO model out there, easy-peasy.

   axle = Object("Axle",
                 [["diameter", "i"], ["length", "i"]],
                 [["diameter", 10],  ["length", undef]]
                 );
   echo( obj_accessor_get(axle, "diameter") );
   // ECHO: 10

"Setting" an attribute's value is a little more interesting, because OpenSCAD doesn't let you change a variable after it's been declared: in other languages, the data for a class or object may be altered and is liable to change, but in OpenSCAD you can't do that. So: instead of returning the new value, or a "you changed this value" success flag, setting an attribute's value returns an entirely new Object. The new Object has the newly-set attribute value, and the original Object is unmodified.

   axle = Object("Axle",
                 [["diameter", "i"], ["length", "i"]],
                 [["diameter", 10],  ["length", undef]]
                 );
   echo( obj_accessor_get(axle, "length") );
   // ECHO: undef
   axle2 = obj_accessor_set(axle, "length", nv=30);
   echo( obj_accessor_get(axle2, "length") );
   // ECHO: 30

There's one mutable accessor, obj_accessor(), that can both get and set values by attribute name. There are also two get- and set-specific accessors: obj_accessor_get() returns attributes in a read-only manner; and, obj_accessor_set() returns a modifed object list after setting the attribute to a new value. And, there is obj_accessor_unset(), to set a named attribute explicitly to undef (essentially, a delete).

Function: obj_accessor()

Synopsis: Generic read/write attribute accessor

Usage:

  • obj_accessor(obj, name, <default=undef>, <nv=undef>);

Usage: to retrieve an attribute's value from an object:

  • value = obj_accessor(obj, name);
  • value = obj_accessor(obj, name, <default=undef>);

Usage: to set an attribute's value into an object:

  • new_object = obj_accessor(obj, name, nv=new_value);

Description:

Basic accessor for object attributes. Given an object obj and an attribute name name, operates on that attribute. The operation depends on what other options are passed. Calls to obj_accessor() with an nv (new-value) option defined will create a new object based on obj with the new value set for name, and then will return that modified object list as new_object (a "set" operation).

Calls to obj_accessor() without the nv option will look the current value of name up in the object and return it (a "get" operation). "Get" operations can provide a default option, for when values aren't set. The precedence order for "gets" is: object-stored-value || default-option || object-toc-stored-default || undef: if the value of name in the object is not defined, the value of the default option passed to obj_accessor() will be returned; if there is no default option provided, the object's TOC default will be returned; if there is no TOC default for the object, undef will be returned.

Arguments:

By Position What it does
obj An Object list. No default.
name The attribute name to access. The name must be present in obj's TOC. No default.
By Name What it does
default If provided, and if there is no existing value for name in the object obj, returns the value of default instead.
nv If provided, obj_accessor() will update the value of the name attribute and return a new Object list. The existing Object list is unmodified.
_consider_toc_default_values If enabled, TOC-stored defaults will be returned according to the mechanics above. If disabled with false, the TOC default for a given attribute will not be considered as a viable return value. Default: true

It's not an error to provide both default and nv in the same request, but doing so will yield a warning nonetheless. If they're both present, obj_accessor() will act on the new value in nv and return a new object list, and will neither evaluate nor set the value from default.

It's not an error to provide a nv argument that is undef; however, if you're unknowningly passing undef with nv expecting it to clear the attribute in that object, or because you thought it was set to a value, obj_accessor() won't know what you meant to do and will act as if you wanted to "get" the value for that attribute. To explicitly clear an object's attribute, use obj_accessor_unset(). To explicitly set an attribute to a new value, use obj_accessor_set() (which will error out if nv is not defined).

Todo:

  • when getting an attribute without a value and a default is provided, do a type check on the default value before returning

Example 1: direct "get" call to obj_accessor():

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 30]);
a1 = obj_accessor(obj, "a1");
// a1 == 30
a2 = obj_accessor(obj, "a2", default=10);
// a2 == undef
// (because `a2` is not set in `obj`, and there is no Object default, there is no value to return.)
a2_2 = obj_accessor(obj, "a2", default=10);
// a2_2 == 10
// (`a2` is still unset in the `obj` object, but `default` was provided to `obj_accessor()`, so that default of 10 is returned instead)



Example 2: direct "set" calls to obj_accessor():

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 30]);
obj2 = obj_accessor(obj, "a1", nv=6);
// obj2 is a new object, of the same type as `obj`; its `a1` value is now 6.
// obj's `a1` value is still 30.



Example 3: gotcha when providing undef as a new-value:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 10, "a2", 30]);
obj2 = obj_accessor(obj, "a1", nv=undef);
// obj2 == 10, because `obj_accessor()` didn't see a value for `nv`: instead of changing `a1`, the value of `a1` was returned.




Function: obj_accessor_get()

Synopsis: Generic read-only attribute accessor

See Also: obj_accessor()

Usage:

  • value = obj_accessor_get(obj, name, <default=undef>);

Description:

Basic "get" accessor for Objects. Given an object obj and attribute name name, obj_accessor_get() will look the current value of name up in the object and return it as value (a "get" operation).

obj_accessor_get() is a simplified wrap around obj_accessor(), and the mechanics on how values are returned are the same. "Get" operations can provide a default option, for when values aren't set. The precedence order for "gets" is: object-stored-value || default-option || object-toc-stored-default || undef: if the value of name in the object is not defined, the value of the default option passed to obj_accessor_get() will be returned; if there is no default option provided, the object's TOC default will be returned; if there is no TOC default for the object, undef will be returned.

Arguments:

By Position What it does
obj An Object list. No default.
name The attribute name to access. The name must be present in obj's TOC. No default.
By Name What it does
default If provided, and if there is no existing value for name in the object obj, returns the value of default instead.
_consider_toc_default_values If enabled, TOC-stored defaults will be returned according to the mechanics above. If disabled with false, the TOC default for a given attribute will not be considered as a viable return value. Default: true

Note that obj_accessor_get() will accept a nv option, to make writing accessor glue easier, but that nv option won't be evaluated or used.

Example 1: direct calls to obj_accessor_get():

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 30]);
value = obj_accessor_get(obj, "a1");
// value == 30



Example 2: passing nv yields no change:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 30]);
value = obj_accessor_get(obj, "a1", nv=25);
// value == 30  (the `nv` option is ignored)




Function: obj_accessor_set()

Synopsis: Generic write-only attribute accessor

See Also: obj_accessor()

Usage:

  • new_object = obj_accessor_set(obj, name, nv);

Description:

Basic "set" accessor for Objects. Given an object obj, an attribute name name, and a new value nv for that attribute, obj_accessor_set() will return a new Object list with the updated value for that attribute as new_object. The existing Object list is unmodified, and a wholly new Object with the new value is returned instead.

Arguments:

By Position What it does
obj An Object list. No default.
name The attribute name to access. The name must be present in obj's TOC. No default.
nv The new value to set as the new attribute. No default.

Unlike obj_accessor(), it is an error to call obj_accessor_set() without a new value (nv) passed. If the value of the attribute name needs to be removed, use obj_accessor_unset() instead.

Note that obj_accessor_set() will accept a default option, to make writing accessor glue easier, but it will be neither evaluated nor used.

Example 1: direct call to obj_accessor_set()

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 30]);
new_obj = obj_accessor_set(obj, "a1", nv=20);
// new_obj's `a1` attribute is now 20




Function: obj_accessor_unset()

Synopsis: Generic attribute deleter

Usage:

  • new_obj = obj_accessor_unset(obj, name);

Description:

Basic "delete" accessor for Objects. Given an Object obj and an attribute name name, a new Object will be returned with the un-set attribute value. The existing Object list is unmodified, and a wholly new Object list with the unset value is returned instead.

Arguments:

By Position What it does
obj An Object list. No default.
name The attribute name to access. The name must be present in obj's TOC. No default.

Example 1:

include <openscad_objects/objects.scad>
obj = Object("ExampleObj", ["a1=i", "a2=i"], ["a1", 30]);
new_obj = obj_accessor_unset(obj, "a1");
// new_obj's `a1` attribute is now unset
echo(obj_accessor_get(new_obj, "a1"));
// emits: ECHO: undef




Section: Managing Lists of Objects

These are functions to help manage lists or collections of Objects. In most cases, standard list manipulation functions work fine, but when you need to select or act on a subset of Objects based on their attribute values, turn here.

Function: obj_select()

Synopsis: Select Objects from a list based on their position in that list

Usage:

  • list = obj_select(obj_list, idxs);

Description:

Given a list of objects obj_list and a list of element indexes idxs, returns the objects in obj_list identified by their index position idx as a new list list.

The Objects need not be all of the same object type.

Arguments:

By Position What it does
obj_list A list of Objects
idxs A list of positional index integers

It's probably a really bad idea to give a list of idxs that doesn't match the length of obj_list.

Todo:

  • turns out this is just a very thinly wrapped select(). Is there a reason to keep this?

Function: obj_select_by_attr_defined()

Synopsis: Select Objects from a list if they have a particular attribute defined

Usage:

  • list = obj_select_by_attr_defined(obj_list, attr);

Description:

Given a list of Objects obj_list and an attribute name attr, return all the Objects in obj_list that have the attribute attr defined as a list list. The Objects are returned in the order they appear in obj_list. The returned list of Objects may not be the same length as obj_list. The returned list list may have no elements in it.

The list of Objects given need not be all of the same type.

Arguments:

By Position What it does
obj_list A list of Objects
attr An attribute name

Function: obj_select_by_attr_value()

Synopsis: Select Objects from a list based on the value of a specified attribute

Usage:

  • list = obj_select_by_attr_value(obj_list, attr, value);

Description:

Given an list of Objects obj_list, an attribute name attr, and a comparison value value, return all Objects in obj_list whose value for attr matches value as a list list. The Objects are returned in the order they appear in obj_list.

The Objects in obj_list need not be all of the same type.

Arguments:

By Position What it does
obj_list A list of Objects
attr An attribute name
value A comparison value

Function: obj_sort_by_attribute()

Synopsis: Sort a list of Objects based on a specified attribute

Usage:

  • list = obj_sort_by_attribute(obj_list, attr);

Description:

Given a list of Objects obj_list and an attribute name attr, sort the list of objects by the value of their attribute attr and return that list.

Objects listed in obj_list need not be all of the same type.

Arguments:

By Position What it does
obj_list A list of Objects
attr An attribute name

Function: obj_select_values_from_obj_list()

Synopsis: Get a list of values for one attribute out of a list of Objects

Usage:

  • list = obj_select_values_from_obj_list(obj_list, attr);
  • list = obj_select_values_from_obj_list(obj_list, attr, <default=undef>);

Description:

Given a list of Objects obj_list and an attribute name attr, return a list of all the values of attr in the Objects in obj_list. The values are returned in the order they appear in obj_list.

The Objects in obj_list need not be all the same type.

Arguments:

By Position What it does
obj_list A list of Objects
attr An attribute name
By Name What it does
default A value to be used as a default for Objects that do not have their attribute attr set. Default: undef

Function: obj_regroup_list_by_attr()

Synopsis: Group a list of Objects based on a specified attribute

Usage:

  • list = obj_regroup_list_by_attr(obj_list, attr);

Description:

Given a list of Objects obj_list and an attribute name attr, return a list of groups of the Objects in obj_list grouped by defined and unique values of attr.

The groupings of Objects are returned in no particular order.

Objects listed in obj_list need not be all of the same type.

Arguments:

By Position What it does
obj_list A list of Objects
attr An attribute name

If an Object within obj_list has the attribute attr but it is neither defined nor has a default value, it will not be grouped. Grouping Objects with an undef value for the attribute is something that'd be nice; however, the functions obj_regroup_list_by_attr() depends on do not today support selecting Objects on an undefined attribute.


Function: obj_select_by_attrs_values()

Synopsis: Select Objects from a list based on one or more sets of attribute-value pairs

See Also: obj_select_by_attr_value()

Usage:

  • list = obj_select_by_attrs_values(obj_list, arglist);

Description:

Given a list of Objects obj_list and a list of selectors arglist, recursively examine obj_list to select items that match each selector, and return those elements as list. The elements in list are returned in the order they appear in obj_list.

For obj_select_by_attrs_values(), the arglist list of selectors is a collection of [attr, value] lists that are used to exclude items from obj_list. attr is the object attribute to examine, and value is the value that it must match in order to be returned. In brief, obj_select_by_attrs_values() is calling obj_select_by_attr_value() for each pairing in arglist against the same obj_list over and over, ideally reducing the number of elements in obj_list to get the desired set. (You could probably achieve the same by getting the results of obj_select_by_attr_value() for each selector, and then calculating the intersection of all those results; however, obj_select_by_attrs_values() is probably going to be faster, since obj_list is likely to be shortened for each recurively-examined selector.)

The Objects in obj_list need not be all the same type, however they all need to support the arglist selectors.

Arguments:

By Position What it does
obj_list A list of Objects
arglist A list of [attr, value] lists, where: attr is an attribute name; and, value is a comparison value

Function: obj_list_debug_obj()

Synopsis: Run obj_debug_obj() against a list of Objects

Usage:

  • list = obj_list_debug_obj(obj_list);

Description:

Given a list of Objects obj_list, run obj_debug_obj() on each Object, and return their output as a list.

Arguments:

By Position What it does
obj_list A list of Objects

Section: Object Attribute Data Types

Constant: ATTRIBUTE_DATA_TYPES

Synopsis: Known data types

Description:

A list of known attribute data types. "Types" in this context are single-character symbols that indicate what the attribute is meant to hold.

Type IDs: The following data type IDs are known:

Type ID What It Represents
s literal strings. Example: "a string". (Note: Strings are always assigned with quotes and we show that here, but as elsewhere in OpenSCAD the quotes are not part of the string.)
i integers. Example: 1
b booleans. Example: true
l lists. There is no restriction on list length or content. Example: [1, 2, "abc"]
u undefined. Example: undef
o objects. Objects in this context lists that are expected to have a valid TOC as their first element. Example: [["Object", ["attribute", "b"]], undef]

Function: obj_data_type_is_valid()

Synopsis: Test to see if the attribute of a given Object data type is valid

Usage:

  • bool = obj_data_type_is_valid(obj, name);

Description:

Given an Object obj and the name of an attribute within that Object name, return true if the defined data type for that attribute is valid, or false otherwise.

Arguments:

By Position What it does
obj An Object list. No default.
name An attribute name that exists within obj. No default.

Function: data_type_is_valid()

Synopsis: Test to see if a given data type is valid

Usage:

  • data_type_is_valid(type);

Description:

Given a type, returns true if the type is found within ATTRIBUTE_DATA_TYPES, or false otherwise.

Arguments:

By Position What it does
type the type of data to check. No default.

Function: obj_type_check_value()

Synopsis: Test if a specified Object attribute matches its data type

See Also: test_value_type()

Usage:

  • bool = obj_type_check_value(obj, name);
  • bool = obj_type_check_value(obj, name, <value=value>);

Description:

Given a valid Object obj and the name of an attribute that exists in that Object name, return true if the value stored in the Object's attribute matches the data type set for that attribute, or false otherwise.

A specific data value value may be optionally provided, and obj_test_check_value() will check that value against the attribute's data type, rather than whatever is in the Object.

Arguments:

By Position What it does
obj An Object list. No default.
name An attribute name that exists within obj. No default.
By Name What it does
value A value to compare against name's data type. Default: undef (meaning the Object's attribute value will be checked)

Todo:

  • figure out if we care about enforcing object types (eg, ["attr-name", "o:Axle"])
  • re-implement a proper range type

Function: test_value_type()

Synopsis: Test if a data value matches its data type

See Also: ATTRIBUTE_DATA_TYPES

Usage:

  • bool = test_value_type(type_id, value);

Description:

Given a valid data type type_id and a data value value, return true if the value matches the data type, or false otherwise.

Arguments:

By Position What it does
type_id A valid data type ID. No default.
value A data value. No default.

It is an error to specify a data type ID that does not exist within ATTRIBUTE_DATA_TYPES.