ioquatix-engines 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/CHANGELOG +280 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +95 -0
  4. data/Rakefile +199 -0
  5. data/about.yml +7 -0
  6. data/bin/rails_engines +103 -0
  7. data/generators/plugin_migration/USAGE +45 -0
  8. data/generators/plugin_migration/plugin_migration_generator.rb +78 -0
  9. data/generators/plugin_migration/templates/plugin_migration.erb +13 -0
  10. data/lib/engines.rb +185 -0
  11. data/lib/engines/assets.rb +38 -0
  12. data/lib/engines/load_engine_tasks.rake +6 -0
  13. data/lib/engines/plugin.rb +173 -0
  14. data/lib/engines/plugin/list.rb +57 -0
  15. data/lib/engines/plugin/migrator.rb +45 -0
  16. data/lib/engines/rails_extensions/action_mailer.rb +85 -0
  17. data/lib/engines/rails_extensions/asset_helpers.rb +149 -0
  18. data/lib/engines/rails_extensions/dependencies.rb +151 -0
  19. data/lib/engines/rails_extensions/routing.rb +88 -0
  20. data/lib/engines/testing.rb +87 -0
  21. data/lib/engines/version.rb +10 -0
  22. data/rails/init.rb +6 -0
  23. data/tasks/engines.rake +249 -0
  24. data/test/app/controllers/app_and_plugin_controller.rb +5 -0
  25. data/test/app/controllers/application.rb +18 -0
  26. data/test/app/controllers/namespace/app_and_plugin_controller.rb +5 -0
  27. data/test/app/helpers/mail_helper.rb +5 -0
  28. data/test/app/models/app_and_plugin_model.rb +3 -0
  29. data/test/app/models/notify_mail.rb +26 -0
  30. data/test/app/things/thing.rb +3 -0
  31. data/test/app/views/app_and_plugin/a_view.html.erb +1 -0
  32. data/test/app/views/namespace/app_and_plugin/a_view.html.erb +1 -0
  33. data/test/app/views/notify_mail/implicit_multipart.text.html.erb +1 -0
  34. data/test/app/views/notify_mail/implicit_multipart.text.plain.erb +1 -0
  35. data/test/app/views/notify_mail/multipart_html.html.erb +1 -0
  36. data/test/app/views/notify_mail/multipart_plain.html.erb +1 -0
  37. data/test/app/views/notify_mail/signup.text.plain.erb +5 -0
  38. data/test/app/views/plugin_mail/mail_from_plugin_with_application_template.text.plain.erb +1 -0
  39. data/test/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb +1 -0
  40. data/test/functional/controller_loading_test.rb +51 -0
  41. data/test/functional/exception_notification_compatibility_test.rb +29 -0
  42. data/test/functional/routes_test.rb +33 -0
  43. data/test/functional/view_helpers_test.rb +32 -0
  44. data/test/functional/view_loading_test.rb +60 -0
  45. data/test/lib/app_and_plugin_lib_model.rb +3 -0
  46. data/test/lib/engines_test_helper.rb +36 -0
  47. data/test/plugins/alpha_plugin/app/controllers/alpha_plugin_controller.rb +8 -0
  48. data/test/plugins/alpha_plugin/app/controllers/app_and_plugin_controller.rb +5 -0
  49. data/test/plugins/alpha_plugin/app/controllers/namespace/alpha_plugin_controller.rb +5 -0
  50. data/test/plugins/alpha_plugin/app/controllers/namespace/app_and_plugin_controller.rb +5 -0
  51. data/test/plugins/alpha_plugin/app/controllers/namespace/shared_plugin_controller.rb +5 -0
  52. data/test/plugins/alpha_plugin/app/controllers/shared_plugin_controller.rb +5 -0
  53. data/test/plugins/alpha_plugin/app/models/alpha_plugin_model.rb +3 -0
  54. data/test/plugins/alpha_plugin/app/models/app_and_plugin_model.rb +7 -0
  55. data/test/plugins/alpha_plugin/app/models/shared_plugin_model.rb +3 -0
  56. data/test/plugins/alpha_plugin/app/views/alpha_plugin/a_view.html.erb +1 -0
  57. data/test/plugins/alpha_plugin/app/views/app_and_plugin/a_view.html.erb +1 -0
  58. data/test/plugins/alpha_plugin/app/views/layouts/plugin_layout.erb +1 -0
  59. data/test/plugins/alpha_plugin/app/views/namespace/alpha_plugin/a_view.html.erb +1 -0
  60. data/test/plugins/alpha_plugin/app/views/namespace/app_and_plugin/a_view.html.erb +1 -0
  61. data/test/plugins/alpha_plugin/app/views/namespace/shared_plugin/a_view.html.erb +1 -0
  62. data/test/plugins/alpha_plugin/app/views/shared_plugin/a_view.html.erb +1 -0
  63. data/test/plugins/alpha_plugin/lib/alpha_plugin_lib_model.rb +3 -0
  64. data/test/plugins/alpha_plugin/lib/app_and_plugin_lib_model.rb +7 -0
  65. data/test/plugins/beta_plugin/app/controllers/app_and_plugin_controller.rb +5 -0
  66. data/test/plugins/beta_plugin/app/controllers/namespace/shared_plugin_controller.rb +5 -0
  67. data/test/plugins/beta_plugin/app/controllers/shared_plugin_controller.rb +5 -0
  68. data/test/plugins/beta_plugin/app/models/shared_plugin_model.rb +3 -0
  69. data/test/plugins/beta_plugin/app/views/namespace/shared_plugin/a_view.html.erb +1 -0
  70. data/test/plugins/beta_plugin/app/views/shared_plugin/a_view.html.erb +1 -0
  71. data/test/plugins/beta_plugin/init.rb +1 -0
  72. data/test/plugins/not_a_plugin/public/should_not_be_copied.txt +0 -0
  73. data/test/plugins/test_assets/app/controllers/assets_controller.rb +2 -0
  74. data/test/plugins/test_assets/app/views/assets/index.html.erb +3 -0
  75. data/test/plugins/test_assets/app/views/layouts/assets.html.erb +3 -0
  76. data/test/plugins/test_assets/init.rb +0 -0
  77. data/test/plugins/test_assets/public/file.txt +0 -0
  78. data/test/plugins/test_assets/public/subfolder/file_in_subfolder.txt +0 -0
  79. data/test/plugins/test_assets_with_assets_directory/assets/file.txt +0 -0
  80. data/test/plugins/test_assets_with_assets_directory/assets/subfolder/file_in_subfolder.txt +0 -0
  81. data/test/plugins/test_assets_with_assets_directory/init.rb +0 -0
  82. data/test/plugins/test_assets_with_no_subdirectory/assets/file.txt +0 -0
  83. data/test/plugins/test_assets_with_no_subdirectory/init.rb +0 -0
  84. data/test/plugins/test_code_mixing/app/things/thing.rb +3 -0
  85. data/test/plugins/test_code_mixing/init.rb +1 -0
  86. data/test/plugins/test_load_path/init.rb +0 -0
  87. data/test/plugins/test_migration/db/migrate/001_create_tests.rb +11 -0
  88. data/test/plugins/test_migration/db/migrate/002_create_others.rb +11 -0
  89. data/test/plugins/test_migration/db/migrate/003_create_extras.rb +11 -0
  90. data/test/plugins/test_migration/init.rb +0 -0
  91. data/test/plugins/test_plugin_mailing/app/models/plugin_mail.rb +26 -0
  92. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/mail_from_plugin.text.plain.erb +1 -0
  93. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_html.html.erb +1 -0
  94. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_plain.html.erb +1 -0
  95. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_html.html.erb +1 -0
  96. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb +1 -0
  97. data/test/plugins/test_plugin_mailing/init.rb +0 -0
  98. data/test/plugins/test_routing/app/controllers/namespace/test_routing_controller.rb +5 -0
  99. data/test/plugins/test_routing/app/controllers/test_routing_controller.rb +9 -0
  100. data/test/plugins/test_routing/init.rb +0 -0
  101. data/test/plugins/test_routing/routes.rb +2 -0
  102. data/test/plugins/test_testing/init.rb +0 -0
  103. data/test/plugins/test_testing/test/fixtures/testing_fixtures.yml +0 -0
  104. data/test/unit/action_mailer_test.rb +54 -0
  105. data/test/unit/arbitrary_code_mixing_test.rb +41 -0
  106. data/test/unit/assets_test.rb +48 -0
  107. data/test/unit/load_path_test.rb +58 -0
  108. data/test/unit/migration_test.rb +63 -0
  109. data/test/unit/model_and_lib_test.rb +37 -0
  110. data/test/unit/plugins_test.rb +11 -0
  111. data/test/unit/testing_test.rb +18 -0
  112. metadata +259 -0
@@ -0,0 +1,151 @@
1
+ # One of the magic features that that engines plugin provides is the ability to
2
+ # override selected methods in controllers and helpers from your application.
3
+ # This is achieved by trapping requests to load those files, and then mixing in
4
+ # code from plugins (in the order the plugins were loaded) before finally loading
5
+ # any versions from the main +app+ directory.
6
+ #
7
+ # The behaviour of this extension is output to the log file for help when
8
+ # debugging.
9
+ #
10
+ # == Example
11
+ #
12
+ # A plugin contains the following controller in <tt>plugin/app/controllers/my_controller.rb</tt>:
13
+ #
14
+ # class MyController < ApplicationController
15
+ # def index
16
+ # @name = "HAL 9000"
17
+ # end
18
+ # def list
19
+ # @robots = Robot.find(:all)
20
+ # end
21
+ # end
22
+ #
23
+ # In one application that uses this plugin, we decide that the name used in the
24
+ # index action should be "Robbie", not "HAL 9000". To override this single method,
25
+ # we create the corresponding controller in our application
26
+ # (<tt>RAILS_ROOT/app/controllers/my_controller.rb</tt>), and redefine the method:
27
+ #
28
+ # class MyController < ApplicationController
29
+ # def index
30
+ # @name = "Robbie"
31
+ # end
32
+ # end
33
+ #
34
+ # The list method remains as it was defined in the plugin controller.
35
+ #
36
+ # The same basic principle applies to helpers, and also views and partials (although
37
+ # view overriding is performed in Engines::RailsExtensions::Templates; see that
38
+ # module for more information).
39
+ #
40
+ # === What about models?
41
+ #
42
+ # Unfortunately, it's not possible to provide this kind of magic for models.
43
+ # The only reason why it's possible for controllers and helpers is because
44
+ # they can be recognised by their filenames ("whatever_controller", "jazz_helper"),
45
+ # whereas models appear the same as any other typical Ruby library ("node",
46
+ # "user", "image", etc.).
47
+ #
48
+ # If mixing were allowed in models, it would mean code mixing for *every*
49
+ # file that was loaded via +require_or_load+, and this could result in
50
+ # problems where, for example, a Node model might start to include
51
+ # functionality from another file called "node" somewhere else in the
52
+ # <tt>$LOAD_PATH</tt>.
53
+ #
54
+ # One way to overcome this is to provide model functionality as a module in
55
+ # a plugin, which developers can then include into their own model
56
+ # implementations.
57
+ #
58
+ # Another option is to provide an abstract model (see the ActiveRecord::Base
59
+ # documentation) and have developers subclass this model in their own
60
+ # application if they must.
61
+ #
62
+ # ---
63
+ #
64
+ # The Engines::RailsExtensions::Dependencies module includes a method to
65
+ # override Dependencies.require_or_load, which is called to load code needed
66
+ # by Rails as it encounters constants that aren't defined.
67
+ #
68
+ # This method is enhanced with the code-mixing features described above.
69
+ #
70
+ module Engines::RailsExtensions::Dependencies
71
+ def self.included(base) #:nodoc:
72
+ base.class_eval { alias_method_chain :require_or_load, :engine_additions }
73
+ end
74
+
75
+ # Attempt to load the given file from any plugins, as well as the application.
76
+ # This performs the 'code mixing' magic, allowing application controllers and
77
+ # helpers to override single methods from those in plugins.
78
+ # If the file can be found in any plugins, it will be loaded first from those
79
+ # locations. Finally, the application version is loaded, using Ruby's behaviour
80
+ # to replace existing methods with their new definitions.
81
+ #
82
+ # If <tt>Engines.disable_code_mixing == true</tt>, the first controller/helper on the
83
+ # <tt>$LOAD_PATH</tt> will be used (plugins' +app+ directories are always lower on the
84
+ # <tt>$LOAD_PATH</tt> than the main +app+ directory).
85
+ #
86
+ # If <tt>Engines.disable_application_code_loading == true</tt>, controllers will
87
+ # not be loaded from the main +app+ directory *if* they are present in any
88
+ # plugins.
89
+ #
90
+ # Returns true if the file could be loaded (from anywhere); false otherwise -
91
+ # mirroring the behaviour of +require_or_load+ from Rails (which mirrors
92
+ # that of Ruby's own +require+, I believe).
93
+ def require_or_load_with_engine_additions(file_name, const_path=nil)
94
+ return require_or_load_without_engine_additions(file_name, const_path) if Engines.disable_code_mixing
95
+
96
+ file_loaded = false
97
+
98
+ # try and load the plugin code first
99
+ # can't use model, as there's nothing in the name to indicate that the file is a 'model' file
100
+ # rather than a library or anything else.
101
+ Engines.code_mixing_file_types.each do |file_type|
102
+ # if we recognise this type
103
+ # (this regexp splits out the module/filename from any instances of app/#{type}, so that
104
+ # modules are still respected.)
105
+ if file_name =~ /^(.*app\/#{file_type}s\/)?(.*_#{file_type})(\.rb)?$/
106
+ base_name = $2
107
+ # ... go through the plugins from first started to last, so that
108
+ # code with a high precedence (started later) will override lower precedence
109
+ # implementations
110
+ Engines.plugins.each do |plugin|
111
+ plugin_file_name = File.expand_path(File.join(plugin.directory, 'app', "#{file_type}s", base_name))
112
+ Engines.logger.debug("checking plugin '#{plugin.name}' for '#{base_name}'")
113
+ if File.file?("#{plugin_file_name}.rb")
114
+ Engines.logger.debug("==> loading from plugin '#{plugin.name}'")
115
+ file_loaded = true if require_or_load_without_engine_additions(plugin_file_name, const_path)
116
+ end
117
+ end
118
+
119
+ # finally, load any application-specific controller classes using the 'proper'
120
+ # rails load mechanism, EXCEPT when we're testing engines and could load this file
121
+ # from an engine
122
+ if Engines.disable_application_code_loading
123
+ Engines.logger.debug("loading from application disabled.")
124
+ else
125
+ # Ensure we are only loading from the /app directory at this point
126
+ app_file_name = File.join(RAILS_ROOT, 'app', "#{file_type}s", "#{base_name}")
127
+ if File.file?("#{app_file_name}.rb")
128
+ Engines.logger.debug("loading from application: #{base_name}")
129
+ file_loaded = true if require_or_load_without_engine_additions(app_file_name, const_path)
130
+ else
131
+ Engines.logger.debug("(file not found in application)")
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ # if we managed to load a file, return true. If not, default to the original method.
138
+ # Note that this relies on the RHS of a boolean || not to be evaluated if the LHS is true.
139
+ file_loaded || require_or_load_without_engine_additions(file_name, const_path)
140
+ end
141
+ end
142
+
143
+ if defined? ActiveSupport::Dependencies
144
+ module ActiveSupport::Dependencies #:nodoc:
145
+ include Engines::RailsExtensions::Dependencies
146
+ end
147
+ else
148
+ module ::Dependencies
149
+ include Engines::RailsExtensions::Dependencies
150
+ end
151
+ end
@@ -0,0 +1,88 @@
1
+ # Effective use of Rails' routes can help create a tidy and elegant set of URLs,
2
+ # and is a significant part of creating an external API for your web application.
3
+ #
4
+ # When developing plugins which contain controllers, it seems obvious that including
5
+ # the corresponding routes would be extremely useful. This is particularly true
6
+ # when exposing RESTful resources using the new REST-ian features of Rails.
7
+ #
8
+ # == Including routes in your plugin
9
+ #
10
+ # The engines plugin makes it possible to include a set of routes within your plugin
11
+ # very simply, as it turns out. In your plugin, you simply include a <tt>routes.rb</tt>
12
+ # file like the one below at the root of your plugin:
13
+ #
14
+ # connect "/login", :controller => "my_plugin/account", :action => "login"
15
+ #
16
+ # # add a named route
17
+ # logout "/logout", :controller => "my_plugin/account", :action => "logout"
18
+ #
19
+ # # some restful stuff
20
+ # resources :things do |t|
21
+ # t.resources :other_things
22
+ # end
23
+ #
24
+ # Everywhere in a normal <tt>RAILS_ROOT/config/routes.rb</tt> file
25
+ # where you might have <tt>map.connect</tt>, you just use <tt>connect</tt> in your
26
+ # plugin's <tt>routes.rb</tt>.
27
+ #
28
+ # === Hooking it up in your application
29
+ #
30
+ # While it would be possible to have each plugin's routes automagically included into
31
+ # the application's route set, to do so would actually be a stunningly bad idea. Route
32
+ # priority is the key issue here. You, the application developer, needs to be in complete
33
+ # control when it comes to specifying the priority of routes in your application, since
34
+ # the ordering of your routes directly affects how Rails will interpret incoming requests.
35
+ #
36
+ # To add plugin routes into your application's <tt>routes.rb</tt> file, you need to explicitly
37
+ # map them in using the Engines::RailsExtensions::Routing#from_plugin method:
38
+ #
39
+ # ApplicationController::Routing::Routes.draw do |map|
40
+ #
41
+ # map.connect "/app_stuff", :controller => "application_thing" # etc...
42
+ #
43
+ # # This line includes the routes from the given plugin at this point, giving you
44
+ # # control over the priority of your application routes
45
+ # map.from_plugin :your_plugin
46
+ #
47
+ # map.connect ":controller/:action/:id"
48
+ # end
49
+ #
50
+ # By including routes in plugins which have controllers, you can now share in a simple way
51
+ # a compact and elegant URL scheme which corresponds to those controllers.
52
+ #
53
+ # ---
54
+ #
55
+ # The Engines::RailsExtensions::Routing module defines extensions to Rails'
56
+ # routing (ActionController::Routing) mechanism such that routes can be loaded
57
+ # from a given plugin.
58
+ #
59
+ # The key method is Engines::RailsExtensions::Routing#from_plugin, which can be called
60
+ # within your application's <tt>config/routes.rb</tt> file to load plugin routes at that point.
61
+ #
62
+
63
+ module Engines
64
+ module RailsExtensions
65
+ module Routing
66
+ # Loads the set of routes from within a plugin and evaluates them at this
67
+ # point within an application's main <tt>routes.rb</tt> file.
68
+ #
69
+ # Plugin routes are loaded from <tt><plugin_root>/routes.rb</tt>.
70
+ def from_plugin(name)
71
+ map = self # to make 'map' available within the plugin route file
72
+ routes_path = Engines.plugins[name].routes_path
73
+ Engines.logger.debug "loading routes from #{routes_path}"
74
+ eval(IO.read(routes_path), binding, routes_path) if File.file?(routes_path)
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ module ::ActionController #:nodoc:
81
+ module Routing #:nodoc:
82
+ class RouteSet #:nodoc:
83
+ class Mapper #:nodoc:
84
+ include Engines::RailsExtensions::Routing
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,87 @@
1
+ # Contains the enhancements to assist in testing plugins. See Engines::Testing
2
+ # for more details.
3
+
4
+ require 'test/unit'
5
+
6
+ require 'tmpdir'
7
+ require 'fileutils'
8
+
9
+ # In most cases, Rails' own plugin testing mechanisms are sufficient. However, there
10
+ # are cases where plugins can be given a helping hand in the testing arena. This module
11
+ # contains some methods to assist when testing plugins that contain fixtures.
12
+ #
13
+ # == Fixtures and plugins
14
+ #
15
+ # Since Rails' own fixtures method is fairly strict about where files can be loaded from,
16
+ # the simplest approach when running plugin tests with fixtures is to simply copy all
17
+ # fixtures into a single temporary location and inform the standard Rails mechanism to
18
+ # use this directory, rather than RAILS_ROOT/test/fixtures.
19
+ #
20
+ # The Engines::Testing#setup_plugin_fixtures method does this, copying all plugin fixtures
21
+ # into the temporary location before and tests are performed. This behaviour is invoked
22
+ # the the rake tasks provided by the Engines plugin, in the "test:plugins" namespace. If
23
+ # necessary, you can invoke the task manually.
24
+ #
25
+ # If you wish to take advantage of this, add a call to the Engines::Testing.set_fixture_path
26
+ # method somewhere before your tests (in a test_helper file, or above the TestCase itself).
27
+ #
28
+ # = Testing plugins
29
+ #
30
+ # Normally testing a plugin will require that Rails is loaded, unless you are including
31
+ # a skeleton Rails environment or set of mocks within your plugin tests. If you require
32
+ # the Rails environment to be started, you must ensure that this actually happens; while
33
+ # it's not obvious, your tests do not automatically run with Rails loaded.
34
+ #
35
+ # The simplest way to setup plugin tests is to include a test helper with the following
36
+ # contents:
37
+ #
38
+ # # Load the normal Rails helper. This ensures the environment is loaded
39
+ # require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
40
+ # # Ensure that we are using the temporary fixture path
41
+ # Engines::Testing.set_fixture_path
42
+ #
43
+ # Then run tests using the provided tasks (<tt>test:plugins</tt>, or the tasks that the engines
44
+ # plugin provides - <tt>test:plugins:units</tt>, etc.).
45
+ #
46
+ # Alternatively, you can explicitly load the environment by adpating the contents of the
47
+ # default <tt>test_helper</tt>:
48
+ #
49
+ # ENV["RAILS_ENV"] = "test"
50
+ # # Note that we are requiring config/environment from the root of the enclosing application.
51
+ # require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
52
+ # require 'test_help'
53
+ #
54
+ module Engines::Testing
55
+ mattr_accessor :temporary_fixtures_directory
56
+ self.temporary_fixtures_directory = FileUtils.mkdir_p(File.join(Dir.tmpdir, "rails_fixtures"))
57
+
58
+ # Copies fixtures from plugins and the application into a temporary directory
59
+ # (Engines::Testing.temporary_fixtures_directory).
60
+ #
61
+ # If a set of plugins is not given, fixtures are copied from all plugins in order
62
+ # of precedence, meaning that plugins can 'overwrite' the fixtures of others if they are
63
+ # loaded later; the application's fixtures are copied last, allowing any custom fixtures
64
+ # to override those in the plugins. If no argument is given, plugins are loaded via
65
+ # PluginList#by_precedence.
66
+ #
67
+ # This method is called by the engines-supplied plugin testing rake tasks
68
+ def self.setup_plugin_fixtures(plugins = Engines.plugins.by_precedence)
69
+
70
+ # Copy all plugin fixtures, and then the application fixtures, into this directory
71
+ plugins.each do |plugin|
72
+ plugin_fixtures_directory = File.join(plugin.directory, "test", "fixtures")
73
+ if File.directory?(plugin_fixtures_directory)
74
+ Engines.mirror_files_from(plugin_fixtures_directory, self.temporary_fixtures_directory)
75
+ end
76
+ end
77
+ Engines.mirror_files_from(File.join(RAILS_ROOT, "test", "fixtures"),
78
+ self.temporary_fixtures_directory)
79
+ end
80
+
81
+ # Sets the fixture path used by Test::Unit::TestCase to the temporary
82
+ # directory which contains all plugin fixtures.
83
+ def self.set_fixture_path
84
+ Test::Unit::TestCase.fixture_path = self.temporary_fixtures_directory
85
+ $LOAD_PATH.unshift self.temporary_fixtures_directory
86
+ end
87
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module Engines
3
+ module VERSION #:nodoc:
4
+ MAJOR = 2
5
+ MINOR = 1
6
+ TINY = 0
7
+
8
+ STRING = [MAJOR, MINOR, TINY].join('.')
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ # Only call Engines.init once, in the after_initialize block so that Rails
2
+ # plugin reloading works when turned on
3
+
4
+ config.after_initialize do
5
+ Engines.init if defined? :Engines
6
+ end
@@ -0,0 +1,249 @@
1
+ # This code lets us redefine existing Rake tasks, which is extremely
2
+ # handy for modifying existing Rails rake tasks.
3
+ # Credit for the original snippet of code goes to Jeremy Kemper
4
+ # http://pastie.caboo.se/9620
5
+ unless Rake::TaskManager.methods.include?('redefine_task')
6
+ module Rake
7
+ module TaskManager
8
+ def redefine_task(task_class, args, &block)
9
+ task_name, arg_names, deps = resolve_args([args])
10
+ task_name = task_class.scope_name(@scope, task_name)
11
+ deps = [deps] unless deps.respond_to?(:to_ary)
12
+ deps = deps.collect {|d| d.to_s }
13
+ task = @tasks[task_name.to_s] = task_class.new(task_name, self)
14
+ task.application = self
15
+ task.add_description(@last_description)
16
+ @last_description = nil
17
+ task.enhance(deps, &block)
18
+ task
19
+ end
20
+
21
+ end
22
+ class Task
23
+ class << self
24
+ def redefine_task(args, &block)
25
+ Rake.application.redefine_task(self, [args], &block)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ namespace :db do
33
+ namespace :migrate do
34
+ desc 'Migrate database and plugins to current status.'
35
+ task :all => [ 'db:migrate', 'db:migrate:plugins' ]
36
+
37
+ desc 'Migrate plugins to current status.'
38
+ task :plugins => :environment do
39
+ Engines.plugins.each do |plugin|
40
+ next unless File.exists? plugin.migration_directory
41
+ puts "Migrating plugin #{plugin.name} ..."
42
+ plugin.migrate
43
+ end
44
+ end
45
+
46
+ desc 'For engines coming from Rails version < 2.0, you need to upgrade the schema info table'
47
+ task :upgrade_plugin_migrations => :environment do
48
+ # This task will upgrade Rails < 2.0, and also databases previously updated with
49
+ # db:migrate:fix_engines_migrations
50
+
51
+ # Old table name
52
+ old_sm_table = ActiveRecord::Migrator.proper_table_name(Engines.schema_info_table)
53
+
54
+ unless ActiveRecord::Base.connection.table_exists?(old_sm_table)
55
+ abort "Cannot find old migration table - assuming nothing needs to be done"
56
+ end
57
+
58
+ # There are two forms of the engines schema info - pre-fix_plugin_migrations and post
59
+ # We need to figure this out before we continue.
60
+
61
+ results = ActiveRecord::Base.connection.select_rows(
62
+ "SELECT version, plugin_name FROM #{old_sm_table}"
63
+ ).uniq
64
+
65
+ def insert_new_version(plugin_name, version)
66
+ version_string = "#{version}-#{plugin_name}"
67
+ new_sm_table = ActiveRecord::Migrator.schema_migrations_table_name
68
+
69
+ # Check if the row already exists for some reason - maybe run this task more than once.
70
+ return if ActiveRecord::Base.connection.select_rows("SELECT * FROM #{new_sm_table} WHERE version = #{version_string.dump}").size > 0
71
+
72
+ puts "Inserting new version #{version} for plugin #{plugin_name}.."
73
+ ActiveRecord::Base.connection.insert("INSERT INTO #{new_sm_table} (version) VALUES (#{version_string.dump})")
74
+ end
75
+
76
+ # We need to figure out if they already used "fix_plugin_migrations"
77
+ versions = {}
78
+ results.each do |r|
79
+ versions[r[1]] ||= []
80
+ versions[r[1]] << r[0].to_i
81
+ end
82
+
83
+ if versions.values.find{ |v| v.size > 1 } == nil
84
+ puts "Fixing migration info"
85
+ # We only have one listed migration per plugin - this is pre-fix_plugin_migrations,
86
+ # so we build all versions required. In this case, all migrations should
87
+ versions.each do |plugin_name, version|
88
+ version = version[0] # There is only one version
89
+
90
+ # We have to make an assumption that numeric migrations won't get this long..
91
+ # I'm not sure if there is a better assumption, it should work in all
92
+ # current cases.. (touch wood..)
93
+ if version.to_s.size < "YYYYMMDDHHMMSS".size
94
+ # Insert version records for each migration
95
+ (1..version).each do |v|
96
+ insert_new_version(plugin_name, v)
97
+ end
98
+ else
99
+ # If the plugin is new-format "YYYYMMDDHHMMSS", we just copy it across...
100
+ # The case in which this occurs is very rare..
101
+ insert_new_version(plugin_name, version)
102
+ end
103
+ end
104
+ else
105
+ puts "Moving migration info"
106
+ # We have multiple migrations listed per plugin - thus we can assume they have
107
+ # already applied fix_plugin_migrations - we just copy it across verbatim
108
+ versions.each do |plugin_name, version|
109
+ version.each { |v| insert_new_version(plugin_name, v) }
110
+ end
111
+ end
112
+
113
+ puts "Migration info successfully migrated - removing old schema info table"
114
+ ActiveRecord::Base.connection.drop_table(old_sm_table)
115
+ end
116
+
117
+ desc 'Migrate a specified plugin.'
118
+ task({:plugin => :environment}, :name, :version) do |task, args|
119
+ name = args[:name] || ENV['NAME']
120
+ if plugin = Engines.plugins[name]
121
+ version = args[:version] || ENV['VERSION']
122
+ puts "Migrating #{plugin.name} to " + (version ? "version #{version}" : 'latest version') + " ..."
123
+ plugin.migrate(version ? version.to_i : nil)
124
+ else
125
+ puts "Plugin #{name} does not exist."
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+
132
+ namespace :db do
133
+ namespace :fixtures do
134
+ namespace :plugins do
135
+
136
+ desc "Load plugin fixtures into the current environment's database."
137
+ task :load => :environment do
138
+ require 'active_record/fixtures'
139
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
140
+ Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', ENV['PLUGIN'] || '**',
141
+ 'test', 'fixtures', '*.yml')).each do |fixture_file|
142
+ Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+ end
149
+
150
+ # this is just a modification of the original task in railties/lib/tasks/documentation.rake,
151
+ # because the default task doesn't support subdirectories like <plugin>/app or
152
+ # <plugin>/component. These tasks now include every file under a plugin's code paths (see
153
+ # Plugin#code_paths).
154
+ namespace :doc do
155
+
156
+ plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) }
157
+
158
+ namespace :plugins do
159
+
160
+ # Define doc tasks for each plugin
161
+ plugins.each do |plugin|
162
+ desc "Create plugin documentation for '#{plugin}'"
163
+ Rake::Task.redefine_task(plugin => :environment) do
164
+ plugin_base = RAILS_ROOT + "/vendor/plugins/#{plugin}"
165
+ options = []
166
+ files = Rake::FileList.new
167
+ options << "-o doc/plugins/#{plugin}"
168
+ options << "--title '#{plugin.titlecase} Plugin Documentation'"
169
+ options << '--line-numbers' << '--inline-source'
170
+ options << '-T html'
171
+
172
+ # Include every file in the plugin's code_paths (see Plugin#code_paths)
173
+ if Engines.plugins[plugin]
174
+ files.include("#{plugin_base}/{#{Engines.plugins[plugin].code_paths.join(",")}}/**/*.rb")
175
+ end
176
+ if File.exists?("#{plugin_base}/README")
177
+ files.include("#{plugin_base}/README")
178
+ options << "--main '#{plugin_base}/README'"
179
+ end
180
+ files.include("#{plugin_base}/CHANGELOG") if File.exists?("#{plugin_base}/CHANGELOG")
181
+
182
+ if files.empty?
183
+ puts "No source files found in #{plugin_base}. No documentation will be generated."
184
+ else
185
+ options << files.to_s
186
+ sh %(rdoc #{options * ' '})
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+
194
+
195
+ namespace :test do
196
+ task :warn_about_multiple_plugin_testing_with_engines do
197
+ puts %{-~============== A Moste Polite Warninge ===========================~-
198
+
199
+ You may experience issues testing multiple plugins at once when using
200
+ the code-mixing features that the engines plugin provides. If you do
201
+ experience any problems, please test plugins individually, i.e.
202
+
203
+ $ rake test:plugins PLUGIN=my_plugin
204
+
205
+ or use the per-type plugin test tasks:
206
+
207
+ $ rake test:plugins:units
208
+ $ rake test:plugins:functionals
209
+ $ rake test:plugins:integration
210
+ $ rake test:plugins:all
211
+
212
+ Report any issues on http://dev.rails-engines.org. Thanks!
213
+
214
+ -~===============( ... as you were ... )============================~-}
215
+ end
216
+
217
+ namespace :plugins do
218
+
219
+ desc "Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)"
220
+ task :all => [:warn_about_multiple_plugin_testing_with_engines,
221
+ :units, :functionals, :integration]
222
+
223
+ desc "Run all plugin unit tests"
224
+ Rake::TestTask.new(:units => :setup_plugin_fixtures) do |t|
225
+ t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/unit/**/*_test.rb"
226
+ t.verbose = true
227
+ end
228
+
229
+ desc "Run all plugin functional tests"
230
+ Rake::TestTask.new(:functionals => :setup_plugin_fixtures) do |t|
231
+ t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/functional/**/*_test.rb"
232
+ t.verbose = true
233
+ end
234
+
235
+ desc "Integration test engines"
236
+ Rake::TestTask.new(:integration => :setup_plugin_fixtures) do |t|
237
+ t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/integration/**/*_test.rb"
238
+ t.verbose = true
239
+ end
240
+
241
+ desc "Mirrors plugin fixtures into a single location to help plugin tests"
242
+ task :setup_plugin_fixtures => :environment do
243
+ Engines::Testing.setup_plugin_fixtures
244
+ end
245
+
246
+ # Patch the default plugin testing task to have setup_plugin_fixtures as a prerequisite
247
+ Rake::Task["test:plugins"].prerequisites << "test:plugins:setup_plugin_fixtures"
248
+ end
249
+ end