Class: Eco::API::Organization::TagTree
- Inherits:
-
Object
- Object
- Eco::API::Organization::TagTree
- Includes:
- Enumerable
- Defined in:
- lib/eco/api/organization/tag_tree.rb
Overview
that currenlty the parsing assumes top level to be array.
This does not allow to capture the name and id of the locations
structure itself into the json storing model.
Provides helpers to deal with tagtrees.
Constant Summary collapse
- HEADER =
[ 'id', 'name', 'weight', 'parent_id', 'archived', 'archived_token' ].freeze
Instance Attribute Summary collapse
-
#archived ⇒ Object
Returns the value of attribute archived.
-
#archived_token ⇒ Object
Returns the value of attribute archived_token.
- #children_count ⇒ Integer readonly
-
#depth ⇒ Object
readonly
Returns the value of attribute depth.
-
#enviro ⇒ Object
readonly
Returns the value of attribute enviro.
-
#id ⇒ Object
(also: #tag)
Returns the value of attribute id.
-
#name ⇒ Object
Returns the value of attribute name.
-
#nodes ⇒ Object
readonly
Returns the value of attribute nodes.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#path(key = nil) ⇒ Array<String>
readonly
Finds the path from a node
keyto its root node in the tree. -
#source ⇒ Object
readonly
Returns the value of attribute source.
-
#weight ⇒ Object
Returns the value of attribute weight.
Instance Method Summary collapse
- #active? ⇒ Boolean
-
#active_tree ⇒ Eco::API::Organization::TagTree
With non
archivednodes only. -
#all_nodes(&block) ⇒ Array<TagTree>
All actual nodes of this tree.
-
#ancestors ⇒ Array<TagTree>
All the acenstor nodes of the current node.
- #archived? ⇒ Boolean
-
#as_json(include_children: true, include_archived: true, max_depth: total_depth) {|node_json, node| ... } ⇒ Array[Hash]
Returns a tree of Hashes form nested via
nodes(or just a list of hash nodes). -
#as_nodes_json(&block) ⇒ Array[Hash]
Returns a plain list form of hash nodes.
-
#count ⇒ Integer
The number of locations.
-
#default_tag(*values) ⇒ String
Helper to decide which among the tags will be the default.
-
#diff(tagtree, differences: {}, level: 0, **options) ⇒ Array
With the differences.
- #dup ⇒ Eco::API::Organization::TagTree
-
#each {|node| ... } ⇒ Enumerable<Eco::API::Organization::TagTree>
Iterate through all the nodes of this tree.
-
#empty? ⇒ Boolean
trueif there are tags in the node,falseotherwise. -
#filter_tags(list) ⇒ Array<String>
Filters tags out that do not belong to the tree.
-
#flat? ⇒ Integer
If there's only top level.
-
#has_children? ⇒ Boolean
It has subnodes.
-
#initialize(tagtree = [], name: nil, id: nil, depth: -1,, path: [], parent: nil, _weight: nil, enviro: nil) ⇒ TagTree
constructor
A new instance of TagTree.
-
#leafs ⇒ Array<String>
Returns all the tags with no children.
-
#node(key) ⇒ TagTree?
Finds a subtree node.
-
#parent_id ⇒ String
The
idof the parent (unless we are on a top level node). -
#parent_name ⇒ String
The
nameof the parent (unless we are on a top level node). -
#reject(&block) ⇒ Array<TagTree>
Plain list of nodes.
-
#select(when_is: true, &block) ⇒ Array<TagTree>
Plain list of nodes.
-
#subtag?(key) ⇒ Boolean
Verifies if a tag exists in the subtree(s).
-
#subtags ⇒ Array<String>
Gets all but the upper level tags of the current node tree.
-
#tag?(key) ⇒ Boolean
Verifies if a tag exists in the tree.
-
#tags(depth: nil) ⇒ Array<String>
Gets all the tags of the current node tree.
- #top? ⇒ Boolean
-
#total_depth ⇒ Integer
The highest
depthof all the children. -
#truncate(max_depth: total_depth) ⇒ Eco::API::Organization::TagTree
With nodes up to
max_depth. -
#user_tags(initial: [], final: [], preserve_custom: true, add_custom: false) ⇒ Array<String>
Helper to assign tags to a person account.
Constructor Details
#initialize(tagtree = [], name: nil, id: nil, depth: -1,, path: [], parent: nil, _weight: nil, enviro: nil) ⇒ TagTree
Returns a new instance of TagTree.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/eco/api/organization/tag_tree.rb', line 38 def initialize(tagtree = [], name: nil, id: nil, depth: -1, path: [], parent: nil, _weight: nil, enviro: nil) @depth = depth @parent = parent 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 if @source.is_a?(Array) @id = id @name = name @raw_nodes = @source else @id = @source.values_at('tag', 'id').compact.first&.upcase @name = @source['name'] @archived = @source['archived'] || false @archived_token = @source['archived_token'] @source['weight'] = @weight = @source['weight'] || _weight @raw_nodes = @source['nodes'] || [] end @path = path || [] @path.push(@id) unless top? @nodes = @raw_nodes.map.with_index do |cnode, idx| TagTree.new(cnode, depth: depth + 1, path: @path.dup, parent: self, _weight: idx, enviro: @enviro) end init_hashes end |
Instance Attribute Details
#archived ⇒ Object
Returns the value of attribute archived.
17 18 19 |
# File 'lib/eco/api/organization/tag_tree.rb', line 17 def archived @archived end |
#archived_token ⇒ Object
Returns the value of attribute archived_token.
17 18 19 |
# File 'lib/eco/api/organization/tag_tree.rb', line 17 def archived_token @archived_token end |
#children_count ⇒ Integer (readonly)
281 282 283 |
# File 'lib/eco/api/organization/tag_tree.rb', line 281 def children_count @children_count end |
#depth ⇒ Object (readonly)
Returns the value of attribute depth.
21 22 23 |
# File 'lib/eco/api/organization/tag_tree.rb', line 21 def depth @depth end |
#enviro ⇒ Object (readonly)
Returns the value of attribute enviro.
22 23 24 |
# File 'lib/eco/api/organization/tag_tree.rb', line 22 def enviro @enviro end |
#id ⇒ Object Also known as: tag
Returns the value of attribute id.
14 15 16 |
# File 'lib/eco/api/organization/tag_tree.rb', line 14 def id @id end |
#name ⇒ Object
Returns the value of attribute name.
16 17 18 |
# File 'lib/eco/api/organization/tag_tree.rb', line 16 def name @name end |
#nodes ⇒ Object (readonly)
Returns the value of attribute nodes.
20 21 22 |
# File 'lib/eco/api/organization/tag_tree.rb', line 20 def nodes @nodes end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
19 20 21 |
# File 'lib/eco/api/organization/tag_tree.rb', line 19 def parent @parent end |
#path(key = nil) ⇒ Array<String> (readonly)
the path is not relative to the subtree, but absolute to the entire tree.
Finds the path from a node key to its root node in the tree.
If key is not specified, returns the path from current node to root.
318 319 320 |
# File 'lib/eco/api/organization/tag_tree.rb', line 318 def path @path end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
24 25 26 |
# File 'lib/eco/api/organization/tag_tree.rb', line 24 def source @source end |
#weight ⇒ Object
Returns the value of attribute weight.
16 17 18 |
# File 'lib/eco/api/organization/tag_tree.rb', line 16 def weight @weight end |
Instance Method Details
#active? ⇒ Boolean
79 80 81 |
# File 'lib/eco/api/organization/tag_tree.rb', line 79 def active? !archived? end |
#active_tree ⇒ Eco::API::Organization::TagTree
Returns with non archived nodes only.
89 90 91 |
# File 'lib/eco/api/organization/tag_tree.rb', line 89 def active_tree self.class.new(as_json(include_archived: false), name: name, id: id) end |
#all_nodes(&block) ⇒ Array<TagTree>
order is that of the parent to child relationships
All actual nodes of this tree
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/eco/api/organization/tag_tree.rb', line 131 def all_nodes(&block) [].tap do |out_nodes| unless top? out_nodes.push(self) yield(self) if block_given? end nodes.each do |nd| out_nodes.concat(nd.all_nodes(&block)) end end end |
#ancestors ⇒ Array<TagTree>
it does not include the current node
All the acenstor nodes of the current node
146 147 148 149 150 151 152 153 |
# File 'lib/eco/api/organization/tag_tree.rb', line 146 def ancestors [].tap do |ans| unless parent.top? ans << parent ans.concat(parent.ancestors) end end end |
#archived? ⇒ Boolean
75 76 77 |
# File 'lib/eco/api/organization/tag_tree.rb', line 75 def archived? @archived end |
#as_json(include_children: true, include_archived: true, max_depth: total_depth) {|node_json, node| ... } ⇒ Array[Hash]
Returns a tree of Hashes form nested via nodes (or just a list of hash nodes)
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/eco/api/organization/tag_tree.rb', line 182 def as_json(include_children: true, include_archived: true, max_depth: total_depth, &block) max_depth ||= total_depth return nil if max_depth < depth return [] if top? && !include_children return nil if archived? && !include_archived if include_children child_nodes = nodes child_nodes = child_nodes.select(&:active?) unless include_archived kargs = { include_children: include_children, include_archived: include_archived, max_depth: max_depth } children_json = child_nodes.map {|nd| nd.as_json(**kargs, &block)}.compact end if top? children_json else values = [id, name, weight, parent_id, archived, archived_token] node_json = self.class::HEADER.zip(values).to_h node_json["nodes"] = children_json if include_children node_json = yield(node_json, self) if block_given? node_json end end |
#as_nodes_json(&block) ⇒ Array[Hash]
Returns a plain list form of hash nodes.
212 213 214 |
# File 'lib/eco/api/organization/tag_tree.rb', line 212 def as_nodes_json(&block) all_nodes.map {|nd| nd.as_json(include_children: false, &block)} end |
#count ⇒ Integer
Returns the number of locations.
222 223 224 |
# File 'lib/eco/api/organization/tag_tree.rb', line 222 def count @hash_tags.keys.count end |
#default_tag(*values) ⇒ String
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
firstalso on top level, but only if there's 1 level for the entire tree
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/eco/api/organization/tag_tree.rb', line 366 def default_tag(*values) values = (values) nodes = []; ddepth = -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 > ddepth nodes = [cnode] ddepth = cnode.depth elsif cnode.depth == ddepth nodes.push(cnode) end end default_tag = nil if nodes.length > 1 common = nodes.reduce(self..reverse) {|com, cnode| com & cnode.path.reverse} default_tag = common.first if common.length > 0 && ddepth > 0 end default_tag ||= nodes.first&.tag if (ddepth > 0) || flat? default_tag end |
#diff(tagtree, differences: {}, level: 0, **options) ⇒ Array
Returns with the differences.
166 167 168 169 |
# File 'lib/eco/api/organization/tag_tree.rb', line 166 def diff(tagtree, differences: {}, level: 0, **) require 'hashdiff' Hashdiff.diff(self.as_json, tagtree.as_json, **.slice(:array_path, :similarity, :use_lcs)) end |
#dup ⇒ Eco::API::Organization::TagTree
84 85 86 |
# File 'lib/eco/api/organization/tag_tree.rb', line 84 def dup self.class.new(as_json, name: name, id: id) end |
#each {|node| ... } ⇒ Enumerable<Eco::API::Organization::TagTree>
Iterate through all the nodes of this tree
102 103 104 105 |
# File 'lib/eco/api/organization/tag_tree.rb', line 102 def each(&block) return to_enum(:each) unless block all_nodes.each(&block) end |
#empty? ⇒ Boolean
Returns true if there are tags in the node, false otherwise.
217 218 219 |
# File 'lib/eco/api/organization/tag_tree.rb', line 217 def empty? count <= 1 end |
#filter_tags(list) ⇒ Array<String>
Filters tags out that do not belong to the tree
308 309 310 311 |
# File 'lib/eco/api/organization/tag_tree.rb', line 308 def (list) return [] unless list && list.is_a?(Array) list.select {|str| tag?(str)} end |
#flat? ⇒ Integer
Returns if there's only top level.
239 240 241 |
# File 'lib/eco/api/organization/tag_tree.rb', line 239 def flat? self.total_depth <= 0 end |
#has_children? ⇒ Boolean
Returns it has subnodes.
286 287 288 |
# File 'lib/eco/api/organization/tag_tree.rb', line 286 def has_children? children_count > 0 end |
#leafs ⇒ Array<String>
Returns all the tags with no children
274 275 276 277 278 |
# File 'lib/eco/api/organization/tag_tree.rb', line 274 def leafs .select do |tag| !node(tag).has_children? end end |
#node(key) ⇒ TagTree?
Finds a subtree node.
300 301 302 303 |
# File 'lib/eco/api/organization/tag_tree.rb', line 300 def node(key) return nil unless tag?(key) @hash_tags[key.upcase] end |
#parent_id ⇒ String
Returns the id of the parent (unless we are on a top level node).
156 157 158 |
# File 'lib/eco/api/organization/tag_tree.rb', line 156 def parent_id parent.id unless parent.top? end |
#parent_name ⇒ String
Returns the name of the parent (unless we are on a top level node).
161 162 163 |
# File 'lib/eco/api/organization/tag_tree.rb', line 161 def parent_name parent.name unless parent.top? end |
#reject(&block) ⇒ Array<TagTree>
rejected nodes will not include their children nodes
Returns plain list of nodes.
124 125 126 |
# File 'lib/eco/api/organization/tag_tree.rb', line 124 def reject(&block) select(when_is: false, &block) end |
#select(when_is: true, &block) ⇒ Array<TagTree>
rejected nodes will not include their children nodes
Returns plain list of nodes.
109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/eco/api/organization/tag_tree.rb', line 109 def select(when_is: true, &block) raise ArgumentError, "Missing block" unless block_given? [].tap do |out_nodes| selected = false selected = (yield(self) == when_is) unless top? out_nodes.push(self) if selected next unless selected || top? nodes.each do |nd| out_nodes.concat(nd.select(when_is: when_is, &block)) end end end |
#subtag?(key) ⇒ Boolean
Verifies if a tag exists in the subtree(s).
268 269 270 |
# File 'lib/eco/api/organization/tag_tree.rb', line 268 def subtag?(key) .include?(key&.upcase) end |
#subtags ⇒ Array<String>
Gets all but the upper level tags of the current node tree.
261 262 263 |
# File 'lib/eco/api/organization/tag_tree.rb', line 261 def - (depth: depth) end |
#tag?(key) ⇒ Boolean
Verifies if a tag exists in the tree.
293 294 295 |
# File 'lib/eco/api/organization/tag_tree.rb', line 293 def tag?(key) @hash_tags.key?(key&.upcase) end |
#tags(depth: nil) ⇒ Array<String>
- this will include the upper level tag(s) as well
- to get all but the upper level tag(s) use
subtagsmethod instead
Gets all the tags of the current node tree.
249 250 251 252 253 254 255 256 257 |
# File 'lib/eco/api/organization/tag_tree.rb', line 249 def (depth: nil) if !depth || depth < 0 @hash_tags.keys else @hash_tags.select do |t, n| n.depth == depth end.keys end end |
#top? ⇒ Boolean
171 172 173 |
# File 'lib/eco/api/organization/tag_tree.rb', line 171 def top? depth == -1 end |
#total_depth ⇒ Integer
Returns the highest depth of all the children.
227 228 229 230 231 232 233 234 235 236 |
# File 'lib/eco/api/organization/tag_tree.rb', line 227 def total_depth @total_depth ||= if has_children? deepest_node = nodes.max_by do |nd| nd.total_depth end deepest_node.total_depth else depth end end |
#truncate(max_depth: total_depth) ⇒ Eco::API::Organization::TagTree
Returns with nodes up to max_depth.
94 95 96 |
# File 'lib/eco/api/organization/tag_tree.rb', line 94 def truncate(max_depth: total_depth) self.class.new(as_json(max_depth: max_depth), name: name, id: id) end |
#user_tags(initial: [], final: [], preserve_custom: true, add_custom: false) ⇒ Array<String>
Helper to assign tags to a person account.
- It preserves the
:initialorder, in case the:finaltags are the same
346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/eco/api/organization/tag_tree.rb', line 346 def (initial: [], final: [], preserve_custom: true, add_custom: false) initial = [initial].flatten.compact final = [final].flatten.compact raise "Expected Array for initial: and final:" unless initial.is_a?(Array) && final.is_a?(Array) final = (final) unless add_custom custom = initial - (initial) final = final + custom if preserve_custom = final - initial # keep same order as they where (initial & final) + end |