hierarchy-tree 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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.