Executing Code For Every Method Call in a Ruby Module

Executing code for every method call in a Ruby module

Like this:

module M
def self.before(*names)
names.each do |name|
m = instance_method(name)
define_method(name) do |*args, &block|
yield
m.bind(self).(*args, &block)
end
end
end
end

module M
def hello
puts "yo"
end

def bye
puts "bum"
end

before(*instance_methods) { puts "start" }
end

class C
include M
end

C.new.bye #=> "start" "bum"
C.new.hello #=> "start" "yo"

Running code before every method in a class (Ruby)

This sounds like the perfect use case for a Proxy object. Fortunately, Ruby's dynamic nature makes implementing it quite easy:

class ExecuteOnceProxy

def initialize(obj)
@obj = obj
@completed = []
end

def method_missing(method, *args)
unless @completed.include?(method)
args.empty? ? @obj.send(method) : @obj.send(method, args)
@completed << method
end
end
end

Initialize your proxy simply by passing the original object in the constructor:

proxy = ExecuteOnceProxy.new(my_obj)

Ruby - Executing same code after most methods in a class

This is trivially easy using method_missing, and composition instead of inheritance. You can build a very simple class which forwards method invocations, and then executes an after callback, except for specific method names:

class Abstract
def initialize(object)
@object = object
end

def method_missing(method, *arguments)
result = @object.send(method, *arguments)

after() unless method == "has_valid_params"

result
end

def after
# whatever
end
end

o = Abstract.new(MyClass.new)

call before methods in model on ruby

You can do this with prepend. prepend is like include in that it adds a module to the ancestors of the class, however instead of adding it after the class it adds it before.

This means that if a method exists both in the prepended module and the class then the module implementation is called first (and it can optionally call super if it wants to call the base class).

This allows you to write a hooks module like so:

module Hooks
def before(*method_names)
to_prepend = Module.new do
method_names.each do |name|
define_method(name) do |*args, &block|
puts "before #{name}"
super(*args,&block)
end
end
end
prepend to_prepend
end
end


class Example
extend Hooks
before :foo, :bar

def foo
puts "in foo"
end
def bar
puts "in bar"
end
end

In real use you would probably want to stash that module somewhere so that each call to before doesn't create a new module but that is just an inplementation detail

Calling a module function in a ruby module

It is just that the method is not defined when you assign fun to ABC. Just change the order:

module M
def self.fun
"works"
end

ABC = fun
end

M::ABC
#=> "works"

If you dislike the order (constants below methods), you might want to consider to have the method itself to memorize its return value. A common pattern looks like:

module M
def self.fun
@cached_fun ||= begin
sleep 4 # complex calculation
Time.now # return value
end
end
end

M.fun
# returns after 4 seconds => 2017-03-03 23:48:57 +0100
M.fun
# returns immediately => 2017-03-03 23:48:57 +0100

Calling a method on a Ruby module

Simple method:

module MyModule
def self.my_method(*args)
MyModule::MyClass.my_method(*args)
end
end

Harder method:

Use metaprogramming to write a function for all cases (like attr_accessor).



Related Topics



Leave a reply



Submit