rails modulos mapas importar diccionarios constantes clases ruby ruby-2.0 refinements

modulos - modulo ruby



¿Mejor manera de convertir una clase de ruby en un módulo que usando refinamientos? (2)

Module#refine método de Module#refine toma una clase y un bloque y devuelve un módulo de refinamiento, así que pensé que podría definir:

class Class def include_refined(klass) _refinement = Module.new do include refine(klass) { yield if block_given? } end self.send :include, _refinement end end

y la siguiente prueba pasa

class Base def foo "foo" end end class Receiver include_refined(Base) { def foo "refined " + super end } end describe Receiver do it { should respond_to(:foo) } its(:foo) { should eq("refined foo") } end

Por lo tanto, utilizando mejoras, puedo convertir una clase en un módulo, refinar su comportamiento sobre la marcha e incluirlo en otras clases.

  • ¿Hay una forma más sencilla de convertir una clase en un módulo en Ruby (por ejemplo, en ruby ​​<2)?
  • En la implementación en C de rb_mod_refine vemos

    refinement = rb_module_new(); RCLASS_SET_SUPER(refinement, klass);

    ¿Esto está configurando la superclase de refinamiento en klass que copia la implementación de la clase dentro del módulo de refinamiento?

  • Soy consciente de que la herencia múltiple se realiza a través de módulos, pero ¿qué pensaría la comunidad de la Class#include_refined mencionada anteriormente? ¿Sería razonable extraer este aspecto de los refinamientos? ¿Parcheando "localmente" dentro de una Clase en lugar de usar "usar" interruptores para activar refinamientos?

Andrea, gracias por la información en el comentario. Disculpe mi falta de conocimiento para entender que esto es realmente necesario, aunque parece factible según su investigación.

No creo que tengamos que ir a un nivel tan bajo para hacer algo en Rails.

Si voy a hacer algo similar en Engine, probaré las siguientes ideas, de fácil a difícil.

  1. En route.rb, monte todo el motor en la ruta correcta.

    Me temo que este uso más común no puede satisfacer su necesidad

  2. En route.rb, personalice la ruta del motor para controladores específicos en la ruta de la aplicación.

    La concepción, como motor, puede hacerse fácilmente. Pero sé que no todos los motores podrían hacer esto .

  3. En route.rb, redirigir el conjunto de rutas específicas o completas a las rutas del motor.

  4. En la acción de su aplicación, redirija a la acción específica del motor en la acción de la aplicación.

    Esto debería ser lo suficientemente personalizado para una acción específica.

    class FoosController < ApplicationController def foo redirect_to some_engine_path if params[:foo] == ''bar'' end

  5. Herede el controlador del motor - para un conjunto de acciones, y si todo lo anterior no encaja

    * Las clases del motor están disponibles en todas las aplicaciones, puede heredar un controlador de ellas, en lugar del ApplicationController normal.

    # class FoosController < ApplicationController class FoosController < BarEngine::BarsController

    * Dado que la mayoría de los controladores del motor heredan de ApplicationController, esta herencia aún le permite usar sus propias cosas de ApplicationController, sin ningún efecto negativo.

  6. Si no se puede hacer todo lo anterior, puedo intentar servir un local personalizado o desde mi repositorio github.

En conclusión, lo anterior debería poder resolver la mayoría de los casos, y yo mismo prefiero el # 5 cuando sea posible y necesario.


Estoy realmente contento con el alcance "privado" de las mejoras de Ruby 2.1 (y más tarde) a nivel de clase. Mi ejemplo anterior se puede reformular como:

# spec/modulify_spec.rb module Modulify refine(Class) do def include_refined(klass) _refined = Module.new do include refine(klass) { yield if block_given? } end include _refined end end end class A def a "I am an ''a''" end end class B using Modulify include_refined(A) do def a super + " and not a ''b''" end end def b "I cannot say: " + a end end RSpec.describe B do it "can use refined methods from A" do expect(subject.b).to eq "I cannot say: I am an ''a'' and not a ''b''" end end

Y se adapta como solución al problema original.