{"action":"created","issue":{"url":"https://api.github.com/repos/bundler/bundler-features/issues/65","labels_url":"https://api.github.com/repos/bundler/bundler-features/issues/65/labels{/name}","comments_url":"https://api.github.com/repos/bundler/bundler-features/issues/65/comments","events_url":"https://api.github.com/repos/bundler/bundler-features/issues/65/events","html_url":"https://github.com/bundler/bundler-features/issues/65","id":45726298,"number":65,"title":"Support requiring Gemfiles inside of Gemfiles (i.e. Gemfileception)","user":{"login":"dtognazzini","id":90865,"avatar_url":"https://avatars.githubusercontent.com/u/90865?v=3","gravatar_id":"","url":"https://api.github.com/users/dtognazzini","html_url":"https://github.com/dtognazzini","followers_url":"https://api.github.com/users/dtognazzini/followers","following_url":"https://api.github.com/users/dtognazzini/following{/other_user}","gists_url":"https://api.github.com/users/dtognazzini/gists{/gist_id}","starred_url":"https://api.github.com/users/dtognazzini/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dtognazzini/subscriptions","organizations_url":"https://api.github.com/users/dtognazzini/orgs","repos_url":"https://api.github.com/users/dtognazzini/repos","events_url":"https://api.github.com/users/dtognazzini/events{/privacy}","received_events_url":"https://api.github.com/users/dtognazzini/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":50,"created_at":"2014-10-14T08:52:02Z","updated_at":"2015-02-20T21:46:15Z","closed_at":"2014-11-06T20:16:20Z","body":"## Background\r\nGems, by themselves, only declare dependencies; they do not inform how to satisfy those dependencies. Bundler declares gem dependencies for package management and also specifies how to satisfy the dependencies (e.g. ```source```, ```path```, ```gem(git:)```, etc.)\r\n\r\nIt would be nice to reuse Gemfile declarations (both dependency specification and satisfaction) in other Gemfiles without copying and pasting.\r\n\r\n## Proposal\r\nProvide a ```require_gemfile``` method in ```Bundler::DSL``` that takes a path to another Gemfile that can hold common dependency resolution declarations. For example:\r\n\r\n_&lt;root&gt;/Gemfile_\r\n\r\n```ruby\r\nrequire_gemfile \"common/Gemfile\"\r\ngem \"some_gem\"\r\n```\r\n\r\n_&lt;root&gt;/common/Gemfile_\r\n```ruby\r\nsource \"https://my_fav_gemserver.net\"\r\npath \"gems\" do\r\n  gem \"my_fav_gem\"\r\nend\r\n```\r\n\r\nThe above would be identical to the following single file:\r\n\r\n_&lt;root&gt;/Gemfile_\r\n```ruby\r\nsource \"https://my_fav_gemserver.net\"\r\npath \"common/gems\" do\r\n  gem \"my_fav_gem\"\r\nend\r\ngem \"some_gem\"\r\n```\r\n\r\n__Notice:__ the resulting Gemfile nests the relative paths of the _required_ Gemfile (```common/Gemfile```) under the relative path from the _requiring_ Gemfile (```common/```).\r\n\r\n## Use Case 1: Sharing common gems\r\nThis is very similar to bundler/bundler#3102, which uses ```eval_gemfile```. In addition to sharing dependency declaration, ```require_gemfile``` allows sharing all supported DSL methods. \r\n\r\nWhat ```require_gemfile``` offers over ```eval_gemfile``` is that it rebases relative paths from the required Gemfile to relative paths from the requiring Gemfile. \r\n\r\n## Use Case 2: Sharing source code, repository local gem paths\r\nIt's become a common pattern amongst Rails projects to decompose the system into an ecosystem of inline gems containing Rails Engines. The main Rails Application pulls in the inline gems by declaring dependencies in the application-level Gemfile. For example:\r\n\r\n_&lt;system_root&gt;/Gemfile_\r\n```ruby\r\npath \"gems\" do\r\n  gem \"subsystem_one\"\r\n  gem \"subsystem_two\"\r\n  gem \"subsystem_three\"\r\nend\r\n```\r\n\r\nIf ```subsystem_one``` grows crazily, it could be further decomposed into many gems, perhaps:\r\n\r\n_&lt;system_root&gt;/subsystem_one/subsystem_one.gemspec_\r\n```ruby\r\n s.add_runtime_dependency(\"subsystem_one-authorization\")\r\n s.add_runtime_dependency(\"subsystem_one-billing\")\r\n s.add_runtime_dependency(\"subsystem_one-analytics\")\r\n```\r\n\r\n_&lt;system_root&gt;/subsystem_one/Gemfile_\r\n```ruby\r\n# path \"gems\" here would be <system_root>/subsystem_one/gems\r\npath \"gems\" do\r\n  gem \"subsystem_one-authorization\"\r\n  gem \"subsystem_one-billing\"\r\n  gem \"subsystem_one-analytics\"\r\nend\r\n```\r\n\r\nTo support this decomposition, the main application's Gemfile would have to be updated:\r\n\r\n_&lt;system_root&gt;/Gemfile_\r\n```ruby\r\n# Declare dependencies on subsystems\r\npath \"gems\" do\r\n  gem \"subsystem_one\"\r\n  gem \"subsystem_two\"\r\n  gem \"subsystem_three\"\r\nend\r\n\r\n# Add the path to find gems required by subsystem_one\r\npath \"subsystem_one/gems\"\r\n```\r\n\r\nUpdating the top level Gemfile for subsystems undergoing structural refactors like this is somewhat painful but reasonably maintainable provided there is only one, conventional \"gems\" repository for each layer.\r\n\r\n### When it becomes unmaintainable\r\nThis strategy becomes unmaintainable with one more level of layering.\r\n\r\nFor example, consider a ```super_system``` project that pulls in the root of the above project (named here as ```system_1```) and the root of another project (```system_2```):\r\n\r\n_&lt;super_system&gt;/systems/system_1.gemspec_\r\n```ruby\r\n s.add_runtime_dependency(\"subsystem_one\")\r\n s.add_runtime_dependency(\"subsystem_two\")\r\n s.add_runtime_dependency(\"subsystem_three\")\r\n```\r\n\r\n_&lt;super_system&gt;/Gemfile_\r\n```ruby\r\npath \"systems\" do\r\n  gem \"system_1\"\r\n  gem \"system_2\"\r\nend\r\n```\r\n\r\nThe ```super_system``` project would have to include paths in its Gemfile for the gems required by ```system_1```:\r\n\r\n_&lt;super_system&gt;/Gemfile_\r\n```ruby\r\n\r\n# Declare dependencies on the systems\r\npath \"systems\" do\r\n  gem \"system_1\"\r\n  gem \"system_2\"\r\nend\r\n\r\n# Add paths to find gems required by system_1 and its subsystems\r\npath \"systems/system_1/gems\"\r\npath \"systems/system_1/gems/subsystem_one/gems\"\r\n```\r\n\r\nThe last line couples ```super_system``` to the internal structure of ```system_1```.\r\n\r\n### Contrived?\r\nThis example may seem a bit contrived, but I work on something similar to this whereby a system is comprised of many Rails Applications. Each Rails Application supplies its own inline gem that the system depends on in its Gemfile. The inline gems provided by the Rails Applications are used by the system to interact with the applications. In the usage above, every restructuring internal to ```system_1``` would need to be handled by the Gemfile for ```super_system```.\r\n\r\nWith ```require_gemfile```, using a convention whereby systems specify their path repositories in a Gempaths file, the above would be simpler:\r\n\r\n_&lt;super_system&gt;/Gemfile_\r\n```ruby\r\n# Reuse gem paths defined by system_1\r\nrequire_gemfile \"systems/system_1/Gempaths\"\r\n\r\npath \"systems\" do\r\n  gem \"system_1\"\r\n  gem \"system_2\"\r\nend\r\n```\r\n\r\n_&lt;super_system&gt;/systems/system_1/Gemfile_\r\n```ruby\r\n# Use gem paths defined for system_1\r\nrequire_gemfile \"Gempaths\"\r\n```\r\n\r\n_&lt;super_system&gt;/systems/system_1/Gempaths_\r\n```ruby\r\n# Reuse gem paths defined by the subsystems\r\nrequire_gemfile \"gems/subsystem_one/Gempaths\"\r\nrequire_gemfile \"gems/subsystem_two/Gempaths\"\r\nrequire_gemfile \"gems/subsystem_three/Gempaths\"\r\n```\r\n\r\n_&lt;super_system&gt;/systems/system_1/gems/subsystem_one/Gemfile_\r\n```ruby\r\n# Use gem paths defined for subsystem_one\r\nrequire_gemfile \"Gempaths\"\r\n```\r\n\r\n_&lt;super_system&gt;/systems/system_1/gems/subsystem_one/Gempaths_\r\n```ruby\r\npath \"gems\"\r\n```\r\n\r\nWith the above, no layer knows about the internals of the layer beneath it.\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/bundler/bundler-features/issues/comments/75324960","html_url":"https://github.com/bundler/bundler-features/issues/65#issuecomment-75324960","issue_url":"https://api.github.com/repos/bundler/bundler-features/issues/65","id":75324960,"user":{"login":"johnnyshields","id":27655,"avatar_url":"https://avatars.githubusercontent.com/u/27655?v=3","gravatar_id":"","url":"https://api.github.com/users/johnnyshields","html_url":"https://github.com/johnnyshields","followers_url":"https://api.github.com/users/johnnyshields/followers","following_url":"https://api.github.com/users/johnnyshields/following{/other_user}","gists_url":"https://api.github.com/users/johnnyshields/gists{/gist_id}","starred_url":"https://api.github.com/users/johnnyshields/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johnnyshields/subscriptions","organizations_url":"https://api.github.com/users/johnnyshields/orgs","repos_url":"https://api.github.com/users/johnnyshields/repos","events_url":"https://api.github.com/users/johnnyshields/events{/privacy}","received_events_url":"https://api.github.com/users/johnnyshields/received_events","type":"User","site_admin":false},"created_at":"2015-02-20T21:46:15Z","updated_at":"2015-02-20T21:46:15Z","body":"@ccutrer supposing `gemspecs` could specify `:git` dependencies, which would be evaluated at higher priority than version numbers `>= 0.3.0` (i.e. Rubygems), does that solve your problem?"}}