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
Why Use Ruby'S Attr_Accessor, Attr_Reader and Attr_Writer
What Is the Easiest Way to Duplicate an Activerecord Record
How to Match All Occurrences of a Regex
Converting a Nested Hash into a Flat Hash
What's the Difference Between a Proc and a Lambda in Ruby
How to Count Duplicate Elements in a Ruby Array
Ruby Regular Expression Using Variable Name
Rails 3: Alias_Method_Chain Still Used
Issue Updating Ruby on MAC With Xcode 4.3.1
How to Override a Setter Method in Ruby on Rails
How to Write a Switch Statement in Ruby
Ruby: How to Post a File Via Http as Multipart/Form-Data
How to Modify Path For Homebrew
Difference Between Collection Route and Member Route in Ruby on Rails
Continuously Read from Stdout of External Process in Ruby
What's Different Between Each and Collect Method in Ruby
Difference Between '..' (Double-Dot) and '...' (Triple-Dot) in Range Generation