Taggable (mixin)
Tag, untag, and query arbitrary string labels on any object.
Tags are stored in the host object’s descriptor as a comma-separated
internal property (_tags). The host class does not need to declare
_tags with has:.
Dependencies
. boop Taggable
Mixing In
boopClass Article isa:SomeBase mixin:Taggable has:title,body public:new,...
Adding Tags
$obj.addTag "urgent"
$obj.addTag "backend" "v2" "reviewed" # multiple at once
$obj.addTag "urgent" # duplicate — silently ignored
Tags are case-sensitive strings. Any non-empty string is a valid tag.
Querying Tags
$obj.hasTag "urgent" && echo "needs attention" # exit 0 = has tag
$obj.hasTag "missing" && echo "yes" # exit 1 — silent
into=all $obj.getTags # all="urgent,backend,v2,reviewed"
into=n $obj.tagCount # n="4"
getTags returns a comma-separated string, or empty string if untagged.
tagCount returns an integer count as a string.
Removing Tags
$obj.removeTag "reviewed"
$obj.removeTag "nonexistent" # no-op — does not crash
Identifying the Mixin
into=v $obj.identify # "Taggable::identify"
Returns the string "Taggable::identify". Used to verify mixin resolution
order when multiple mixins provide the same method name. The first mixin
listed in boopClass wins; call $obj.Taggable::identify to force
Taggable’s version regardless of resolution order.
Common Patterns
Filtering by tag
# Given a list of object IDs, find those tagged "urgent"
for id in "${objects[@]}"; do
_Self="$id" Taggable.hasTag "urgent" && urgent_list+=("$id")
done
Tag-based routing
if $task.hasTag "async"; then
queue_task "$task"
elif $task.hasTag "immediate"; then
run_now "$task"
fi
Reporting tag inventory
into=tags $obj.getTags
IFS=',' read -ra tag_arr <<< "$tags"
printf "Tags (%d):\n" "${#tag_arr[@]}"
for tag in "${tag_arr[@]}"; do
printf " - %s\n" "$tag"
done
Design Notes
No has: required. Tags go into the descriptor under the _tags
key using __boop.set/__boop.get. The leading underscore is a naming
convention for internal/private properties that the host class did not
declare. This avoids polluting the host class’s declared property list.
Comma separator. Tags are stored as tag1,tag2,tag3. This means commas
are not valid characters within a tag value. Any other character is fine.
Conflict resolution. If another mixin also declares identify, the first
mixin listed in boopClass wins. Call $obj.Taggable::identify to invoke
Taggable’s version explicitly regardless of resolution order.