require 'byebug'
require 'benchmark'
require 'timeout'

module Decorator
  def decorate(method, &block)
    decorator = Module.new do
      define_method(method, &block)
    end

    prepend(decorator)
    method
  end

  def registry
    @_registry ||= ObjectSpace::WeakMap.new
    @_registry[self] ||= []
  end

  def decorator(&block)
    registry << block
  end

  def method_added(method)
    registry.each do |wrapper|
      decorate(method, &wrapper)
    end
    registry.clear
  end
end

module Profiling
  include Decorator

  def timeout(n)
    decorator do
      begin
        Timeout.timeout(n){ super() }
      rescue Timeout::Error
        puts "Timed out!"
        nil
      end
    end
  end

  def benchmark
    decorator do
      Benchmark.bm do |bm|
        bm.report(__method__){ super() }
      end
    end
  end
end

class Thyme
  extend Profiling

  benchmark
  timeout(3)
  def now(ohai = true)
    sleep 4
    Time.now
  end

  def hey
    "help!"
  end
end

thyme = Thyme.new

puts thyme.now
puts thyme.hey