Сделайте так, чтобы все подклассы методов ActiveRecord :: Base произносили свое имя - PullRequest
1 голос
/ 10 марта 2010

В целях удаления жира я хотел бы регистрироваться всякий раз, когда вызывается метод из одной из моих моделей AR.

Я могу получить все эти классы примерно так:

subclasses = [] ; ObjectSpace.each_object(Module) {|m| subclasses << m if m.ancestors.include? ActiveRecord::Base } ; subclasses.map(&:name)

Но тогда мне нужен список только методов, определенных в этих классах (методы экземпляра и класса), и способ добавить в них оператор logger.

Результат будет эквивалентен вставке этого в каждый метод

def foo
  logger.info "#{class.name} - #{__method__}"
  # ...
end

def self.foo
  logger.info  "#{name} - #{__method__}"
  # ...
end

Как я могу это сделать, не добавляя его в каждый метод?

Может быть, какая-то удивительная мета?

Ответы [ 5 ]

1 голос
/ 11 марта 2010

Для этого вы должны использовать шаблон аспектно-ориентированного программирования. В Ruby Aquarium gem предоставляет AOP DSL.

Создать каталог log_method_initializer.rb в config/initializers/.

require 'aquarium'
Aspect.new(:around, :calls_to => :all_methods, 
            :in_types => [ActiveRecord::Base] ) do |join_point, object, *args|

  log "Entering: #{join_point.target_type.name}##{join_point.method_name}" 

  result = join_point.proceed

  log "Leaving: #{join_point.target_type.name}##{join_point.method_name}" 

  result  
end

Все вызовы методов классов, унаследованных от ActiveRecord::Base, будут регистрироваться.

1 голос
/ 11 марта 2010

Если вам нужны только методы, определенные в классе, вы можете сделать это:

>> Project.instance_methods
=> ["const_get", "validates_associated", "before_destroy_callback_chain", "reset_mocha", "parent_name", "inspect", "slug_normalizer_block", "set_sequence_name", "require_library_or_gem", "method_exists?", "valid_keys_for_has_and_belongs_to_many_association=", "table_name=", "validate_find_options_without_friendly", "quoted_table_name" (another 100 or so methods)]

Только методы, определенные в вашем классе

>> Project.instance_methods(false)
=> ["featured_asset", "category_list", "before_save_associated_records_for_slugs", "asset_ids", "primary_asset", "friendly_id_options", "description", "description_plain"]
0 голосов
/ 24 февраля 2013

Для Аквариума кажется, что добавление method_options => :exclude_ancestor_methods делает свое дело. У меня была слишком большая проблема со стеком.

Источник http://andrzejonsoftware.blogspot.com/2011/08/tracing-aspect-for-rails-application.html

0 голосов
/ 10 марта 2010

Например, для вызова метода вы можете использовать этот шаблон прокси:

class BlankSlate
   instance_methods.each { |m| undef_method m unless m =~ /^__/ }
end

class MyProxy < BlankSlate
  def initialize(obj, &proc)
    @proc = proc
    @obj = obj
  end

  def method_missing(sym, *args, &block)
    @proc.call(@obj,sym, *args)
    @obj.__send__(sym, *args, &block)
  end
end

Пример:

cust = Customer.first
cust = MyProxy.new(cust) do |obj, method_name, *args|
  ActiveRecord::Base.logger.info  "#{obj.class}##{method_name}"
end

cust.city

# This will log:
# Customer#city

Это вдохновлено от: http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc

Вам нужно будет найти способ применить этот шаблон при создании объекта ActiveRecord :: Base.

0 голосов
/ 10 марта 2010

У вас есть

AR :: Base.instance_methods

и AR :: Base.class_eval "некоторая строка"

так что вы, вероятно, можете использовать их, чтобы поместить заголовок в каждый существующий метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...