objetos metodos manejo lista instanciar importar herencia ejemplos clases ruby parameters methods

manejo - metodos en ruby



Pasar un método como parámetro en Ruby (8)

La forma normal de Ruby de hacer esto es usar un bloque.

Entonces sería algo así como:

def weightedknn( data, vec1, k = 5 ) foo weight = yield( dist ) foo end

Y usado como:

weightenknn( data, vec1 ) { |dist| gaussian( dist ) }

Este patrón se usa ampliamente en Ruby.

Estoy tratando de perder el tiempo con Ruby. Por lo tanto, intento implementar los algoritmos (dados en Python) del libro "Programming Collective Intelligence" Ruby.

En el capítulo 8, el autor pasa un método a como parámetro. Esto parece funcionar en Python pero no en Ruby.

Tengo aquí el método

def gaussian(dist, sigma=10.0) foo end

y quiero llamar esto con otro método

def weightedknn(data, vec1, k = 5, weightf = gaussian) foo weight = weightf(dist) foo end

Todo lo que tengo es un error

ArgumentError: wrong number of arguments (0 for 1)


Los comentarios que se refieren a bloques y Proc son correctos porque son más comunes en Ruby. Pero puede pasar un método si lo desea. Llame al method para obtener el método y .call para llamarlo:

def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) ) ... weight = weightf.call( dist ) ... end


Puede pasar un método como parámetro con la forma de method(:function) . A continuación, un ejemplo muy simple:

def double(a) return a * 2 end => nil def method_with_function_as_param( callback, number) callback.call(number) end => nil method_with_function_as_param( method(:double) , 10 ) => 20



Quieres un objeto de proceso:

gaussian = Proc.new do |dist, *args| sigma = args.first || 10.0 ... end def weightedknn(data, vec1, k = 5, weightf = gaussian) ... weight = weightf.call(dist) ... end

Solo tenga en cuenta que no puede establecer un argumento predeterminado en una declaración de bloque como esa. Entonces necesita usar un splat y configurar el predeterminado en el código de proc mismo.

O bien, dependiendo del alcance de todo esto, puede ser más fácil pasar un nombre de método en su lugar.

def weightedknn(data, vec1, k = 5, weightf = :gaussian) ... weight = self.send(weightf) ... end

En este caso, solo está llamando a un método que está definido en un objeto en lugar de pasar un fragmento completo de código. Dependiendo de cómo se estructura esto, puede ser necesario reemplazar self.send con object_that_has_the_these_math_methods.send

Por último, pero no menos importante, puedes colgar un bloque del método.

def weightedknn(data, vec1, k = 5) ... weight = if block_given? yield(dist) else gaussian.call(dist) end end ... end weightedknn(foo, bar) do |dist| # square the dist dist * dist end

Pero parece que quisieras más fragmentos reutilizables de código aquí.


Tienes que llamar al método "call" del objeto de función:

weight = weightf.call( dist )

EDITAR: como se explica en los comentarios, este enfoque es incorrecto. Funcionaría si está utilizando Procs en lugar de funciones normales.


Yo recomendaría utilizar el signo & para tener acceso a los bloques con nombre dentro de una función. Siguiendo las recomendaciones dadas en este artículo , puedes escribir algo como esto (esta es una chatarra real de mi programa de trabajo):

# Returns a valid hash for html form select element, combined of all entities # for the given +model+, where only id and name attributes are taken as # values and keys correspondingly. Provide block returning boolean if you # need to select only specific entities. # # * *Args* : # - +model+ -> ORM interface for specific entities'' # - +&cond+ -> block {|x| boolean}, filtering entities upon iterations # * *Returns* : # - hash of {entity.id => entity.name} # def make_select_list( model, &cond ) cond ||= proc { true } # cond defaults to proc { true } # Entities filtered by cond, followed by filtration by (id, name) model.all.map do |x| cond.( x ) ? { x.id => x.name } : {} end.reduce Hash.new do |memo, e| memo.merge( e ) end end

Afterwerds, puede llamar a esta función de esta manera:

@contests = make_select_list Contest do |contest| logged_admin? or contest.organizer == @current_user end

Si no necesita filtrar su selección, simplemente omita el bloque:

@categories = make_select_list( Category ) # selects all categories

Tanto por el poder de los bloques de Ruby.


también puede usar "eval" y pasar el método como un argumento de cadena, y luego simplemente evaluarlo en el otro método.