Lets say I have a class with hundreds of instance methods in it. Now I have the requirement to run each method only if a certain thing is detected. Also I want to run my detection algorithm once for whole class instance no matter how many methods got called. If not detected first time no methods get called. I cannot afford if else around that many methods so I have to get a workaround. I have the following said class:
class CrawlerModule
extend Callbacks
before_run [:method_names, :of, :my, :class], :check_if_detected
@detected = nil
def check_if_detected
if @detected.nil?
detect
end
@detected
end
#hundreds of methods
private
def detect
detected_now = #my_detection_algorithm
@detected = detected_now
end
end
What I have done so far is to include following Callbacks module to call my check_if_detected method before every method but it doesn't work because method_added called at the very start of program and my detect function need some things to get initialized before detection. So the result array is always nil. Here's that complete module:
module Callbacks
def self.extended(base)
base.send(:include, InstanceMethods)
end
def overridden_methods
@overridden_methods ||= []
end
def callbacks
@callbacks ||= Hash.new { |hash, key| hash[key] = [] }
end
def method_added(method_name)
return if should_override?(method_name)
overridden_methods << method_name
original_method_name = "original_#{method_name}"
alias_method(original_method_name, method_name)
define_method(method_name) do |*args|
result = run_callbacks_for(method_name)
if result[0] || (self.class.callbacks.values.flatten.include? method_name)
send(original_method_name, *args)
end
end
end
def should_override?(method_name)
overridden_methods.include?(method_name) || method_name =~ /original_/
end
def before_run(method_names, callback)
method_names.each do |method_name|
callbacks[method_name] << callback unless method_name.eql? callback
end
end
module InstanceMethods
def run_callbacks_for(method_name)
result = []
self.class.callbacks[method_name].to_a.each do |callback|
result << send(callback)
end
result
end
end
end