hierarchy-tree 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hierarchy_tree.rb +88 -11
  3. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a387476231d9e229cd35249afe3cdd379d88cb8de7ad5e20147788f905e37868
4
- data.tar.gz: 71289f5698f69dd47c36c1ba1127b14ce0d0a5a409149e3be284e4f6406890d6
3
+ metadata.gz: cab69803c942b2cda581356ae1c3701febf660db154041a799d0c2dd22eefbfa
4
+ data.tar.gz: de33c12ba0a884a268d0730a3fce604591b9d62ff5b07e994e583b9e8524316a
5
5
  SHA512:
6
- metadata.gz: aa5205f67c7ac11a1e981de223fd1d18d19ac65b44ec0695db6b093043d3f185776a887f2c51ab30521c37ddf68b6c08605ae8a399d379b6ad6063b1b65636a1
7
- data.tar.gz: 97029a37131556fa12d7bb2e8394cbcadfa7236e186f03e6c006ffc2a54a6dd79307f89c1307c50f6d276c20db020f824745576abcec7d32ccf043f12c0967e7
6
+ metadata.gz: eecf514e48906d8fcc98e5c80896e56b0d2cf1d2f60d207ce644dc72b131c35fe0d6329d3f786cb2ed35df8f113bf9c11d6b3083835a39e7600c22adc7d3c631
7
+ data.tar.gz: 9dacd1c66e4bb7355eeee8bf51341bcfa3d3a6cea7d76b6bce0a6057614e48a6bf8751ba064da6ec54b5f84cb1a41063e3c7904c4f8fbf12cec4db86905e98cf
@@ -1,17 +1,73 @@
1
1
  require 'active_record'
2
2
  require 'active_support/core_ext/object/inclusion.rb'
3
3
 
4
+ ################ Debug ################
5
+ # gem uninstall hierarchy-tree -v 0.3.0
6
+ # rm hierarchy-tree-0.3.0.gem
7
+ # gem build hierarchy_tree
8
+ # gem install hierarchy-tree-0.3.0.gem
9
+ # ruby -Itest test/test_hierarchy_tree.rb
10
+
4
11
  class Hierarchy
5
- # Return the full hierarchy starting from the provided class
12
+ # Return the full hierarchy as associations starting from the provided class
6
13
  def self.associations(klass)
7
- build_hierarchy(klass)
14
+ build_hierarchy(class: klass)
15
+ end
16
+
17
+ # Return the full hierarchy as classes starting from the provided class
18
+ def self.classes(klass)
19
+ build_hierarchy(class: klass, classes?: true)
8
20
  end
9
21
 
10
- # Return just the descendant classes of a provided class
11
- def self.descendants(klass)
12
- @descendants = []
22
+ # Return the array of children classes
23
+ def self.classes_list(klass)
24
+ @classes_list = []
13
25
  build_descendants(klass)
14
- @descendants
26
+ @classes_list
27
+ end
28
+
29
+ # Return the ancestors associations by navigating through :belongs_to
30
+ # Starting from the "from" class towards the "to" class
31
+ # Using DFS - Depth First Search, thus finding the Deepest Path (more likely)
32
+ def self.ancestors_dfs(from:, to:, descendants: [])
33
+ return if from.to_s == to.to_s and descendants == [] # Base case
34
+ return 'loop' if from.in? descendants # Avoids cycle
35
+
36
+ descendants.push(from)
37
+
38
+ from.reflect_on_all_associations(:belongs_to).map do |relation|
39
+ return relation.name if relation.klass.to_s == to.to_s # Path is found
40
+ path = ancestors_dfs(from: relation.klass, to: to, descendants: descendants)
41
+ return { relation.name => path } if valid_path?(path, to.model_name.param_key.to_sym)
42
+ end.compact.first
43
+ end
44
+
45
+ # Return the ancestors associations by navigating through :belongs_to
46
+ # Starting from the "from" class towards the "to" class
47
+ # Using BFS - Breadth First Search, thus finding the Shortest Path
48
+ def self.ancestors_bfs(from:, to:)
49
+ return if from == to
50
+
51
+ queue = [{ class: from, path: [] }]
52
+ visited = [from]
53
+
54
+ while queue.any?
55
+ current = queue.shift
56
+ current_class = current[:class]
57
+ current_path = current[:path]
58
+
59
+ current_class.reflect_on_all_associations(:belongs_to).each do |relation|
60
+ next_class = relation.klass
61
+ next_path = current_path + [relation.name]
62
+
63
+ return hashify(next_path) if next_class.to_s == to.to_s
64
+
65
+ if visited.exclude?(next_class)
66
+ visited << next_class
67
+ queue.push({ class: next_class, path: next_path })
68
+ end
69
+ end
70
+ end
15
71
  end
16
72
 
17
73
  def self.loop?(klass)
@@ -23,9 +79,9 @@ class Hierarchy
23
79
 
24
80
  private_class_method
25
81
 
26
- def self.build_hierarchy(klass)
82
+ def self.build_hierarchy(opts)
27
83
  @cache = {}
28
- dfs_hierarchy(class: klass)
84
+ dfs_hierarchy(opts)
29
85
  rescue SystemStackError
30
86
  Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} hierarchy", :warn
31
87
  []
@@ -81,17 +137,38 @@ class Hierarchy
81
137
  def self.build_descendants(klass)
82
138
  dfs_descendants(class: klass, classes?: true)
83
139
  rescue SystemStackError
84
- Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} descendants", :warn
140
+ Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} classes_list", :warn
85
141
  []
86
142
  end
87
143
 
88
144
  def self.dfs_descendants(opts, klass_name = nil)
89
- return if klass_name.in? @descendants
90
- @descendants.push(klass_name) if klass_name.present?
145
+ return if klass_name.in? @classes_list
146
+ @classes_list.push(klass_name) if klass_name.present?
91
147
  children_classes(opts).each do |child_klass, child_name|
92
148
  child_opts = { class: child_klass, classes?: opts[:classes?] }
93
149
  dfs_descendants(child_opts, child_name)
94
150
  end
95
151
  true
96
152
  end
153
+
154
+ def self.valid_path?(path, target)
155
+ return true if path == target
156
+
157
+ case path
158
+ when Array
159
+ path.any? { |sub_path| valid_path?(sub_path, target) }
160
+ when Hash
161
+ path.values.any? { |value| valid_path?(value, target) }
162
+ else
163
+ false
164
+ end
165
+ end
166
+
167
+ def self.hashify(array)
168
+ if array.length == 1
169
+ array.first
170
+ else
171
+ { array.first => hashify(array.drop(1)) }
172
+ end
173
+ end
97
174
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hierarchy-tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Cordeiro Costa
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-15 00:00:00.000000000 Z
11
+ date: 2023-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -66,7 +66,7 @@ homepage: https://github.com/Victorcorcos/hierarchy-tree
66
66
  licenses:
67
67
  - MIT
68
68
  metadata: {}
69
- post_install_message:
69
+ post_install_message:
70
70
  rdoc_options: []
71
71
  require_paths:
72
72
  - lib
@@ -82,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
82
  version: '0'
83
83
  requirements: []
84
84
  rubygems_version: 3.1.6
85
- signing_key:
85
+ signing_key:
86
86
  specification_version: 4
87
87
  summary: hierarchy-tree is a gem that shows the whole hierarchy and the associations
88
88
  related to a desired class.