Я динамично определяю метод в модуле, и я хотел бы проверить, что, после того как метод связывается с экземпляром класса, что тело метода - то, что я ожидаю. Существует ли способ произвести (как текст) тела метода?
Модуль controller_mixins.rb
:
module ControllerMixin
instance_eval "def search_by_vendor (*args) \n" \
" @#{self.class.name.sub(/Controller/, '').tableize} = #{self.class.name.sub(/Controller/, '')}.find_all_by_vendor_id(params[:vendor_id]) \n"\
"respond_to do |format| \n" \
" format.html { render :template=>'/#{self.class.name.sub(/Controller/, '').tableize}/index', :layout=>'vendor_info'} \n" \
" format.xml { render :xml => @#{self.class.name.sub(/Controller/, '').tableize} } \n" \
"end \n"\
"end \n"
end
класс, смешиваемый с:
class VendorOrdersController < ApplicationController
# GET /vendor_orders
# GET /vendor_orders.xml
require 'controller_mixins'
include ControllerMixin
<rest of class>
Таким образом, я хотел бы видеть реализацию смешивания при применении к VendorOrdersController
вероятно, через script/console
для удобства.
ОБНОВЛЕНИЕ: На ~ / я сохранил строку к переменной и puts
'd это. Это работало отлично. Который обнаружил ошибку в моем коде (причина, я хотел видеть код во-первых). Код ниже намного лучше, и работает как ожидалось.
module ControllerMixin
def self.included(mod)
method_body = "def search_by_vendor \n" \
" @#{mod.name.sub(/Controller/, '').tableize} = #{mod.name.sub(/Controller/, '')}.find_all_by_vendor_id(params[:vendor_id]) \n"\
"respond_to do |format| \n" \
" format.html { render :template=>'/#{mod.name.sub(/Controller/, '').tableize}/index', :layout=>'vendor_info'} \n" \
" format.xml { render :xml => @#{mod.name.sub(/Controller/, '').tableize} } \n" \
"end \n"\
"end \n"
puts method_body
mod.class_eval(method_body)
end
end
Нет, вы не можете получить исходный код метода.
Лучшее, что вы можете сделать, - это получить объект Method
, который представляет метод, использующий Object # method
. Например:
m = VendorOrdersController.method(:search_by_vendor)
Но вы обнаружите, что это не что иное, как Method # name
, Method # arity
, Method # source_location
и т. Д.
В вашем случае, однако, почему бы просто не сохранить строку в переменной и не распечатать ее перед использованием instance_eval
?
Тем не менее, ваш instance_eval
будет выполнен в данный момент объявления модуля. Вы, вероятно, захотите заключить его в включенный обратный вызов
, чтобы он выполнялся в момент включения.
module ControllerMixin
def self.included(mod)
mod.instance_eval([...])
end
end
Лучший способ убедиться, что в результате вы получите желаемый результат ... - это написать тест.
Также - я не одобряю использование instance_eval таким образом. Если вы ДОЛЖНЫ использовать такую метапрограмму, используйте define_method
, или вы, вероятно, могли бы обойтись, не делая ничего из этого, передав параметр из маршрутов, конечно, это немного больше типизации, но такое количество метапрограммирования просто неприятно .
Не могли бы вы присвоить строку переменной до запуска instance_eval и вывода ее на консоль?
Поскольку ваша строка определяет весь метод, у вас, по сути, уже есть исходный код.