Rails 3 Engine-Gem(也是一个应用程序)想要通过 Mixin 共享 DRY 配置
我有很多引擎,它们也是宝石和应用程序(Rails3)。它们是 gem,因此可以轻松安装,并通过多个应用程序中的捆绑器管理依赖项(它是构建多个应用程序的整个堆栈)。它们是利用 Rails 资源(模型等)的引擎。它们是应用程序有两个原因:1) 提供一个与其包含的应用程序隔离的完整测试环境,因此您可以执行“rails c”,2) 以便运行“rake db:migrate”和种子等内容更多的。
我希望我的引擎和应用程序都将一些混合注入到较低级别的依赖项中。这是我想出的解决方案。它工作得很好 - 我只是想知道是否有人对该方法有任何批评或分享有关共享问题的最佳实践或引擎宝石应用程序的总体思想:
引擎:
#my_engine/lib/my_engine.rb
require 'my_engine/config.rb'
module MyEngine
class Engine < Rails::Engine
config.to_prepare do
MyEngine.inject_mixins
end
end
end
应用程序:
#my_engine/config/application.rb
require 'my_engine/config'
module MyEngine
class Application < Rails::Application
config.to_prepare do
MyEngine.inject_mixins
end
end
end
mixin:(
#my_engine/lib/my_engine/config.rb
module MyEngine
module CLASSMETHODS
def inject_mixins
::ApplicationHelper.send(:include, MyEngine)
::SomeDependency::SomeClass.send(:include, MyEngine::SomeClassMixin)
end
#root should be defined as the root of this engine, ie relative to this file
def root
File.join(File.dirname(__FILE__), '..','..')
end
end
extend CLASS_METHODS
end
更新:我编辑上面的内容以将模块包装在 my_engine 模块中,否则多个引擎同时使用此模式可能会产生不可预测的效果,例如 MyEngine.root == SomeOtherEngine.root)
I have a number of engines which are also gems and also applications (Rails3). They are gems so they can be easily installed and the dependencies managed via bundler in more than one application (its a whole stack upon which multiple applications are built). They are engines to take advantage of Rails resources - models and such. They are applications for two reasons: 1) to provide a full testing environment which is isolated from their including applications so you can do 'rails c' for example and 2) in order to run things like 'rake db:migrate' and seed and more.
I want both my engine and my application to inject some mixins into lower level dependencies. Here is the solution I came up with. It works fine - I am just wondering if anyone has any criticisms of the approach OR a best practice to share regarding the sharing issue OR the overall idea of engine-gem-applications:
The engine:
#my_engine/lib/my_engine.rb
require 'my_engine/config.rb'
module MyEngine
class Engine < Rails::Engine
config.to_prepare do
MyEngine.inject_mixins
end
end
end
The application:
#my_engine/config/application.rb
require 'my_engine/config'
module MyEngine
class Application < Rails::Application
config.to_prepare do
MyEngine.inject_mixins
end
end
end
The mixin:
#my_engine/lib/my_engine/config.rb
module MyEngine
module CLASSMETHODS
def inject_mixins
::ApplicationHelper.send(:include, MyEngine)
::SomeDependency::SomeClass.send(:include, MyEngine::SomeClassMixin)
end
#root should be defined as the root of this engine, ie relative to this file
def root
File.join(File.dirname(__FILE__), '..','..')
end
end
extend CLASS_METHODS
end
(Update: I edited the above to wrap the module in my_engine module, otherwise more than one engine using this pattern simultaneously could have unpredictable effects, like MyEngine.root == SomeOtherEngine.root)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这没有规律或规则,但你有几个不同的选择。
您的 gem 的测试可以包含用于测试的虚拟应用程序。例如,Devis 就是这样做的。对于严重依赖 Rails 的 gem,这是公认的做法。
您也可以将其分开。过去,我使用 Gemfile 设置了一个测试应用程序,该文件通过路径 (
gem 'mygem', :path => 'some/path'
) 指向 gem,这使得测试相对容易简单的。这可以兼作示例应用程序,您可以在单独的存储库中提供它(请记住,在标记 gem 时,您应该将示例应用程序的 :path 参数更改为特定版本)。这样做的好处是您的示例应用程序始终保持最新。如果您只是讨论单元测试模型,则可以跳过上述内容,只需添加对 Active Record 和 SQLite 的测试依赖项。将夹具数据与 gem 一起保存。
由于您有多个这样的引擎,并且它们将在不同的应用程序中混合和匹配,因此我的建议是建立一个使用所有这些 gem 的应用程序并用作您的功能测试台。当然,对各个 gem 进行单元测试。这具有在所有引擎之间进行集成测试的额外好处,以确保不存在冲突。
There's no rhyme or rule to this, but you have a couple different options.
Your gem's tests can contain a dummy application for testing. Devise does this, for example. This is accepted practice for gems that are heavily Rails-dependent.
You can also keep it separate. In the past I've set up a testing application with a Gemfile that points to the gem via path (
gem 'mygem', :path => 'some/path'
), which makes testing relatively easy. This can double as a sample application that you can provide in a separate repository (keep in mind when tagging the gem you should change the sample application's :path parameter to a specific version). The benefit here is that your sample application is always kept up to date.If you're simply talking about unit testing models, you can skip the above and just add a testing dependency on Active Record and SQLite. Keep fixture data with the gem.
Since you have several of these engines and they will be mixed and matched in different applications, my suggestion is to set up an application that uses all of these gems and serves as your functional testbed. Keep unit tests with the individual gems, of course. This has the added benefit of integration testing between all engines, to ensure there are no conflicts.