How to decorate a method in Ruby without alias_method_chain

We all know that if the target class consists of modules, you can just call super in a new module. But what if this is a regular method in a class?

 class Logger def message(msg) puts msg end end 

Let's say Logger is a class that I cannot change (for example, it is in stone). And I want Logger to put the line "================" before each message. How to do it in beauty ? Inheritance? Aggregation? How?

+4
source share
4 answers

I would either do a subclassification (in one @iain answer), or include a custom module in my own instances:

 module LoggerLiner def message(*args) puts "="*15 super end end log = Logger.new(STDOUT) log.extend(LoggerLiner) 
+2
source

You can save the original method as an unbound object object, instead of storing it in an alias.

Then you can use define_method with a block. The block will capture the unbound method_object in closure, allowing you to use it in the new method without polluting your module / class.

The only drawback is that you probably cannot define a method that gives or receives a block in this way:

 module Mod unbound_method = instance_method(:original_method) define_method :original_method do |*args| #do something before #call the original method unbound_method.bind(self).call(*args) #do something after end end 
+3
source

This may not be what you mean by “beauty”, but probably the easiest way is in your code somewhere:

 class Logger alias message old_message def message(msg) puts "================" old_message(msg) end end 
+2
source

You can inherit from the registrar and use the namespace to use it:

 class LinedLogger < Logger def message(*) puts "=" * 15 super end end 

And when you want to use it:

 class Post Logger = LinedLogger end 

Only in the Post namespace will you get LinedLogger instead of Logger . This is a good way to limit your patches. However, it will not work globally.

+2
source

All Articles