Class: Hometown::CreationTracer

Inherits:
Object
  • Object
show all
Defined in:
lib/hometown/creation_tracer.rb

Constant Summary collapse

HOMETOWN_TRACE_ON_INSTANCE =
:@__hometown_creation_backtrace

Instance Method Summary collapse

Constructor Details

#initializeCreationTracer

Returns a new instance of CreationTracer.



3
4
5
# File 'lib/hometown/creation_tracer.rb', line 3

def initialize
  @tracing_classes = {}
end

Instance Method Details

#add_trace_for(instance) ⇒ Object



48
49
50
51
# File 'lib/hometown/creation_tracer.rb', line 48

def add_trace_for(instance)
  trace = Hometown::Trace.new(instance.class, scrubbed_caller)
  instance.instance_variable_set(HOMETOWN_TRACE_ON_INSTANCE, trace)
end

#find_trace_for(instance) ⇒ Object



58
59
60
# File 'lib/hometown/creation_tracer.rb', line 58

def find_trace_for(instance)
  instance.instance_variable_get(HOMETOWN_TRACE_ON_INSTANCE)
end

#install_traced_new(clazz) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/hometown/creation_tracer.rb', line 31

def install_traced_new(clazz)
  clazz.instance_eval do
    class << self
      def new_traced(*args, &blk)
        instance = new_untraced(*args, &blk)
        @instance_hooks.each { |hook| hook.call(instance) }
        instance
      end

      alias_method :new_untraced, :new
      alias_method :new, :new_traced
    end
  end
end

#on_creation_add_trace_for_instance(clazz) ⇒ Object



27
28
29
# File 'lib/hometown/creation_tracer.rb', line 27

def on_creation_add_trace_for_instance(clazz)
  update_on_instance_created(clazz, method(:add_trace_for))
end

#patch(clazz, other_instance_hook = nil) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
# File 'lib/hometown/creation_tracer.rb', line 7

def patch(clazz, other_instance_hook=nil)
  if !patched?(clazz)
    remember_patched(clazz)
    on_creation_add_trace_for_instance(clazz)
    install_traced_new(clazz)
  end

  # Critical that we only add other instance hooks after our primary
  # creation hook is registered above!
  update_on_instance_created(clazz, other_instance_hook)
end

#patched?(clazz) ⇒ Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/hometown/creation_tracer.rb', line 19

def patched?(clazz)
  @tracing_classes.include?(clazz)
end

#remember_patched(clazz) ⇒ Object



23
24
25
# File 'lib/hometown/creation_tracer.rb', line 23

def remember_patched(clazz)
  @tracing_classes[clazz] = true
end

#scrubbed_callerObject



53
54
55
56
# File 'lib/hometown/creation_tracer.rb', line 53

def scrubbed_caller
  backtrace = caller.dup
  backtrace.reject { |line| %r{/lib/hometown/creation_tracer.rb}.match(line) }
end

#update_on_instance_created(clazz, on_instance_created) ⇒ Object

This hook allows other tracing in Hometown to get a whack at an object after it’s been created without forcing them to patch new themselves



64
65
66
67
68
69
70
# File 'lib/hometown/creation_tracer.rb', line 64

def update_on_instance_created(clazz, on_instance_created)
  return unless on_instance_created
  clazz.instance_eval do
    @instance_hooks ||= []
    @instance_hooks << on_instance_created
  end
end