class Eco::API::Organization::TagTree
Provides helpers to deal with tagtrees.
Attributes
Public Class Methods
@example Node format:
{"tag": "NODE NAME", "nodes": subtree}
@example Tree/subtree format:
[[Node], ...]
@example Input format example:
tree = [{"tag" => "AUSTRALIA", "nodes" => [ {"tag" => "SYDNEY", "nodes" => []} ]}] tree = TagTree.new(tree.to_json)
@param tagtree [String] representation of the tagtree in json.
# File lib/eco/api/organization/tag_tree.rb, line 21 def initialize(tagtree = [], depth: -1, path: [], enviro: nil) case tagtree when String @source = JSON.parse(tagtree) else @source = tagtree end fatal("You are trying to initialize a TagTree with a null tagtree") if !@source fatal("Expecting Environment object. Given: #{enviro}") if enviro && !enviro.is_a?(API::Common::Session::Environment) @enviro = enviro @depth = depth @tag = @source.is_a?(Array) ? nil : @source.dig('tag')&.upcase @path = path || [] @path.push(@tag) unless !@tag nodes = @source.is_a?(Array) ? @source : @source.dig('nodes') || [] @nodes = nodes.map {|cnode| TagTree.new(cnode, depth: @depth + 1, path: @path.dup, enviro: @enviro)} @children_count = @nodes.count init_hashes end
Public Instance Methods
Helper to decide which among the tags will be the default.
-
take the deepest tag (the one that is further down in the tree)
-
if there are different options (several nodes at the same depth):
* take the common node between them (i.e. you have Hamilton and Auckland -> take New Zealand) * if there's no common node between them, take the `first`, unless they are at top level of the tree * to the above, take the `first` also on top level, but only if there's 1 level for the entire tree
@param [Array<String>] values list of tags. @return [String] default tag.
# File lib/eco/api/organization/tag_tree.rb, line 203 def default_tag(*values) values = filter_tags(values) nodes = []; depth = -1 values.each do |tag| raise("Couldn't find the node of #{tag} in the tag-tree definition") unless cnode = node(tag) if cnode.depth > depth nodes = [cnode] depth = cnode.depth elsif cnode.depth == depth nodes.push(cnode) end end default_tag = nil if nodes.length > 1 common = nodes.reduce(self.tags.reverse) {|com, cnode| com & cnode.path.reverse} default_tag = common.first if common.length > 0 && depth > 0 end default_tag = nodes.first&.tag if !default_tag && ( (depth > 0) || flat?) default_tag end
@return [Array] with the differences
# File lib/eco/api/organization/tag_tree.rb, line 56 def diff(tagtree, differences: {}, level: 0, **options) require 'hashdiff' Hashdiff.diff(self.as_json, tagtree.as_json, **options.slice(:array_path, :similarity, :use_lcs)) end
@return [Eco::API::Organization::TagTree]
# File lib/eco/api/organization/tag_tree.rb, line 51 def dup self.class.new(as_json) end
@return [Boolean] `true` if there are tags in the node, `false` otherwise.
# File lib/eco/api/organization/tag_tree.rb, line 79 def empty? @has_tags.empty? end
@return [Integer] if there's only top level.
# File lib/eco/api/organization/tag_tree.rb, line 94 def flat? self.total_depth <= 0 end
Finds a subtree node. @param key [String] parent node of subtree. @return [TagTree, nil] if the tag `key` is a node, returns that node.
# File lib/eco/api/organization/tag_tree.rb, line 137 def node(key) return nil unless tag?(key) @hash_tags[key.upcase] end
Verifies if a tag exists in the subtree(s). @param key [String] tag to verify. @return [Boolean]
# File lib/eco/api/organization/tag_tree.rb, line 123 def subtag?(key) subtags.include?(key&.upcase) end
Updates the tag of the current tree
# File lib/eco/api/organization/tag_tree.rb, line 46 def tag=(value) @tag = value end
Verifies if a tag exists in the tree. @param key [String] tag to verify. @return [Boolean]
# File lib/eco/api/organization/tag_tree.rb, line 130 def tag?(key) @hash_tags.key?(key&.upcase) end
# File lib/eco/api/organization/tag_tree.rb, line 61 def top? depth == -1 end
@return [Integer] the highest `depth` of all the children.
# File lib/eco/api/organization/tag_tree.rb, line 84 def total_depth @total_depth ||= if children_count > 0 deepest_node = nodes.max_by {|node| node.total_depth} deepest_node.depth else depth end end
Protected Instance Methods
# File lib/eco/api/organization/tag_tree.rb, line 228 def hash @hash_tags end
# File lib/eco/api/organization/tag_tree.rb, line 232 def hash_paths @hash_paths end
Private Instance Methods
# File lib/eco/api/organization/tag_tree.rb, line 251 def fatal(msg) raise msg if !@enviro @enviro.logger.fatal(msg) raise msg end
# File lib/eco/api/organization/tag_tree.rb, line 238 def init_hashes @hash_tags = {} @hash_tags[@tag] = self unless !@tag @hash_tags = @nodes.reduce(@hash_tags) do |h,n| h.merge(n.hash) end @hash_paths = {} @hash_paths[@tag] = @path @hash_paths = @nodes.reduce(@hash_paths) do |h,n| h.merge(n.hash_paths) end end
# File lib/eco/api/organization/tag_tree.rb, line 257 def warn(msg) raise msg if !@enviro @enviro.logger.warn(msg) end