Skip to content

Instantly share code, notes, and snippets.

@we4tech
Last active July 25, 2018 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save we4tech/cf4ebd7963183153dfd78570f7ae52a6 to your computer and use it in GitHub Desktop.
Save we4tech/cf4ebd7963183153dfd78570f7ae52a6 to your computer and use it in GitHub Desktop.
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