2009-02-12 16 views
9

Nunca he visto undef, o cualquier otra cosa que le permita definir un método, en cualquier otro lenguaje de programación. ¿Por qué es necesario en Ruby?undef - ¿Por qué quieres definir un método en rubí?

EDITAR: No estoy argumentando que haya algo de malo en esto. Simplemente no entiendo el propósito de definir métodos en tiempo de ejecución? ¿Cuál es el propósito de eso? ¿Cómo se usa? Nunca he hecho esto en C o Java.

Respuesta

18

También existe el patrón de clase en blanco en Ruby que necesita la funcionalidad undef.

La idea es quitar todos los métodos de su nueva clase para que cada llamada que realice finalice en #method_missing. De esta forma, puede implementar un proxy real que simplemente lo revuelve todo. Implementar el patrón de decorador con esto es alrededor de diez líneas de código, sin importar cuán grande sea su clase objetivo.

Si quiere ver ese modismo en acción, mire uno de los marcos de burla de Ruby, lo usan mucho. Algo así como flexmock.

Otro ejemplo es cuando agrega funciones dinámicamente a una clase en función de alguna condición. En un juego, puede agregar un método #attack en el objeto del jugador y luego quitárselo cuando esté paralizado en lugar de hacerlo con una bandera booleana. De esta forma, la clase llamante puede verificar la disponibilidad del método y no la bandera. No estoy diciendo que esto sea una buena idea, solo que es posible y que hay personas mucho más inteligentes que yo que tengo algo útil que hacer con esto.

+0

Me gusta tu ejemplo de #ataque. Gracias. –

2

La definición de métodos, clases y objetos en tiempo de ejecución es una muy buena característica de Ruby. Te permite extender clases (recuerda que están "abiertas"). Si observa Rails, tiene un método #find para encontrar objetos en un modelo, pero también puede usar find_by_user; ese método no existe (por lo que se llama a #method_missing) pero se crea en tiempo de ejecución.

Si desea crear un Domain Specific Language o DSL, usar #missing_method puede ser útil.

+1

realidad #method_missing isnt utilizado por activercord cuando llame find_by_user. el método está definido en la clase init – LDomagala

0

Puede buscar en todos los Rails ejemplos de métodos de definición en el tiempo de ejecución (también conocido como metaprogramación). Al invocar un método en su definición de clase, puede definir un montón de métodos para todas las instancias de esa clase ...

1

La técnica de incluir módulos según sea necesario se relaciona con la definición de métodos en el tiempo de ejecución. Trabajo en una aplicación de Rails donde a veces tenemos que exportar datos en varios formatos. 99% de las veces, el objeto formulario no necesita métodos relacionados con la exportación, pero en nuestra tarea Rake exportadora, que hacer algo como:

Form.send(:include, FormExportingMethods) 

lo tanto, sólo tiene esos métodos cuando las necesita.

Este tipo de dinamismo es una de las cosas que amo de Ruby. Mientras que en algunos idiomas, tienes que definir tus clases y objetos al principio, Ruby te permite decir "oh, necesito que mi cerdo tenga alas ahora mismo". Simplemente las adjuntaré ".

Observe en mi ejemplo que los objetos de formularios específicos no se están modificando; la clase de forma es. Esto funciona porque, cuando envía un mensaje a un objeto, busca en su cadena de búsqueda de métodos una respuesta en el momento en que pregunta. Entonces puede crear un objeto, luego agregar un método en cualquier lugar de su cadena de herencia, luego llamar al método en el objeto y lo tendrá. Obviamente, tener que revisar toda la cadena de herencia para cada método es costoso, pero es una compensación para este tipo de flexibilidad.

0

Si utiliza la herencia de tabla única con un ORM, como ActiveRecord, puede definir los métodos para los campos que no se utilizan para una clase/objeto en particular.

# table: shapes, with columns: name, sides, radius, type 
class Shape < ActiveRecord::Base 
end 

class Circle < Shape 
end 

class Square < Shape 
    undefine_method :radius 
end 

Nota: Esto no funciona realmente en ActiveRecord, ya que internamente espera un método para cada campo para siempre ser definido.

Nota: Un cuadrado tiene un radio que no se usa comúnmente, pero ¿entiendes? Piense en alguna propiedad que guarde en la base de datos que tiene un círculo, pero no en un cuadrado.

0

Estoy consumiendo una API externa, y una de las respuestas de JSON contiene un campo llamado "métodos". Estoy creando un OpenStruct alrededor del json, solo para hacer que el json sea más manejable. Al llamar a openStruct.methods, devuelve el resultado del método de instancia de objeto "métodos".

Así que lo hice:

class MyOpenStruct < OpenStruct 
    def methods 
    end 

    undef :methods 
end 

openStruct = OpenStruct.new(my_json) 
0

que he visto este utiliza en conjunción con Mixins; para que pueda incluir todo y luego determinar los métodos que no debería admitir ... p. la biblioteca de gráficos ruby ​​shoes.

La clase button se mezcla en el módulo clickable, y luego undef 's el método release ya que estos últimos no lo soportan.

Otro ejemplo rápido, por lo que es disponible aquí:

module Walkable 
    attr_accessor :location 
    def walk(steps) 
    @location += steps 
    end 
    def walk_back(steps) 
    @location -= steps 
    end 
end 
class Zombie 
    include Walkable 
    undef walk_back #zombies can only walk forwards 
end 
Cuestiones relacionadas