hierarchy-tree 0.1.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.
- checksums.yaml +7 -0
- data/lib/hierarchy_tree.rb +97 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c69d1d28db8ef461d3a9dbdc093cee55aeb3899d0127965f5f282402e3a92d20
|
4
|
+
data.tar.gz: 66637e5ac94c03c4add0fe2373141761ce89cb96aeff0b0bf7eda20cdda1a50c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d24c501e41cf7594dd4ade171659fda73b0fde49dd812bd4ac05af3e1fc77b77e9845b101972e067db10cb54af3890d19ed84f1bbddd8b20d1fcac7d1e227dd
|
7
|
+
data.tar.gz: 006ad25440512ff39490a5b7ed8988c7b34c0ce2f73d4085a6947c9cd4e00e2e70f653560c386ff02d8a6e3e3e0ab8ef5bf14ccc09db9f01d641e1fe493b0b72
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_support/core_ext/object/inclusion.rb'
|
3
|
+
|
4
|
+
class Hierarchy
|
5
|
+
# Return the full hierarchy starting from the provided class
|
6
|
+
def self.associations(klass)
|
7
|
+
build_hierarchy(klass)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Return just the descendant classes of a provided class
|
11
|
+
def self.descendants(klass)
|
12
|
+
@descendants = []
|
13
|
+
build_descendants(klass)
|
14
|
+
@descendants
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.loop?(klass)
|
18
|
+
@cache = {}
|
19
|
+
false if dfs_hierarchy(class: klass, classes?: false)
|
20
|
+
rescue SystemStackError
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
private_class_method
|
25
|
+
|
26
|
+
def self.build_hierarchy(klass)
|
27
|
+
@cache = {}
|
28
|
+
dfs_hierarchy(class: klass)
|
29
|
+
rescue SystemStackError
|
30
|
+
Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} hierarchy", :warn
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.dfs_hierarchy(opts, klass_name = nil, ancestral_nodes = [])
|
35
|
+
return @cache[klass_name] if klass_name.in? @cache.keys
|
36
|
+
return klass_name if opts[:class].in? ancestral_nodes # Early abort to not enter in a cycle
|
37
|
+
if leaf?(opts[:class])
|
38
|
+
@cache[klass_name] = klass_name
|
39
|
+
return klass_name if klass_name.present? # Leaf
|
40
|
+
[] # Leaf and Root
|
41
|
+
else
|
42
|
+
ancestral_nodes.push(opts[:class])
|
43
|
+
children_hierarchies = children_classes(opts).map do |c_class, c_name|
|
44
|
+
dfs_hierarchy({ class: c_class, classes?: opts[:classes?] }, c_name, ancestral_nodes.dup)
|
45
|
+
end
|
46
|
+
@cache[klass_name] = { klass_name => children_hierarchies }
|
47
|
+
return @cache[klass_name] if klass_name.present? # Middle
|
48
|
+
children_hierarchies # Root
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.leaf?(klass)
|
53
|
+
return true if walkables(klass).empty?
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.children_classes(opts)
|
58
|
+
walkables(opts[:class]).map do |reflection|
|
59
|
+
child_class = get_class(reflection)
|
60
|
+
if opts[:classes?]
|
61
|
+
[child_class, child_class.to_s]
|
62
|
+
else
|
63
|
+
[child_class, reflection.name]
|
64
|
+
end
|
65
|
+
end.uniq
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.walkables(klass)
|
69
|
+
# get all models associated with :has_many or :has_one that are walkable.
|
70
|
+
klass.reflections.values.select do |r|
|
71
|
+
r.macro.in? %i[has_one has_many] and not r.options.key?(:through)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.get_class(reflection)
|
76
|
+
child = reflection.name.to_s.singularize.classify
|
77
|
+
child = reflection.options[:class_name].to_s if reflection.options.key?(:class_name)
|
78
|
+
child.constantize
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.build_descendants(klass)
|
82
|
+
dfs_descendants(class: klass, classes?: true)
|
83
|
+
rescue SystemStackError
|
84
|
+
Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} descendants", :warn
|
85
|
+
[]
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.dfs_descendants(opts, klass_name = nil)
|
89
|
+
return if klass_name.in? @descendants
|
90
|
+
@descendants.push(klass_name) if klass_name.present?
|
91
|
+
children_classes(opts).each do |child_klass, child_name|
|
92
|
+
child_opts = { class: child_klass, classes?: opts[:classes?] }
|
93
|
+
dfs_descendants(child_opts, child_name)
|
94
|
+
end
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hierarchy-tree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Victor Cordeiro Costa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-02-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activerecord
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.2'
|
55
|
+
description: |-
|
56
|
+
hierarchy-tree is a gem that shows the whole hierarchy
|
57
|
+
and the associations related to a desired class.
|
58
|
+
email:
|
59
|
+
- victorcorcos@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- lib/hierarchy_tree.rb
|
65
|
+
homepage: https://github.com/Victorcorcos/hierarchy-tree
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.7.9
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: hierarchy-tree is a gem that shows the whole hierarchy and the associations
|
89
|
+
related to a desired class.
|
90
|
+
test_files: []
|