2009-09-03 3 views
2

Я пытаюсь написать плагин, который псевдонимы некоторые методы ActiveRecord в следующей манере:методы Aliasing ActiveRecord внутри плагина

class Foo < ActiveRecord::Base 
    include MyOwnPlugin 
    acts_as_my_own_plugin :methods => [:bar] 

    def bar 
    puts 'do something' 
    end 
end 

Внутри плагина:

module MyOwnPlugin 
    def self.included(base)  
    base.class_eval do 
     extend ClassMethods 
    end 
    end 
    module ClassMethods 
    def acts_as_my_own_plugin(options) 
     options[:methods].each do |m| 
     self.class_eval <<-END 
      alias_method :origin_#{m}, :#{m} 
     END 
     end 
    end 
    end 
end 

Этот подход не будет потому что, когда запускается #acts_as_my_own_plugin, Foo # bar еще не определен, поскольку он не был запущен.

положить acts_as_my_own_plugin: методы => [: бар] ПОСЛЕ бар объявление функции будет работать. Однако это некрасиво.

Я хочу, чтобы action_as_my_own_plugin помещался поверх определения класса, как это делают большинство плагинов.

Есть ли альтернативный подход для удовлетворения этого состояния?

+0

Где вы можете добавить свой модуль в ActiveRecord :: Base? Не могли бы вы также опубликовать этот код? Спасибо. –

+0

Извините за то, что вы ленивы, lol ... Я изменил свое сообщение, чтобы задать ваши вопросы –

ответ

5

Всегда помните: в Ruby есть обратный вызов почти для всего.

Попробуйте следующее:

module MyOwnPlugin 
    def self.included(base) 
    base.extend(ClassMethods) 
    end 

    module ClassMethods 
    # gets called from within the models 
    def acts_as_my_own_plugin(options) 
     # store the list of methods in a class variable and symbolize them 
     @@methods = [] 
     options[:methods].each { |method| @@methods << method.to_sym } 
    end 

    # callback method. gets called by ruby if a new method is added. 
    def method_added(name_of_method) 
     if @@methods.include?(name_of_method) 
     # delete the current method from our @@methods array 
     # in order to avoid infinite loops 
     @@methods.delete(name_of_method) 
     #puts "DEBUG: #{name_of_method.to_s} has been added!" 

     # code from your original plugin 
     self.class_eval <<-END 
      alias_method :origin_#{name_of_method}, :#{name_of_method} 
      def #{name_of_method} 
      puts "Called #{name_of_method}" 
      origin_#{name_of_method} 
      end 
     END 

     end 
    end 
    end 
end 

# include the plugin module in ActiveRecord::Base 
# in order to make acts_as_my_own_plugin available in all models 
ActiveRecord::Base.class_eval do 
    include MyOwnPlugin 
end 

# just call acts_as_my_own_plugin and define your methods afterwards 
class Foo < ActiveRecord::Base 
    acts_as_my_own_plugin :methods => [:bar] 

    def bar 
    puts 'do something' 
    end 
end 

Я надеюсь, что это полезно. Сумасшедшие вещи, которые вы можете сделать с Ruby, - это просто soooo cool;)

Если вы хотите разрешить методы, которые должны быть определены до И после вызова acts_as_my_own_plugin, вам нужно снова изменить код, чтобы это разрешить. Однако сложная часть выполнена.

Отказ от ответственности: Это было протестировано с помощью Ruby 1.8.7. Может не работать с Ruby 1.9. *.

+0

Awesomeness! Я не знал, что существует обратный вызов #method_added! –

+0

Итак, это работает для вас? –

Смежные вопросы