Class: 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 =
%w[ id name weight parent_id archived archived_token classifications classification_names level ].freeze
Instance Attribute Summary collapse
-
#archived ⇒ Object
Returns the value of attribute archived.
-
#archived_token ⇒ Object
Returns the value of attribute archived_token.
-
#classification_names ⇒ Object
Returns the value of attribute classification_names.
-
#classifications ⇒ Object
Returns the value of attribute classifications.
-
#depth ⇒ Object
readonly
Returns the value of attribute depth.
-
#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.
-
#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.
-
#children? ⇒ Boolean
It has subnodes.
- #children_count ⇒ Integer
-
#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.
-
#initialize(tagtree = [], name: nil, id: nil, depth: -1,, path: [], parent: nil, _weight: nil) ⇒ TagTree
constructor
A new instance of TagTree.
-
#leafs ⇒ Array<String>
Returns all the tags with no children.
-
#merge(other) ⇒ Eco::API::Organization::TagTree
It generates a merged tagtree out of two sources.
-
#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). -
#path(key = nil) ⇒ Array<String>
Finds the path from a node
keyto its root node in the tree. -
#reject(&block) ⇒ Array<TagTree>
Plain list of nodes.
-
#select(when_is: true, &block) ⇒ Array<TagTree>
Plain list of nodes.
-
#subtag?(key) ⇒ Boolean
(also: #subid?)
Verifies if a tag exists in the subtree(s).
-
#subtags ⇒ Array<String>
(also: #subids)
Gets all but the upper level tags of the current node tree.
-
#tag?(key) ⇒ Boolean
(also: #id?)
Verifies if a tag exists in the tree.
-
#tags(depth: nil) ⇒ Array<String>
(also: #ids)
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) ⇒ TagTree
Returns a new instance of TagTree.
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 74 75 76 77 78 79 80 81 |
# File 'lib/eco/api/organization/tag_tree.rb', line 41 def initialize( tagtree = [], name: nil, id: nil, depth: -1, path: [], parent: nil, _weight: nil # rubocop:disable Lint/UnderscorePrefixedVariableName ) @source = parse_source_input(tagtree) msg = "You are trying to initialize a TagTree with a null tagtree" raise ArgumentError, msg unless source @parent = parent @depth = depth @path = path || [] if source.is_a?(Array) @id = id @name = name @raw_nodes = source else source['weight'] ||= _weight init_node end @path.push(self.id) unless top? @nodes = @raw_nodes.map.with_index do |cnode, idx| self.class.new( cnode, depth: depth + 1, path: @path.dup, parent: self, _weight: idx ) end init_hashes end |
Instance Attribute Details
#archived ⇒ Object
Returns the value of attribute archived.
24 25 26 |
# File 'lib/eco/api/organization/tag_tree.rb', line 24 def archived @archived end |
#archived_token ⇒ Object
Returns the value of attribute archived_token.
24 25 26 |
# File 'lib/eco/api/organization/tag_tree.rb', line 24 def archived_token @archived_token end |
#classification_names ⇒ Object
Returns the value of attribute classification_names.
25 26 27 |
# File 'lib/eco/api/organization/tag_tree.rb', line 25 def classification_names @classification_names end |
#classifications ⇒ Object
Returns the value of attribute classifications.
25 26 27 |
# File 'lib/eco/api/organization/tag_tree.rb', line 25 def classifications @classifications end |
#depth ⇒ Object (readonly)
Returns the value of attribute depth.
29 30 31 |
# File 'lib/eco/api/organization/tag_tree.rb', line 29 def depth @depth end |
#id ⇒ Object Also known as: tag
Returns the value of attribute id.
20 21 22 |
# File 'lib/eco/api/organization/tag_tree.rb', line 20 def id @id end |
#name ⇒ Object
Returns the value of attribute name.
23 24 25 |
# File 'lib/eco/api/organization/tag_tree.rb', line 23 def name @name end |
#nodes ⇒ Object (readonly)
Returns the value of attribute nodes.
28 29 30 |
# File 'lib/eco/api/organization/tag_tree.rb', line 28 def nodes @nodes end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
27 28 29 |
# File 'lib/eco/api/organization/tag_tree.rb', line 27 def parent @parent end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
18 19 20 |
# File 'lib/eco/api/organization/tag_tree.rb', line 18 def source @source end |
#weight ⇒ Object
Returns the value of attribute weight.
23 24 25 |
# File 'lib/eco/api/organization/tag_tree.rb', line 23 def weight @weight end |
Instance Method Details
#active? ⇒ Boolean
87 88 89 |
# File 'lib/eco/api/organization/tag_tree.rb', line 87 def active? !archived? end |
#active_tree ⇒ Eco::API::Organization::TagTree
Returns with non archived nodes only.
116 117 118 |
# File 'lib/eco/api/organization/tag_tree.rb', line 116 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
161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/eco/api/organization/tag_tree.rb', line 161 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
177 178 179 180 181 182 183 184 |
# File 'lib/eco/api/organization/tag_tree.rb', line 177 def ancestors [].tap do |ans| next if parent.top? ans << parent ans.concat(parent.ancestors) end end |
#archived? ⇒ Boolean
83 84 85 |
# File 'lib/eco/api/organization/tag_tree.rb', line 83 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)
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/eco/api/organization/tag_tree.rb', line 207 def as_json( # rubocop:disable Metrics/AbcSize include_children: true, include_archived: true, max_depth: total_depth, &block ) max_depth ||= total_depth return if max_depth < depth return [] if top? && !include_children return 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 return children_json if top? end values = [ id, name, weight, parent_id, archived, archived_token, classifications.dup, classification_names.dup, depth + 1 ] 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 |
#as_nodes_json(&block) ⇒ Array[Hash]
Returns a plain list form of hash nodes.
247 248 249 |
# File 'lib/eco/api/organization/tag_tree.rb', line 247 def as_nodes_json(&block) all_nodes.map {|nd| nd.as_json(include_children: false, &block)} end |
#children? ⇒ Boolean
Returns it has subnodes.
323 324 325 |
# File 'lib/eco/api/organization/tag_tree.rb', line 323 def children? children_count&.positive? end |
#children_count ⇒ Integer
318 319 320 |
# File 'lib/eco/api/organization/tag_tree.rb', line 318 def children_count nodes.count end |
#count ⇒ Integer
Returns the number of locations.
257 258 259 |
# File 'lib/eco/api/organization/tag_tree.rb', line 257 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
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/eco/api/organization/tag_tree.rb', line 415 def default_tag(*values) default_tag = nil values = (values) tnodes, ddepth = (*values) unless tnodes.empty? common = tnodes.reduce(.reverse) do |com, cnode| com & cnode.path.reverse end default_tag = common.first if common.any? && ddepth&.positive? end default_tag ||= tnodes.first&.tag if ddepth&.positive? || flat? default_tag end |
#diff(tagtree, _differences: {}, _level: 0, **options) ⇒ Array
Returns with the differences.
98 99 100 101 |
# File 'lib/eco/api/organization/tag_tree.rb', line 98 def diff(tagtree, _differences: {}, _level: 0, **) require 'hashdiff' Hashdiff.diff(as_json, tagtree.as_json, **.slice(:array_path, :similarity, :use_lcs)) end |
#dup ⇒ Eco::API::Organization::TagTree
that archived nodes will also be passed over to the copy
93 94 95 |
# File 'lib/eco/api/organization/tag_tree.rb', line 93 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
129 130 131 132 133 |
# File 'lib/eco/api/organization/tag_tree.rb', line 129 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.
252 253 254 |
# File 'lib/eco/api/organization/tag_tree.rb', line 252 def empty? count <= 1 end |
#filter_tags(list) ⇒ Array<String>
Filters tags out that do not belong to the tree
347 348 349 350 351 |
# File 'lib/eco/api/organization/tag_tree.rb', line 347 def (list) return [] unless list.is_a?(Array) list.select {|str| tag?(str)} end |
#flat? ⇒ Integer
Returns if there's only top level.
272 273 274 |
# File 'lib/eco/api/organization/tag_tree.rb', line 272 def flat? total_depth <= 0 end |
#leafs ⇒ Array<String>
Returns all the tags with no children
311 312 313 314 315 |
# File 'lib/eco/api/organization/tag_tree.rb', line 311 def leafs .reject do |tag| node(tag).children? end end |
#merge(other) ⇒ Eco::API::Organization::TagTree
it merges the first level nodes (and their children) as it comes
It generates a merged tagtree out of two sources
106 107 108 109 110 111 112 113 |
# File 'lib/eco/api/organization/tag_tree.rb', line 106 def merge(other) msg = "Expecting Eco::API::Organization::TagTree. Given: #{other.class}" raise ArgumentError, msg unless other.is_a?(Eco::API::Organization::TagTree) mid = [id, other.id].join('|') mname = [name, other.name].join('|') self.class.new(as_json | other.as_json, id: mid, name: mname) end |
#node(key) ⇒ TagTree?
Finds a subtree node.
338 339 340 341 342 |
# File 'lib/eco/api/organization/tag_tree.rb', line 338 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).
187 188 189 |
# File 'lib/eco/api/organization/tag_tree.rb', line 187 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).
192 193 194 |
# File 'lib/eco/api/organization/tag_tree.rb', line 192 def parent_name parent.name unless parent.top? end |
#path(key = nil) ⇒ Array<String>
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.
358 359 360 361 362 |
# File 'lib/eco/api/organization/tag_tree.rb', line 358 def path(key = nil) return @path.dup unless key @hash_paths[key.upcase].dup end |
#reject(&block) ⇒ Array<TagTree>
rejected nodes will not include their children nodes
Returns plain list of nodes.
154 155 156 |
# File 'lib/eco/api/organization/tag_tree.rb', line 154 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.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/eco/api/organization/tag_tree.rb', line 137 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 Also known as: subid?
Verifies if a tag exists in the subtree(s).
304 305 306 |
# File 'lib/eco/api/organization/tag_tree.rb', line 304 def subtag?(key) .include?(key&.upcase) end |
#subtags ⇒ Array<String> Also known as: subids
Gets all but the upper level tags of the current node tree.
296 297 298 |
# File 'lib/eco/api/organization/tag_tree.rb', line 296 def - (depth: depth) end |
#tag?(key) ⇒ Boolean Also known as: id?
Verifies if a tag exists in the tree.
330 331 332 |
# File 'lib/eco/api/organization/tag_tree.rb', line 330 def tag?(key) @hash_tags.key?(key&.upcase) end |
#tags(depth: nil) ⇒ Array<String> Also known as: ids
- 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.
283 284 285 286 287 288 289 290 291 |
# File 'lib/eco/api/organization/tag_tree.rb', line 283 def (depth: nil) if !depth || depth&.negative? @hash_tags.keys else @hash_tags.select do |_t, n| n.depth == depth end.keys end end |
#top? ⇒ Boolean
196 197 198 |
# File 'lib/eco/api/organization/tag_tree.rb', line 196 def top? depth == -1 end |
#total_depth ⇒ Integer
Returns the highest depth of all the children.
262 263 264 265 266 267 268 269 |
# File 'lib/eco/api/organization/tag_tree.rb', line 262 def total_depth @total_depth ||= if children? nodes.max_by(&:total_depth)&.total_depth else depth end end |
#truncate(max_depth: total_depth) ⇒ Eco::API::Organization::TagTree
Returns with nodes up to max_depth.
121 122 123 |
# File 'lib/eco/api/organization/tag_tree.rb', line 121 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
394 395 396 397 398 399 400 401 402 403 404 405 |
# File 'lib/eco/api/organization/tag_tree.rb', line 394 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 |= custom if preserve_custom = final - initial # keep same order as they where (initial & final) + end |