update api documentation

This commit is contained in:
Eric Coissac
2024-11-16 05:59:41 +01:00
parent 03f4e88a17
commit f5d79d0bc4
13 changed files with 372 additions and 62 deletions

View File

@ -4,6 +4,16 @@ import (
"regexp" "regexp"
) )
// IFilterOnName filters the Taxon instances in the Taxonomy based on the specified name.
// If strict is true, it looks for an exact match of the name. If false, it allows for pattern matching.
// It returns a new ITaxon iterator containing the filtered results.
//
// Parameters:
// - name: The name to filter Taxon instances by.
// - strict: A boolean indicating whether to perform strict matching (true) or pattern matching (false).
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances that match the specified name.
func (taxonomy *Taxonomy) IFilterOnName(name string, strict bool) *ITaxon { func (taxonomy *Taxonomy) IFilterOnName(name string, strict bool) *ITaxon {
if strict { if strict {
nodes, ok := taxonomy.index[taxonomy.names.Innerize(name)] nodes, ok := taxonomy.index[taxonomy.names.Innerize(name)]
@ -18,6 +28,16 @@ func (taxonomy *Taxonomy) IFilterOnName(name string, strict bool) *ITaxon {
return taxonomy.Iterator().IFilterOnName(name, strict) return taxonomy.Iterator().IFilterOnName(name, strict)
} }
// IFilterOnName filters the Taxon instances in the iterator based on the specified name.
// If strict is true, it looks for an exact match of the name. If false, it allows for pattern matching.
// It returns a new ITaxon iterator containing the filtered results.
//
// Parameters:
// - name: The name to filter Taxon instances by.
// - strict: A boolean indicating whether to perform strict matching (true) or pattern matching (false).
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances that match the specified name.
func (iterator *ITaxon) IFilterOnName(name string, strict bool) *ITaxon { func (iterator *ITaxon) IFilterOnName(name string, strict bool) *ITaxon {
newIterator := NewITaxon() newIterator := NewITaxon()
sentTaxa := make(map[*string]bool) sentTaxa := make(map[*string]bool)

View File

@ -1,5 +1,15 @@
package obitax package obitax
// IFilterOnTaxRank filters the iterator to include only those Taxon instances
// that match the specified taxonomic rank. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - rank: A string representing the taxonomic rank to filter by.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that have the specified taxonomic rank.
func (iterator *ITaxon) IFilterOnTaxRank(rank string) *ITaxon { func (iterator *ITaxon) IFilterOnTaxRank(rank string) *ITaxon {
newIter := NewITaxon() newIter := NewITaxon()
var prank *string var prank *string
@ -24,14 +34,44 @@ func (iterator *ITaxon) IFilterOnTaxRank(rank string) *ITaxon {
return newIter return newIter
} }
// IFilterOnTaxRank filters the TaxonSet to include only those Taxon instances
// that match the specified taxonomic rank. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - rank: A string representing the taxonomic rank to filter by.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that have the specified taxonomic rank.
func (set *TaxonSet) IFilterOnTaxRank(rank string) *ITaxon { func (set *TaxonSet) IFilterOnTaxRank(rank string) *ITaxon {
return set.Iterator().IFilterOnTaxRank(rank) return set.Iterator().IFilterOnTaxRank(rank)
} }
// IFilterOnTaxRank filters the TaxonSlice to include only those Taxon instances
// that match the specified taxonomic rank. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - rank: A string representing the taxonomic rank to filter by.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that have the specified taxonomic rank.
func (slice *TaxonSlice) IFilterOnTaxRank(rank string) *ITaxon { func (slice *TaxonSlice) IFilterOnTaxRank(rank string) *ITaxon {
return slice.Iterator().IFilterOnTaxRank(rank) return slice.Iterator().IFilterOnTaxRank(rank)
} }
// IFilterOnTaxRank filters the Taxonomy to include only those Taxon instances
// that match the specified taxonomic rank. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - rank: A string representing the taxonomic rank to filter by.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that have the specified taxonomic rank.
func (taxonomy *Taxonomy) IFilterOnTaxRank(rank string) *ITaxon { func (taxonomy *Taxonomy) IFilterOnTaxRank(rank string) *ITaxon {
return taxonomy.Iterator().IFilterOnTaxRank(rank) return taxonomy.Iterator().IFilterOnTaxRank(rank)
} }

View File

@ -1,5 +1,15 @@
package obitax package obitax
// IFilterOnSubcladeOf filters the iterator to include only those Taxon instances
// that are subclades of the specified Taxon. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - taxon: A pointer to the Taxon to filter subclades against.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that are subclades of the specified Taxon.
func (iterator *ITaxon) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon { func (iterator *ITaxon) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon {
newIter := NewITaxon() newIter := NewITaxon()
@ -16,26 +26,66 @@ func (iterator *ITaxon) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon {
return newIter return newIter
} }
// IFilterOnSubcladeOf filters the TaxonSet to include only those Taxon instances
// that are subclades of the specified Taxon. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - taxon: A pointer to the Taxon to filter subclades against.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that are subclades of the specified Taxon.
func (set *TaxonSet) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon { func (set *TaxonSet) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon {
return set.Iterator().IFilterOnSubcladeOf(taxon) return set.Iterator().IFilterOnSubcladeOf(taxon)
} }
// IFilterOnSubcladeOf filters the TaxonSlice to include only those Taxon instances
// that are subclades of the specified Taxon. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - taxon: A pointer to the Taxon to filter subclades against.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that are subclades of the specified Taxon.
func (slice *TaxonSlice) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon { func (slice *TaxonSlice) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon {
return slice.Iterator().IFilterOnSubcladeOf(taxon) return slice.Iterator().IFilterOnSubcladeOf(taxon)
} }
// IFilterOnSubcladeOf filters the Taxonomy to include only those Taxon instances
// that are subclades of the specified Taxon. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - taxon: A pointer to the Taxon to filter subclades against.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that are subclades of the specified Taxon.
func (taxonomy *Taxonomy) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon { func (taxonomy *Taxonomy) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon {
return taxonomy.Iterator().IFilterOnSubcladeOf(taxon) return taxonomy.Iterator().IFilterOnSubcladeOf(taxon)
} }
// IFilterBelongingSubclades filters the iterator to include only those Taxon instances
// that belong to any of the specified subclades. It returns a new ITaxon iterator
// containing the filtered results.
//
// Parameters:
// - clades: A pointer to a TaxonSet containing the subclades to filter against.
//
// Returns:
// - A pointer to a new ITaxon iterator containing only the Taxon instances
// that belong to the specified subclades. If the clades set is empty,
// it returns the original iterator.
func (iterator *ITaxon) IFilterBelongingSubclades(clades *TaxonSet) *ITaxon { func (iterator *ITaxon) IFilterBelongingSubclades(clades *TaxonSet) *ITaxon {
if clades.Len() == 0 { if clades.Len() == 0 {
return iterator return iterator
} }
// Considers the second simplest case when only // Considers the second simplest case when only
// a single subclase is provided // a single subclade is provided
if clades.Len() == 1 { if clades.Len() == 1 {
keys := make([]*string, 0, len(clades.set)) keys := make([]*string, 0, len(clades.set))
for k := range clades.set { for k := range clades.set {

View File

@ -5,12 +5,12 @@ import "sync"
// InnerString is a struct that holds a map of strings and a read-write lock for concurrent access. // InnerString is a struct that holds a map of strings and a read-write lock for concurrent access.
// The index map is used to store key-value pairs of strings. // The index map is used to store key-value pairs of strings.
type InnerString struct { type InnerString struct {
index map[string]*string index map[string]*string // Map to store string values
lock sync.RWMutex lock sync.RWMutex // Read-write lock for concurrent access
} }
// NewInnerString creates a new instance of InnerString. // NewInnerString creates a new instance of InnerString.
// The lock is set to false. // It initializes the index map and prepares the lock for use.
func NewInnerString() *InnerString { func NewInnerString() *InnerString {
return &InnerString{ return &InnerString{
index: make(map[string]*string), index: make(map[string]*string),
@ -18,14 +18,14 @@ func NewInnerString() *InnerString {
} }
// Innerize stores the given value in the index map if it is not already present. // Innerize stores the given value in the index map if it is not already present.
// It returns the value associated with the key, which is either the newly stored value // It returns the pointer to the string associated with the key, which is either the newly stored value
// or the existing value if it was already present in the map. // or the existing value if it was already present in the map.
// //
// Parameters: // Parameters:
// - value: The string value to be stored in the index map. // - value: The string value to be stored in the index map.
// //
// Returns: // Returns:
// - The string value associated with the key. // - A pointer to the string value associated with the key.
func (i *InnerString) Innerize(value string) *string { func (i *InnerString) Innerize(value string) *string {
i.lock.Lock() i.lock.Lock()
defer i.lock.Unlock() defer i.lock.Unlock()
@ -38,6 +38,7 @@ func (i *InnerString) Innerize(value string) *string {
return s return s
} }
// Slice returns a slice of strings containing all the values stored in the index map.
func (i *InnerString) Slice() []string { func (i *InnerString) Slice() []string {
rep := make([]string, len(i.index)) rep := make([]string, len(i.index))
j := 0 j := 0

View File

@ -2,8 +2,16 @@ package obitax
import log "github.com/sirupsen/logrus" import log "github.com/sirupsen/logrus"
// IsSubCladeOf checks if the current Taxon is a subclade of the specified parent Taxon.
// It returns true if the current Taxon is a descendant of the parent Taxon in the taxonomy hierarchy.
//
// Parameters:
// - parent: A pointer to the parent Taxon to check against.
//
// Returns:
// - A boolean indicating whether the current Taxon is a subclade of the parent Taxon.
// - Logs a fatal error if the two taxa do not belong to the same taxonomy.
func (taxon *Taxon) IsSubCladeOf(parent *Taxon) bool { func (taxon *Taxon) IsSubCladeOf(parent *Taxon) bool {
if taxon.Taxonomy != parent.Taxonomy { if taxon.Taxonomy != parent.Taxonomy {
log.Fatalf( log.Fatalf(
"Both taxa %s and %s must belong to the same taxonomy", "Both taxa %s and %s must belong to the same taxonomy",
@ -21,6 +29,15 @@ func (taxon *Taxon) IsSubCladeOf(parent *Taxon) bool {
return false return false
} }
// IsBelongingSubclades checks if the current Taxon belongs to any of the specified subclades.
// It traverses up the taxonomy hierarchy to determine if the current Taxon or any of its ancestors
// belong to the provided TaxonSet.
//
// Parameters:
// - clades: A pointer to a TaxonSet containing the subclades to check against.
//
// Returns:
// - A boolean indicating whether the current Taxon or any of its ancestors belong to the specified subclades.
func (taxon *Taxon) IsBelongingSubclades(clades *TaxonSet) bool { func (taxon *Taxon) IsBelongingSubclades(clades *TaxonSet) bool {
ok := clades.Contains(taxon.Node.id) ok := clades.Contains(taxon.Node.id)

View File

@ -1,22 +1,28 @@
package obitax package obitax
// ITaxon represents an iterator for traversing Taxon instances.
// It provides methods to retrieve the next Taxon and check if the iteration is finished.
type ITaxon struct { type ITaxon struct {
source chan *Taxon source chan *Taxon // Channel to receive Taxon instances
current *Taxon current *Taxon // Current Taxon instance
finished bool finished bool // Indicates if the iteration is finished
p_finished *bool p_finished *bool // Pointer to the finished status
} }
// NewITaxon creates a new ITaxon iterator instance and initializes its fields.
func NewITaxon() *ITaxon { func NewITaxon() *ITaxon {
i := ITaxon{ i := ITaxon{
source: make(chan *Taxon), source: make(chan *Taxon),
current: nil, current: nil,
finished: false, finished: false,
p_finished: nil} p_finished: nil,
}
i.p_finished = &i.finished i.p_finished = &i.finished
return &i return &i
} }
// Iterator creates a new ITaxon iterator for the TaxonSet.
// It starts a goroutine to send Taxon instances from the set to the iterator's source channel.
func (set *TaxonSet) Iterator() *ITaxon { func (set *TaxonSet) Iterator() *ITaxon {
i := NewITaxon() i := NewITaxon()
@ -33,6 +39,8 @@ func (set *TaxonSet) Iterator() *ITaxon {
return i return i
} }
// Iterator creates a new ITaxon iterator for the TaxonSlice.
// It starts a goroutine to send Taxon instances from the slice to the iterator's source channel.
func (set *TaxonSlice) Iterator() *ITaxon { func (set *TaxonSlice) Iterator() *ITaxon {
i := NewITaxon() i := NewITaxon()
@ -49,10 +57,13 @@ func (set *TaxonSlice) Iterator() *ITaxon {
return i return i
} }
func (taxonmy *Taxonomy) Iterator() *ITaxon { // Iterator creates a new ITaxon iterator for the Taxonomy's nodes.
return taxonmy.nodes.Iterator() func (taxonomy *Taxonomy) Iterator() *ITaxon {
return taxonomy.nodes.Iterator()
} }
// Next advances the iterator to the next Taxon instance.
// It returns true if there is a next Taxon, and false if the iteration is finished.
func (iterator *ITaxon) Next() bool { func (iterator *ITaxon) Next() bool {
if *(iterator.p_finished) { if *(iterator.p_finished) {
return false return false
@ -69,20 +80,19 @@ func (iterator *ITaxon) Next() bool {
return false return false
} }
// The 'Get' method returns the instance of *TaxNode // Get returns the current Taxon instance pointed to by the iterator.
// currently pointed by the iterator. You have to use the // You must call 'Next' before calling 'Get' to retrieve the next instance.
// 'Next' method to move to the next entry before calling
// 'Get' to retreive the following instance.
func (iterator *ITaxon) Get() *Taxon { func (iterator *ITaxon) Get() *Taxon {
return iterator.current return iterator.current
} }
// Finished returns 'true' value if no more data is available // Finished returns true if no more data is available from the iterator.
// from the iterator.
func (iterator *ITaxon) Finished() bool { func (iterator *ITaxon) Finished() bool {
return *iterator.p_finished return *iterator.p_finished
} }
// Split creates a new ITaxon iterator that shares the same source channel
// and finished status as the original iterator.
func (iterator *ITaxon) Split() *ITaxon { func (iterator *ITaxon) Split() *ITaxon {
return &ITaxon{ return &ITaxon{
source: iterator.source, source: iterator.source,

View File

@ -1,16 +1,35 @@
package obitax package obitax
import ( import (
log "github.com/sirupsen/logrus" "fmt"
) )
// LCA computes the Lowest Common Ancestor (LCA) of two Taxon instances.
// It traverses the paths from both taxa to the root and finds the deepest
// common node in the taxonomy hierarchy.
//
// Parameters:
// - t2: A pointer to another Taxon instance to find the LCA with.
//
// Returns:
// - A pointer to the Taxon representing the LCA of the two taxa, or an error
// if either of the taxa is nil, if they are not in the same taxonomy, or
// if the taxonomy is unrooted.
func (t1 *Taxon) LCA(t2 *Taxon) (*Taxon, error) { func (t1 *Taxon) LCA(t2 *Taxon) (*Taxon, error) {
if t1 == nil { if t1 == nil || t1.Node == nil {
log.Panicf("Try to get LCA of nil taxon") return nil, fmt.Errorf("try to get LCA of nil taxon")
} }
if t2 == nil { if t2 == nil || t2.Node == nil {
log.Panicf("Try to get LCA of nil taxon") return nil, fmt.Errorf("try to get LCA of nil taxon")
}
if t1.Taxonomy != t2.Taxonomy {
return nil, fmt.Errorf("taxa are not in the same taxonomy")
}
if !t1.Taxonomy.HasRoot() {
return nil, fmt.Errorf("taxa belong to an unrooted taxonomy")
} }
p1 := t1.Path() p1 := t1.Path()

View File

@ -11,8 +11,8 @@ import (
// it belongs to and the specific taxon node information. // it belongs to and the specific taxon node information.
// //
// Fields: // Fields:
// - Taxonomy: A pointer to the Taxonomy[T] instance that this taxon is part of. // - Taxonomy: A pointer to the Taxonomy instance that this taxon is part of.
// - Node: A pointer to the TaxNode[T] instance representing the specific taxon. // - Node: A pointer to the TaxNode instance representing the specific taxon.
type Taxon struct { type Taxon struct {
Taxonomy *Taxonomy Taxonomy *Taxonomy
Node *TaxNode Node *TaxNode
@ -42,6 +42,14 @@ func (taxon *Taxon) ScientificName() string {
return taxon.Node.ScientificName() return taxon.Node.ScientificName()
} }
// Name retrieves the name of the Taxon based on the specified class.
// It uses the taxonomy's name classes to format the name appropriately.
//
// Parameters:
// - class: A string representing the name class to use for retrieval.
//
// Returns:
// - The name of the taxon as a string.
func (taxon *Taxon) Name(class string) string { func (taxon *Taxon) Name(class string) string {
if taxon == nil { if taxon == nil {
return "NA" return "NA"
@ -50,6 +58,14 @@ func (taxon *Taxon) Name(class string) string {
return taxon.Node.Name(pclass) return taxon.Node.Name(pclass)
} }
// IsNameEqual checks if the given name is equal to the name of the Taxon.
// It compares the provided name with the name stored in the TaxNode.
//
// Parameters:
// - name: A string representing the name to compare against.
//
// Returns:
// - A boolean indicating whether the names are equal.
func (taxon *Taxon) IsNameEqual(name string) bool { func (taxon *Taxon) IsNameEqual(name string) bool {
if taxon == nil { if taxon == nil {
return false return false
@ -58,6 +74,13 @@ func (taxon *Taxon) IsNameEqual(name string) bool {
return taxon.Node.IsNameEqual(name) return taxon.Node.IsNameEqual(name)
} }
// IsNameMatching checks if the name of the Taxon matches the given regular expression pattern.
//
// Parameters:
// - pattern: A pointer to a compiled regular expression to match against the taxon's name.
//
// Returns:
// - A boolean indicating whether the taxon's name matches the specified pattern.
func (taxon *Taxon) IsNameMatching(pattern *regexp.Regexp) bool { func (taxon *Taxon) IsNameMatching(pattern *regexp.Regexp) bool {
if taxon == nil { if taxon == nil {
return false return false
@ -66,6 +89,12 @@ func (taxon *Taxon) IsNameMatching(pattern *regexp.Regexp) bool {
return taxon.Node.IsNameMatching(pattern) return taxon.Node.IsNameMatching(pattern)
} }
// SetName sets the name of the Taxon based on the provided name and class.
// It logs a panic if the taxon pointer is nil.
//
// Parameters:
// - name: A string representing the new name to set for the taxon.
// - class: A string representing the name class to associate with the taxon.
func (taxon *Taxon) SetName(name, class string) { func (taxon *Taxon) SetName(name, class string) {
if taxon == nil { if taxon == nil {
log.Panicf("nil taxon pointer for name %s [%s]", name, class) log.Panicf("nil taxon pointer for name %s [%s]", name, class)
@ -76,6 +105,11 @@ func (taxon *Taxon) SetName(name, class string) {
taxon.Node.SetName(pname, pclass) taxon.Node.SetName(pname, pclass)
} }
// IsRoot checks if the Taxon is the root of the taxonomy.
// It returns true if the taxon is nil or if it matches the root node of the taxonomy.
//
// Returns:
// - A boolean indicating whether the Taxon is the root of the taxonomy.
func (taxon *Taxon) IsRoot() bool { func (taxon *Taxon) IsRoot() bool {
if taxon == nil { if taxon == nil {
return true return true
@ -101,7 +135,7 @@ func (taxon *Taxon) Rank() string {
// to create a new Taxon instance representing the parent taxon. // to create a new Taxon instance representing the parent taxon.
// //
// Returns: // Returns:
// - A pointer to the parent Taxon[T]. If the parent does not exist, it returns // - A pointer to the parent Taxon. If the parent does not exist, it returns
// a Taxon with a nil Node. // a Taxon with a nil Node.
func (taxon *Taxon) Parent() *Taxon { func (taxon *Taxon) Parent() *Taxon {
if taxon == nil { if taxon == nil {
@ -120,7 +154,6 @@ func (taxon *Taxon) Parent() *Taxon {
// is called with each Taxon in the path from the current taxon to the root. If the // is called with each Taxon in the path from the current taxon to the root. If the
// taxonomy has no root node, the method logs a fatal error and terminates the program. // taxonomy has no root node, the method logs a fatal error and terminates the program.
func (taxon *Taxon) IPath() iter.Seq[*Taxon] { func (taxon *Taxon) IPath() iter.Seq[*Taxon] {
if taxon.Taxonomy.root == nil { if taxon.Taxonomy.root == nil {
log.Fatalf("Taxon[%v].IPath(): Taxonomy has no root node", taxon.Taxonomy.name) log.Fatalf("Taxon[%v].IPath(): Taxonomy has no root node", taxon.Taxonomy.name)
} }
@ -140,13 +173,13 @@ func (taxon *Taxon) IPath() iter.Seq[*Taxon] {
} }
} }
// Path returns a slice of TaxNode[T] representing the path from the current Taxon // Path returns a slice of TaxNode representing the path from the current Taxon
// to the root Taxon in the associated Taxonomy. It collects all the nodes in the path // to the root Taxon in the associated Taxonomy. It collects all the nodes in the path
// using the IPath method and returns them as a TaxonSlice. // using the IPath method and returns them as a TaxonSlice.
// //
// Returns: // Returns:
// - A pointer to a TaxonSlice[T] containing the TaxNode[T] instances in the path // - A pointer to a TaxonSlice containing the TaxNode instances in the path
// from the current taxon to the root. // from the current taxon to the root. If the taxon is nil, it returns nil.
func (taxon *Taxon) Path() *TaxonSlice { func (taxon *Taxon) Path() *TaxonSlice {
if taxon == nil { if taxon == nil {
return nil return nil
@ -196,7 +229,7 @@ func (taxon *Taxon) HasRankDefined(rank string) bool {
// - rank: A string representing the rank to search for (e.g., "species", "genus"). // - rank: A string representing the rank to search for (e.g., "species", "genus").
// //
// Returns: // Returns:
// - A pointer to the Taxon[T] that matches the specified rank, or nil if no such taxon exists // - A pointer to the Taxon that matches the specified rank, or nil if no such taxon exists
// in the path to the root. // in the path to the root.
func (taxon *Taxon) TaxonAtRank(rank string) *Taxon { func (taxon *Taxon) TaxonAtRank(rank string) *Taxon {
if taxon == nil { if taxon == nil {
@ -219,7 +252,7 @@ func (taxon *Taxon) TaxonAtRank(rank string) *Taxon {
// the matching Taxon. // the matching Taxon.
// //
// Returns: // Returns:
// - A pointer to the Taxon[T] that matches the "species" rank, or nil if no such taxon // - A pointer to the Taxon that matches the "species" rank, or nil if no such taxon
// exists in the path to the root. // exists in the path to the root.
func (taxon *Taxon) Species() *Taxon { func (taxon *Taxon) Species() *Taxon {
return taxon.TaxonAtRank("species") return taxon.TaxonAtRank("species")
@ -230,7 +263,7 @@ func (taxon *Taxon) Species() *Taxon {
// the matching Taxon. // the matching Taxon.
// //
// Returns: // Returns:
// - A pointer to the Taxon[T] that matches the "genus" rank, or nil if no such taxon // - A pointer to the Taxon that matches the "genus" rank, or nil if no such taxon
// exists in the path to the root. // exists in the path to the root.
func (taxon *Taxon) Genus() *Taxon { func (taxon *Taxon) Genus() *Taxon {
return taxon.TaxonAtRank("genus") return taxon.TaxonAtRank("genus")
@ -241,7 +274,7 @@ func (taxon *Taxon) Genus() *Taxon {
// the matching Taxon. // the matching Taxon.
// //
// Returns: // Returns:
// - A pointer to the Taxon[T] that matches the "family" rank, or nil if no such taxon // - A pointer to the Taxon that matches the "family" rank, or nil if no such taxon
// exists in the path to the root. // exists in the path to the root.
func (taxon *Taxon) Family() *Taxon { func (taxon *Taxon) Family() *Taxon {
return taxon.TaxonAtRank("family") return taxon.TaxonAtRank("family")

View File

@ -11,12 +11,12 @@ import (
// scientific name, and alternate names. // scientific name, and alternate names.
// //
// Fields: // Fields:
// - id: The unique identifier of the taxon of type T. // - id: A pointer to the unique identifier of the taxon of type T.
// - parent: The identifier of the parent taxon of type T. // - parent: A pointer to the identifier of the parent taxon of type T.
// - rank: The rank of the taxon (e.g., species, genus). // - rank: A pointer to the rank of the taxon (e.g., species, genus).
// - scientificname: A pointer to a string representing the scientific name of the taxon. // - scientificname: A pointer to a string representing the scientific name of the taxon.
// - alternatenames: A pointer to a map of alternate names for the taxon, where the key is // - alternatenames: A pointer to a map of alternate names for the taxon, where the key is
// a string representing the class name and the value is a pointer to a string // a pointer to a string representing the class name and the value is a pointer to a string
// representing the name. // representing the name.
type TaxNode struct { type TaxNode struct {
id *string id *string
@ -45,7 +45,7 @@ func (node *TaxNode) String(taxonomyCode string) string {
// It retrieves the identifier of type T associated with the taxon node. // It retrieves the identifier of type T associated with the taxon node.
// //
// Returns: // Returns:
// - The unique identifier of the taxon node of type T. // - A pointer to the unique identifier of the taxon node of type T.
func (node *TaxNode) Id() *string { func (node *TaxNode) Id() *string {
return node.id return node.id
} }
@ -54,7 +54,7 @@ func (node *TaxNode) Id() *string {
// It retrieves the parent identifier of type T associated with the taxon node. // It retrieves the parent identifier of type T associated with the taxon node.
// //
// Returns: // Returns:
// - The identifier of the parent taxon of type T. // - A pointer to the identifier of the parent taxon of type T.
func (node *TaxNode) ParentId() *string { func (node *TaxNode) ParentId() *string {
return node.parent return node.parent
} }
@ -64,8 +64,9 @@ func (node *TaxNode) ParentId() *string {
// //
// Returns: // Returns:
// - The scientific name of the taxon as a string. // - The scientific name of the taxon as a string.
// - Note: This method assumes that scientificname is not nil; // - If the scientific name is nil, it returns "NA".
// if it may be nil, additional error handling should be implemented. // - Note: This method assumes that the TaxNode itself is not nil; if it may be nil,
// additional error handling should be implemented.
func (node *TaxNode) ScientificName() string { func (node *TaxNode) ScientificName() string {
if node == nil { if node == nil {
return "NA" return "NA"
@ -77,18 +78,18 @@ func (node *TaxNode) ScientificName() string {
} }
// Name retrieves the name of the TaxNode based on the specified class. // Name retrieves the name of the TaxNode based on the specified class.
// If the class is "scientificname", it returns the scientific name of the taxon. // If the class is "scientific name", it returns the scientific name of the taxon.
// If the class corresponds to an alternate name, it retrieves that name from the alternatenames map. // If the class corresponds to an alternate name, it retrieves that name from the alternatenames map.
// If the class is not recognized or if no alternate names exist, it returns an empty string. // If the class is not recognized or if no alternate names exist, it returns an empty string.
// //
// Parameters: // Parameters:
// - class: A string representing the class of name to retrieve (e.g., "scientificname" or an alternate name class). // - class: A pointer to a string representing the class of name to retrieve
// (e.g., "scientific name" or an alternate name class).
// //
// Returns: // Returns:
// - The name of the taxon as a string. If the class is not recognized or if no name is available, // - The name of the taxon as a string. If the class is not recognized or if no name is available,
// an empty string is returned. // an empty string is returned.
func (node *TaxNode) Name(class *string) string { func (node *TaxNode) Name(class *string) string {
if *class == "scientific name" { if *class == "scientific name" {
return *node.scientificname return *node.scientificname
} }
@ -106,6 +107,14 @@ func (node *TaxNode) Name(class *string) string {
return "" return ""
} }
// SetName sets the name of the TaxNode based on the specified class.
// If the class is "scientific name", it updates the scientific name of the taxon.
// If the class corresponds to an alternate name, it adds or updates that name in the alternatenames map.
//
// Parameters:
// - name: A pointer to a string representing the name to set.
// - class: A pointer to a string representing the class of name to set
// (e.g., "scientific name" or an alternate name class).
func (node *TaxNode) SetName(name, class *string) { func (node *TaxNode) SetName(name, class *string) {
if node == nil { if node == nil {
log.Panic("Cannot set name of nil TaxNode") log.Panic("Cannot set name of nil TaxNode")

View File

@ -1,3 +1,10 @@
/*
Package obitax provides functionality for managing taxonomic data structures,
including hierarchical classifications of taxa. It includes the Taxonomy struct,
which represents a taxonomy and provides methods for working with taxon identifiers
and retrieving information about taxa.
*/
package obitax package obitax
import ( import (
@ -14,9 +21,13 @@ import (
// Fields: // Fields:
// - name: The name of the taxonomy. // - name: The name of the taxonomy.
// - code: A unique code representing the taxonomy. // - code: A unique code representing the taxonomy.
// - ids: A pointer to an InnerString instance that holds the taxon identifiers.
// - ranks: A pointer to an InnerString instance that holds the ranks of the taxa. // - ranks: A pointer to an InnerString instance that holds the ranks of the taxa.
// - nameclasses: A pointer to an InnerString instance that holds the name classes.
// - names: A pointer to an InnerString instance that holds the names of the taxa.
// - nodes: A pointer to a TaxonSet containing all the nodes (taxa) in the taxonomy. // - nodes: A pointer to a TaxonSet containing all the nodes (taxa) in the taxonomy.
// - root: A pointer to the root TaxNode of the taxonomy. // - root: A pointer to the root TaxNode of the taxonomy.
// - matcher: A regular expression used for validating taxon identifiers.
// - index: A map that indexes taxa by their string representation for quick access. // - index: A map that indexes taxa by their string representation for quick access.
type Taxonomy struct { type Taxonomy struct {
name string name string
@ -37,14 +48,13 @@ type Taxonomy struct {
// Parameters: // Parameters:
// - name: The name of the taxonomy to be created. // - name: The name of the taxonomy to be created.
// - code: A unique code representing the taxonomy. // - code: A unique code representing the taxonomy.
// - codeCharacters: A string representing valid characters for the taxon identifiers.
// //
// Returns: // Returns:
// - A pointer to the newly created Taxonomy instance. // - A pointer to the newly created Taxonomy instance.
func NewTaxonomy(name, code, codeCharacters string) *Taxonomy { func NewTaxonomy(name, code, codeCharacters string) *Taxonomy {
set := make(map[*string]*TaxNode) set := make(map[*string]*TaxNode)
// codeCharacters := "[[:alnum:]]" // [[:digit:]]
matcher := regexp.MustCompile(fmt.Sprintf("^[[:blank:]]*(%s:)?(%s+)", code, codeCharacters)) matcher := regexp.MustCompile(fmt.Sprintf("^[[:blank:]]*(%s:)?(%s+)", code, codeCharacters))
taxonomy := &Taxonomy{ taxonomy := &Taxonomy{
@ -119,7 +129,7 @@ func (taxonomy *Taxonomy) TaxidSting(id string) (string, error) {
// - taxid: A string representation of the taxon identifier to be retrieved. // - taxid: A string representation of the taxon identifier to be retrieved.
// //
// Returns: // Returns:
// - A pointer to the Taxon[T] instance associated with the provided taxid. // - A pointer to the Taxon instance associated with the provided taxid.
// - If the taxid is unknown, the method will log a fatal error. // - If the taxid is unknown, the method will log a fatal error.
func (taxonomy *Taxonomy) Taxon(taxid string) *Taxon { func (taxonomy *Taxonomy) Taxon(taxid string) *Taxon {
id, err := taxonomy.Id(taxid) id, err := taxonomy.Id(taxid)
@ -139,11 +149,11 @@ func (taxonomy *Taxonomy) Taxon(taxid string) *Taxon {
return taxon return taxon
} }
// TaxonSet returns the set of taxon nodes contained within the Taxonomy. // AsTaxonSet returns the set of taxon nodes contained within the Taxonomy.
// It provides access to the underlying collection of taxon nodes for further operations. // It provides access to the underlying collection of taxon nodes for further operations.
// //
// Returns: // Returns:
// - A pointer to the TaxonSet[T] representing the collection of taxon nodes in the taxonomy. // - A pointer to the TaxonSet representing the collection of taxon nodes in the taxonomy.
func (taxonomy *Taxonomy) AsTaxonSet() *TaxonSet { func (taxonomy *Taxonomy) AsTaxonSet() *TaxonSet {
return taxonomy.nodes return taxonomy.nodes
} }
@ -168,7 +178,7 @@ func (taxonomy *Taxonomy) Len() int {
// - replace: A boolean indicating whether to replace an existing taxon with the same taxid. // - replace: A boolean indicating whether to replace an existing taxon with the same taxid.
// //
// Returns: // Returns:
// - A pointer to the newly created Taxon[T] instance. // - A pointer to the newly created Taxon instance.
// - An error if the taxon cannot be added (e.g., it already exists and replace is false). // - An error if the taxon cannot be added (e.g., it already exists and replace is false).
func (taxonomy *Taxonomy) AddTaxon(taxid, parent string, rank string, isRoot bool, replace bool) (*Taxon, error) { func (taxonomy *Taxonomy) AddTaxon(taxid, parent string, rank string, isRoot bool, replace bool) (*Taxon, error) {
@ -204,6 +214,19 @@ func (taxonomy *Taxonomy) AddTaxon(taxid, parent string, rank string, isRoot boo
}, nil }, nil
} }
// AddAlias adds an alias for an existing taxon in the taxonomy.
// It associates a new taxon identifier with an existing taxon identifier,
// allowing for alternative names to be used. If specified, it can replace
// an existing alias.
//
// Parameters:
// - newtaxid: The new identifier to be added as an alias.
// - oldtaxid: The existing identifier of the taxon to which the alias is added.
// - replace: A boolean indicating whether to replace an existing alias with the same newtaxid.
//
// Returns:
// - A pointer to the Taxon associated with the oldtaxid.
// - An error if the alias cannot be added (e.g., the old taxon does not exist).
func (taxonomy *Taxonomy) AddAlias(newtaxid, oldtaxid string, replace bool) (*Taxon, error) { func (taxonomy *Taxonomy) AddAlias(newtaxid, oldtaxid string, replace bool) (*Taxon, error) {
newid, err := taxonomy.Id(newtaxid) newid, err := taxonomy.Id(newtaxid)
@ -241,14 +264,56 @@ func (taxonomy *Taxonomy) RankList() []string {
return taxonomy.ranks.Slice() return taxonomy.ranks.Slice()
} }
// Index returns a pointer to the map that indexes taxa by their string representation.
// This allows for quick access to taxon sets based on their identifiers.
//
// Returns:
// - A pointer to the map that indexes taxa in the taxonomy.
func (taxonomy *Taxonomy) Index() *map[*string]*TaxonSet { func (taxonomy *Taxonomy) Index() *map[*string]*TaxonSet {
return &(taxonomy.index) return &(taxonomy.index)
} }
// Name returns the name of the taxonomy.
//
// Returns:
// - A string representing the name of the taxonomy.
func (taxonomy *Taxonomy) Name() string { func (taxonomy *Taxonomy) Name() string {
return taxonomy.name return taxonomy.name
} }
// Code returns the unique code representing the taxonomy.
//
// Returns:
// - A string representing the unique code of the taxonomy.
func (taxonomy *Taxonomy) Code() string { func (taxonomy *Taxonomy) Code() string {
return taxonomy.code return taxonomy.code
} }
// SetRoot sets the root taxon for the taxonomy.
// It associates the provided Taxon instance as the root of the taxonomy.
//
// Parameters:
// - root: A pointer to the Taxon instance to be set as the root.
func (taxonomy *Taxonomy) SetRoot(root *Taxon) {
taxonomy.root = root.Node
}
// Root returns the root taxon of the taxonomy.
// It returns a pointer to a Taxon instance associated with the root node.
//
// Returns:
// - A pointer to the Taxon instance representing the root of the taxonomy.
func (taxonomy *Taxonomy) Root() *Taxon {
return &Taxon{
Taxonomy: taxonomy,
Node: taxonomy.root,
}
}
// HasRoot checks if the Taxonomy has a root node defined.
//
// Returns:
// - A boolean indicating whether the Taxonomy has a root node (true) or not (false).
func (taxonomy *Taxonomy) HasRoot() bool {
return taxonomy.root != nil
}

View File

@ -1,4 +1,10 @@
// Package obitax provides functionality for managing taxonomic data structures. /*
Package obitax provides functionality for managing taxonomic data structures,
specifically for representing and manipulating collections of taxa within a taxonomy.
It includes the TaxonSet structure, which holds mappings of taxon identifiers to their
corresponding TaxNode instances, along with methods for managing and querying these taxa.
*/
package obitax package obitax
import log "github.com/sirupsen/logrus" import log "github.com/sirupsen/logrus"
@ -17,6 +23,11 @@ type TaxonSet struct {
taxonomy *Taxonomy taxonomy *Taxonomy
} }
// NewTaxonSet creates a new TaxonSet associated with the given Taxonomy.
// It initializes the set as an empty map and sets the alias count to zero.
//
// Returns:
// - A pointer to the newly created TaxonSet.
func (taxonomy *Taxonomy) NewTaxonSet() *TaxonSet { func (taxonomy *Taxonomy) NewTaxonSet() *TaxonSet {
return &TaxonSet{ return &TaxonSet{
set: make(map[*string]*TaxNode), set: make(map[*string]*TaxNode),
@ -77,10 +88,16 @@ func (set *TaxonSet) Insert(node *TaxNode) {
set.set[node.id] = node set.set[node.id] = node
} }
// InsertTaxon adds a Taxon to the TaxonSet. It verifies that the Taxon belongs
// to the same Taxonomy as the TaxonSet before insertion. If they do not match,
// it logs a fatal error and terminates the program.
//
// Parameters:
// - taxon: A pointer to the Taxon instance to be added to the TaxonSet.
func (set *TaxonSet) InsertTaxon(taxon *Taxon) { func (set *TaxonSet) InsertTaxon(taxon *Taxon) {
if set.taxonomy != taxon.Taxonomy { if set.taxonomy != taxon.Taxonomy {
log.Fatalf( log.Fatalf(
"Cannot insert taxon %s into taxon set belonging %s taxonomy", "Cannot insert taxon %s into taxon set belonging to %s taxonomy",
taxon.String(), taxon.String(),
set.taxonomy.name, set.taxonomy.name,
) )

View File

@ -1,3 +1,13 @@
/*
Package obitax provides functionality for handling taxonomic data structures,
specifically for representing and manipulating collections of taxon nodes
within a taxonomy.
The primary data structure is the TaxonSlice, which encapsulates a slice of
TaxNode instances and provides methods for accessing, counting, and
formatting these nodes.
*/
package obitax package obitax
import ( import (
@ -7,17 +17,26 @@ import (
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils"
) )
// TaxonSlice represents a slice of TaxNode[T] instances within a taxonomy. // TaxonSlice represents a slice of TaxNode instances within a taxonomy.
// It encapsulates a collection of taxon nodes and the taxonomy they belong to. // It encapsulates a collection of taxon nodes and the taxonomy they belong to.
// //
// Fields: // Fields:
// - slice: A slice of pointers to TaxNode[T] representing the taxon nodes. // - slice: A slice of pointers to TaxNode representing the taxon nodes.
// - taxonomy: A pointer to the Taxonomy[T] instance that these taxon nodes are part of. // - taxonomy: A pointer to the Taxonomy instance that these taxon nodes are part of.
type TaxonSlice struct { type TaxonSlice struct {
slice []*TaxNode slice []*TaxNode
taxonomy *Taxonomy taxonomy *Taxonomy
} }
// NewTaxonSlice creates a new TaxonSlice with the specified size and capacity.
// It initializes the slice of TaxNode pointers and associates it with the given taxonomy.
//
// Parameters:
// - size: The initial size of the slice.
// - capacity: The capacity of the slice.
//
// Returns:
// - A pointer to the newly created TaxonSlice.
func (taxonomy *Taxonomy) NewTaxonSlice(size, capacity int) *TaxonSlice { func (taxonomy *Taxonomy) NewTaxonSlice(size, capacity int) *TaxonSlice {
return &TaxonSlice{ return &TaxonSlice{
slice: make([]*TaxNode, size, capacity), slice: make([]*TaxNode, size, capacity),
@ -25,14 +44,14 @@ func (taxonomy *Taxonomy) NewTaxonSlice(size, capacity int) *TaxonSlice {
} }
} }
// Get retrieves the TaxNode[T] at the specified index from the TaxonSlice. // Get retrieves the TaxNode at the specified index from the TaxonSlice.
// It returns the taxon node corresponding to the provided index. // It returns the taxon node corresponding to the provided index.
// //
// Parameters: // Parameters:
// - i: An integer representing the index of the taxon node to retrieve. // - i: An integer representing the index of the taxon node to retrieve.
// //
// Returns: // Returns:
// - A pointer to the TaxNode[T] at the specified index in the slice. // - A pointer to the TaxNode at the specified index in the slice.
func (slice *TaxonSlice) Get(i int) *TaxNode { func (slice *TaxonSlice) Get(i int) *TaxNode {
if slice == nil { if slice == nil {
return nil return nil
@ -40,7 +59,7 @@ func (slice *TaxonSlice) Get(i int) *TaxNode {
return slice.slice[i] return slice.slice[i]
} }
// Len returns the number of TaxNode[T] instances in the TaxonSlice. // Len returns the number of TaxNode instances in the TaxonSlice.
// It provides the count of taxon nodes contained within the slice. // It provides the count of taxon nodes contained within the slice.
// //
// Returns: // Returns:
@ -81,6 +100,15 @@ func (path *TaxonSlice) String() string {
return buffer.String() return buffer.String()
} }
// Reverse reverses the order of the TaxonSlice.
// If inplace is true, the original slice is modified; otherwise, a new reversed
// TaxonSlice is returned.
//
// Parameters:
// - inplace: A boolean indicating whether to reverse the slice in place.
//
// Returns:
// - A pointer to the reversed TaxonSlice. If inplace is true, it returns the original slice.
func (slice *TaxonSlice) Reverse(inplace bool) *TaxonSlice { func (slice *TaxonSlice) Reverse(inplace bool) *TaxonSlice {
if slice == nil { if slice == nil {
return nil return nil

View File

@ -77,6 +77,7 @@ func TaxonAsString(taxon *obitax.Taxon, pattern string) string {
} }
func TaxonWriter(itaxa *obitax.ITaxon, pattern string) { func TaxonWriter(itaxa *obitax.ITaxon, pattern string) {
for itaxa.Next() { for itaxa.Next() {
fmt.Println(TaxonAsString(itaxa.Get(), pattern)) fmt.Println(TaxonAsString(itaxa.Get(), pattern))
} }