I'm deeping into ruby metaprogramming and have next question. Example:
module ExampleAliaser
def do_example_alias(prefix=:origin)
class_eval <<-EOS
class << self
alias_method :#{prefix}_example, :example
def example
puts "in aliase will call :#{prefix}_example"
#{prefix}_example
end
end
EOS
end
end
class Example1
def self.example
puts "Example"
end
end
Example1.extend(ExampleAliaser)
class Example1
do_example_alias(:origin)
end
class Example2 < Example1
do_example_alias(:origin)
end
Example1.example
in aliase will call :origin_example
Example
=> nil
Example2.example
in aliase will call :origin_example
in aliase will call :origin_example
in aliase will call :origin_example
SystemStackError: stack level too deep
from /Users/igorfedoronchuk/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/irb/workspace.rb:80
Maybe IRB bug!!
So when mixin used 2 times it causes error. What is the best way to fix such things? How to determine that mixing exists and remove it before new mixing
Follow the definition of methods to see why this is happening.
You first define Example1::example
in the class definition of Example1
. It writes a string to the console.
Then you extend ExampleAliaser
. When you call Example1::do_example_alias
, you then alias the method example
to origin_example
and redefine the method example
to write a different string to the console and call origin_example
.
Then you define the class Example2
to inherit from Example1
, which now has two methods defined on it: origin_example
and example
. When you call Example2::do_example_alias
, you alias the method example
to origin_example
. But remember that example
was already redefined to call origin_example
. So effectively, Example2::example
will call itself until you run out of room on the stack.
If you want to avoid double-aliasing, you could include some kind of guard in do_example_alias
:
def do_example_alias(prefix = :origin)
unless methods.include?("#{prefix}_example")
# do the aliasing
end
end
You can also undef :method_name
in subclasses to remove methods that you no longer want defined.