Access a methods content without executing it in Ruby - ruby-on-rails

This question has been keeping me busy for some time now, so I hope someone has an idea on how to tackle this.
Lets take a simple Class with a method (simplified without an initialize method):
class MyClass
def my_method
page.search('//p')
end
end
Now, is there a way to retrieve the content of my_method without executing it? I am looking to get the code that it will run when executed:
"page.search('//p')"
Is there a way to do that in Ruby?

It's possible with pry gem, provided my_method source is saved in some file. pry adds source method to Method class:
require 'pry'
method = MyClass.instance_method(:my_method)
method.source
# => " def my_method\n page.search('//p')\n end"

Related

Safe and best way to monkey patch a rails gem

I have tried, seriously. Many questions out there but many developers say "It dont work for me"; I'm one of them -- said to say.
I was reading up on the best way to monkey-patch a rails gem. I've found few but decided to use this method.
I want to monkey-patch the xeroizer gem but rather the invoice.rb model.
# lib/xeroizer/invoice/invoice_url.rb
module Xeroizer
module Invoice
module InvoiceUrl
def invoice_url(id)
#application.http_get(#application.client, "#{url}/#{CGI.escape(id)}/OnlineInvoice")
end
end
end
end
Going with the "this method" link, I assume this should work, but it dosent.
Controller:
include Xeroizer::Invoice::InvoiceUrl
# Invoice.include Xeroizer::Invoice::InvoiceUrl
def some_method
# #xero is in a private method. It's here for short demonstration
#xero = Xeroizer::PrivateApplication.new("MY_CONSUMER_KEY", "MY_SECRET_KEY", "#{Rails.root}/privatekey.pem")
Rails.logger = #xero.Invoice.invoice_url("ad61ea97-b9e9-4a1e-b754-7c19e62f8cd7")
end
undefined method `invoice_url' for Xeroizer::Record::InvoiceModel
How do you add custom methods to a rails gem's class?
Assuming you are trying to monkey-patch Xeroizer::Record::InvoiceModel with Xeroizer::Invoice::InvoiceUrl, you might just do the following right after the first mention of Xeroizer::Record::InvoiceModel (to make Rails to autoload it):
Xeroizer::Record::InvoiceModel.prepend Xeroizer::Invoice::InvoiceUrl
This will override original invoice_url method. The original one still might be called from a prepended using super.

how to mixin gem-modules in ruby-on-rails model

I am building a gem in which i have a module OtpGenerator. inside this module i have methods like generate_otp, verify_otp etc. This is just a begining for me and its very simple gem only to generate and verify and save and send, nothing else. Now anyone who uses this gem will have to include this module in their model. for e.g. there is a user model. now what i want is first i will create a instance
user = User.new(params[:user])
now i need to do the operation user.generate_otp, this will assign otp related things in the activerecord instance.
after that user.save, which is also fine.
But i also want a function generate_otp!, which will do all task like generates otp, than save it and sends it. My problem is that i am not getting how to achieve this functionality.
Note: I am very new to ruby. and really getting confused with mixins.
here is my code for otp.rb file
require 'securerandom'
module OtpGenerator
def generate_otp
#do something here
end
def verify_otp(otp)
#do something here
end
def regenerate_otp
#do something here
end
def matches?(generated, otp)
#do something here
end
def expired?(otp_expiry_time)
#do something here
end
end
This code is still in development, i just want to know that how to implement generate_otp! function, which will do all three operation,i.e,
(1) generates otp(user.generate_otp)
(2) saves otp(user.save)
(3) sends otp (i have created the send function, so thats not a problem.)
If this is a mixin in your model, then your model should also have access to it. Here is what I mean:
class User
include OtpGenerator
end
module OtpGenerator
...
def generate_otp!
generate_otp
save
send_generated_otp
end
end
When you call User.find(45).generate_otp!
That would work because of the way inheritances work in Ruby. Once the module is included within a class, it inherits all the methods of the module and the module has access to the context of the included class.
Hope that answers your question

How to use ActionView::Helpers::NumberHelpers "number_with_delimeter" in script

I'm writing a script for my rails application and I'm trying to format the numbers with delimeters so they're easier to read. But I have a problem in calling the number_with_delimeter method from ActionView::Helpers::NumberHelpers
I tried
class MyClass < ActiveRecord::base
extend ActiveView::Helpers::NumberHelper
def self.run
puts "#{number_with_delimeter(1234567)}"
end
end
MyClass.run
but it just doesn't work. I always get undefined method errors. I tried it with include instead of extend and some other variations. None of them worked. I don't know how to proceed.
Is there any way to call this method in a script?
*Note: * I call the script with rails r script/my_script.rb
An elegant solution consists in delegation:
def self.run
puts "#{helper.number_with_delimiter(1234567)}"
end
def self.helper
Helper.instance
end
class Helper
include Singleton
include ActionView::Helpers::NumberHelper
end
Sidenotes:
including modules overloads your class
including the helpers didn't help because you were working at the class level.
formatting should not be model's job, you should extract this kind of logic within presenters.

NameError: undefined local variable or method `desired_preferences'

I have created a module with a method
module Adding_preferences
def desired_preferences
#preference = %w(motabilitySpecialist newCars bodyshop filter8 filter7).each do |selection|
#browser.label(:for, selection ).click
end
end
end
I have included this module into a class:
class Pages
include Adding_preferences
attr_accessor :browser, :preference
def initialize
#browser = Watir::Browser.new :ff
end
end
World do
Pages.new
end
I am calling this method in a Cucumber scenario
When /^I select a desired preference$/ do
desired_preferences
end
But at runtime I receive an error, "NameError: undefined local variable or method `desired_preferences'". Where am i going wrong?
When you include a module to a class you can use this method in the instance methods of this class. You cant call the included method in a View that displays the data from the model that includes the module. For me it looks like you just dont use the desired_preferences method in an instance method.
Please show us the peace of code you try to call the method if this still doesnt help you out.
// The naming of the Module is not conventional. You should call it module AddingPreferences isntead ofmodule Adding_preferences and the file should be named adding_preferences.rb then try to include AddingPreferences
It's a good idea for you to spend some time getting more familiar with Ruby's Class/Module/Object/Method inheritance model, because the way you're structuring your code there is a little bit messy.
However, a simple thing to try (and I'm not going to guarantee that it will work flawlessly) is the following modifications:
Assign your instantiated Pages class to a class instance variable:
World do
#page = Pages.new
end
...and then use that instance variable in your step definition...
When /^I select a desired preference$/ do
#page.desired_preferences
end
I hope that helps!

How do I make a library function in a plugin that is accessible by everything in Rails 3?

I would like to create a plugin library function that can be used anywhere in my rails app. I'm sure this must be very easy to do but I can not seem to find examples on how to do this. All the tutorials I've found so far show how to only extend classes or make methods that only work inside model or controllers.
Even RailsGuide does not seem to show how to do this.
Hey thanks for the help!
The simplest way to do this is to create a module or class method and then call that. For example:
module MySpecialModule
def self.do_something
puts 'hello world'
end
end
Then, the following can be called from anywhere:
MySpecialModule.do_something
If you are really intent on having your do_something method be called from every single object in Ruby, then you can extend the object class like this:
class Object
def do_something
puts 'hello world'
end
end
class K
end
K.new.do_something
=> hello world
You can use this same method to extend any base class, for example ActiveRecord::Base.

Resources