Commit 682ee5be54c21ad12f78597fca0e18a6f03af5d7

Authored by Braulio Bhavamitra
1 parent 99ae59ff

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.
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  
... ...
lib/noosfero/plugin/parent_methods.rb 0 → 100644
... ... @@ -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
... ... @@ -23,7 +23,7 @@ class PluginTest &lt; ActiveSupport::TestCase
23 23 end
24 24  
25 25 should 'returns empty hash for class method extra_blocks by default if no blocks are defined on plugin' do
26   -
  26 +
27 27 class SomePlugin1 < Noosfero::Plugin
28 28 end
29 29  
... ...