ruby-on-rails - punteros - ruby on rails vs php
undef-¿Por qué querrías definir un método en rubí? (7)
La definición de métodos, clases y objetos en tiempo de ejecución es una característica muy buena 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 #method_missing
se llama #method_missing
) pero se crea en tiempo de ejecución.
Si desea crear un lenguaje específico de dominio o DSL, usar #missing_method
puede ser útil.
Nunca he visto undef, o cualquier otra cosa que te permita descifrar un método, en cualquier otro lenguaje de programación. ¿Por qué es necesario en Ruby?
EDITAR: No estoy argumentando que haya nada 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.
Puede ver todos los Rails para ver ejemplos de métodos de definición en tiempo de ejecución (también conocido como metaprogramación). Al invocar un método en la definición de su clase, puede definir un montón de métodos para todas las instancias de esa clase ...
La técnica de incluir módulos según sea necesario se relaciona con la definición de métodos en tiempo de ejecución. Trabajo en una aplicación de Rails donde a veces tenemos que exportar datos en varios formatos. El 99% de las veces, el objeto Formulario no necesita métodos relacionados con la exportación, pero en nuestra tarea de exportación de Rake, hacemos algo como:
Form.send(:include, FormExportingMethods)
Entonces solo tiene esos métodos cuando los 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 formulario específicos no están siendo modificados; la clase de forma es. Esto funciona porque, cuando envías un mensaje a un objeto, busca una respuesta en la cadena de búsqueda de métodos en el momento en que lo pides . 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.
Si usa 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 realmente no funciona en ActiveRecord ya que internamente espera que siempre se defina un método para cada campo.
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.
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)
He visto esto usado junto con Mixins; para que pueda incluir todo y luego determinar los métodos que no debería admitir ... por ejemplo, los zapatos de la biblioteca gráfica de ruby.
La clase de button
mezcla en el módulo undef
y luego undef
está disponible el método de release
porque los botones no lo admiten.
Otro ejemplo rápido, por lo que está 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
También está el patrón de clase en blanco en Ruby que necesita la funcionalidad undef
.
La idea es eliminar todos los métodos de tu nueva clase para que cada llamada que hagas termine 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 quieres ver ese modismo en acción, mira 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 basada en alguna condición. En un juego puedes agregar un método #attack
al 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.