Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

define_method: How to dynamically create methods with arguments

I want to create a bunch of methods for a find_by feature. I don't want to write the same thing over and over again so I want to use metaprogramming.

Say I want to create a method for finding by name, accepting the name as an argument. How would I do it? I've used define_method in the past but I didn't have any arguments for the method to take. Here's my (bad) approach

["name", "brand"].each do |attribute|     define_method("self.find_by_#{attribute}") do |attr_|       all.each do |prod|         return prod if prod.attr_ == attr_       end     end   end 

Any thoughts? Thanks in advance.

like image 428
Kostas Andrianos Avatar asked Jul 06 '16 20:07

Kostas Andrianos


People also ask

How do you define a method dynamically in Ruby?

define_method is a method defined in Module class which you can use to create methods dynamically. To use define_method , you call it with the name of the new method and a block where the parameters of the block become the parameters of the new method.

What is MetaProgramming in Ruby on Rails?

Metaprogramming is a technique in which code operates on code rather than on data. It can be used to write programs that write code dynamically at run time. MetaProgramming gives Ruby the ability to open and modify classes, create methods on the fly and much more.

What is method in Ruby?

A method in Ruby is a set of expressions that returns a value. With methods, one can organize their code into subroutines that can be easily invoked from other areas of their program. Other languages sometimes refer to this as a function. A method may be defined as a part of a class or separately.


2 Answers

If I understand your question correctly, you want something like this:

class Product   class << self     [:name, :brand].each do |attribute|       define_method :"find_by_#{attribute}" do |value|         all.find {|prod| prod.public_send(attribute) == value }       end     end   end end 

(I'm assuming that the all method returns an Enumerable.)

The above is more-or-less equivalent to defining two class methods like this:

class Product   def self.find_by_name(value)     all.find {|prod| prod.name == value }   end    def self.find_by_brand(value)     all.find {|prod| prod.brand == value }   end end 
like image 188
Jordan Running Avatar answered Sep 19 '22 08:09

Jordan Running


It if you read the examples here http://apidock.com/ruby/Module/define_method you will find this one:

define_method(:my_method) do |foo, bar| # or even |*args|   # do something end 

is the same as

def my_method(foo, bar)    # do something end 
like image 32
Albin Avatar answered Sep 22 '22 08:09

Albin