From f5d79d0bc4c9f816acada6edc6e64ca7e19b0605 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sat, 16 Nov 2024 05:59:41 +0100 Subject: [PATCH] update api documentation --- pkg/obitax/filter_on_name.go | 20 ++++++++ pkg/obitax/filter_on_rank.go | 40 +++++++++++++++ pkg/obitax/filter_on_subclade_of.go | 54 +++++++++++++++++++- pkg/obitax/inner.go | 11 +++-- pkg/obitax/issuubcladeof.go | 19 ++++++- pkg/obitax/iterator.go | 36 +++++++++----- pkg/obitax/lca.go | 29 +++++++++-- pkg/obitax/taxon.go | 55 ++++++++++++++++----- pkg/obitax/taxonnode.go | 31 +++++++----- pkg/obitax/taxonomy.go | 77 ++++++++++++++++++++++++++--- pkg/obitax/taxonset.go | 21 +++++++- pkg/obitax/taxonslice.go | 40 ++++++++++++--- pkg/obitools/obifind/iterator.go | 1 + 13 files changed, 372 insertions(+), 62 deletions(-) diff --git a/pkg/obitax/filter_on_name.go b/pkg/obitax/filter_on_name.go index b4321f5..446c1cf 100644 --- a/pkg/obitax/filter_on_name.go +++ b/pkg/obitax/filter_on_name.go @@ -4,6 +4,16 @@ import ( "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 { if strict { 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) } +// 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 { newIterator := NewITaxon() sentTaxa := make(map[*string]bool) diff --git a/pkg/obitax/filter_on_rank.go b/pkg/obitax/filter_on_rank.go index 08df40d..4ed7e94 100644 --- a/pkg/obitax/filter_on_rank.go +++ b/pkg/obitax/filter_on_rank.go @@ -1,5 +1,15 @@ 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 { newIter := NewITaxon() var prank *string @@ -24,14 +34,44 @@ func (iterator *ITaxon) IFilterOnTaxRank(rank string) *ITaxon { 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 { 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 { 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 { return taxonomy.Iterator().IFilterOnTaxRank(rank) } diff --git a/pkg/obitax/filter_on_subclade_of.go b/pkg/obitax/filter_on_subclade_of.go index 0cb6883..7016f6b 100644 --- a/pkg/obitax/filter_on_subclade_of.go +++ b/pkg/obitax/filter_on_subclade_of.go @@ -1,5 +1,15 @@ 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 { newIter := NewITaxon() @@ -16,26 +26,66 @@ func (iterator *ITaxon) IFilterOnSubcladeOf(taxon *Taxon) *ITaxon { 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 { 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 { 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 { 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 { - if clades.Len() == 0 { return iterator } // Considers the second simplest case when only - // a single subclase is provided + // a single subclade is provided if clades.Len() == 1 { keys := make([]*string, 0, len(clades.set)) for k := range clades.set { diff --git a/pkg/obitax/inner.go b/pkg/obitax/inner.go index 8053f13..f86a029 100644 --- a/pkg/obitax/inner.go +++ b/pkg/obitax/inner.go @@ -5,12 +5,12 @@ import "sync" // 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. type InnerString struct { - index map[string]*string - lock sync.RWMutex + index map[string]*string // Map to store string values + lock sync.RWMutex // Read-write lock for concurrent access } // 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 { return &InnerString{ 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. -// 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. // // Parameters: // - value: The string value to be stored in the index map. // // 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 { i.lock.Lock() defer i.lock.Unlock() @@ -38,6 +38,7 @@ func (i *InnerString) Innerize(value string) *string { return s } +// Slice returns a slice of strings containing all the values stored in the index map. func (i *InnerString) Slice() []string { rep := make([]string, len(i.index)) j := 0 diff --git a/pkg/obitax/issuubcladeof.go b/pkg/obitax/issuubcladeof.go index 50d186f..9c76496 100644 --- a/pkg/obitax/issuubcladeof.go +++ b/pkg/obitax/issuubcladeof.go @@ -2,8 +2,16 @@ package obitax 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 { - if taxon.Taxonomy != parent.Taxonomy { log.Fatalf( "Both taxa %s and %s must belong to the same taxonomy", @@ -21,6 +29,15 @@ func (taxon *Taxon) IsSubCladeOf(parent *Taxon) bool { 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 { ok := clades.Contains(taxon.Node.id) diff --git a/pkg/obitax/iterator.go b/pkg/obitax/iterator.go index 2b6568d..9a6099a 100644 --- a/pkg/obitax/iterator.go +++ b/pkg/obitax/iterator.go @@ -1,22 +1,28 @@ 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 { - source chan *Taxon - current *Taxon - finished bool - p_finished *bool + source chan *Taxon // Channel to receive Taxon instances + current *Taxon // Current Taxon instance + finished bool // Indicates if the iteration is finished + p_finished *bool // Pointer to the finished status } +// NewITaxon creates a new ITaxon iterator instance and initializes its fields. func NewITaxon() *ITaxon { i := ITaxon{ source: make(chan *Taxon), current: nil, finished: false, - p_finished: nil} + p_finished: nil, + } i.p_finished = &i.finished 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 { i := NewITaxon() @@ -33,6 +39,8 @@ func (set *TaxonSet) Iterator() *ITaxon { 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 { i := NewITaxon() @@ -49,10 +57,13 @@ func (set *TaxonSlice) Iterator() *ITaxon { return i } -func (taxonmy *Taxonomy) Iterator() *ITaxon { - return taxonmy.nodes.Iterator() +// Iterator creates a new ITaxon iterator for the Taxonomy's nodes. +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 { if *(iterator.p_finished) { return false @@ -69,20 +80,19 @@ func (iterator *ITaxon) Next() bool { return false } -// The 'Get' method returns the instance of *TaxNode -// currently pointed by the iterator. You have to use the -// 'Next' method to move to the next entry before calling -// 'Get' to retreive the following instance. +// Get returns the current Taxon instance pointed to by the iterator. +// You must call 'Next' before calling 'Get' to retrieve the next instance. func (iterator *ITaxon) Get() *Taxon { return iterator.current } -// Finished returns 'true' value if no more data is available -// from the iterator. +// Finished returns true if no more data is available from the iterator. func (iterator *ITaxon) Finished() bool { 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 { return &ITaxon{ source: iterator.source, diff --git a/pkg/obitax/lca.go b/pkg/obitax/lca.go index 4909847..271a6a4 100644 --- a/pkg/obitax/lca.go +++ b/pkg/obitax/lca.go @@ -1,16 +1,35 @@ package obitax 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) { - if t1 == nil { - log.Panicf("Try to get LCA of nil taxon") + if t1 == nil || t1.Node == nil { + return nil, fmt.Errorf("try to get LCA of nil taxon") } - if t2 == nil { - log.Panicf("Try to get LCA of nil taxon") + if t2 == nil || t2.Node == nil { + 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() diff --git a/pkg/obitax/taxon.go b/pkg/obitax/taxon.go index 09401d5..c7587cb 100644 --- a/pkg/obitax/taxon.go +++ b/pkg/obitax/taxon.go @@ -11,8 +11,8 @@ import ( // it belongs to and the specific taxon node information. // // Fields: -// - Taxonomy: A pointer to the Taxonomy[T] instance that this taxon is part of. -// - Node: A pointer to the TaxNode[T] instance representing the specific taxon. +// - Taxonomy: A pointer to the Taxonomy instance that this taxon is part of. +// - Node: A pointer to the TaxNode instance representing the specific taxon. type Taxon struct { Taxonomy *Taxonomy Node *TaxNode @@ -42,6 +42,14 @@ func (taxon *Taxon) ScientificName() string { 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 { if taxon == nil { return "NA" @@ -50,6 +58,14 @@ func (taxon *Taxon) Name(class string) string { 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 { if taxon == nil { return false @@ -58,6 +74,13 @@ func (taxon *Taxon) IsNameEqual(name string) bool { 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 { if taxon == nil { return false @@ -66,6 +89,12 @@ func (taxon *Taxon) IsNameMatching(pattern *regexp.Regexp) bool { 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) { if taxon == nil { 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) } +// 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 { if taxon == nil { return true @@ -101,7 +135,7 @@ func (taxon *Taxon) Rank() string { // to create a new Taxon instance representing the parent taxon. // // 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. func (taxon *Taxon) Parent() *Taxon { 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 // taxonomy has no root node, the method logs a fatal error and terminates the program. func (taxon *Taxon) IPath() iter.Seq[*Taxon] { - if taxon.Taxonomy.root == nil { 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 // using the IPath method and returns them as a TaxonSlice. // // Returns: -// - A pointer to a TaxonSlice[T] containing the TaxNode[T] instances in the path -// from the current taxon to the root. +// - A pointer to a TaxonSlice containing the TaxNode instances in the path +// from the current taxon to the root. If the taxon is nil, it returns nil. func (taxon *Taxon) Path() *TaxonSlice { if taxon == 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"). // // 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. func (taxon *Taxon) TaxonAtRank(rank string) *Taxon { if taxon == nil { @@ -219,7 +252,7 @@ func (taxon *Taxon) TaxonAtRank(rank string) *Taxon { // the matching Taxon. // // 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. func (taxon *Taxon) Species() *Taxon { return taxon.TaxonAtRank("species") @@ -230,7 +263,7 @@ func (taxon *Taxon) Species() *Taxon { // the matching Taxon. // // 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. func (taxon *Taxon) Genus() *Taxon { return taxon.TaxonAtRank("genus") @@ -241,7 +274,7 @@ func (taxon *Taxon) Genus() *Taxon { // the matching Taxon. // // 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. func (taxon *Taxon) Family() *Taxon { return taxon.TaxonAtRank("family") diff --git a/pkg/obitax/taxonnode.go b/pkg/obitax/taxonnode.go index f5f67fc..e7c0d8b 100644 --- a/pkg/obitax/taxonnode.go +++ b/pkg/obitax/taxonnode.go @@ -11,12 +11,12 @@ import ( // scientific name, and alternate names. // // Fields: -// - id: The unique identifier of the taxon of type T. -// - parent: The identifier of the parent taxon of type T. -// - rank: The rank of the taxon (e.g., species, genus). +// - id: A pointer to the unique identifier of the taxon of type T. +// - parent: A pointer to the identifier of the parent taxon of type T. +// - 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. // - 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. type TaxNode struct { 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. // // 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 { 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. // // 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 { return node.parent } @@ -64,8 +64,9 @@ func (node *TaxNode) ParentId() *string { // // Returns: // - The scientific name of the taxon as a string. -// - Note: This method assumes that scientificname is not nil; -// if it may be nil, additional error handling should be implemented. +// - If the scientific name is nil, it returns "NA". +// - 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 { if node == nil { return "NA" @@ -77,18 +78,18 @@ func (node *TaxNode) ScientificName() string { } // 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 is not recognized or if no alternate names exist, it returns an empty string. // // 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: // - 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. func (node *TaxNode) Name(class *string) string { - if *class == "scientific name" { return *node.scientificname } @@ -106,6 +107,14 @@ func (node *TaxNode) Name(class *string) string { 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) { if node == nil { log.Panic("Cannot set name of nil TaxNode") diff --git a/pkg/obitax/taxonomy.go b/pkg/obitax/taxonomy.go index 2f84334..c7e628e 100644 --- a/pkg/obitax/taxonomy.go +++ b/pkg/obitax/taxonomy.go @@ -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 import ( @@ -14,9 +21,13 @@ import ( // Fields: // - name: The name of 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. +// - 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. // - 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. type Taxonomy struct { name string @@ -37,14 +48,13 @@ type Taxonomy struct { // Parameters: // - name: The name of the taxonomy to be created. // - code: A unique code representing the taxonomy. +// - codeCharacters: A string representing valid characters for the taxon identifiers. // // Returns: // - A pointer to the newly created Taxonomy instance. func NewTaxonomy(name, code, codeCharacters string) *Taxonomy { set := make(map[*string]*TaxNode) - // codeCharacters := "[[:alnum:]]" // [[:digit:]] - matcher := regexp.MustCompile(fmt.Sprintf("^[[:blank:]]*(%s:)?(%s+)", code, codeCharacters)) 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. // // 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. func (taxonomy *Taxonomy) Taxon(taxid string) *Taxon { id, err := taxonomy.Id(taxid) @@ -139,11 +149,11 @@ func (taxonomy *Taxonomy) Taxon(taxid string) *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. // // 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 { 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. // // 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). 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 } +// 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) { newid, err := taxonomy.Id(newtaxid) @@ -241,14 +264,56 @@ func (taxonomy *Taxonomy) RankList() []string { 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 { return &(taxonomy.index) } +// Name returns the name of the taxonomy. +// +// Returns: +// - A string representing the name of the taxonomy. func (taxonomy *Taxonomy) Name() string { 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 { 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 +} diff --git a/pkg/obitax/taxonset.go b/pkg/obitax/taxonset.go index 3d690ef..22fd84b 100644 --- a/pkg/obitax/taxonset.go +++ b/pkg/obitax/taxonset.go @@ -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 import log "github.com/sirupsen/logrus" @@ -17,6 +23,11 @@ type TaxonSet struct { 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 { return &TaxonSet{ set: make(map[*string]*TaxNode), @@ -77,10 +88,16 @@ func (set *TaxonSet) Insert(node *TaxNode) { 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) { if set.taxonomy != taxon.Taxonomy { 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(), set.taxonomy.name, ) diff --git a/pkg/obitax/taxonslice.go b/pkg/obitax/taxonslice.go index 7acf119..89ca161 100644 --- a/pkg/obitax/taxonslice.go +++ b/pkg/obitax/taxonslice.go @@ -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 import ( @@ -7,17 +17,26 @@ import ( "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. // // Fields: -// - slice: A slice of pointers to TaxNode[T] representing the taxon nodes. -// - taxonomy: A pointer to the Taxonomy[T] instance that these taxon nodes are part of. +// - slice: A slice of pointers to TaxNode representing the taxon nodes. +// - taxonomy: A pointer to the Taxonomy instance that these taxon nodes are part of. type TaxonSlice struct { slice []*TaxNode 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 { return &TaxonSlice{ 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. // // Parameters: // - i: An integer representing the index of the taxon node to retrieve. // // 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 { if slice == nil { return nil @@ -40,7 +59,7 @@ func (slice *TaxonSlice) Get(i int) *TaxNode { 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. // // Returns: @@ -81,6 +100,15 @@ func (path *TaxonSlice) String() 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 { if slice == nil { return nil diff --git a/pkg/obitools/obifind/iterator.go b/pkg/obitools/obifind/iterator.go index 52e38af..6f261fc 100644 --- a/pkg/obitools/obifind/iterator.go +++ b/pkg/obitools/obifind/iterator.go @@ -77,6 +77,7 @@ func TaxonAsString(taxon *obitax.Taxon, pattern string) string { } func TaxonWriter(itaxa *obitax.ITaxon, pattern string) { + for itaxa.Next() { fmt.Println(TaxonAsString(itaxa.Get(), pattern)) }