Ruby module to print all method calls and returns in class
You can achieve that by defining a new wrapper method for each public instance method of the class that performs the log logic that you need.
module Loginator
def logify_me
self.public_instance_methods.each do |method|
proxy = Module.new do
define_method(method) do |*args|
puts "Method #{method}(#{args.join(', ')}) called"
# added join to match the exact desired output
value = super *args
puts "returns #{value}"
value
end
end
self.prepend proxy
end
end
end
class A
extend Loginator
def add(a, b)
a + b
end
def sub(a, b)
a - b
end
logify_me
end
Which yields the following output:
>> A.new.sub(1,2)
Method 'sub' called with args '[1, 2]'
returns -1
=> -1
>> A.new.add(4,7)
Method 'add' called with args '[4, 7]'
returns 11
=> 11
Explanation for the future :)
define_method(method)
:Defines an instance method in the receiver. The method parameter can be a Proc, a Method, or an UnboundMethod object. If a block is specified, it is used as the method body. This block is evaluated using instance_eval ref. can be found here
prepend
prepend will insert the module at the bottom of the chain, even before the class itself.fourth ref on my post
Section to Edit by @pedrosfdcarneiro
please, add some brief explanation about the second inner module proxy = Module.new do end
and why it's important for the return value and the usage of the super.
plus why did you preferred to use the public_instance_methods
over instance_methods
.
please kindly add some explanation about it because first its a bit unclear to me and secondly for the other noobs out there.
thanks in advance :)
This answer was heavily based on this fantastic answer: https://stackoverflow.com/a/23898539/1781212.
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"
When monkey patching an instance method, can you call the overridden method from the new implementation?
EDIT: It has been 9 years since I originally wrote this answer, and it deserves some cosmetic surgery to keep it current.
You can see the last version before the edit here.
You can’t call the overwritten method by name or keyword. That’s one of the many reasons why monkey patching should be avoided and inheritance be preferred instead, since obviously you can call the overridden method.
Avoiding Monkey Patching
Inheritance
So, if at all possible, you should prefer something like this:
class Foo
def bar
'Hello'
end
end
class ExtendedFoo < Foo
def bar
super + ' World'
end
end
ExtendedFoo.new.bar # => 'Hello World'
This works, if you control creation of the Foo
objects. Just change every place which creates a Foo
to instead create an ExtendedFoo
. This works even better if you use the Dependency Injection Design Pattern, the Factory Method Design Pattern, the Abstract Factory Design Pattern or something along those lines, because in that case, there is only place you need to change.
Delegation
If you do not control creation of the Foo
objects, for example because they are created by a framework that is outside of your control (like ruby-on-rails for example), then you could use the Wrapper Design Pattern:
require 'delegate'
class Foo
def bar
'Hello'
end
end
class WrappedFoo < DelegateClass(Foo)
def initialize(wrapped_foo)
super
end
def bar
super + ' World'
end
end
foo = Foo.new # this is not actually in your code, it comes from somewhere else
wrapped_foo = WrappedFoo.new(foo) # this is under your control
wrapped_foo.bar # => 'Hello World'
Basically, at the boundary of the system, where the Foo
object comes into your code, you wrap it into another object, and then use that object instead of the original one everywhere else in your code.
This uses the Object#DelegateClass
helper method from the delegate
library in the stdlib.
“Clean” Monkey Patching
Module#prepend
: Mixin Prepending
The two methods above require changing the system to avoid monkey patching. This section shows the preferred and least invasive method of monkey patching, should changing the system not be an option.
Module#prepend
was added to support more or less exactly this use case. Module#prepend
does the same thing as Module#include
, except it mixes in the mixin directly below the class:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
prepend FooExtensions
end
Foo.new.bar # => 'Hello World'
Note: I also wrote a little bit about Module#prepend
in this question: Ruby module prepend vs derivation
Mixin Inheritance (broken)
I have seen some people try (and ask about why it doesn’t work here on StackOverflow) something like this, i.e. include
ing a mixin instead of prepend
ing it:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
include FooExtensions
end
Unfortunately, that won’t work. It’s a good idea, because it uses inheritance, which means that you can use super
. However, Module#include
inserts the mixin above the class in the inheritance hierarchy, which means that FooExtensions#bar
will never be called (and if it were called, the super
would not actually refer to Foo#bar
but rather to Object#bar
which doesn’t exist), since Foo#bar
will always be found first.
Method Wrapping
The big question is: how can we hold on to the bar
method, without actually keeping around an actual method? The answer lies, as it does so often, in functional programming. We get a hold of the method as an actual object, and we use a closure (i.e. a block) to make sure that we and only we hold on to that object:
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() + ' World'
end
end
Foo.new.bar # => 'Hello World'
This is very clean: since old_bar
is just a local variable, it will go out of scope at the end of the class body, and it is impossible to access it from anywhere, even using reflection! And since Module#define_method
takes a block, and blocks close over their surrounding lexical environment (which is why we are using define_method
instead of def
here), it (and only it) will still have access to old_bar
, even after it has gone out of scope.
Short explanation:
old_bar = instance_method(:bar)
Here we are wrapping the bar
method into an UnboundMethod
method object and assigning it to the local variable old_bar
. This means, we now have a way to hold on to bar
even after it has been overwritten.
old_bar.bind(self)
This is a bit tricky. Basically, in Ruby (and in pretty much all single-dispatch based OO languages), a method is bound to a specific receiver object, called self
in Ruby. In other words: a method always knows what object it was called on, it knows what its self
is. But, we grabbed the method directly from a class, how does it know what its self
is?
Well, it doesn’t, which is why we need to bind
our UnboundMethod
to an object first, which will return a Method
object that we can then call. (UnboundMethod
s cannot be called, because they don’t know what to do without knowing their self
.)
And what do we bind
it to? We simply bind
it to ourselves, that way it will behave exactly like the original bar
would have!
Lastly, we need to call the Method
that is returned from bind
. In Ruby 1.9, there is some nifty new syntax for that (.()
), but if you are on 1.8, you can simply use the call
method; that’s what .()
gets translated to anyway.
Here are a couple of other questions, where some of those concepts are explained:
- How do I reference a function in Ruby?
- Is Ruby’s code block same as C♯’s lambda expression?
“Dirty” Monkey Patching
alias_method
chain
The problem we are having with our monkey patching is that when we overwrite the method, the method is gone, so we cannot call it anymore. So, let’s just make a backup copy!
class Foo
def bar
'Hello'
end
end
class Foo
alias_method :old_bar, :bar
def bar
old_bar + ' World'
end
end
Foo.new.bar # => 'Hello World'
Foo.new.old_bar # => 'Hello'
The problem with this is that we have now polluted the namespace with a superfluous old_bar
method. This method will show up in our documentation, it will show up in code completion in our IDEs, it will show up during reflection. Also, it still can be called, but presumably we monkey patched it, because we didn’t like its behavior in the first place, so we might not want other people to call it.
Despite the fact that this has some undesirable properties, it has unfortunately become popularized through AciveSupport’s Module#alias_method_chain
.
An aside: Refinements
In case you only need the different behavior in a few specific places and not throughout the whole system, you can use Refinements to restrict the monkey patch to a specific scope. I am going to demonstrate it here using the Module#prepend
example from above:
class Foo
def bar
'Hello'
end
end
module ExtendedFoo
module FooExtensions
def bar
super + ' World'
end
end
refine Foo do
prepend FooExtensions
end
end
Foo.new.bar # => 'Hello'
# We haven’t activated our Refinement yet!
using ExtendedFoo
# Activate our Refinement
Foo.new.bar # => 'Hello World'
# There it is!
You can see a more sophisticated example of using Refinements in this question: How to enable monkey patch for specific method?
Abandoned ideas
Before the Ruby community settled on Module#prepend
, there were multiple different ideas floating around that you may occasionally see referenced in older discussions. All of these are subsumed by Module#prepend
.
Method Combinators
One idea was the idea of method combinators from CLOS. This is basically a very lightweight version of a subset of Aspect-Oriented Programming.
Using syntax like
class Foo
def bar:before
# will always run before bar, when bar is called
end
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
you would be able to “hook into” the execution of the bar
method.
It is however not quite clear if and how you get access to bar
’s return value within bar:after
. Maybe we could (ab)use the super
keyword?
class Foo
def bar
'Hello'
end
end
class Foo
def bar:after
super + ' World'
end
end
Replacement
The before combinator is equivalent to prepend
ing a mixin with an overriding method that calls super
at the very end of the method. Likewise, the after combinator is equivalent to prepend
ing a mixin with an overriding method that calls super
at the very beginning of the method.
You can also do stuff before and after calling super
, you can call super
multiple times, and both retrieve and manipulate super
’s return value, making prepend
more powerful than method combinators.
class Foo
def bar:before
# will always run before bar, when bar is called
end
end
# is the same as
module BarBefore
def bar
# will always run before bar, when bar is called
super
end
end
class Foo
prepend BarBefore
end
and
class Foo
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
# is the same as
class BarAfter
def bar
original_return_value = super
# will always run after bar, when bar is called
# has access to and can change bar’s return value
end
end
class Foo
prepend BarAfter
end
old
keyword
This idea adds a new keyword similar to super
, which allows you to call the overwritten method the same way super
lets you call the overridden method:
class Foo
def bar
'Hello'
end
end
class Foo
def bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
The main problem with this is that it is backwards incompatible: if you have method called old
, you will no longer be able to call it!
Replacement
super
in an overriding method in a prepend
ed mixin is essentially the same as old
in this proposal.
redef
keyword
Similar to above, but instead of adding a new keyword for calling the overwritten method and leaving def
alone, we add a new keyword for redefining methods. This is backwards compatible, since the syntax currently is illegal anyway:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
Instead of adding two new keywords, we could also redefine the meaning of super
inside redef
:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
super + ' World'
end
end
Foo.new.bar # => 'Hello World'
Replacement
redef
ining a method is equivalent to overriding the method in a prepend
ed mixin. super
in the overriding method behaves like super
or old
in this proposal.
Decorating a method in Ruby
Here's a simple example of how to wrap methods with a validator:
class Foo
def foo(a, b, c)
p a, b, c
end
def bar(a, b)
p a, b
end
validate(:foo, :bar) {|*args, &blk| args.reduce(:+) == 6 }
end
The Module#validate
method takes a list of method names, and a block with the validation logic for those methods.
foo = Foo.new
foo.foo(1, 2, 3)
# 1
# 2
# 3
foo.bar(2, 4)
# 2
# 4
foo.foo(2, 3, 4)
# [2, 3, 4] (Validator::ValidationError)
foo.bar(2, 3)
# [2, 3] (Validator::ValidationError)
As you can see, the validator rejected the argument list in the last two calls because they didn't pass the condition in the block.
This is the "magic" which makes it all happen, which isn't actually that magic. We generate a module
which overrides the methods we want to validate with a version that raise
s an exception if the validation fails and then simply calls super
. Then we prepend
that module to the class/module that we are currently in, i.e. the one that the call to the validate
method is in. And that's it, basically.
I chose to also be a good Ruby citizen and wrap the whole thing in a Refinement, so you need to say
using Validator
to actually activate it.
module Validator
class ValidationError < ArgumentError; end
refine Module do
def validate(*methods, &validator)
prepend(Module.new do
methods.each do |method|
define_method(method) do |*args, &blk|
raise ValidationError, args.inspect unless yield *args
super(*args, &blk)
end
end
end)
end
end
end
Get included module name in module's method
I've never had to dynamically define module
extension methods before, it's unusually difficult to manage on a class
but you can always manage this using an intermediate module to help package and import the methods wherever you want:
module Helper
def self.extended(base)
base_name = base.to_s
extension = Module.new
extension.send(:define_method, :module_name) do
base_name
end
base.send(:extend, extension)
end
end
module A
extend Helper
end
module B
extend Helper
end
A.module_name
# => "A"
B.module_name
# => "B"
This is probably a lot less messy than defining module instance variables. Closures, in practice, tend to be a lot cleaner.
How do I properly use the Ruby DelegateClass to wrap YAML::Store?
To go over some of your questions regarding delegation:
- Forwardable:
This module when extended allows you to specify specific methods that should be delegated to a designated Object (most often an instance variable) Example:
require 'forwardable'
class A
attr_reader :obj
extend Forwardable
def_delegator :@obj, :<<
def initialize(val)
@obj = val
end
end
a = A.new([])
a << 1
#=> [1]
a.obj
#=> [1]
Delegator: Inheriting from this class allows methods to be delegated to an Object passed via
new
. This Object is internalized upon instantiation using the__setobj__
method and calls are forwarded viamethod_missing
; however the caveat here is that it uses 2 methods that are not defined by default(__setobj__
and__getobj__
) and you would need to define them in the inheriting classSimpleDelegator: Inherits from
Delegator
and shares its personality in most regards; however it predefines the 2 methods previously discussed. Generally inheriting fromSimpleDelegator
is preferred over inheriting directly from theDelegator
class for its ease of use.DelegateClass: Is similar to
SimpleDelegator
however it creates a new anonymous class which defines all the instance methods of the class passed in as an argument and then your inheriting class inherits from this anonymous class directly which allows method via inheritance rather than using method_missing for delegation. e.g.
class A < Delegator;end
class B < DelegateClass(String);end
A.ancestors
#=> [A, Delegator, #<Module:0x00007fffcc1cc9c8>, BasicObject]
B.ancestors
#=> [B, #<Class:0x00007fffcc5603c8>, Delegator, #<Module:0x00007fffcc1cc9c8>, BasicObject]
A.instance_methods - Object.instance_methods
#=> [:__getobj__, :__setobj__, :method_missing, :marshal_dump, :marshal_load]
B.instance_methods - Object.instance_methods
#=> Array of all the public the instance methods of String plus the above
This is generally preferable when you are expecting the class to be instantiated with a specific type of Object because the Module injection avoids the full inheritance chain traversal that comes in to play with method_missing
. This does not mean that you cannot instantiate this class with another object (however if you do and that object defines methods not defined in the class argument passed to DelegateClass
it will fall back to the default method_missing
behavior)
Now to your Code
Your first error is the call to super
. The Delegator
expects 1 argument which an instance of the Object
being delegated to (YAML::Store
in your case) however you have defined 2 arguments (neither of which represents the object you wish to delegate to) and when you call super
both these arguments are forwarded on, thus the error.
Removing thread_safe
works because you now only have a single argument but your delegated object in this case is actually the String "store.yml"
For Example the following modification should work (Similar to the example provided in the Source Code
module ExampleDelegator
class MultiWriter < DelegateClass(YAML::Store)
attr_reader :store
def initialize file_name="store.yml", thread_safe=true
@store = YAML::Store.new(file_name,thread_safe)
super(@store)
end
end
end
Your second issue is that you are calling write
on the CollaboratorWithData
object which does not define this method and is not otherwise delegating.
While I am not 100% sure what your intent is here as there are some other oddities like attr_accessor
in the Module body which is then being included in the global space and as it stands I do not see a true reason for a Delegator
becuase you could just use the Object directly via the yaml_store
instance variable being set to an instance of YAML::Store
(as you already mentioned) but you can rewrite your code as follows to use delegation if you wish
require 'delegate'
require 'yaml/store'
require 'forwardable'
module ExampleDelegator
class CollaboratorWithData
extend Forwardable
def_delegators :@yaml_store, :read, :write
attr_reader :yaml_store
attr_accessor :data
def initialize(file_name="store.yml", thread_safe=true)
@yaml_store = MultiWriter.new(YAML::Store.new(file_name,thread_safe))
@data = {}
end
def some_data
{a: 1, b:2, c: [1, 2, 3]}
end
end
class MultiWriter < DelegateClass(YAML::Store)
def write **kwargs
transaction { kwargs.each { |k, v| @store[k] = v } }
end
def read *keys
transaction(read_only=true) { keys.map { |k| @store[k] } }
end
end
end
How to execute a method only once in Ruby? Are there static variables?
There is an idiom in ruby: x ||= y
.
def something
@something ||= calculate_something
end
private
def calculate_something
# some long process
end
But there is a problem with this idiom if your 'long running utility' may return a false value (false or nil), since the ||=
operator will still cause the right side to be evaluated.
If you expect false values then use an additional variable, in a way similar to the proposed by DigitalRoss:
def something
return @something if @something_calculated
@something = calculate_something
@something_calculated = true
return @something
end
Don't try to save a line of code by setting the @something_calculated variable first, an then running calculate_something. If your calculate function raises an exception your function will always return nil and will never call the calculate again.
More generally, in Ruby you use instance variables. Note however, that they are visible in all the methods of given object - they are not local to the method.
If you need a variable shared by all instances, define the method in the class object, and in every instance call self.class.something
class User
def self.something
@something ||= calculate_something
end
def self.calculate_something
# ....
end
def something
self.class.something
end
end
Related Topics
Sprockets::Circulardependencyerror in Store#Index
How to Use Watir::Waiter::Wait_Until to Force Chrome to Wait
How to Validate Members of an Array Field
Jekyll - Generating JSON Files Alongside the HTML Files
How to Use Correct Ruby in Vim? How to Modify $Path in Vim
Dynamically Creating a Multi-Dimensional Hash in Ruby
How to Sort in Ruby/Rails on Two Fields
Hash Ordering Preserved Between Iterations If Not Modified
Sidekiq Not Deallocating Memory After Workers Have Finished
How to Backreference in Ruby Regular Expression (Regex) with Gsub When I Use Grouping
How to Get My MAChine's Ip Address from Ruby Without Leveraging from Other Ip Address
How to Reverse Ruby's Include Function
How to Use Xmlns Declarations with Xpath in Nokogiri
What Is the %W "Thing" in Ruby
Factorygirl Association Model Trouble: "Systemstackerror: Stack Level Too Deep"
Are Rails Controllers Multithreaded? Thread.Exclusive in Controllers