Not to beat a dead horse, but I threw together a few ideas for working
towards the plugins-as-gems approach.  Attached are two possible ways of
going about it.  They are not, by any means, complete solutions (or
completely tested solutions) but offer an insight at a possibility for
plugins.  Both patches basically replace the current plugin loading
mechanism with the gem system.  This way, we get support for versioning, the
gem repository, dependencies, etc.

For both patches, existing plugins would:
1. No longer need an init.rb
2. Follow the standard gem structure (i.e. my_plugin/lib/my_plugin.rb)
3. Need to create a Rakefile which defines the gem specification (which some
already do)

gem_always.diff - This patch assumes that everything (plugins and gems)
would exist under vendor/ (a true vendor everything).

gem_optional.diff - This patch would require config.plugin_loader to be set
to Rails::Plugin::GemLoader in order to use the gem system for loading
plugins.  This patch assumes that plugins and gems (except rails) would
exist under vendor/plugins.

Essentially, plugins would now simply refer to gems installed locally in the
application.  This would also mean that you wouldn't need to do anything
special for loading gems which are normally stored under vendor/ or
vendor/gems.

Anyway, what are everyone's thoughts?

On 9/19/07, Michael Koziarski <[EMAIL PROTECTED]> wrote:
>
>
> > Ignoring anything about requiring specific versions, couldn't this be
> > achieved by having all of the plugins added to the load path before
> > any init.rb files are evaluated (my suggestion above)? That way the
> > normal Ruby "require" would seem to provide everything that you
> > describe here.
>
> This sounds like it's probably harmless and could solve a bunch of the
> different issues people have been mentioning.  If you wanted to take a
> look at this, I'd be happy to apply it.
>
> We're definitely not going to go down the route of a massive
> dependency system of our own.  Rubygems does this kind of thing
> already, and perhaps we just need to go down the plugins-as-gems
> approach.
>
> Either way,  I'd be open to applying a patch to add :all to
> config.plugins or the load order changing,  but that's about it for
> 2.0.
>
> --
> Cheers
>
> Koz
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-core?hl=en
-~----------~----~----~----~------~----~------~--~---

Index: railties/lib/initializer.rb
===================================================================
--- railties/lib/initializer.rb	(revision 7515)
+++ railties/lib/initializer.rb	(working copy)
@@ -180,6 +180,18 @@
     def load_plugins
       configuration.plugin_locators.each do |locator|
         locator.new(self).each do |plugin|
+          plugin.add_gemspec
+        end
+      end
+
+      configuration.plugin_locators.each do |locator|
+        locator.new(self).each do |plugin|
+          plugin.load_gemspec
+        end
+      end
+
+      configuration.plugin_locators.each do |locator|
+        locator.new(self).each do |plugin|
           plugin.load
         end
       end
@@ -634,7 +646,7 @@
       end
 
       def default_plugin_paths
-        ["#{root_path}/vendor/plugins"]
+        ["#{root_path}/vendor"]
       end
 
       def default_plugin_locators
Index: railties/lib/rails/plugin/locator.rb
===================================================================
--- railties/lib/rails/plugin/locator.rb	(revision 7515)
+++ railties/lib/rails/plugin/locator.rb	(working copy)
@@ -48,7 +48,7 @@
               plugin_loader = initializer.configuration.plugin_loader.new(initializer, path)
               if plugin_loader.plugin_path? && plugin_loader.enabled?
                 plugins << plugin_loader
-              elsif File.directory?(path)
+              elsif File.directory?(path) && File.basename(path) != 'rails'
                 plugins.concat locate_plugins_under(path)
               end
               plugins
@@ -56,4 +56,4 @@
           end
     end
   end
-end
\ No newline at end of file
+end
Index: railties/lib/rails/plugin/loader.rb
===================================================================
--- railties/lib/rails/plugin/loader.rb	(revision 7515)
+++ railties/lib/rails/plugin/loader.rb	(working copy)
@@ -25,12 +25,20 @@
         true
       end
   
+      def add_gemspec
+        Gem.source_index.add_spec(gemspec) if gemspec
+      end
+  
+      def load_gemspec
+        gem gemspec.name if gemspec
+      end
+  
       def loaded?
         initializer.loaded_plugins.include?(name)
       end
   
       def plugin_path?
-        File.directory?(directory) && (has_lib_directory? || has_init_file?)
+        File.directory?(directory) && has_rakefile? && gemspec
       end
       
       def enabled?
@@ -66,33 +74,49 @@
           File.join(directory, 'lib')
         end
   
-        def init_path
-          File.join(directory, 'init.rb')
+        def rakefile_path
+          File.join(directory, 'Rakefile')
         end
   
         def has_lib_directory?
           File.directory?(lib_path)
         end
+        
+        def has_rakefile?
+          File.file?(rakefile_path)
+        end
   
-        def has_init_file?
-          File.file?(init_path)
+        def gemspec
+          unless @gemspec
+            yaml = `cd #{directory} && ruby -e "require 'rubygems'; gemspec = Gem::Specification.load('#{rakefile_path}'); puts gemspec.to_yaml if gemspec"`
+            
+            unless yaml.blank?
+              @gemspec = Gem::Specification.from_yaml(yaml)
+              @gemspec.loaded_from = rakefile_path
+              class << @gemspec
+                def full_gem_path
+                  File.join(installation_path, File.dirname(@loaded_from).split(File::SEPARATOR)[-1])
+                end
+              end
+            end
+          end
+          
+          @gemspec
         end
+      
+        def application_library_path
+          File.join(RAILS_ROOT, 'lib')
+        end
   
         def add_to_load_path!
           # Add lib to load path *after* the application lib, to allow
           # application libraries to override plugin libraries.
           if has_lib_directory?
-            application_lib_index = $LOAD_PATH.index(application_library_path) || 0
-            $LOAD_PATH.insert(application_lib_index + 1, lib_path)
             Dependencies.load_paths      << lib_path
             Dependencies.load_once_paths << lib_path
           end
         end
       
-        def application_library_path
-          File.join(RAILS_ROOT, 'lib')
-        end
-  
         # Allow plugins to reference the current configuration object
         def config
           initializer.configuration
@@ -102,9 +126,9 @@
           initializer.loaded_plugins << name
         end
   
-        # Evaluate in init.rb
+        # Load the gem
         def evaluate
-          silence_warnings { eval(IO.read(init_path), binding, init_path)} if has_init_file?
+          require gemspec.name
         end
       
         def <=>(other_plugin_loader)

Index: railties/lib/rails/plugin/gem_loader.rb
===================================================================
--- railties/lib/rails/plugin/gem_loader.rb	(revision 0)
+++ railties/lib/rails/plugin/gem_loader.rb	(revision 0)
@@ -0,0 +1,91 @@
+module Rails
+  module Plugin
+    class GemLoader < Loader
+      @@loaded_gemspecs = false
+      
+      def load
+        load_gemspecs
+        super
+      end
+      
+      def add_gemspec
+        Gem.source_index.add_spec(gemspec) if gemspec
+      end
+      
+      def load_gemspec
+        gem gemspec.name if gemspec
+      end
+      
+      def plugin_path?
+        File.directory?(directory) && has_rakefile? && gemspec
+      end
+      
+      private
+        def load_gemspecs
+          unless @@loaded_gemspecs
+            initializer.configuration.plugin_locators.each do |locator|
+              locator.new(initializer).each do |plugin|
+                plugin.add_gemspec
+              end
+            end
+
+            initializer.configuration.plugin_locators.each do |locator|
+              locator.new(initializer).each do |plugin|
+                plugin.load_gemspec
+              end
+            end
+            
+            @@loaded_gemspecs = true
+          end
+        end
+        
+        def lib_file_path
+          File.join(lib_path, "#{gemspec.name}.rb")
+        end
+        
+        def rakefile_path
+          File.join(directory, 'Rakefile')
+        end
+        
+        def has_lib_file?
+          File.file?(lib_file_path)
+        end
+        
+        def has_rakefile?
+          File.file?(rakefile_path)
+        end
+        
+        def gemspec
+          unless @gemspec
+            yaml = `cd #{directory} && ruby -e "require 'rubygems'; gemspec = Gem::Specification.load('#{rakefile_path}'); puts gemspec.to_yaml if gemspec"`
+            
+            unless yaml.blank?
+              @gemspec = Gem::Specification.from_yaml(yaml)
+              @gemspec.loaded_from = rakefile_path
+              class << @gemspec
+                def full_gem_path
+                  File.join(installation_path, File.dirname(@loaded_from).split(File::SEPARATOR)[-1])
+                end
+              end
+            end
+          end
+          
+          @gemspec
+        end
+        
+        def add_to_load_path!
+          # Add lib to load path *after* the application lib, to allow
+          # application libraries to override plugin libraries.
+          if has_lib_directory?
+            Dependencies.load_paths      << lib_path
+            Dependencies.load_once_paths << lib_path
+          end
+        end
+        
+        # Load the gem
+        def evaluate
+          require lib_file_path if has_lib_file?
+        end
+    end
+  end
+end

Reply via email to