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
因此,使用细化,我可以将类转换为模块,动态优化其行为,并将其包含在其他类中。
在rb_mod_refine的C实现中 我们看到
refinement = rb_module_new();
RCLASS_SET_SUPER(refinement, klass);
这只是将精炼的超类设置为klass
,在复制模块中复制类的实现吗?
Class#include_refined
的看法是什么?
从改进中提取这个方面是否合理?
在本地“修补”而不是使用“使用”开关激活优化? 答案 0 :(得分:3)
我很高兴使用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
并且适合作为原始问题的解决方案。
答案 1 :(得分:1)
Andrea,谢谢你在评论中的信息。借口我缺乏知识,了解这是非常必要的,尽管根据你的研究听起来可行。
我认为我们不需要在Rails中做那么低级别的事情。
如果我要在引擎上做类似的话,我会尝试以下想法,从易到难。
在routes.rb中,将整个引擎安装在正确的路径中。
我担心这种最常见的用法不能满足您的需求
在routes.rb中,为应用程序路由中的特定控制器自定义引擎的路由。
作为引擎,Devise可以轻松完成。但我知道不是每个引擎都能做到这一点。
在routes.rb中,将特定或整套路线重定向到引擎的路线
在您的应用程序操作中,重定向到应用程序操作中的特定引擎操作。
这应该足够自定义以执行特定操作
class FoosController < ApplicationController
def foo
redirect_to some_engine_path if params[:foo] == 'bar'
end
继承引擎的控制器 - 进行一系列操作,如果上述所有操作都不合适
*引擎的类在所有应用程序中都可用,您可以从它们继承控制器,而不是普通的ApplicationController。
# class FoosController < ApplicationController
class FoosController < BarEngine::BarsController
*由于大多数引擎的控制器都继承自ApplicationController,因此这种继承仍允许您使用ApplicationController中自己的东西,完全没有任何不良影响。
如果上述所有情况都无法做到,我可以尝试在本地或从我的github回购中进行定制。
总之,上述应该能够解决大多数情况,我自己更喜欢#5,如果可能和需要。