2

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

Fivell
  • 11,829
  • 3
  • 61
  • 99

1 Answers1

1

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.

Brandan
  • 14,735
  • 3
  • 56
  • 71
  • Yes , I understand this, my qustion is about how to change module so it can find out it was extended earlier and redefine aliases again – Fivell Feb 24 '12 at 15:43
  • I mean how to reselve such conflicts, if module was extended earlier. Also if Example2 will call do_example_alias(:other_prefix), how to remove previously defined aliases? – Fivell Feb 24 '12 at 15:46
  • Sorry, I didn't even see your last paragraph after the code block. I'll update my answer. – Brandan Feb 24 '12 at 16:01