Commit 682ee5be54c21ad12f78597fca0e18a6f03af5d7
1 parent
99ae59ff
Exists in
master
and in
22 other branches
plugins: Support plugin to be defined as module instead of object
This makes possible for a plugin to be defined as module and have its main class defined inside it with the name Base (e.g. MyPlugin::Base). The advantages of this is to correctly scope plugins constants inside the module. There are many conflicts with the core if the plugin is defined as klass, for example: - if you define a MyPlugin::DisplayHelper you'll get the error 'warning: toplevel constant DisplayHelper referenced by MyPlugin::DisplayHelper' and your class won't be loaded unless you put a "require 'my_plugin/display_helper'" - `require` is also needed for contants with the sames of constants declared under Noosfero::Plugin. For example, if you define a MyPlugin::Manager or MyPlugin::Settings, Noosfero::Plugin::Manager or Noosfero::Plugin::Settings will be returned instead of your plugin's definition. - other hard to debug errors may also happen. This also encapsulates loading procedures into methods of Noosfero::Plugin.
Showing
4 changed files
with
76 additions
and
43 deletions
Show diff stats
lib/noosfero/plugin.rb
1 | 1 | require_dependency 'noosfero' |
2 | +require 'noosfero/plugin/parent_methods' | |
2 | 3 | |
3 | 4 | class Noosfero::Plugin |
4 | 5 | |
... | ... | @@ -14,13 +15,9 @@ class Noosfero::Plugin |
14 | 15 | |
15 | 16 | class << self |
16 | 17 | |
17 | - attr_writer :should_load | |
18 | + include Noosfero::Plugin::ParentMethods | |
18 | 19 | |
19 | - # Called for each ActiveRecord class with parents | |
20 | - # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix | |
21 | - def table_name_prefix | |
22 | - @table_name_prefix ||= "#{name.to_s.underscore}_" | |
23 | - end | |
20 | + attr_writer :should_load | |
24 | 21 | |
25 | 22 | def should_load |
26 | 23 | @should_load.nil? && true || @boot |
... | ... | @@ -92,8 +89,14 @@ class Noosfero::Plugin |
92 | 89 | end |
93 | 90 | end |
94 | 91 | |
95 | - def load_plugin(plugin_name) | |
96 | - (plugin_name.to_s.camelize + 'Plugin').constantize | |
92 | + def load_plugin_identifier identifier | |
93 | + klass = identifier.to_s.camelize.constantize | |
94 | + klass = klass.const_get :Base if klass.class == Module | |
95 | + klass | |
96 | + end | |
97 | + | |
98 | + def load_plugin public_name | |
99 | + load_plugin_identifier "#{public_name.to_s.camelize}Plugin" | |
97 | 100 | end |
98 | 101 | |
99 | 102 | # This is a generic method that initialize any possible filter defined by a |
... | ... | @@ -135,7 +138,7 @@ class Noosfero::Plugin |
135 | 138 | filters = [filters] |
136 | 139 | end |
137 | 140 | filters.each do |plugin_filter| |
138 | - filter_method = (plugin.name.underscore.gsub('/','_') + '_' + plugin_filter[:method_name]).to_sym | |
141 | + filter_method = "#{plugin.identifier}_#{plugin_filter[:method_name]}".to_sym | |
139 | 142 | controller_class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {})) |
140 | 143 | controller_class.send(:define_method, filter_method) do |
141 | 144 | instance_exec(&plugin_filter[:block]) if environment.plugin_enabled?(plugin) |
... | ... | @@ -168,38 +171,6 @@ class Noosfero::Plugin |
168 | 171 | @all ||= available_plugins.map{ |dir| (File.basename(dir) + "_plugin").camelize } |
169 | 172 | end |
170 | 173 | |
171 | - def public_name | |
172 | - self.name.underscore.gsub('_plugin','') | |
173 | - end | |
174 | - | |
175 | - def public_path file = '', relative=false | |
176 | - File.join "#{if relative then '' else '/' end}plugins", public_name, file | |
177 | - end | |
178 | - | |
179 | - def root_path | |
180 | - Rails.root.join('plugins', public_name) | |
181 | - end | |
182 | - | |
183 | - def view_path | |
184 | - File.join(root_path,'views') | |
185 | - end | |
186 | - | |
187 | - # Here the developer should specify the meta-informations that the plugin can | |
188 | - # inform. | |
189 | - def plugin_name | |
190 | - self.name.underscore.humanize | |
191 | - end | |
192 | - def plugin_description | |
193 | - _("No description informed.") | |
194 | - end | |
195 | - | |
196 | - def admin_url | |
197 | - {:controller => "#{name.underscore}_admin", :action => 'index'} | |
198 | - end | |
199 | - | |
200 | - def has_admin_url? | |
201 | - File.exists?(File.join(root_path, 'controllers', "#{name.underscore}_admin_controller.rb")) | |
202 | - end | |
203 | 174 | end |
204 | 175 | |
205 | 176 | def expanded_template(file_path, locals = {}) | ... | ... |
lib/noosfero/plugin/manager.rb
... | ... | @@ -76,7 +76,7 @@ class Noosfero::Plugin::Manager |
76 | 76 | |
77 | 77 | def enabled_plugins |
78 | 78 | @enabled_plugins ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin| |
79 | - plugin.constantize.new(context) | |
79 | + Noosfero::Plugin.load_plugin_identifier(plugin).new context | |
80 | 80 | end |
81 | 81 | end |
82 | 82 | ... | ... |
... | ... | @@ -0,0 +1,62 @@ |
1 | +class Noosfero::Plugin | |
2 | + | |
3 | + # Plugins that are defined as modules should extend | |
4 | + # this module manually, for example: | |
5 | + # module MyPlugin | |
6 | + # extend Noosfero::Plugin::ParentMethods | |
7 | + # end | |
8 | + module ParentMethods | |
9 | + | |
10 | + def identifier | |
11 | + @identifier ||= (if self.parents.first.instance_of? Module then self.parents.first else self end).name.underscore | |
12 | + end | |
13 | + | |
14 | + def public_name | |
15 | + @public_name ||= self.identifier.gsub '_plugin', '' | |
16 | + end | |
17 | + | |
18 | + # Here the developer should specify the meta-informations that the plugin can | |
19 | + # inform. | |
20 | + def plugin_name | |
21 | + self.identifier.humanize | |
22 | + end | |
23 | + def plugin_description | |
24 | + _("No description informed.") | |
25 | + end | |
26 | + | |
27 | + # Called for each ActiveRecord model with parents | |
28 | + # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix | |
29 | + def table_name_prefix | |
30 | + @table_name_prefix ||= "#{self.identifier}_" | |
31 | + end | |
32 | + | |
33 | + def public_path file = '', relative=false | |
34 | + File.join "#{if relative then '' else '/' end}plugins", public_name, file | |
35 | + end | |
36 | + | |
37 | + def root_path | |
38 | + Rails.root.join('plugins', public_name) | |
39 | + end | |
40 | + | |
41 | + def view_path | |
42 | + File.join(root_path,'views') | |
43 | + end | |
44 | + | |
45 | + def admin_url | |
46 | + {:controller => "#{self.identifier}_admin", :action => 'index'} | |
47 | + end | |
48 | + | |
49 | + def has_admin_url? | |
50 | + File.exists?(File.join(root_path, 'controllers', "#{self.identifier}_admin_controller.rb")) | |
51 | + end | |
52 | + | |
53 | + def controllers | |
54 | + @controllers ||= Dir.glob("#{self.root_path}/controllers/*/*").map do |controller_file| | |
55 | + next unless controller_file =~ /_controller.rb$/ | |
56 | + controller = File.basename(controller_file).gsub(/.rb$/, '').camelize | |
57 | + end.compact | |
58 | + end | |
59 | + | |
60 | + end | |
61 | + | |
62 | +end | ... | ... |
test/unit/plugin_test.rb