Class: PaperTrailDiff::AssociationDiscovery
- Inherits:
-
Object
- Object
- PaperTrailDiff::AssociationDiscovery
- Defined in:
- lib/paper_trail_diff/association_discovery.rb,
sig/generated/paper_trail_diff/association_discovery.rbs
Overview
Discovers finite, supported association paths for configuration UIs.
Instance Method Summary collapse
-
#association_path(prefix, name) ⇒ String
: (String, String) -> String.
-
#call ⇒ Array[AssociationDescriptor]
: () -> Array.
- #describe_and_descend(reflection, prefix:, ancestry:, depth:) ⇒ Array[AssociationDescriptor]
-
#descriptor_for(reflection, path, target_class, cycle) ⇒ AssociationDescriptor
: (untyped, String, untyped, bool) -> AssociationDescriptor.
- #discover(model_class, prefix:, ancestry:, depth:) ⇒ Array[AssociationDescriptor]
-
#initialize(model_or_record, max_depth:) ⇒ AssociationDiscovery
constructor
: (untyped, max_depth: Integer) -> void.
-
#paper_trail_versions?(model_class, reflection) ⇒ Boolean
: (untyped, untyped) -> bool.
-
#reflection_target(reflection) ⇒ Object
: (untyped) -> untyped.
-
#reflection_target_name(reflection) ⇒ String?
: (untyped) -> String?.
-
#supported_reflections(model_class) ⇒ Array[untyped]
: (untyped) -> Array.
Constructor Details
#initialize(model_or_record, max_depth:) ⇒ AssociationDiscovery
: (untyped, max_depth: Integer) -> void
41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 41 def initialize(model_or_record, max_depth:) unless max_depth.is_a?(Integer) && max_depth.positive? raise ConfigurationError, 'max_depth: must be a positive integer' end @model_class = model_or_record.is_a?(Class) ? model_or_record : model_or_record.class @max_depth = max_depth return if @model_class.respond_to?(:reflect_on_all_associations) raise ConfigurationError, 'expected an ActiveRecord model class or record' end |
Instance Method Details
#association_path(prefix, name) ⇒ String
: (String, String) -> String
128 129 130 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 128 def association_path(prefix, name) prefix.empty? ? name : "#{prefix}.#{name}" end |
#call ⇒ Array[AssociationDescriptor]
: () -> Array
54 55 56 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 54 def call discover(@model_class, prefix: '', ancestry: [@model_class], depth: 1).freeze end |
#describe_and_descend(reflection, prefix:, ancestry:, depth:) ⇒ Array[AssociationDescriptor]
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 71 def describe_and_descend(reflection, prefix:, ancestry:, depth:) path = association_path(prefix, reflection.name.to_s) target_class = reflection_target(reflection) cycle = target_class ? ancestry.include?(target_class) : false descriptor = descriptor_for(reflection, path, target_class, cycle) return [descriptor] unless target_class && !cycle && depth < @max_depth descendants = discover( target_class, prefix: path, ancestry: [*ancestry, target_class], depth: depth + 1 ) [descriptor, *descendants] end |
#descriptor_for(reflection, path, target_class, cycle) ⇒ AssociationDescriptor
: (untyped, String, untyped, bool) -> AssociationDescriptor
88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 88 def descriptor_for(reflection, path, target_class, cycle) flags = [] #: Array[Symbol] flags << :polymorphic if reflection.polymorphic? flags << :cycle if cycle AssociationDescriptor.new( path: path, kind: reflection.macro, target_type: target_class&.name || reflection_target_name(reflection), through: reflection.[:through]&.to_s, flags: flags ) end |
#discover(model_class, prefix:, ancestry:, depth:) ⇒ Array[AssociationDescriptor]
64 65 66 67 68 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 64 def discover(model_class, prefix:, ancestry:, depth:) supported_reflections(model_class).flat_map do |reflection| describe_and_descend(reflection, prefix: prefix, ancestry: ancestry, depth: depth) end end |
#paper_trail_versions?(model_class, reflection) ⇒ Boolean
: (untyped, untyped) -> bool
110 111 112 113 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 110 def paper_trail_versions?(model_class, reflection) model_class.respond_to?(:versions_association_name) && reflection.name.to_s == model_class.versions_association_name.to_s end |
#reflection_target(reflection) ⇒ Object
: (untyped) -> untyped
116 117 118 119 120 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 116 def reflection_target(reflection) reflection.klass unless reflection.polymorphic? rescue NameError nil end |
#reflection_target_name(reflection) ⇒ String?
: (untyped) -> String?
123 124 125 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 123 def reflection_target_name(reflection) reflection.class_name.to_s unless reflection.polymorphic? end |
#supported_reflections(model_class) ⇒ Array[untyped]
: (untyped) -> Array
102 103 104 105 106 107 |
# File 'lib/paper_trail_diff/association_discovery.rb', line 102 def supported_reflections(model_class) model_class.reflect_on_all_associations .select { |reflection| SUPPORTED_ASSOCIATION_MACROS.include?(reflection.macro) } .reject { |reflection| paper_trail_versions?(model_class, reflection) } .sort_by { |reflection| reflection.name.to_s } end |