Domanda

Sto profondendo nel metaprogrammazione di Ruby e ho la prossima domanda. Esempio:

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!!

Quindi, quando la mixin usata 2 volte causa l'errore. Qual è il modo migliore per sistemare tali cose? Come determinare che esiste la miscelazione e rimuoverlo prima di una nuova miscelazione

È stato utile?

Soluzione

Segui la definizione di metodi per capire perché questo sta accadendo.

Per prima cosa definisci Example1::example Nella definizione di classe di Example1. Scrive una stringa alla console.

Quindi estendi ExampleAliaser. Quando chiami Example1::do_example_alias, quindi alias il metodo example a origin_example e ridefinire il metodo example Per scrivere una stringa diversa alla console e chiama origin_example.

Quindi definisci la classe Example2 ereditare da Example1, che ora ha due metodi definiti su di esso: origin_example e example. Quando chiami Example2::do_example_alias, alias il metodo example a origin_example. Ma ricordalo example era già ridefinito per chiamare origin_example. Così efficacemente, Example2::example Si chiamerà finché non esaurirai lo spazio sullo stack.


Se vuoi evitare il doppio aliasing, potresti includere una sorta di guardia do_example_alias:

def do_example_alias(prefix = :origin)
  unless methods.include?("#{prefix}_example")
    # do the aliasing
  end
end

Puoi anche undef :method_name Nelle sottoclassi per rimuovere i metodi che non si desidera più definire.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top