Class: SelfishAssociations::AssociationTraverser

Inherits:
BasicObject
Defined in:
lib/selfish_associations/utils/association_traverser.rb

Instance Method Summary collapse

Constructor Details

#initialize(klass) ⇒ AssociationTraverser

Returns a new instance of AssociationTraverser.



38
39
40
41
42
43
# File 'lib/selfish_associations/utils/association_traverser.rb', line 38

def initialize(klass)
  klass.is_a?(::Class) or ::Kernel.raise ::ArgumentError, "Input must be a Class"
  @original = klass
  @associations = []
  reset!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

Method Missing pattern (reluctantly). Really we could initialize a new at each node and pre-define all methods But this actually seems more lightweight.



85
86
87
# File 'lib/selfish_associations/utils/association_traverser.rb', line 85

def method_missing(method, *args)
  send(method, *args)
end

Instance Method Details

#associations!(merge: true) ⇒ Object

Return associations traversed Default behavior is to return an array of each path (Array of associations) Use argument merge = true to return a Hash where duplicate keys are merged



53
54
55
# File 'lib/selfish_associations/utils/association_traverser.rb', line 53

def associations!(merge: true)
  merge ? PathMerger.new(@associations).merge : @associations
end

#reset!Object



45
46
47
48
# File 'lib/selfish_associations/utils/association_traverser.rb', line 45

def reset!
  @path = []
  @klass = @original
end

#send(method, *args) ⇒ Object

Check if method is an association or a column If Association, store current node and iterate to the association. If it is a column, return an Arel::Node representing that value Else, raise NoMethodError



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/selfish_associations/utils/association_traverser.rb', line 61

def send(method, *args)
  if @klass.column_names.include?(method.to_s)
    @associations << @path if @path.present?
    node = @klass.arel_table[method]
    reset!
    return node
  elsif @klass.reflect_on_association(method)
    @path << method
    @klass = @klass.reflect_on_association(method).klass
    return self
  elsif @klass.selfish_associations[method].present?
    @path << method
    @klass = @klass.selfish_associations[method].foreign_class
    return self
  else
    message = "No association or field named #{method} found for class #{@klass}"
    reset!
    ::Kernel.raise ::NoMethodError, message
  end
end