I'm dynamically defining a method in a module, and I'd like to check that once the method is bound to a class instance that the body of the method is what I'm expecting. Is there a way to output (as text) of the body of a method?
Module 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 being mixed with:
class VendorOrdersController < ApplicationController
# GET /vendor_orders
# GET /vendor_orders.xml
require 'controller_mixins'
include ControllerMixin
<rest of class>
So I'd like to see the implementation of the mixin when applied to VendorOrdersController
probably via script/console
for convenience.
UPDATE: Per @~/ I saved the string to a variable and puts
'd it. That worked perfectly. Which brought to light an error in my code (the reason I wanted to see the code in the first place). Code below is much better, and works as expected.
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
No, you cannot get the source code behind a method.
The best you can do is get the Method
object that represents the method using Object#method
. For example:
m = VendorOrdersController.method(:search_by_vendor)
But you'll find that there's not much more than a Method#name
, Method#arity
, Method#source_location
, etc.
In your case however, why not simply store the string in a variable, print it, before using instance_eval
?
Regardless, your instance_eval
will be executed at the moment of module declaration. You probably want to wrap it in an included
callback to have it executed at the moment of inclusion.
module ControllerMixin
def self.included(mod)
mod.instance_eval([...])
end
end
The best way to ensure you get your intended output as a result ... is to write a test.
Also - i don't approve of using instance_eval like that. If you MUST metaprogram like that, use define_method
, or you could probably get away without doing any of that by passing a parameter from the routes, sure, it's a little more typing, but that much metaprogramming is just icky.
Couldn't you assign the string to a variable before instance_eval runs and output it to the console?
As your string defines the whole method you essentially already have the source code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With