Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
require 'byebug'
module MethodMetadata
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def method_advice(data = {})
lineno = caller_locations(1, 1).first.lineno
register(lineno, data)
end
def register(lineno, data)
method_metadata[lineno] = data
end
def method_metadata_at(lineno)
method_metadata[lineno]
end
def method_metadata
@method_metadata ||= {}
end
def method_advices
@method_advices ||= {}
end
def execute_with_advice(advice)
puts "Executing advices #{advice}"
##
# Implement your advices here
#
advice.each do |advice_type, args|
case advice_type
when :required_envvar
args.each { |key| ENV.fetch(key) }
end
end
yield
end
def attach_advice_with_singleton_method(method_name, advice)
method_advices[method_name] = advice
class_eval(<<-CODE, __FILE__, __LINE__ + 1)
class << self
alias_method :#{method_name}_without_advice, :#{method_name}
def #{method_name}(*args)
advice = method_advices.fetch(:#{method_name}, nil)
execute_with_advice(advice) { #{method_name}_without_advice(*args) } if advice
end
end
CODE
end
# FYI: Needs to implement method_added in order to support instance methods
def singleton_method_added(method_name)
return if method_name.to_s.match(/_without_advice$/)
advice = method_metadata_at(method(method_name).source_location.last - 1)
attach_advice_with_singleton_method(method_name, advice) if advice
end
end
end
module Hello
include MethodMetadata
# FYI, currently it has to be just before the method name, but you can extend this method implementation to setup
# as per your desire range - :singleton_method_added
#
method_advice required_envvar: %w[HELLO WORLD]
def self.connection(arg1, arg2)
puts 'Connection'
puts method_metadata.inspect
end
def self.hi_there
puts 'Hi there'
end
def hello
end
end
Hello.connection(1, 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.