joe / merb-app-local-gem-management
- Source
- Commits
- Network (0)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Branch:
master
README
THIS IS A DRAFT. I REPEAT, THIS IS A DRAFT!
===========================================
Introduction
============
Merb App-Local Gem Management is all about keeping your Merb app's requirements as local as possible. Right now, the
"requirements" managed by this collection of stuff are limited to gems.
Why???, you ask?
- With this approach, everything is versioned along with your app. As the gems and gem versions you require evolve, that
evolution is recorded by your repository.
- Getting a new developer up with your app and keeping developers in sync is much simpler. Running a rake task to update
all the necessary gems is much simpler than IM'ing and emailing and reading commit logs to figure out what gems to
install/update.
- This approach forces you to DRY-yet-completely-specify the environment necessary for your app to run successfully. All
gems and exact versions of those gems are specified exactly, exactly once.
Perhaps I'm preaching to the choir with the above two points and you're just asking the question "why not just keep all
your gems 'frozen' in a gems or frameworks directory?" My reasons are two:
- Many gems require native build steps, this debilitates keeping gems pre-installed in the app.
- You might want to use git's submodules to track a few projects outside of their gem release cycle.
- Related to my cause, frozen merb and other "just install gems into gems or frameworks and version that" still require
that you install (and therefore worry about versioning manually) some of merb in order to be "app-local." (It's worth
noting that this bullet can be covered by just doing the PATH/GEM\_HOME process that is a part of the total gem
management approach described below.)
The scripts and conventions contained herein keep you structured with both of all of those issues solved.
How to "Enable" a Merb Application with These Scripts
=====================================================
1. Copy the scripts/local\_paths and scripts/gem\_install\_rake BASH scripts to your Merb app's scripts directory
(creating that directory if necessary).
2. Copy the tasks/gems.rake tasks file over to your Merb app's tasks directory (creating that directory if necessary).
3. Edit your app's .gitignore file. Add the line 'gems/**' to it.
4. Edit your app's Rakefile to march on (but log) even if Merb and its dependencies are not yet installed. This allows
us to use Rake for building the environment itself (including Merb and all its dependencies). For example:
<pre><code>
require 'rubygems'
Gem.clear_paths
Gem.path.unshift(File.join(File.dirname(__FILE__), "gems"))
require 'rake'
require 'rake/rdoctask'
require 'rake/testtask'
begin
require 'spec/rake/spectask'
require 'fileutils'
rescue LoadError
puts "* Loading spec/rake/spectask or fileutils failed! Continuing in case you're doing rake tasks that does not
require it."
end
begin
require 'merb-core'
rescue LoadError
puts "* Loading merb-core failed! Continuing in case you're doing rake tasks that does not require it."
end
begin
require 'rubigen'
rescue LoadError
puts "* Loading rubigen failed! Continuing in case you're doing rake tasks that does not require it."
end
include FileUtils
init_env = ENV['MERB_ENV'] || 'rake'
begin
Merb.load_dependencies(:environment => init_env)
Merb::Plugins.rakefiles.each { |r| require r }
rescue LoadError, Exception
puts "* Loading merb's dependencies failed! Continuing in case you're doing rake tasks that do not require them."
end
</pre></code>
5. Edit your app's config/init.rb to clearly declare every gem that you app depends on. Here's a quick example set of
dependency declarations:
<pre><code>
dependency 'activesupport', '= 2.0.2'
dependency 'rubigen','= 1.3.1'
dependency 'fastthread','= 1.0.1'
dependency 'hpricot','= 0.6'
dependency 'rspec', '= 1.1.3', 'spec'
</pre></code>
Each dependency declaration takes the following parameters:
1. the name of the gem as it should be called with a 'gem install xyz'
2. the exact version of the gem that you require for your application
3. the string to use in a 'require' statement for loading the gem if that string differs from the gem's name (this is
optional for those gems that do not follow the friendly convention of installing and requiring under the same name).
As you can see, RSpec (at least through 1.1.3) is an example case where the 3rd parameter to dependency is necessary.
You do a 'gem install rspec' but need to do a 'require 'spec'.'
NOTA BENE: That 3rd parameter to dependency is NOT in wycat's mainline of merb-core ... hopefully it will be soon. If
you'd like to use my fork of merb-core in order to get that dependency fix, please do. Or, cherry pick my commit that
makes the necessary fix (42ae4c8).
6. Optionally, put a copy of each gem (e.g. the rspec-1.1.3.gem file) that you use in your app inside of a directory
named gem\_cache. The gem\_cache directory should be in your app's base directory. This saves you and everyone else from
downloading the gem from rubyforge or somewhere else (and doing the dreaded bulk update of the gem index).
If you want to keep track of some projects/gems (including the merb-* and dm-* framework gems) as git submodules, also
do the following:
1. Create a sources directory inside your app's base directory. Use git's submodules feature to "add" git submodules for
each into your app. For example:
git submodule add git://github.com/wycats/merb-core.git sources/merb-core
(repeat that for each git project you want)
git submodule init
git submodule update
2. Copy the config/gems.rb file over to your Merb app's config directory. Edit the file to suit your git submodules ...
note the way the example file is populated with paths to the specific projects in the cases of merb-more, merb-plugins
and dm-more.
The above two steps make it so that the rake tasks for installing basic gems will *not* install the gems for the git
submodules that you want to track in your sources directory. For example, if you have merb-core tracked as a source and
indicated in your config/gems.rb, then you don't want to gem install it from rubforge. Instead you'll use the
gems:submodule\_ tasks to update/install the gems from the sources.
How to Use an "Enabled" Merb Application as a Developer/Deployer
================================================================
1. Install Ruby, Ruby Gems and git on your development/deployment box. (Ideally, even this process would be automated by
a script inside your app.) And if you use MySQL, etc, you'll need to install those separately as well.
2. Clone your app. Move into your app's base directory.
3. Set up app-local PATH and GEM\_HOME environment variables. If you're using BASH or a compatible shell, then you can
use my pre-made script via 'source scripts/local_paths.' You'll need to set these paths each time you go to develop or
deploy your app.
4. Install Rake inside your app's local gem environment. If you're using BASH or a compatible shell, then you can use my
pre-made script via 'source scripts/gem\_install\_rake.'
5. Run 'rake gems:install\_all.' This will install all of the gems specified in your config/init.rb (excluding the gems
mentioned in config/gems.rb if you're going that route) and (if you're going this route) also package and install the
specified gems from your sources directory.
From there on out, any time you call "merb" or "rake" or any other gem that has a bin file, you'll be 100% app-local.
Just as the heart of Merb meant it to be!!! ;)
How to Add a "Managed" Gem to Your "Enabled" Merb Application
================================================================
1. You're using your app-local PATH and GEM\_HOME environment, right? :)
2. Go ahead and do a "gem install thenewgem" to get it in your app's gem system. Develop, test, enjoy. Ready to make
sure that gem is included for you and others in the future? Great!
3. If you're using the gem\_cache directory approach, copy the gem file (and any dependencies installed when you did
your gem install) from your app's local gems/cache directory over to your gem\_cache directory.
4. Make sure there is a proper dependency line in your config/init.rb file (it should be there already if you're
managing your gems within Merb properly). For example:
<pre><code>
dependency 'thenewgem', '1.2.0'
</pre></code>
5. Commit the gem\_cache addition and the update to config/init.rb. Either advise fellow developers to re-run "rake
gem:install_all" or build a git commit hook that takes care of it automatically.
6. Enjoy cleaner, more reliable living.
FAQ
===
Got questions? Send them my way and I'll update this section! :)

