将ruby类转换为模块比使用优化更好的方法?

Module#refine方法接受一个类和一个块并返回一个细化模块,所以我想我可以定义:

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

并且以下测试通过

 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 

因此,使用细化,我可以将类转换为模块,动态优化其行为,并将其包含在其他类中。

  • 是否有更简单的方法将类转换为Ruby中的模块(比如ruby <2)?
  • 在rb_mod_refine的C实现中我们看到了

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

    这只是将精炼的超类设置为klass ,它在精简模块中复制了类的实现吗?

  • 我知道多重inheritance是通过模块完成的,但是社区会想到上面的Class#include_refined ? 从改进中提取这个方面是否合理? 在本地“修补”而不是使用“使用”开关激活优化?

我很高兴使用Ruby 2.1(及更高版本)类级“私有”范围的改进。 我上面的例子可以改为:

 # 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 

并适合作为原始问题的解决方案。

安德里亚,谢谢你的评论信息。 借口我缺乏知识,了解这是非常必要的,尽管根据你的研究听起来可行。

我认为我们不需要在Rails中做那么低级别的事情。

如果我要在引擎上做类似的话,我会尝试以下想法,从易到难。

  1. 在routes.rb中,将整个引擎安装在正确的路径中。

    我担心这种最常见的用法无法满足您的需求

  2. 在routes.rb中,为应用程序路由中的特定控制器自定义引擎的路由。

    作为引擎,设计可以轻松完成。 但我知道不是每个发动机都能做到这一点

  3. 在routes.rb中,将特定或整组路由重定向到引擎的路由

  4. 在应用程序的操作中,重定向到应用程序操作中的特定引擎操作。

    这应该足够自定义以执行特定操作

     class FoosController < ApplicationController def foo redirect_to some_engine_path if params[:foo] == 'bar' end 
  5. inheritance引擎的控制器 - 用于一组操作,如果以上所有操作都不适合

    *引擎的类在所有应用程序中都可用,您可以从它们inheritance控制器,而不是普通的ApplicationController。

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

    *由于大多数引擎的控制器都inheritance自ApplicationController,因此这种inheritance仍允许您在ApplicationController中使用自己的东西,完全没有任何不良影响。

  6. 如果以上都不能做,我可以尝试在本地或从我的github repo提供定制服务。

总之,上面应该能够解决大多数情况,我自己更喜欢#5尽可能需要。