aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--railties/CHANGELOG17
-rw-r--r--railties/lib/initializer.rb45
-rw-r--r--railties/lib/rails/gem_dependency.rb78
-rw-r--r--railties/lib/tasks/gems.rake31
-rw-r--r--railties/test/gem_dependency_test.rb62
5 files changed, 231 insertions, 2 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 672131b96e..7950e6a14f 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,22 @@
*SVN*
+* Added config.gem for specifying which gems are required by the application, as well as rake tasks for installing and freezing gems. [rick]
+
+ Rails::Initializer.run do |config|
+ config.gems "bj"
+ config.gems "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
+ config.gems "aws-s3", :lib => "aws/s3"
+ end
+
+ # List required gems.
+ rake gems
+
+ # Install all required gems:
+ rake gems:install
+
+ # Unpack specified gem to vendor/gems/gem_name-x.x.x
+ rake gems:unpack GEM=bj
+
* Removed the default .htaccess configuration as there are so many good deployment options now (kept it as an example in README) [DHH]
* config.time_zone accepts TZInfo::Timezone identifiers as well as Rails TimeZone identifiers [Geoff Buesing]
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index c60fe3d700..4be7b06f93 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -7,6 +7,7 @@ require 'railties_path'
require 'rails/version'
require 'rails/plugin/locator'
require 'rails/plugin/loader'
+require 'rails/gem_dependency'
RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
@@ -77,6 +78,7 @@ module Rails
require_frameworks
set_autoload_paths
+ add_gem_load_paths
add_plugin_load_paths
load_environment
@@ -98,8 +100,8 @@ module Rails
add_support_load_paths
+ load_gems
load_plugins
-
load_application_initializers
# the framework is now fully initialized
@@ -185,6 +187,17 @@ module Rails
plugin_loader.add_plugin_load_paths
end
+ def add_gem_load_paths
+ unless @configuration.gems.empty?
+ require "rubygems"
+ @configuration.gems.each &:add_load_paths
+ end
+ end
+
+ def load_gems
+ @configuration.gems.each &:load
+ end
+
# Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
# defaults to <tt>vendor/plugins</tt> but may also be set to a list of
# paths, such as
@@ -229,7 +242,11 @@ module Rails
def load_observers
if configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.instantiate_observers
+ if @configuration.gems.any? { |g| !g.loaded? }
+ puts "Unable to instantiate observers, some gems that this application depends on are missing. Run 'rake gems:install'"
+ else
+ ActiveRecord::Base.instantiate_observers
+ end
end
end
@@ -494,6 +511,25 @@ module Rails
# a sub class would have access to fine grained modification of the loading behavior. See
# the implementation of Rails::Plugin::Loader for more details.
attr_accessor :plugin_loader
+
+ # An array of gems that this rails application depends on. Rails will automatically load
+ # these gems during installation, and allow you to install any missing gems with:
+ #
+ # rake gems:install
+ #
+ # You can add with the #gem method.
+ attr_accessor :gems
+
+ # Adds a single Gem dependency to the rails application.
+ #
+ # # gem 'aws-s3', '>= 0.4.0'
+ # # require 'aws/s3'
+ # config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0', \
+ # :source => "http://code.whytheluckystiff.net"
+ #
+ def gem(name, options = {})
+ @gems << Rails::GemDependency.new(name, options)
+ end
# Deprecated options:
def breakpoint_server(_ = nil)
@@ -529,6 +565,7 @@ module Rails
self.plugin_locators = default_plugin_locators
self.plugin_loader = default_plugin_loader
self.database_configuration_file = default_database_configuration_file
+ self.gems = default_gems
for framework in default_frameworks
self.send("#{framework}=", Rails::OrderedOptions.new)
@@ -712,6 +749,10 @@ module Rails
:memory_store
end
end
+
+ def default_gems
+ []
+ end
end
end
diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb
new file mode 100644
index 0000000000..ed16464887
--- /dev/null
+++ b/railties/lib/rails/gem_dependency.rb
@@ -0,0 +1,78 @@
+module Rails
+ class GemDependency
+ attr_accessor :name, :requirement, :version, :lib, :source
+
+ def self.unpacked_path
+ @unpacked_path ||= File.join(RAILS_ROOT, 'vendor', 'gems')
+ end
+
+ def initialize(name, options = {})
+ @name = name.to_s
+ if options[:version]
+ @requirement = Gem::Requirement.create(options[:version])
+ @version = @requirement.requirements.first.last
+ end
+ @lib = options[:lib]
+ @source = options[:source]
+ @loaded = false
+ @load_paths_added = false
+ @unpack_directory = nil
+ end
+
+ def add_load_paths
+ return if @loaded || @load_paths_added
+ unpacked_paths = Dir[File.join(self.class.unpacked_path, "#{@name}-#{@version || "*"}")]
+ if unpacked_paths.empty?
+ args = [@name]
+ args << @requirement.to_s if @requirement
+ gem *args
+ else
+ $LOAD_PATH << File.join(unpacked_paths.first, 'lib')
+ end
+ @load_paths_added = true
+ rescue Gem::LoadError
+ puts $!.to_s
+ end
+
+ def load
+ return if @load_paths_added == false
+ require(@lib || @name)
+ @loaded = true
+ rescue LoadError
+ puts $!.to_s
+ $!.backtrace.each { |b| puts b }
+ end
+
+ def loaded?
+ @loaded
+ end
+
+ def load_paths_added?
+ @load_paths_added
+ end
+
+ def install
+ Gem::GemRunner.new.run(install_command)
+ end
+
+ def unpack_to(directory)
+ FileUtils.mkdir_p directory
+ Dir.chdir directory do
+ Gem::GemRunner.new.run(unpack_command)
+ end
+ end
+
+ def install_command
+ cmd = %w(install) << @name
+ cmd << "--version" << "#{@requirement.to_s}" if @requirement
+ cmd << "--source" << @source if @source
+ cmd
+ end
+
+ def unpack_command
+ cmd = %w(unpack) << @name
+ cmd << "--version" << "#{@requirement.to_s}" if @requirement
+ cmd
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/lib/tasks/gems.rake b/railties/lib/tasks/gems.rake
new file mode 100644
index 0000000000..198f6050c3
--- /dev/null
+++ b/railties/lib/tasks/gems.rake
@@ -0,0 +1,31 @@
+desc "List the gems that this rails application depends on"
+task :gems => :environment do
+ Rails.configuration.gems.each do |gem|
+ puts "[#{gem.loaded? ? '*' : ' '}] #{gem.name} #{gem.requirement.to_s}"
+ end
+end
+
+namespace :gems do
+ desc "Installs all required gems for this application."
+ task :install => :environment do
+ require 'rubygems'
+ require 'rubygems/gem_runner'
+ Rails.configuration.gems.each { |gem| gem.install unless gem.loaded? }
+ end
+
+ desc "Unpacks the specified gem into vendor/gems."
+ task :unpack do
+ raise "Specify name of gem in the config.gems array with GEM=" if ENV['GEM'].blank?
+ Rake::Task["environment"].invoke
+ require 'rubygems'
+ require 'rubygems/gem_runner'
+ unless Rails.configuration.gems.select do |gem|
+ if gem.loaded? && gem.name == ENV['GEM']
+ gem.unpack_to(File.join(RAILS_ROOT, 'vendor', 'gems'))
+ true
+ end
+ end.any?
+ puts "No gem named #{ENV['GEM'].inspect} found."
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/test/gem_dependency_test.rb b/railties/test/gem_dependency_test.rb
new file mode 100644
index 0000000000..887ad53589
--- /dev/null
+++ b/railties/test/gem_dependency_test.rb
@@ -0,0 +1,62 @@
+require 'plugin_test_helper'
+
+uses_mocha "Plugin Tests" do
+ class GemDependencyTest < Test::Unit::TestCase
+ def setup
+ @gem = Rails::GemDependency.new "hpricot"
+ @gem_with_source = Rails::GemDependency.new "hpricot", :source => "http://code.whytheluckystiff.net"
+ @gem_with_version = Rails::GemDependency.new "hpricot", :version => "= 0.6"
+ @gem_with_lib = Rails::GemDependency.new "aws-s3", :lib => "aws/s3"
+ end
+
+ def test_configuration_adds_gem_dependency
+ config = Rails::Configuration.new
+ config.gem "aws-s3", :lib => "aws/s3", :version => "0.4.0"
+ assert_equal [["install", "aws-s3", "--version", "= 0.4.0"]], config.gems.collect(&:install_command)
+ end
+
+ def test_gem_creates_install_command
+ assert_equal %w(install hpricot), @gem.install_command
+ end
+
+ def test_gem_with_source_creates_install_command
+ assert_equal %w(install hpricot --source http://code.whytheluckystiff.net), @gem_with_source.install_command
+ end
+
+ def test_gem_with_version_creates_install_command
+ assert_equal ["install", "hpricot", "--version", "= 0.6"], @gem_with_version.install_command
+ end
+
+ def test_gem_creates_unpack_command
+ assert_equal %w(unpack hpricot), @gem.unpack_command
+ end
+
+ def test_gem_with_version_unpack_install_command
+ assert_equal ["unpack", "hpricot", "--version", "= 0.6"], @gem_with_version.unpack_command
+ end
+
+ def test_gem_adds_load_paths
+ @gem.expects(:gem).with(@gem.name)
+ @gem.add_load_paths
+ end
+
+ def test_gem_with_version_adds_load_paths
+ @gem_with_version.expects(:gem).with(@gem_with_version.name, @gem_with_version.requirement.to_s)
+ @gem_with_version.add_load_paths
+ end
+
+ def test_gem_loading
+ @gem.expects(:gem).with(@gem.name)
+ @gem.expects(:require).with(@gem.name)
+ @gem.add_load_paths
+ @gem.load
+ end
+
+ def test_gem_with_lib_loading
+ @gem_with_lib.expects(:gem).with(@gem_with_lib.name)
+ @gem_with_lib.expects(:require).with(@gem_with_lib.lib)
+ @gem_with_lib.add_load_paths
+ @gem_with_lib.load
+ end
+ end
+end \ No newline at end of file