Class: SaveChainInspector

Inherits:
Object
  • Object
show all
Defined in:
lib/save_chain_inspector.rb,
lib/save_chain_inspector/version.rb

Overview

rubocop:disable Metrics/ClassLength, Style/Documentation

Constant Summary collapse

VERSION =
'0.1.2'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSaveChainInspector

Returns a new instance of SaveChainInspector.



30
31
32
33
34
35
36
37
38
# File 'lib/save_chain_inspector.rb', line 30

def initialize
  ActiveRecord::Base.descendants.each do |klass|
    next if klass.abstract_class
    next if klass.instance_variable_get(:@save_chain_inspector_initialized)

    klass.instance_variable_set(:@save_chain_inspector_initialized, true)
    add_hooks(klass)
  end
end

Class Attribute Details

.enableObject

Returns the value of attribute enable.



7
8
9
# File 'lib/save_chain_inspector.rb', line 7

def enable
  @enable
end

.indent_countObject

Returns the value of attribute indent_count.



7
8
9
# File 'lib/save_chain_inspector.rb', line 7

def indent_count
  @indent_count
end

Instance Attribute Details

#last_call_classObject

Returns the value of attribute last_call_class.



40
41
42
# File 'lib/save_chain_inspector.rb', line 40

def last_call_class
  @last_call_class
end

#last_call_methodObject

Returns the value of attribute last_call_method.



40
41
42
# File 'lib/save_chain_inspector.rb', line 40

def last_call_method
  @last_call_method
end

#last_return_classObject

Returns the value of attribute last_return_class.



40
41
42
# File 'lib/save_chain_inspector.rb', line 40

def last_return_class
  @last_return_class
end

#last_return_methodObject

Returns the value of attribute last_return_method.



40
41
42
# File 'lib/save_chain_inspector.rb', line 40

def last_return_method
  @last_return_method
end

Class Method Details

.decrement_indentObject



25
26
27
# File 'lib/save_chain_inspector.rb', line 25

def decrement_indent
  self.indent_count -= 1 if indent_count.positive?
end

.increment_indentObject



21
22
23
# File 'lib/save_chain_inspector.rb', line 21

def increment_indent
  self.indent_count += 1
end

.indentObject



17
18
19
# File 'lib/save_chain_inspector.rb', line 17

def indent
  ' ' * (indent_count * 2)
end

.start(&block) ⇒ Object



9
10
11
12
13
14
15
# File 'lib/save_chain_inspector.rb', line 9

def start(&block)
  self.indent_count = 0
  self.enable = true
  new.call(&block)
ensure
  self.enable = false
end

Instance Method Details

#add_hooks(klass) ⇒ Object

rubocop:disable Metrics/AbcSize, Metrics/MethodLength



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/save_chain_inspector.rb', line 42

def add_hooks(klass) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  klass.before_save(prepend: true) do |model|
    next unless SaveChainInspector.enable

    puts "#{SaveChainInspector.indent}#{model.class}#before_save start"
    SaveChainInspector.increment_indent
  end
  klass.before_save do |model|
    next unless SaveChainInspector.enable

    SaveChainInspector.decrement_indent
    puts "#{SaveChainInspector.indent}#{model.class}#before_save end"
  end
  klass.set_callback(:create, :after) do |model|
    next unless SaveChainInspector.enable

    puts "#{SaveChainInspector.indent}#{model.class}#after_create start"
    SaveChainInspector.increment_indent
  end
  klass.after_create do |model|
    next unless SaveChainInspector.enable

    SaveChainInspector.decrement_indent
    puts "#{SaveChainInspector.indent}#{model.class}#after_create end"
  end
  klass.set_callback(:update, :after) do |model|
    next unless SaveChainInspector.enable

    puts "#{SaveChainInspector.indent}#{model.class}#after_update start"
    SaveChainInspector.increment_indent
  end
  klass.after_update do |model|
    next unless SaveChainInspector.enable

    SaveChainInspector.decrement_indent
    puts "#{SaveChainInspector.indent}#{model.class}#after_update end"
  end
end

#autosave_method?(trace_point) ⇒ Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/save_chain_inspector.rb', line 81

def autosave_method?(trace_point)
  trace_point.method_id.match?(/autosave_associated_records_for_/)
end

#autosave_to_save?(trace_point) ⇒ Boolean

Returns:

  • (Boolean)


97
98
99
100
# File 'lib/save_chain_inspector.rb', line 97

def autosave_to_save?(trace_point)
  (trace_point.method_id == :save || trace_point.method_id == :save!) &&
    last_call_method&.match?(/autosave_associated_records_for_/)
end

#call(&block) ⇒ Object



112
113
114
115
116
117
# File 'lib/save_chain_inspector.rb', line 112

def call(&block)
  trace.enable
  block.yield
ensure
  trace.disable
end

#duplicate_save_method_call?(trace_point) ⇒ Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/save_chain_inspector.rb', line 89

def duplicate_save_method_call?(trace_point)
  last_call_method == trace_point.method_id && last_call_class == trace_point.self.class
end

#duplicate_save_method_return?(trace_point) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/save_chain_inspector.rb', line 93

def duplicate_save_method_return?(trace_point)
  last_return_method == trace_point.method_id && last_return_class == trace_point.self.class
end

#save_method?(trace_point) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/save_chain_inspector.rb', line 85

def save_method?(trace_point)
  trace_point.method_id == :save || trace_point.method_id == :save!
end

#traceObject

rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/save_chain_inspector.rb', line 119

def trace # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  @trace ||= TracePoint.new(:call, :return) do |trace_point|
    if trace_point.event == :call
      if autosave_method?(trace_point) || (save_method?(trace_point) && !duplicate_save_method_call?(trace_point))
        update_last_call(trace_point)
        puts "#{self.class.indent}#{trace_point.self.class.name}##{trace_point.method_id} start"
        self.class.increment_indent
      end
    else # :return
      if save_method?(trace_point) && !duplicate_save_method_return?(trace_point)
        self.class.decrement_indent
        update_last_return(trace_point)
        puts "#{self.class.indent}#{trace_point.self.class.name}##{trace_point.method_id} end"
      end

      if autosave_method?(trace_point)
        self.class.decrement_indent
        puts "#{self.class.indent}#{trace_point.self.class.name}##{trace_point.method_id} end"
      end
    end
  end
end

#update_last_call(trace_point) ⇒ Object



102
103
104
105
# File 'lib/save_chain_inspector.rb', line 102

def update_last_call(trace_point)
  self.last_call_class = trace_point.self.class
  self.last_call_method = trace_point.method_id
end

#update_last_return(trace_point) ⇒ Object



107
108
109
110
# File 'lib/save_chain_inspector.rb', line 107

def update_last_return(trace_point)
  self.last_return_class = trace_point.self.class
  self.last_return_method = trace_point.method_id
end