ruby metaprogramming

ruby - define_method: Cómo crear dinámicamente métodos con argumentos



metaprogramming (3)

Quiero crear un montón de métodos para una característica find_by. No quiero escribir lo mismo una y otra vez, así que quiero usar metaprogramación.

Digamos que quiero crear un método para buscar por nombre, aceptando el nombre como un argumento. ¿Cómo lo haría? He usado define_method en el pasado, pero no tenía ningún argumento para tomar el método. Aquí está mi (mal) enfoque

["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

¿Alguna idea? Gracias por adelantado.


Cuando haces esto: define_method("self.find_by_#{attribute}")

Eso es incorrecto. El argumento para define_method es un símbolo con una sola palabra.

Déjame mostrarte un código correcto, espero que esto quede claro:

class MyClass < ActiveRecord::Base ["name", "brand"].each do |attribute| define_method(:"find_by_#{attribute}") do |attr_| first(attribute.to_sym => attr_) end end end

Esto producirá métodos de clase para find_by_brand y find_by_name .

Tenga en cuenta que si está buscando metaprogramación, este es un buen caso de uso para method_missing. Aquí hay un tutorial para usar method_missing para implementar la misma funcionalidad que busca ( find_by_<x> )


Si entiendo tu pregunta correctamente, quieres algo como esto:

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

(Supongo que el método all devuelve un Enumerable).

Lo anterior es más o menos equivalente a definir dos métodos de clase como este:

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


Si lees los ejemplos aquí http://apidock.com/ruby/Module/define_method , encontrarás este:

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

es lo mismo que

def my_method(foo, bar) # do something end