parlement 0.10 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +11 -0
- data/MEMORY +9 -1
- data/README +5 -4
- data/app/controllers/account_controller.rb +10 -13
- data/app/controllers/application.rb +4 -5
- data/app/controllers/elt_controller.rb +9 -7
- data/app/controllers/person_controller.rb +1 -3
- data/app/controllers/subscriber_controller.rb +10 -10
- data/app/helpers/elt_helper.rb +2 -0
- data/app/models/elt.rb +28 -19
- data/app/models/mail.rb +26 -14
- data/app/models/mail_notify.rb +5 -4
- data/app/models/person.rb +11 -2
- data/app/views/account/_login.rhtml +3 -3
- data/app/views/account/_show.rhtml +12 -14
- data/app/views/elt/_choice.rhtml +3 -3
- data/app/views/elt/_elt.rhtml +4 -4
- data/app/views/elt/_list.rhtml +2 -2
- data/app/views/elt/_listByDate.rhtml +1 -1
- data/app/views/elt/_listByVote.rhtml +1 -1
- data/app/views/elt/new.rhtml +3 -3
- data/app/views/elt/show.rhtml +2 -2
- data/app/views/layouts/top.rhtml +6 -0
- data/app/views/mail_notify/publish.text.html.rhtml +1 -1
- data/app/views/person/_listElts.rhtml +5 -3
- data/app/views/person/show.rhtml +1 -2
- data/config/boot.rb +5 -4
- data/config/environment.rb +6 -4
- data/config/routes.rb +3 -2
- data/db/development_structure.sql +15 -4
- data/db/migrate/006_last_activity.rb +10 -0
- data/db/schema.rb +67 -49
- data/public/dispatch.fcgi +1 -0
- data/public/javascripts/controls.js +41 -23
- data/public/javascripts/dragdrop.js +317 -99
- data/public/javascripts/effects.js +301 -166
- data/public/javascripts/prototype.js +932 -402
- data/public/stylesheets/default.css +3 -2
- data/test/unit/elt_test.rb +13 -0
- data/test/unit/mail_test.rb +3 -1
- data/vendor/plugins/engines/CHANGELOG +203 -99
- data/vendor/plugins/engines/MIT-LICENSE +1 -1
- data/vendor/plugins/engines/README +32 -384
- data/vendor/plugins/engines/Rakefile +14 -0
- data/vendor/plugins/engines/UPGRADING +93 -0
- data/vendor/plugins/engines/about.yml +7 -0
- data/vendor/plugins/engines/generators/plugin_migration/USAGE +45 -0
- data/vendor/plugins/engines/generators/plugin_migration/plugin_migration_generator.rb +79 -0
- data/vendor/plugins/engines/generators/plugin_migration/templates/plugin_migration.erb +13 -0
- data/vendor/plugins/engines/init.rb +34 -47
- data/vendor/plugins/engines/install.rb +32 -0
- data/vendor/plugins/engines/lib/engines/{ruby_extensions.rb → deprecated_config_support.rb} +135 -113
- data/vendor/plugins/engines/lib/engines/plugin.rb +214 -0
- data/vendor/plugins/engines/lib/engines/plugin_list.rb +31 -0
- data/vendor/plugins/engines/lib/engines/plugin_migrator.rb +60 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/active_record.rb +19 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb +143 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/migrations.rb +155 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/public_asset_helpers.rb +116 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/rails.rb +20 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/rails_initializer.rb +86 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/routing.rb +77 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions/templates.rb +140 -0
- data/vendor/plugins/engines/lib/engines/rails_extensions.rb +6 -0
- data/vendor/plugins/engines/lib/engines/testing.rb +88 -0
- data/vendor/plugins/engines/lib/engines.rb +281 -425
- data/vendor/plugins/engines/tasks/engines.rake +108 -137
- metadata +218 -250
- data/db/ROOT/perso.txt +0 -214
- data/public/images/indicator.gif +0 -0
- data/public/images/orange_by_darren_Hester_350o.jpg +0 -0
- data/public/images/smile.png +0 -0
- data/vendor/plugins/engines/generators/engine/USAGE +0 -26
- data/vendor/plugins/engines/generators/engine/engine_generator.rb +0 -199
- data/vendor/plugins/engines/generators/engine/templates/README +0 -85
- data/vendor/plugins/engines/generators/engine/templates/init_engine.erb +0 -15
- data/vendor/plugins/engines/generators/engine/templates/install.erb +0 -4
- data/vendor/plugins/engines/generators/engine/templates/lib/engine.erb +0 -6
- data/vendor/plugins/engines/generators/engine/templates/licenses/GPL +0 -18
- data/vendor/plugins/engines/generators/engine/templates/licenses/LGPL +0 -19
- data/vendor/plugins/engines/generators/engine/templates/licenses/MIT +0 -22
- data/vendor/plugins/engines/generators/engine/templates/licenses/None +0 -1
- data/vendor/plugins/engines/generators/engine/templates/public/javascripts/engine.js +0 -0
- data/vendor/plugins/engines/generators/engine/templates/public/stylesheets/engine.css +0 -0
- data/vendor/plugins/engines/generators/engine/templates/tasks/engine.rake +0 -0
- data/vendor/plugins/engines/generators/engine/templates/test/test_helper.erb +0 -17
- data/vendor/plugins/engines/lib/bundles/require_resource.rb +0 -124
- data/vendor/plugins/engines/lib/bundles.rb +0 -77
- data/vendor/plugins/engines/lib/engines/action_mailer_extensions.rb +0 -140
- data/vendor/plugins/engines/lib/engines/action_view_extensions.rb +0 -141
- data/vendor/plugins/engines/lib/engines/active_record_extensions.rb +0 -21
- data/vendor/plugins/engines/lib/engines/dependencies_extensions.rb +0 -129
- data/vendor/plugins/engines/lib/engines/migration_extensions.rb +0 -53
- data/vendor/plugins/engines/lib/engines/routing_extensions.rb +0 -28
- data/vendor/plugins/engines/lib/engines/testing_extensions.rb +0 -327
- data/vendor/plugins/engines/tasks/deprecated_engines.rake +0 -7
- data/vendor/plugins/engines/test/action_view_extensions_test.rb +0 -9
- data/vendor/plugins/engines/test/ruby_extensions_test.rb +0 -115
- data/vendor/plugins/guid/README.TXT +0 -29
- data/vendor/plugins/guid/init.rb +0 -30
- data/vendor/plugins/guid/lib/usesguid.rb +0 -37
- data/vendor/plugins/guid/lib/uuid22.rb +0 -43
- data/vendor/plugins/guid/lib/uuidtools.rb +0 -572
- data/vendor/plugins/responds_to_parent/MIT-LICENSE +0 -20
- data/vendor/plugins/responds_to_parent/README +0 -42
- data/vendor/plugins/responds_to_parent/Rakefile +0 -22
- data/vendor/plugins/responds_to_parent/init.rb +0 -1
- data/vendor/plugins/responds_to_parent/lib/responds_to_parent.rb +0 -46
- data/vendor/plugins/responds_to_parent/test/responds_to_parent_test.rb +0 -115
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# An instance of Plugin is created for each plugin loaded by Rails, and
|
|
2
|
+
# stored in the <tt>Rails.plugins</tt> PluginList
|
|
3
|
+
# (see Engines::RailsExtensions::RailsInitializer for more details).
|
|
4
|
+
#
|
|
5
|
+
# Once the engines plugin is loaded, other plugins can take advantage of
|
|
6
|
+
# their own instances by accessing either Engines.current, or the preferred mechanism
|
|
7
|
+
#
|
|
8
|
+
# Rails.plugins[:plugin_name]
|
|
9
|
+
#
|
|
10
|
+
# Useful properties of this object include Plugin#version, which plugin developers
|
|
11
|
+
# can set in their <tt>init.rb</tt> scripts:
|
|
12
|
+
#
|
|
13
|
+
# Rails.plugins[:my_plugin].version = "1.4.2"
|
|
14
|
+
#
|
|
15
|
+
# Plugin developers can also access the contents of their <tt>about.yml</tt> files
|
|
16
|
+
# via Plugin#about, which returns a Hash if the <tt>about.yml</tt> file exists for
|
|
17
|
+
# this plugin. Note that if <tt>about.yml</tt> contains a "version" key, it will
|
|
18
|
+
# automatically be loaded into the <tt>version</tt> attribute described above.
|
|
19
|
+
#
|
|
20
|
+
# If this plugin contains paths in directories other than <tt>app/controllers</tt>,
|
|
21
|
+
# <tt>app/helpers</tt>, <tt>app/models</tt> and <tt>components</tt>, authors can
|
|
22
|
+
# declare this by adding extra paths to #code_paths:
|
|
23
|
+
#
|
|
24
|
+
# Rails.plugin[:my_plugin].code_paths << "app/sweepers" << "vendor/my_lib"
|
|
25
|
+
#
|
|
26
|
+
# Other properties of the Plugin instance can also be set.
|
|
27
|
+
class Plugin
|
|
28
|
+
|
|
29
|
+
# The name of this plugin
|
|
30
|
+
attr_accessor :name
|
|
31
|
+
|
|
32
|
+
# The directory in which this plugin is located
|
|
33
|
+
attr_accessor :root
|
|
34
|
+
|
|
35
|
+
# The version of this plugin
|
|
36
|
+
attr_accessor :version
|
|
37
|
+
|
|
38
|
+
# The about.yml information as a Hash, if it exists
|
|
39
|
+
attr_accessor :about
|
|
40
|
+
|
|
41
|
+
# Plugins can add code paths to this attribute in init.rb if they
|
|
42
|
+
# need plugin directories to be added to the load path, i.e.
|
|
43
|
+
#
|
|
44
|
+
# plugin.code_paths << 'app/other_classes'
|
|
45
|
+
#
|
|
46
|
+
# Defaults to ["app/controllers", "app/helpers", "app/models", "components"]
|
|
47
|
+
# (see #default_code_paths). NOTE: if you want to set this, you must
|
|
48
|
+
# ensure that the engines plugin is loaded before any plugins which
|
|
49
|
+
# reference this since it's not available before the engines plugin has worked
|
|
50
|
+
# its magic.
|
|
51
|
+
attr_accessor :code_paths
|
|
52
|
+
|
|
53
|
+
# Plugins can add paths to this attribute in init.rb if they need
|
|
54
|
+
# controllers loaded from additional locations. See also #default_controller_paths, and
|
|
55
|
+
# the caveat surrounding the #code_paths accessor.
|
|
56
|
+
attr_accessor :controller_paths
|
|
57
|
+
|
|
58
|
+
# The directory in this plugin to mirror into the shared directory
|
|
59
|
+
# under +public+. See Engines.initialize_base_public_directory
|
|
60
|
+
# for more information.
|
|
61
|
+
#
|
|
62
|
+
# Defaults to "assets" (see default_public_directory).
|
|
63
|
+
attr_accessor :public_directory
|
|
64
|
+
|
|
65
|
+
protected
|
|
66
|
+
|
|
67
|
+
# The default set of code paths which will be added to $LOAD_PATH
|
|
68
|
+
# and Dependencies.load_paths
|
|
69
|
+
def default_code_paths
|
|
70
|
+
# lib will actually be removed from the load paths when we call
|
|
71
|
+
# uniq! in #inject_into_load_paths, but it's important to keep it
|
|
72
|
+
# around (for the documentation tasks, for instance).
|
|
73
|
+
%w(app/controllers app/helpers app/models components lib)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The default set of code paths which will be added to the routing system
|
|
77
|
+
def default_controller_paths
|
|
78
|
+
%w(app/controllers components)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Attempts to detect the directory to use for public files.
|
|
82
|
+
# If +assets+ exists in the plugin, this will be used. If +assets+ is missing
|
|
83
|
+
# but +public+ is found, +public+ will be used.
|
|
84
|
+
def default_public_directory
|
|
85
|
+
%w(assets public).select { |dir| File.directory?(File.join(root, dir)) }.first || "assets"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
public
|
|
89
|
+
|
|
90
|
+
# Creates a new Plugin instance, and loads any other data from <tt>about.yml</tt>
|
|
91
|
+
def initialize(name, path)
|
|
92
|
+
@name = name
|
|
93
|
+
@root = path
|
|
94
|
+
|
|
95
|
+
@code_paths = default_code_paths
|
|
96
|
+
@controller_paths = default_controller_paths
|
|
97
|
+
@public_directory = default_public_directory
|
|
98
|
+
|
|
99
|
+
load_about_information
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Load the information from <tt>about.yml</tt>. This Hash is then accessible
|
|
103
|
+
# from #about.
|
|
104
|
+
#
|
|
105
|
+
# If <tt>about.yml</tt> includes a "version", this will be assigned
|
|
106
|
+
# automatically into #version.
|
|
107
|
+
def load_about_information
|
|
108
|
+
about_path = File.join(self.root, 'about.yml')
|
|
109
|
+
if File.exist?(about_path)
|
|
110
|
+
@about = YAML.load(File.open(about_path).read)
|
|
111
|
+
@about.stringify_keys!
|
|
112
|
+
@version = @about["version"]
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Load the plugin. Since Rails takes care of evaluating <tt>init.rb</tt> and
|
|
117
|
+
# adding +lib+ to the <tt>$LOAD_PATH</tt>, we don't need to do that here (see
|
|
118
|
+
# Engines::RailsExtensions::RailsInitializer.load_plugins_with_engine_additions).
|
|
119
|
+
#
|
|
120
|
+
# Here we add controller/helper code to the appropriate load paths (see
|
|
121
|
+
# #inject_into_load_path) and mirror the plugin assets into the shared public
|
|
122
|
+
# directory (#mirror_public_assets).
|
|
123
|
+
def load
|
|
124
|
+
logger.debug "Plugin '#{name}': starting load."
|
|
125
|
+
|
|
126
|
+
inject_into_load_path
|
|
127
|
+
mirror_public_assets
|
|
128
|
+
|
|
129
|
+
logger.debug "Plugin '#{name}': loaded."
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Adds all directories in the +app+ and +lib+ directories within the engine
|
|
133
|
+
# to the three relevant load paths mechanism that Rails might use:
|
|
134
|
+
#
|
|
135
|
+
# * <tt>$LOAD_PATH</tt>
|
|
136
|
+
# * <tt>Dependencies.load_paths</tt>
|
|
137
|
+
# * <tt>ActionController::Routing.controller_paths</tt>
|
|
138
|
+
#
|
|
139
|
+
def inject_into_load_path
|
|
140
|
+
|
|
141
|
+
load_path_index = $LOAD_PATH.index(Engines.rails_final_load_path)
|
|
142
|
+
dependency_index = ::Dependencies.load_paths.index(Engines.rails_final_dependency_load_path)
|
|
143
|
+
|
|
144
|
+
# Add relevant paths under the engine root to the load path
|
|
145
|
+
code_paths.map { |p| File.join(root, p) }.each do |path|
|
|
146
|
+
if File.directory?(path)
|
|
147
|
+
# Add to the load paths
|
|
148
|
+
$LOAD_PATH.insert(load_path_index + 1, path)
|
|
149
|
+
# Add to the dependency system, for autoloading.
|
|
150
|
+
::Dependencies.load_paths.insert(dependency_index + 1, path)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Add controllers to the Routing system specifically. We actually add our paths
|
|
155
|
+
# to the configuration too, since routing is started AFTER plugins are. Plugins
|
|
156
|
+
# which are loaded by engines specifically (i.e. because of the '*' in
|
|
157
|
+
# +config.plugins+) will need their paths added directly to the routing system,
|
|
158
|
+
# since at that point it has already been configured.
|
|
159
|
+
controller_paths.map { |p| File.join(root, p) }.each do |path|
|
|
160
|
+
if File.directory?(path)
|
|
161
|
+
ActionController::Routing.controller_paths << path
|
|
162
|
+
Rails.configuration.controller_paths << path
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
$LOAD_PATH.uniq!
|
|
167
|
+
::Dependencies.load_paths.uniq!
|
|
168
|
+
ActionController::Routing.controller_paths.uniq!
|
|
169
|
+
Rails.configuration.controller_paths.uniq!
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Replicates the subdirectories under the plugins's +assets+ (or +public+) directory into
|
|
173
|
+
# the corresponding public directory. See also Plugin#public_directory for more.
|
|
174
|
+
def mirror_public_assets
|
|
175
|
+
|
|
176
|
+
begin
|
|
177
|
+
source = File.join(root, self.public_directory)
|
|
178
|
+
# if there is no public directory, just return after this file
|
|
179
|
+
return if !File.exist?(source)
|
|
180
|
+
|
|
181
|
+
logger.debug "Attempting to copy plugin plugin asset files from '#{source}' to '#{Engines.public_directory}'"
|
|
182
|
+
|
|
183
|
+
Engines.mirror_files_from(source, File.join(Engines.public_directory, name))
|
|
184
|
+
|
|
185
|
+
rescue Exception => e
|
|
186
|
+
logger.warn "WARNING: Couldn't create the public file structure for plugin '#{name}'; Error follows:"
|
|
187
|
+
logger.warn e
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# The path to this plugin's public files
|
|
192
|
+
def public_asset_directory
|
|
193
|
+
"#{File.basename(Engines.public_directory)}/#{name}"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>)
|
|
197
|
+
def migration_directory
|
|
198
|
+
File.join(self.root, 'db', 'migrate')
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Returns the version number of the latest migration for this plugin. Returns
|
|
202
|
+
# nil if this plugin has no migrations.
|
|
203
|
+
def latest_migration
|
|
204
|
+
migrations = Dir[migration_directory+"/*.rb"]
|
|
205
|
+
return nil if migrations.empty?
|
|
206
|
+
migrations.map { |p| File.basename(p) }.sort.last.match(/0*(\d+)\_/)[1].to_i
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Migrate this plugin to the given version. See Engines::PluginMigrator for more
|
|
210
|
+
# information.
|
|
211
|
+
def migrate(version = nil)
|
|
212
|
+
Engines::PluginMigrator.migrate_plugin(self, version)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# The PluginList class is an array, enhanced to allow access to loaded plugins
|
|
2
|
+
# by name, and iteration over loaded plugins in order of priority. This array is used
|
|
3
|
+
# by Engines::RailsExtensions::RailsInitializer to create the Rails.plugins array.
|
|
4
|
+
#
|
|
5
|
+
# Each loaded plugin has a corresponding Plugin instance within this array, and
|
|
6
|
+
# the order the plugins were loaded is reflected in the entries in this array.
|
|
7
|
+
#
|
|
8
|
+
# For more information, see the Rails module.
|
|
9
|
+
class PluginList < Array
|
|
10
|
+
# Finds plugins with the set with the given name (accepts Strings or Symbols), or
|
|
11
|
+
# index. So, Rails.plugins[0] returns the first-loaded Plugin, and Rails.plugins[:engines]
|
|
12
|
+
# returns the Plugin instance for the engines plugin itself.
|
|
13
|
+
def [](name_or_index)
|
|
14
|
+
if name_or_index.is_a?(Fixnum)
|
|
15
|
+
super
|
|
16
|
+
else
|
|
17
|
+
self.find { |plugin| plugin.name.to_s == name_or_index.to_s }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Go through each plugin, highest priority first (last loaded first). Effectively,
|
|
22
|
+
# this is like <tt>Rails.plugins.reverse</tt>, except when given a block, when it behaves
|
|
23
|
+
# like <tt>Rails.plugins.reverse.each</tt>.
|
|
24
|
+
def by_precedence(&block)
|
|
25
|
+
if block_given?
|
|
26
|
+
reverse.each { |x| yield x }
|
|
27
|
+
else
|
|
28
|
+
reverse
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# The PluginMigrator class contains the logic to run migrations from
|
|
2
|
+
# within plugin directories. The directory in which a plugin's migrations
|
|
3
|
+
# should be is determined by the Plugin#migration_directory method.
|
|
4
|
+
#
|
|
5
|
+
# To migrate a plugin, you can simple call the migrate method (Plugin#migrate)
|
|
6
|
+
# with the version number that plugin should be at. The plugin's migrations
|
|
7
|
+
# will then be used to migrate up (or down) to the given version.
|
|
8
|
+
#
|
|
9
|
+
# For more information, see Engines::RailsExtensions::Migrations
|
|
10
|
+
class Engines::PluginMigrator < ActiveRecord::Migrator
|
|
11
|
+
|
|
12
|
+
# We need to be able to set the 'current' engine being migrated.
|
|
13
|
+
cattr_accessor :current_plugin
|
|
14
|
+
|
|
15
|
+
# Runs the migrations from a plugin, up (or down) to the version given
|
|
16
|
+
def self.migrate_plugin(plugin, version)
|
|
17
|
+
self.current_plugin = plugin
|
|
18
|
+
migrate(plugin.migration_directory, version)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns the name of the table used to store schema information about
|
|
22
|
+
# installed plugins.
|
|
23
|
+
#
|
|
24
|
+
# See Engines.schema_info_table for more details.
|
|
25
|
+
def self.schema_info_table_name
|
|
26
|
+
ActiveRecord::Base.wrapped_table_name Engines.schema_info_table
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns the current version of the given plugin
|
|
30
|
+
def self.current_version(plugin=current_plugin)
|
|
31
|
+
result = ActiveRecord::Base.connection.select_one(<<-ESQL
|
|
32
|
+
SELECT version FROM #{schema_info_table_name}
|
|
33
|
+
WHERE plugin_name = '#{plugin.name}'
|
|
34
|
+
ESQL
|
|
35
|
+
)
|
|
36
|
+
if result
|
|
37
|
+
result["version"].to_i
|
|
38
|
+
else
|
|
39
|
+
# There probably isn't an entry for this engine in the migration info table.
|
|
40
|
+
# We need to create that entry, and set the version to 0
|
|
41
|
+
ActiveRecord::Base.connection.execute(<<-ESQL
|
|
42
|
+
INSERT INTO #{schema_info_table_name} (version, plugin_name)
|
|
43
|
+
VALUES (0,'#{plugin.name}')
|
|
44
|
+
ESQL
|
|
45
|
+
)
|
|
46
|
+
0
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Sets the version of the plugin in Engines::PluginMigrator.current_plugin to
|
|
51
|
+
# the given version.
|
|
52
|
+
def set_schema_version(version)
|
|
53
|
+
ActiveRecord::Base.connection.update(<<-ESQL
|
|
54
|
+
UPDATE #{self.class.schema_info_table_name}
|
|
55
|
+
SET version = #{down? ? version.to_i - 1 : version.to_i}
|
|
56
|
+
WHERE plugin_name = '#{self.current_plugin.name}'
|
|
57
|
+
ESQL
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Here we add a single helpful method to ActiveRecord::Base. This method may be deprecated
|
|
2
|
+
# in the future, since support for the Module#config mechanism which required it has
|
|
3
|
+
# also been dropped.
|
|
4
|
+
module Engines::RailsExtensions::ActiveRecord
|
|
5
|
+
# NOTE: Currently the Migrations system will ALWAYS wrap given table names
|
|
6
|
+
# in the prefix/suffix, so any table name set via ActiveRecord::Base#set_table_name,
|
|
7
|
+
# for instance will always get wrapped in the process of migration. For this
|
|
8
|
+
# reason, whatever value you give to the config will be wrapped when set_table_name
|
|
9
|
+
# is used in the model.
|
|
10
|
+
#
|
|
11
|
+
# This method is useful for determining the actual name (including prefix and
|
|
12
|
+
# suffix) that Rails will use for a model, given a particular set_table_name
|
|
13
|
+
# parameter.
|
|
14
|
+
def wrapped_table_name(name)
|
|
15
|
+
table_name_prefix + name + table_name_suffix
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
::ActiveRecord::Base.extend(Engines::RailsExtensions::ActiveRecord)
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
['controller', 'helper'].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
|
+
Rails.plugins.each do |plugin|
|
|
111
|
+
plugin_file_name = File.expand_path(File.join(plugin.root, 'app', "#{file_type}s", base_name))
|
|
112
|
+
logger.debug("checking plugin '#{plugin.name}' for '#{base_name}'")
|
|
113
|
+
if File.file?("#{plugin_file_name}.rb")
|
|
114
|
+
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
|
+
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
|
+
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
|
+
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
|
+
::Dependencies.send(:include, Engines::RailsExtensions::Dependencies)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Contains the enhancements to Rails' migrations system to support the
|
|
2
|
+
# Engines::PluginMigrator. See Engines::RailsExtensions::Migrations for more
|
|
3
|
+
# information.
|
|
4
|
+
|
|
5
|
+
require "engines/plugin_migrator"
|
|
6
|
+
|
|
7
|
+
# = Plugins and Migrations: Background
|
|
8
|
+
#
|
|
9
|
+
# Rails uses migrations to describe changes to the databases as your application
|
|
10
|
+
# evolves. Each change to your application - adding and removing models, most
|
|
11
|
+
# commonly - might require tweaks to your schema in the form of new tables, or new
|
|
12
|
+
# columns on existing tables, or possibly the removal of tables or columns. Migrations
|
|
13
|
+
# can even include arbitrary code to *transform* data as the underlying schema
|
|
14
|
+
# changes.
|
|
15
|
+
#
|
|
16
|
+
# The point is that at any particular stage in your application's development,
|
|
17
|
+
# migrations serve to transform the database into a state where it is compatible
|
|
18
|
+
# and appropriate at that time.
|
|
19
|
+
#
|
|
20
|
+
# == What about plugins?
|
|
21
|
+
#
|
|
22
|
+
# If you want to share models using plugins, chances are that you might also
|
|
23
|
+
# want to include the corresponding migrations to create tables for those models.
|
|
24
|
+
# With the engines plugin installed, plugins can carry migration data easily:
|
|
25
|
+
#
|
|
26
|
+
# vendor/
|
|
27
|
+
# |
|
|
28
|
+
# plugins/
|
|
29
|
+
# |
|
|
30
|
+
# my_plugin/
|
|
31
|
+
# |- init.rb
|
|
32
|
+
# |- lib/
|
|
33
|
+
# |- db/
|
|
34
|
+
# |-migrate/
|
|
35
|
+
# |- 001_do_something.rb
|
|
36
|
+
# |- 002_and_something_else.rb
|
|
37
|
+
# |- ...
|
|
38
|
+
#
|
|
39
|
+
# When you install a plugin which contains migrations, you are undertaking a
|
|
40
|
+
# further step in the development of your application, the same as the addition
|
|
41
|
+
# of any other code. With this in mind, you may want to 'roll back' the
|
|
42
|
+
# installation of this plugin at some point, and the database should be able
|
|
43
|
+
# to migrate back to the point without this plugin in it too.
|
|
44
|
+
#
|
|
45
|
+
# == An example
|
|
46
|
+
#
|
|
47
|
+
# For example, our current application is at version 14 (according to the
|
|
48
|
+
# +schema_info+ table), when we decide that we want to add a tagging plugin. The
|
|
49
|
+
# tagging plugin chosen includes migrations to create the tables it requires
|
|
50
|
+
# (say, _tags_ and _taggings_, for instance), along with the models and helpers
|
|
51
|
+
# one might expect.
|
|
52
|
+
#
|
|
53
|
+
# After installing this plugin, these tables should be created in our database.
|
|
54
|
+
# Rather than running the migrations directly from the plugin, they should be
|
|
55
|
+
# integrated into our main migration stream in order to accurately reflect the
|
|
56
|
+
# state of our application's database *at this moment in time*.
|
|
57
|
+
#
|
|
58
|
+
# $ script/generate plugin_migration
|
|
59
|
+
# exists db/migrate
|
|
60
|
+
# create db/migrate/015_migrate_tagging_plugin_to_version_3.rb
|
|
61
|
+
#
|
|
62
|
+
# This migration will take our application to version 15, and contains the following,
|
|
63
|
+
# typical migration code:
|
|
64
|
+
#
|
|
65
|
+
# class MigrateTaggingPluginToVersion3 < ActiveRecord::Migration
|
|
66
|
+
# def self.up
|
|
67
|
+
# Rails.plugins[:tagging].migrate(3)
|
|
68
|
+
# end
|
|
69
|
+
# def self.down
|
|
70
|
+
# Rails.plugins[:tagging].migrate(0)
|
|
71
|
+
# end
|
|
72
|
+
# end
|
|
73
|
+
#
|
|
74
|
+
# When we migrate our application up, using <tt>rake db:migrate</tt> as normal,
|
|
75
|
+
# the plugin will be migrated up to its latest version (3 in this example). If we
|
|
76
|
+
# ever decide to migrate the application back to the state it was in at version 14,
|
|
77
|
+
# the plugin migrations will be taken back down to version 0 (which, typically,
|
|
78
|
+
# would remove all tables the plugin migrations define).
|
|
79
|
+
#
|
|
80
|
+
# == Upgrading plugins
|
|
81
|
+
#
|
|
82
|
+
# It might happen that later in an application's life, we update to a new version of
|
|
83
|
+
# the tagging plugin which requires some changes to our database. The tagging plugin
|
|
84
|
+
# provides these changes in the form of its own migrations.
|
|
85
|
+
#
|
|
86
|
+
# In this case, we just need to re-run the plugin_migration generator to create a
|
|
87
|
+
# new migration from the current revision to the newest one:
|
|
88
|
+
#
|
|
89
|
+
# $ script/generate plugin_migration
|
|
90
|
+
# exists db/migrate
|
|
91
|
+
# create db/migrate/023_migrate_tagging_plugin_to_version_5.rb
|
|
92
|
+
#
|
|
93
|
+
# The contents of this migration are:
|
|
94
|
+
#
|
|
95
|
+
# class MigrateTaggingPluginToVersion3 < ActiveRecord::Migration
|
|
96
|
+
# def self.up
|
|
97
|
+
# Rails.plugins[:tagging].migrate(5)
|
|
98
|
+
# end
|
|
99
|
+
# def self.down
|
|
100
|
+
# Rails.plugins[:tagging].migrate(3)
|
|
101
|
+
# end
|
|
102
|
+
# end
|
|
103
|
+
#
|
|
104
|
+
# Notice that if we were to migrate down to revision 22 or lower, the tagging plugin
|
|
105
|
+
# will be migrated back down to version 3 - the version we were previously at.
|
|
106
|
+
#
|
|
107
|
+
#
|
|
108
|
+
# = Creating migrations in plugins
|
|
109
|
+
#
|
|
110
|
+
# In order to use the plugin migration functionality that engines provides, a plugin
|
|
111
|
+
# only needs to provide regular migrations in a <tt>db/migrate</tt> folder within it.
|
|
112
|
+
#
|
|
113
|
+
# = Explicitly migrating plugins
|
|
114
|
+
#
|
|
115
|
+
# It's possible to migrate plugins within your own migrations, or any other code.
|
|
116
|
+
# Simply get the Plugin instance, and its Plugin#migrate method with the version
|
|
117
|
+
# you wish to end up at:
|
|
118
|
+
#
|
|
119
|
+
# Rails.plugins[:whatever].migrate(version)
|
|
120
|
+
#
|
|
121
|
+
# ---
|
|
122
|
+
#
|
|
123
|
+
# The Engines::RailsExtensions::Migrations module defines extensions for Rails'
|
|
124
|
+
# migration systems. Specifically:
|
|
125
|
+
#
|
|
126
|
+
# * Adding a hook to initialize_schema_information to create the plugin schema
|
|
127
|
+
# info table.
|
|
128
|
+
#
|
|
129
|
+
module Engines::RailsExtensions::Migrations
|
|
130
|
+
def self.included(base) # :nodoc:
|
|
131
|
+
base.class_eval { alias_method_chain :initialize_schema_information, :engine_additions }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Create the schema tables, and ensure that the plugin schema table
|
|
135
|
+
# is also initialized. The plugin schema info table is defined by
|
|
136
|
+
# Engines::PluginMigrator.schema_info_table_name.
|
|
137
|
+
def initialize_schema_information_with_engine_additions
|
|
138
|
+
initialize_schema_information_without_engine_additions
|
|
139
|
+
|
|
140
|
+
# create the plugin schema stuff.
|
|
141
|
+
begin
|
|
142
|
+
execute <<-ESQL
|
|
143
|
+
CREATE TABLE #{Engines::PluginMigrator.schema_info_table_name}
|
|
144
|
+
(plugin_name #{type_to_sql(:string)}, version #{type_to_sql(:integer)})
|
|
145
|
+
ESQL
|
|
146
|
+
rescue ActiveRecord::StatementInvalid
|
|
147
|
+
# Schema has been initialized
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, Engines::RailsExtensions::Migrations)
|
|
153
|
+
|
|
154
|
+
# Set ActiveRecord to ignore the plugin schema table by default
|
|
155
|
+
::ActiveRecord::SchemaDumper.ignore_tables << Engines.schema_info_table
|