Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

365
Vistas
Eliminar dinámicamente el antepasado mixin de la clase

Estoy tratando de desarrollar una aplicación de consola de juegos de cartas simple en Ruby como un proyecto favorito. Una de las interacciones que me gustaría agregar a este juego de cartas es algo como "Durante tu turno, puedes comprar cartas como si costaran X menos". Ahora, pensé en modelar este comportamiento con la ayuda de decoradores mixin. Suponiendo la siguiente clase:

 class Card attr_reader :cost def initialize(cost) self.cost = cost end def play(*_args) raise NotImplementedError, "Override me!" end private attr_writer :cost end

Pensé que una solución simple sería algo como esto:

 class CardThatDiscounts < Card def play(*_args) @mod = Module.new do def cost super - 1 end end Card.prepend(@mod) end end

Esto me daría la flexibilidad de apuntar a la clase en sí o a instancias específicas de las tarjetas. Sin embargo, no estoy seguro de cómo revertir este efecto al final del turno. Vi algunas preguntas similares a esta, cuyas respuestas decían algo como:

  1. Elimina el método definido manualmente.

Este enfoque realmente no funcionará para mí, ya que estoy decorando métodos existentes en lugar de agregar otros nuevos. Tal vez podría cambiar el nombre del método existente cuando antepongo el módulo y luego devolverlo, pero ¿qué sucede en caso de que quiera encadenar varios decoradores de este tipo?

  1. Usa la mixología de gemas

La mixología es una joya antigua y parece que ya no se mantiene. Aunque, según la documentación, es exactamente lo que necesito. Sin embargo, la implementación se ocupa principalmente de los componentes internos de Ruby, que lamentablemente no entiendo. ¿No es posible modificar una cadena de ancestros de clase desde Ruby, o necesito la extensión c/Java para esto?

Consideré otras alternativas, como SimpleDelegator o DelegateClass , pero ambas requieren que cree instancias de nuevos objetos y luego, de alguna manera, reemplace las referencias a los objetos Card existentes con estos nuevos objetos envueltos, y viceversa, al final del turno. Lo que parecía un poco más complicado que modificar la cadena de ascendencia directamente.

Supongo que mi pregunta tiene 2 partes. ¿Es posible eliminar un ancestro específico de la cadena de ancestros de una clase usando rubí puro (dado que mixology gem ya sugiere que es posible hacerlo con extensiones c/Java)? Si no, ¿cuál sería una solución adecuada para obtener un comportamiento similar?

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Lo que estás tratando de lograr es un patrón muy malo. Casi nunca debe usar prepend o include dinámicamente, pero modele su código en torno a los conceptos que usted (y las personas que posiblemente lean su código) entienden.

Lo que probablemente quieras hacer es crear (algún tipo de) un Delegador llamado CardAffectedByEnvironment - y luego, en lugar de hacer Card.new(x) , siempre harás CardAffectedByEnvironment.new(Card.new(x), env) , donde env mantendrá todos sus cambios de estado, o agregará un método real_cost que calcularía las cosas en función de su cost y entorno y usaría este método.

A continuación se muestra un código con CardAffectedByEnvironment que tal vez describa mejor cómo asumiría que funcionaría:

 class Environment def initialize @modifiers = [] end attr_reader :modifiers def next_round @modifiers = [] end def modifiers_for(method) @modifiers.select { |i| i.first == method } end end class CardAffectedByEnvironment def initialize(card, env) @card, @env = card, env end # Since Ruby 3.0 you can write `...` instead of `*args, **kwargs, &block` def method_missing(method, *args, **kwargs, &block) value = @card.public_send(method, *args, **kwargs, &block) @env.modifiers_for(method).each do |_, modifier| value = modifier.call(value) end value end end class Joker def cost 10 end end env = Environment.new card = CardAffectedByEnvironment.new(Joker.new, env) p card.cost # => 10 env.modifiers << [:cost, ->(i) { i - 1 }] p card.cost # => 9 env.next_round p card.cost # => 10
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda