Ticket #6726: add_elective_gem_plugin_support.diff
| File add_elective_gem_plugin_support.diff, 9.6 kB (added by wbruce, 2 years ago) |
|---|
-
railties/test/plugin_test.rb
old new 31 31 assert !@init.send(:plugin_path?, "#{File.dirname(__FILE__)}/fixtures/plugins/default/jalskdjflkas") 32 32 end 33 33 34 def test_find_plugin s34 def test_find_plugin_paths 35 35 base = "#{File.dirname(__FILE__)}/fixtures/plugins" 36 36 default = "#{base}/default" 37 37 alt = "#{base}/alternate" 38 38 acts = "#{default}/acts" 39 assert_equal ["#{acts}/acts_as_chunky_bacon"], @init.send(:find_plugin s, acts)40 assert_equal ["#{acts}/acts_as_chunky_bacon", "#{default}/stubby"], @init.send(:find_plugin s, default).sort41 assert_equal ["#{alt}/a", "#{acts}/acts_as_chunky_bacon", "#{default}/stubby"], @init.send(:find_plugin s, base).sort39 assert_equal ["#{acts}/acts_as_chunky_bacon"], @init.send(:find_plugin_paths, acts) 40 assert_equal ["#{acts}/acts_as_chunky_bacon", "#{default}/stubby"], @init.send(:find_plugin_paths, default).sort 41 assert_equal ["#{alt}/a", "#{acts}/acts_as_chunky_bacon", "#{default}/stubby"], @init.send(:find_plugin_paths, base).sort 42 42 end 43 43 44 def test_load_plugin 44 def test_load_plugin_path 45 45 stubby = "#{File.dirname(__FILE__)}/fixtures/plugins/default/stubby" 46 46 expected = Set.new(['stubby']) 47 47 48 assert @init.send(:load_plugin , stubby)48 assert @init.send(:load_plugin_path, stubby) 49 49 assert_equal expected, @init.loaded_plugins 50 50 51 assert !@init.send(:load_plugin , stubby)51 assert !@init.send(:load_plugin_path, stubby) 52 52 assert_equal expected, @init.loaded_plugins 53 53 54 assert_raise(LoadError) { @init.send(:load_plugin , 'lakjsdfkasljdf') }54 assert_raise(LoadError) { @init.send(:load_plugin_path, 'lakjsdfkasljdf') } 55 55 assert_equal expected, @init.loaded_plugins 56 56 end 57 57 -
railties/lib/initializer.rb
old new 99 99 # could overwrite anything set from the defaults/global through 100 100 # the individual base class configurations. 101 101 load_environment 102 103 load_plugins 102 104 103 105 add_support_load_paths 104 106 105 load_plugins106 107 107 # Observers are loaded after plugins in case Observers or observed models are modified by plugins. 108 108 load_observers 109 109 … … 166 166 def add_support_load_paths 167 167 end 168 168 169 # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt> 169 # Loads all plugins in <tt>config.plugin_paths</tt>, then attempts to load 170 # any RubyGem plugins listed in <tt>config.plugins</tt>. 171 # 172 # <tt>plugin_paths</tt> 170 173 # defaults to <tt>vendor/plugins</tt> but may also be set to a list of 171 174 # paths, such as 172 175 # config.plugin_paths = ['lib/plugins', 'vendor/plugins'] 173 176 # 174 # Each plugin discovered in <tt>plugin_paths</tt> is initialized: 175 # * add its +lib+ directory, if present, to the beginning of the load path 176 # * evaluate <tt>init.rb</tt> if present 177 # <tt>plugins</tt> is the list of plugins to enable (either in in <tt>plugin_paths</tt> 178 # or from gems). For RubyGem plugins to be loaded, they need to be in this list (incidently, 179 # if you're mixing plugins from <tt>plugin_paths</tt> as well, you'll need to include them in 180 # this list also if you want them loaded) 177 181 # 182 # To include version requirements for a gem plugin, use an array (like the arguments you'd pass 183 # to <tt>require_gem</tt>), such as 184 # config.plugins = ['foo', ['bar', '>1.0.7', '<=1.0.9'], 'baz'] 185 # 178 186 # After all plugins are loaded, duplicates are removed from the load path. 179 # Plugins are loaded in alphabetical order. 187 # Plugins are loaded in alphabetical order; plugins from <tt>plugin_paths</tt> first, then 188 # gem plugins. 180 189 def load_plugins 181 find_plugins(configuration.plugin_paths).sort.each { |path| load_plugin path } 190 find_plugin_paths(configuration.plugin_paths).sort.each { |path| load_plugin_path(path) } 191 load_paths_before_gems = configuration.load_paths.size 192 find_gem_plugins.sort_by{|p| p.last.name }.each do |plugin, gemspec| 193 load_gem_plugin(plugin, gemspec) 194 end 195 # Add gem load paths, if changed 196 if configuration.load_paths.size > load_paths_before_gems 197 set_load_path 198 set_autoload_paths 199 end 182 200 $LOAD_PATH.uniq! 183 201 end 184 202 … … 323 341 end 324 342 325 343 protected 344 326 345 # Return a list of plugin paths within base_path. A plugin path is 327 346 # a directory that contains either a lib directory or an init.rb file. 328 347 # This recurses into directories which are not plugin paths, so you 329 348 # may organize your plugins within the plugin path. 330 def find_plugin s(*base_paths)349 def find_plugin_paths(*base_paths) 331 350 base_paths.flatten.inject([]) do |plugins, base_path| 332 351 Dir.glob(File.join(base_path, '*')).each do |path| 333 352 if plugin_path?(path) 334 plugins << path if plugin_ enabled?(path)353 plugins << path if plugin_path_enabled?(path) 335 354 elsif File.directory?(path) 336 plugins += find_plugin s(path)355 plugins += find_plugin_paths(path) 337 356 end 338 357 end 339 358 plugins 340 359 end 341 360 end 361 362 # Return a list of plugins and related gemspecs for plugins set in <tt>configuration.plugins</tt> 363 # and available as RubyGems (when not already loaded from <tt>find_plugins_paths</tt>). 364 def find_gem_plugins 365 configuration.plugins.inject([]) do |plugins,plugin| 366 next plugins if loaded_plugins.include?(plugin) 367 name, version_requirements = plugin.to_a 368 gem = Gem::Dependency.new(name, version_requirements || []) 369 if gemspec = Gem.source_index.find_name(gem.name, gem.version_requirements).last 370 plugins.push([plugin, gemspec]) 371 end 372 plugins 373 end 374 end 342 375 343 376 def plugin_path?(path) 344 377 File.directory?(path) and (File.directory?(File.join(path, 'lib')) or File.file?(File.join(path, 'init.rb'))) 345 378 end 346 379 347 def plugin_ enabled?(path)380 def plugin_path_enabled?(path) 348 381 configuration.plugins.empty? || configuration.plugins.include?(File.basename(path)) 349 382 end 350 383 … … 357 390 # Returns <tt>true</tt> if the plugin is successfully loaded or 358 391 # <tt>false</tt> if it is already loaded (similar to Kernel#require). 359 392 # Raises <tt>LoadError</tt> if the plugin is not found. 360 def load_plugin (directory)393 def load_plugin_path(directory) 361 394 name = File.basename(directory) 395 # Check this just in case, even though <tt>find_gem_plugins</tt> does when used normally 362 396 return false if loaded_plugins.include?(name) 363 397 364 398 # Catch nonexistent and empty plugins. … … 366 400 367 401 lib_path = File.join(directory, 'lib') 368 402 init_path = File.join(directory, 'init.rb') 369 has_lib = File.directory?(lib_path) 370 has_init = File.file?(init_path) 371 372 # Add lib to load path *after* the application lib, to allow 373 # application libraries to override plugin libraries. 374 if has_lib 403 404 if File.directory?(lib_path) 375 405 application_lib_index = $LOAD_PATH.index(File.join(RAILS_ROOT, "lib")) || 0 376 406 $LOAD_PATH.insert(application_lib_index + 1, lib_path) 377 407 end 378 379 # Allow plugins to reference the current configuration object 380 config = configuration 381 408 382 409 # Add to set of loaded plugins before 'name' collapsed in eval. 383 410 loaded_plugins << name 384 411 385 # Evaluate init.rb. 386 silence_warnings { eval(IO.read(init_path), binding, init_path) } if has_init 387 412 if File.file?(init_path) 413 # Allow plugins to reference the current configuration object 414 config = configuration 415 # Evaluate init.rb. 416 silence_warnings { eval(IO.read(init_path), binding, init_path) } 417 end 418 388 419 true 389 420 end 421 422 # Load plugin from RubyGem unless already loaded. 423 # 424 # Each plugin is initialized: 425 # * the gem is required (and its <tt>autorequire</tt>s automatically, too) 426 # * add its +lib+ directory, if present, to the beginning of the load path 427 # * evaluate <tt>init.rb</tt> if present 428 # 429 # Returns <tt>true</tt> if the plugin is successfully loaded or 430 # <tt>false</tt> if it is already loaded (similar to Kernel#require). 431 # Raises <tt>LoadError</tt> if the plugin is not found. 432 def load_gem_plugin(plugin, gemspec) 433 return false if loaded_plugins.include?(plugin) 434 require_gem gemspec.name, gemspec.version.version 435 directory = gemspec.full_gem_path 436 lib_path = File.join(directory, 'lib') 437 init_path = File.join(directory, 'init.rb') 438 439 if File.directory?(lib_path) 440 configuration.load_paths << lib_path 441 # Circumvent freeze 442 configuration.load_once_paths = configuration.load_once_paths.dup + [lib_path] 443 end 444 445 if File.file?(init_path) 446 # Allow plugins to reference the current configuration object 447 config = configuration 448 # Evaluate init.rb. 449 silence_warnings { eval(IO.read(init_path), binding, init_path) } 450 end 451 452 rescue LoadError => e 453 raise LoadError, "No such gem plugin: #{plugin.inspect} (#{e.message})" 454 end 455 390 456 end 391 457 392 458 # The Configuration class holds all the parameters for the Initializer and