Rails 3引擎- gem也是一个应用程序,它希望通过Mixin共享一个干巴巴的配置

时间:2022-06-01 20:14:46

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.

我有许多引擎也是gem和应用程序(Rails3)。它们是gem,因此可以方便地安装它们,并且可以通过bundler在多个应用程序中管理依赖项(它是构建多个应用程序的整个堆栈)。它们是利用Rails资源的引擎——模型等等。它们是应用程序有两个原因:1)提供一个完整的测试环境,与包含它们的应用程序隔离,因此您可以执行“rails c”,例如2),以便运行“rake db:migrate”和seed等程序。

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:

我希望我的引擎和应用程序都将一些混合物注入到较低的依赖关系中。这是我想到的解决办法。它工作得很好——我只是想知道是否有人对这种方法或关于共享问题或引擎-gem-应用程序的总体想法有任何批评或最好的做法:

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)

(更新:我编辑了上面的代码以在my_engine模块中封装模块,否则使用此模式的多个引擎可能会产生不可预测的效果,比如MyEngine。根= = SomeOtherEngine.root)

1 个解决方案

#1


1  

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.

您的gem的测试可以包含一个用于测试的伪应用程序。设计公司就是这样做的。这是公认的对严重依赖铁路的宝石的做法。

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.

你也可以把它分开。过去,我使用Gemfile设置了一个测试应用程序,它通过路径指向gem (gem 'mygem',:path => 'some/path'),这使得测试相对容易。这可以作为一个示例应用程序,您可以在一个单独的存储库中提供这个示例应用程序(请记住,在标记gem时,应该将示例应用程序的:path参数更改为特定的版本)。这里的好处是您的示例应用程序始终保持最新。

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.

如果您只是在讨论单元测试模型,您可以跳过上面的内容,只在活动记录和SQLite上添加一个测试依赖项。将夹具数据保存在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.

由于您有几个这样的引擎,并且它们将在不同的应用程序中混合和匹配,所以我的建议是建立一个应用程序,使用所有这些gem并作为您的功能测试床。当然,要对单个的宝石进行单元测试。这增加了所有引擎之间集成测试的好处,以确保没有冲突。

#1


1  

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.

您的gem的测试可以包含一个用于测试的伪应用程序。设计公司就是这样做的。这是公认的对严重依赖铁路的宝石的做法。

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.

你也可以把它分开。过去,我使用Gemfile设置了一个测试应用程序,它通过路径指向gem (gem 'mygem',:path => 'some/path'),这使得测试相对容易。这可以作为一个示例应用程序,您可以在一个单独的存储库中提供这个示例应用程序(请记住,在标记gem时,应该将示例应用程序的:path参数更改为特定的版本)。这里的好处是您的示例应用程序始终保持最新。

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.

如果您只是在讨论单元测试模型,您可以跳过上面的内容,只在活动记录和SQLite上添加一个测试依赖项。将夹具数据保存在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.

由于您有几个这样的引擎,并且它们将在不同的应用程序中混合和匹配,所以我的建议是建立一个应用程序,使用所有这些gem并作为您的功能测试床。当然,要对单个的宝石进行单元测试。这增加了所有引擎之间集成测试的好处,以确保没有冲突。