Last active
December 27, 2015 23:08
-
-
Save markbates/7403345 to your computer and use it in GitHub Desktop.
Code and slides from my RubyConf 2013 talk, "Mangling Ruby with TracePoint". Slides: http://www.slideshare.net/markykang/mangling-ruby-withtracepoint
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'singleton' | |
tracer = TracePoint.new(:end) do |tp| | |
ancestors = tp.self.ancestors.dup | |
ancestors.delete(tp.self) | |
missing_methods = [] | |
ancestors.each do |ancestor| | |
methods = AbstractMethodManager.instance.methods[ancestor] | |
if methods | |
methods.each do |m| | |
unless tp.self.instance_methods.include?(m) | |
missing_methods << m | |
end | |
end | |
end | |
end | |
if missing_methods.any? | |
raise AbstractInterface::NotImplementedError.new(*missing_methods) | |
end | |
end | |
tracer.enable | |
class AbstractMethodManager | |
include Singleton | |
attr_accessor :methods | |
def initialize | |
@methods = {} | |
end | |
def add(klass, *methods) | |
@methods[klass] ||= [] | |
@methods[klass].concat(methods) | |
end | |
end | |
module AbstractInterface | |
class NotImplementedError < StandardError | |
def initialize(*methods) | |
super "You must implement the following methods: #{methods.join(', ')}" | |
end | |
end | |
class << self | |
def included(klass) | |
klass.extend(ClassMethods) | |
end | |
end | |
module ClassMethods | |
def abstract_method(*methods) | |
AbstractMethodManager.instance.add(self, *methods) | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative "./method_call_collector.rb" | |
class Foo | |
def bar | |
"bar" | |
end | |
end | |
foo = Foo.new | |
puts foo.bar |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative "./abstract_interfaces.rb" | |
module ApiInterface | |
include AbstractInterface | |
abstract_method :get, :put | |
end | |
class HttpLibrary | |
include ApiInterface | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'singleton' | |
class TraceCollector | |
include Singleton | |
def initialize | |
@calls = {} | |
end | |
def collect(tp) | |
klass = tp.self.class.name | |
klass = klass ? klass : "NilClass" | |
items = @calls.dup | |
items[klass] ||= {} | |
items[klass][tp.method_id] ||= 0 | |
items[klass][tp.method_id] += 1 | |
@calls = items | |
end | |
def self.method_missing(name, *args, &block) | |
instance.send(name, *args, &block) | |
end | |
def each(&block) | |
@calls.each(&block) | |
end | |
end | |
tracers = [] | |
[:c_call, :call].each do |event| | |
tracers << TracePoint.new(event) do |tp| | |
TraceCollector.collect(tp) | |
end | |
end | |
tracers.map(&:enable) | |
at_exit do | |
tracers.map(&:disable) | |
totals = {} | |
longest_name_size = 0 | |
TraceCollector.each do |klass, methods| | |
if klass && klass.length > longest_name_size | |
longest_name_size = klass.length | |
end | |
totals[klass] ||= 0 | |
puts "#{klass}:" | |
methods = methods.sort_by {|k, v| v}.reverse | |
methods.each do |method, count| | |
totals[klass] += count | |
printf "\t%-30s %s\n", method, count | |
end | |
puts "\n" | |
end | |
puts "-------------" | |
puts "Totals:\n" | |
totals = totals.sort_by {|k, v| v}.reverse | |
total_calls = 0 | |
totals.each do |klass, total| | |
total_calls += total | |
printf "\t%-#{longest_name_size}s %s\n", klass, total | |
end | |
puts "\n\n Total Method Calls: #{total_calls}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment