将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中做那么低级别的事情。
如果我要在引擎上做类似的话,我会尝试以下想法,从易到难。
-
在routes.rb中,将整个引擎安装在正确的路径中。
我担心这种最常见的用法无法满足您的需求
-
在routes.rb中,为应用程序路由中的特定控制器自定义引擎的路由。
作为引擎,设计可以轻松完成。 但我知道不是每个发动机都能做到这一点 。
-
在routes.rb中,将特定或整组路由重定向到引擎的路由
-
在应用程序的操作中,重定向到应用程序操作中的特定引擎操作。
这应该足够自定义以执行特定操作
class FoosController < ApplicationController def foo redirect_to some_engine_path if params[:foo] == 'bar' end
-
inheritance引擎的控制器 - 用于一组操作,如果以上所有操作都不适合
*引擎的类在所有应用程序中都可用,您可以从它们inheritance控制器,而不是普通的ApplicationController。
# class FoosController < ApplicationController class FoosController < BarEngine::BarsController
*由于大多数引擎的控制器都inheritance自ApplicationController,因此这种inheritance仍允许您在ApplicationController中使用自己的东西,完全没有任何不良影响。
-
如果以上都不能做,我可以尝试在本地或从我的github repo提供定制服务。
总之,上面应该能够解决大多数情况,我自己更喜欢#5尽可能需要。