diff --git a/lib/radiant/extension_loader.rb b/lib/radiant/extension_loader.rb index c5ef7374f..21542ec3d 100644 --- a/lib/radiant/extension_loader.rb +++ b/lib/radiant/extension_loader.rb @@ -73,7 +73,7 @@ def load_extensions @observer ||= DependenciesObserver.new(configuration).observe(::ActiveSupport::Dependencies) self.extensions = load_extension_roots.map do |root| begin - extension_file = "#{File.basename(root).sub(/^\d+_/,'')}_extension" + extension_file = "#{File.basename(root).sub(/^\d+_|-[\d.]+$/,'')}_extension" extension = extension_file.camelize.constantize extension.unloadable extension.root = root @@ -124,19 +124,17 @@ def load_extension_roots def select_extension_roots all_roots = all_extension_roots.dup - roots = configuration.extensions.map do |ext_name| if :all === ext_name :all else ext_path = all_roots.detect do |maybe_path| - File.basename(maybe_path).sub(/^\d+_/, '') == ext_name.to_s + File.basename(maybe_path).sub(/^\d+_|-[\d.]+$/, '') == ext_name.to_s end raise LoadError, "Cannot find the extension '#{ext_name}'!" if ext_path.nil? all_roots.delete(ext_path) end end - if placeholder = roots.index(:all) # replace the :all symbol with any remaining paths roots[placeholder, 1] = all_roots @@ -145,9 +143,16 @@ def select_extension_roots end def all_extension_roots - @all_extension_roots ||= configuration.extension_paths.map do |path| - Dir["#{path}/*"].map {|f| File.expand_path(f) if File.directory?(f) }.compact.sort - end.flatten + @all_extension_roots ||= begin + roots = configuration.extension_paths.map do |path| + Dir["#{path}/*"].map {|f| File.expand_path(f) if File.directory?(f) }.compact.sort + end + configuration.gems.inject(roots) do |paths,gem| + paths.tap { |p| p << gem.specification.full_gem_path if gem.specification and Dir[gem.specification.full_gem_path+'/*_extension.rb'].any? } + end + roots.flatten + end end + end end diff --git a/lib/radiant/initializer.rb b/lib/radiant/initializer.rb index 99a9f35c2..70ee55f8b 100644 --- a/lib/radiant/initializer.rb +++ b/lib/radiant/initializer.rb @@ -35,9 +35,16 @@ def extensions end def all_available_extensions - extension_paths.map do |path| + # load vendorized extensions by inspecting load path(s) + all = extension_paths.map do |path| Dir["#{path}/*"].select {|f| File.directory?(f) } - end.flatten.map {|f| File.basename(f).sub(/^\d+_/, '') }.sort.map {|e| e.to_sym } + end + # load any gem that looks like an extension. (too informal?) + gems.inject(all) do |available,gem| + available.tap { |a| a << gem.specification.full_gem_path if gem.specification and Dir[gem.specification.full_gem_path + '/*_extension.rb' ].any? } + end + # strip version info to glean proper extension names + all.flatten.map {|f| File.basename(f).sub(/^\d+_|-[\d\.]+$/, '') }.sort.map {|e| e.to_sym } end def admin diff --git a/spec/lib/radiant/extension_loader_spec.rb b/spec/lib/radiant/extension_loader_spec.rb index 338a956ab..2153b6f2a 100644 --- a/spec/lib/radiant/extension_loader_spec.rb +++ b/spec/lib/radiant/extension_loader_spec.rb @@ -35,6 +35,13 @@ @instance.send(:select_extension_roots).should == [File.expand_path("#{RADIANT_ROOT}/test/fixtures/extensions/01_basic")] end + it "should load extensions from gem paths" do + gem_path = File.join RADIANT_ROOT, %w(test fixtures gems gem_ext-0.0.0) + @configuration.should_receive(:extensions).at_least(:once).and_return([:gem_ext]) + @instance.stub!(:all_extension_roots).and_return([File.expand_path gem_path]) + @instance.send(:select_extension_roots).should == [gem_path] + end + it "should select extensions in an explicit order from the configuration" do extensions = [:load_order_red, :load_order_blue, :load_order_green] extension_roots = extensions.map {|ext| File.expand_path("#{RADIANT_ROOT}/test/fixtures/extensions/#{ext}") } @@ -58,6 +65,12 @@ lambda { @instance.send(:select_extension_roots) }.should raise_error(LoadError) end + it "should skip invalid gems" do + @configuration.stub!(:extension_paths).and_return([]) + @configuration.stub!(:gems).and_return([Rails::GemDependency.new('bogus_gem')]) + @instance.send(:all_extension_roots).should eql([]) + end + it "should determine load paths from an extension path" do @instance.send(:load_paths_for, "#{RADIANT_ROOT}/vendor/extensions/archive").should == %W{ #{RADIANT_ROOT}/vendor/extensions/archive/lib diff --git a/spec/lib/radiant/initializer_spec.rb b/spec/lib/radiant/initializer_spec.rb index 22132111a..65effe566 100644 --- a/spec/lib/radiant/initializer_spec.rb +++ b/spec/lib/radiant/initializer_spec.rb @@ -70,6 +70,29 @@ @configuration.check_extension_dependencies }.should raise_error(SystemExit) end + + describe "#all_available_extensions" do + before do + @spec = mock(Gem::Specification) + @gem = mock(Rails::GemDependency, :specification => @spec) + @configuration.gems = [@gem] + end + + it "should include valid gems" do + @spec.stub!(:full_gem_path).and_return(File.join RADIANT_ROOT, %w(test fixtures gems gem_ext-0.0.0)) + @configuration.all_available_extensions.should include(:gem_ext) + end + + it "should not load gems that don't appear to be extensions" do + @spec.stub!(:full_gem_path).and_return(File.join RADIANT_ROOT, %w(test fixtures gems not_ext-0.0.0)) + @configuration.all_available_extensions.should_not include(:not_ext) + end + + it "should skip gems with invalid specifications" do + @configuration.gems = [Rails::GemDependency.new 'bogus_gem'] + @configuration.all_available_extensions.should_not include(:bogus_gem) + end + end end describe Radiant::Initializer do diff --git a/test/fixtures/gems/gem_ext-0.0.0/gem_ext_extension.rb b/test/fixtures/gems/gem_ext-0.0.0/gem_ext_extension.rb new file mode 100644 index 000000000..1ea2f7892 --- /dev/null +++ b/test/fixtures/gems/gem_ext-0.0.0/gem_ext_extension.rb @@ -0,0 +1,2 @@ +class GemExtExtension +end \ No newline at end of file