Class: Hierarchy
- Inherits:
-
Object
- Object
- Hierarchy
- Defined in:
- lib/hierarchy_tree.rb
Overview
Debug ################ rm hierarchy-tree-X.Y.Z.gem gem build hierarchy_tree gem install hierarchy-tree-X.Y.Z.gem ruby -Itest test/test_hierarchy_tree.rb
Class Method Summary collapse
-
.associations(klass) ⇒ Object
Return the full hierarchy starting from the provided class.
- .build_descendants(klass) ⇒ Object
- .build_hierarchy(opts) ⇒ Object
- .children_classes(opts) ⇒ Object
-
.classes(klass) ⇒ Object
Return the full hierarchy starting from the provided class.
-
.classes_list(klass) ⇒ Object
Return an array o.
- .dfs_descendants(opts, klass_name = nil) ⇒ Object
- .dfs_hierarchy(opts, klass_name = nil, ancestral_nodes = []) ⇒ Object
- .get_class(reflection) ⇒ Object
- .leaf?(klass) ⇒ Boolean
- .loop?(klass) ⇒ Boolean
- .walkables(klass) ⇒ Object
Class Method Details
.associations(klass) ⇒ Object
Return the full hierarchy starting from the provided class
12 13 14 |
# File 'lib/hierarchy_tree.rb', line 12 def self.associations(klass) build_hierarchy(class: klass) end |
.build_descendants(klass) ⇒ Object
92 93 94 95 96 97 |
# File 'lib/hierarchy_tree.rb', line 92 def self.build_descendants(klass) dfs_descendants(class: klass, classes?: true) rescue SystemStackError Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} classes_list", :warn [] end |
.build_hierarchy(opts) ⇒ Object
37 38 39 40 41 42 43 |
# File 'lib/hierarchy_tree.rb', line 37 def self.build_hierarchy(opts) @cache = {} dfs_hierarchy(opts) rescue SystemStackError Rails.logger.ap "Infinite loop detected and handled for #{opts[:class]} hierarchy", :warn [] end |
.children_classes(opts) ⇒ Object
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/hierarchy_tree.rb', line 68 def self.children_classes(opts) walkables(opts[:class]).map do |reflection| child_class = get_class(reflection) if opts[:classes?] [child_class, child_class.to_s] else [child_class, reflection.name] end end.uniq end |
.classes(klass) ⇒ Object
Return the full hierarchy starting from the provided class
17 18 19 |
# File 'lib/hierarchy_tree.rb', line 17 def self.classes(klass) build_hierarchy(class: klass, classes?: true) end |
.classes_list(klass) ⇒ Object
Return an array o
22 23 24 25 26 |
# File 'lib/hierarchy_tree.rb', line 22 def self.classes_list(klass) @classes_list = [] build_descendants(klass) @classes_list end |
.dfs_descendants(opts, klass_name = nil) ⇒ Object
99 100 101 102 103 104 105 106 107 |
# File 'lib/hierarchy_tree.rb', line 99 def self.dfs_descendants(opts, klass_name = nil) return if klass_name.in? @classes_list @classes_list.push(klass_name) if klass_name.present? children_classes(opts).each do |child_klass, child_name| child_opts = { class: child_klass, classes?: opts[:classes?] } dfs_descendants(child_opts, child_name) end true end |
.dfs_hierarchy(opts, klass_name = nil, ancestral_nodes = []) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/hierarchy_tree.rb', line 45 def self.dfs_hierarchy(opts, klass_name = nil, ancestral_nodes = []) return @cache[klass_name] if klass_name.in? @cache.keys return klass_name if opts[:class].in? ancestral_nodes # Early abort to not enter in a cycle if leaf?(opts[:class]) @cache[klass_name] = klass_name return klass_name if klass_name.present? # Leaf [] # Leaf and Root else ancestral_nodes.push(opts[:class]) children_hierarchies = children_classes(opts).map do |c_class, c_name| dfs_hierarchy({ class: c_class, classes?: opts[:classes?] }, c_name, ancestral_nodes.dup) end @cache[klass_name] = { klass_name => children_hierarchies } return @cache[klass_name] if klass_name.present? # Middle children_hierarchies # Root end end |
.get_class(reflection) ⇒ Object
86 87 88 89 90 |
# File 'lib/hierarchy_tree.rb', line 86 def self.get_class(reflection) child = reflection.name.to_s.singularize.classify child = reflection.[:class_name].to_s if reflection..key?(:class_name) child.constantize end |
.leaf?(klass) ⇒ Boolean
63 64 65 66 |
# File 'lib/hierarchy_tree.rb', line 63 def self.leaf?(klass) return true if walkables(klass).empty? false end |
.loop?(klass) ⇒ Boolean
28 29 30 31 32 33 |
# File 'lib/hierarchy_tree.rb', line 28 def self.loop?(klass) @cache = {} false if dfs_hierarchy(class: klass, classes?: false) rescue SystemStackError true end |
.walkables(klass) ⇒ Object
79 80 81 82 83 84 |
# File 'lib/hierarchy_tree.rb', line 79 def self.walkables(klass) # get all models associated with :has_many or :has_one that are walkable. klass.reflections.values.select do |r| r.macro.in? %i[has_one has_many] and not r..key?(:through) end end |