sirve que programacion para lenguaje funcion estructuras def contadores comandos codigo asignacion ruby dynamic metaprogramming

que - funcion ruby



¿Cómo llamar a los métodos de forma dinámica en función de su nombre? (5)

Existen múltiples formas de lograr un despacho dinámico en Ruby, cada una con sus propias ventajas y desventajas. Se debe tener cuidado de seleccionar el método más apropiado para la situación.

La siguiente tabla desglosa algunas de las técnicas más comunes:

+---------------+-----------------+-----------------+------------+------------+ | Method | Arbitrary Code? | Access Private? | Dangerous? | Fastest On | +---------------+-----------------+-----------------+------------+------------+ | eval | Yes | No | Yes | TBD | | instance_eval | Yes | No | Yes | TBD | | send | No | Yes | Yes | TBD | | public_send | No | No | Yes | TBD | | method | No | Yes | Yes | TBD | +---------------+-----------------+-----------------+------------+------------+

Código Arbitrario

Algunas técnicas están limitadas a los métodos de llamadas solamente, mientras que otras pueden ejecutar básicamente cualquier cosa. Los métodos que permiten la ejecución de código arbitrario deben usarse con extrema precaución, si no se evitan por completo .

Acceso privado

Algunas técnicas se limitan a llamar solo a los métodos públicos, mientras que otras pueden llamar a métodos públicos y privados. Idealmente, debe esforzarse por utilizar el método con la menor cantidad de visibilidad que cumpla con sus requisitos.

Nota : Si una técnica puede ejecutar código arbitrario, puede usarse fácilmente para acceder a métodos privados a los que de otro modo no podría tener acceso.

Peligroso

El hecho de que una técnica no pueda ejecutar código arbitrario o llamar a un método privado no significa que sea seguro, especialmente si está utilizando valores proporcionados por el usuario. Eliminar es un método público.

Lo más rápido posible

Algunas de estas técnicas pueden ser más efectivas que otras, según tu versión de Ruby. Puntos de referencia a seguir ....

Ejemplos

class MyClass def foo(*args); end private def bar(*args); end end obj = MyClass.new

eval

eval(''obj.foo'') #=> nil eval(''obj.bar'') #=> NoMethodError: private method `bar'' called # With arguments: eval(''obj.foo(:arg1, :arg2)'') #=> nil eval(''obj.bar(:arg1, :arg2)'') #=> NoMethodError: private method `bar'' called

instance_eval

obj.instance_eval(''foo'') #=> nil obj.instance_eval(''bar'') #=> nil # With arguments: obj.instance_eval(''foo(:arg1, :arg2)'') #=> nil obj.instance_eval(''bar(:arg1, :arg2)'') #=> nil

enviar

obj.send(''foo'') #=> nil obj.send(''bar'') #=> nil # With arguments: obj.send(''foo'', :arg1, :arg2) #=> nil obj.send(''bar'', :arg1, :arg2) #=> nil

public_send

obj.public_send(''foo'') #=> nil obj.public_send(''bar'') #=> NoMethodError: private method `bar'' called # With arguments: obj.public_send(''foo'', :arg1, :arg2) #=> nil obj.public_send(''bar'', :arg1, :arg2) #=> NoMethodError: private method `bar'' called

método

obj.method(''foo'').call #=> nil obj.method(''bar'').call #=> nil # With arguments: obj.method(''foo'').call(:arg1, :arg2) #=> nil obj.method(''bar'').call(:arg1, :arg2) #=> nil

¿Cómo puedo llamar un método dinámicamente cuando su nombre está contenido en una variable de cadena? Por ejemplo:

class MyClass def foo; end def bar; end end obj = MyClass.new str = get_data_from_user # e.g. `gets`, `params`, DB access, etc. str #=> "foo" # somehow call `foo` on `obj` using the value in `str`.

¿Cómo puedo hacer esto? ¿Es un riesgo de seguridad?


Lo que quiere hacer se llama despacho dinámico . Es muy fácil en Ruby, solo usa public_send :

method_name = ''foobar'' obj.public_send(method_name) if obj.respond_to? method_name

Si el método es privado / protegido, use send lugar, pero prefiera public_send .

Este es un posible riesgo de seguridad si el valor de method_name proviene del usuario. Para evitar vulnerabilidades, debe validar qué métodos se pueden llamar realmente. Por ejemplo:

if obj.respond_to?(method_name) && %w[foo bar].include?(method_name) obj.send(method_name) end


Puede verificar la disponibilidad del método usando respond_to? . Si está disponible, entonces llama a send . Por ejemplo:

if obj.respond_to?(str) obj.send(str) end


Use send para llamar a un método de forma dinámica:

obj.send(str)


Realmente vas a querer tener cuidado con esto. El uso de los datos del usuario para llamar a cualquier método mediante el send podría dejar espacio para que los usuarios ejecuten cualquier método que deseen. send se usa a menudo para llamar dinámicamente a los nombres de los métodos, pero asegúrese de que los valores de entrada sean confiables y no puedan ser manipulados por los usuarios.

La regla de oro nunca confía en ninguna entrada que provenga del usuario.