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.
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.
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.
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.
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
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
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