Commit 06c13aaeed3d5f0ef85ab45b87c084aa43bb49b7

Authored by Rodrigo Souto
1 parent 2be7f5f4

Modularizing the hotspot feature

  * Every class now can declare that it is able to inlcude hotspots by
    declaring 'acts_as_having_hotspots'. It's important to note that
    every class that have hotspots must define an instance method named
    'environment' that returns the environment associated with the
    instance.

  * Now the enabled_plugins method is centralized in the Thread.current
    making the plugins instantiation happen only once by Thread. Every
    request reinstantiate the plugins since every request creates a new
    Thread. The models that access this method only instantiate it if it
    wasn't instantiated already.

  * Since the models doesn't reinstantiate the plugins in the same
    Thread and the tests run in only one Thread, the tests that have
    some plugin stuff must clean the instantiation in the teardown.
app/controllers/application_controller.rb
1 class ApplicationController < ActionController::Base 1 class ApplicationController < ActionController::Base
2 2
3 before_filter :change_pg_schema 3 before_filter :change_pg_schema
  4 + before_filter :detect_stuff_by_domain
  5 + before_filter :init_noosfero_plugins
4 6
5 include ApplicationHelper 7 include ApplicationHelper
6 layout :get_layout 8 layout :get_layout
@@ -51,8 +53,6 @@ class ApplicationController &lt; ActionController::Base @@ -51,8 +53,6 @@ class ApplicationController &lt; ActionController::Base
51 53
52 include NeedsProfile 54 include NeedsProfile
53 55
54 - before_filter :detect_stuff_by_domain  
55 - before_filter :init_noosfero_plugins  
56 attr_reader :environment 56 attr_reader :environment
57 57
58 before_filter :load_terminology 58 before_filter :load_terminology
config/initializers/plugins.rb
1 require 'noosfero/plugin' 1 require 'noosfero/plugin'
  2 +require 'noosfero/plugin/acts_as_having_hotspots'
2 require 'noosfero/plugin/manager' 3 require 'noosfero/plugin/manager'
3 require 'noosfero/plugin/context' 4 require 'noosfero/plugin/context'
4 require 'noosfero/plugin/active_record' 5 require 'noosfero/plugin/active_record'
lib/noosfero/plugin/acts_as_having_hotspots.rb 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +module ActsAsHavingHotspots
  2 + module ClassMethods
  3 + # Adding this feature to a class demands that it defines an instance method
  4 + # 'environment' that returns the environment associated with the instance.
  5 + def acts_as_having_hotspots
  6 + send :include, InstanceMethods
  7 + end
  8 +
  9 + module InstanceMethods
  10 + # Dispatches +event+ to each enabled plugin and collect the results.
  11 + #
  12 + # Returns an Array containing the objects returned by the event method in
  13 + # each plugin. This array is compacted (i.e. nils are removed) and flattened
  14 + # (i.e. elements of arrays are added to the resulting array). For example, if
  15 + # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will
  16 + # return [1,0,1,2,3]
  17 + #
  18 + def dispatch(event, *args)
  19 + enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact.flatten
  20 + end
  21 +
  22 + # Dispatch without flatten since scopes are executed if you run flatten on them
  23 + def dispatch_scopes(event, *args)
  24 + enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact
  25 + end
  26 +
  27 + def enabled_plugins
  28 + Thread.current[:enabled_plugins] ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name|
  29 + plugin = plugin_name.constantize.new
  30 + plugin.context = context
  31 + plugin
  32 + end
  33 + end
  34 +
  35 + if !method_defined?(:context)
  36 + define_method(:context) do
  37 + Noosfero::Plugin::Context.new
  38 + end
  39 + end
  40 + end
  41 + end
  42 +end
  43 +
  44 +ActiveRecord::Base.send(:extend, ActsAsHavingHotspots::ClassMethods)
lib/noosfero/plugin/context.rb
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 # controller that can be accessed by plugins 2 # controller that can be accessed by plugins
3 class Noosfero::Plugin::Context 3 class Noosfero::Plugin::Context
4 4
5 - def initialize(controller) 5 + def initialize(controller = ApplicationController.new)
6 @controller = controller 6 @controller = controller
7 end 7 end
8 8
lib/noosfero/plugin/manager.rb
1 class Noosfero::Plugin::Manager 1 class Noosfero::Plugin::Manager
2 2
3 - attr_reader :context 3 + extend ActsAsHavingHotspots::ClassMethods
  4 + acts_as_having_hotspots
4 5
5 - def initialize(controller)  
6 - @context = Noosfero::Plugin::Context.new(controller)  
7 - end 6 + attr_reader :context
8 7
  8 + delegate :environment, :to => :context
9 delegate :each, :to => :enabled_plugins 9 delegate :each, :to => :enabled_plugins
10 include Enumerable 10 include Enumerable
11 11
12 - # Dispatches +event+ to each enabled plugin and collect the results.  
13 - #  
14 - # Returns an Array containing the objects returned by the event method in  
15 - # each plugin. This array is compacted (i.e. nils are removed) and flattened  
16 - # (i.e. elements of arrays are added to the resulting array). For example, if  
17 - # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will  
18 - # return [1,0,1,2,3]  
19 - #  
20 - def dispatch(event, *args)  
21 - map { |plugin| plugin.send(event, *args) }.compact.flatten  
22 - end  
23 -  
24 - def enabled_plugins  
25 - @enabled_plugins ||= (Noosfero::Plugin.all & context.environment.enabled_plugins).map do |plugin|  
26 - p = plugin.constantize.new  
27 - p.context = context  
28 - p 12 + def initialize(controller)
  13 + @context = Noosfero::Plugin::Context.new(controller)
  14 + Thread.current[:enabled_plugins] = (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name|
  15 + plugin = plugin_name.constantize.new
  16 + plugin.context = context
  17 + plugin
29 end 18 end
30 end 19 end
31 20
test/unit/person_test.rb
@@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39; @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 class PersonTest < ActiveSupport::TestCase 3 class PersonTest < ActiveSupport::TestCase
4 fixtures :profiles, :users, :environments 4 fixtures :profiles, :users, :environments
5 5
  6 + def teardown
  7 + Thread.current[:enabled_plugins] = nil
  8 + end
  9 +
6 def test_person_must_come_form_the_cration_of_an_user 10 def test_person_must_come_form_the_cration_of_an_user
7 p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john') 11 p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john')
8 assert !p.valid? 12 assert !p.valid?
test/unit/plugin_manager_test.rb
@@ -10,10 +10,8 @@ class PluginManagerTest &lt; ActiveSupport::TestCase @@ -10,10 +10,8 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
10 @controller.stubs(:response).returns() 10 @controller.stubs(:response).returns()
11 @controller.stubs(:environment).returns(@environment) 11 @controller.stubs(:environment).returns(@environment)
12 @controller.stubs(:params).returns() 12 @controller.stubs(:params).returns()
13 - @manager = Noosfero::Plugin::Manager.new(@controller)  
14 end 13 end
15 attr_reader :environment 14 attr_reader :environment
16 - attr_reader :manager  
17 15
18 should 'return the intersection between environment\'s enabled plugins and system available plugins' do 16 should 'return the intersection between environment\'s enabled plugins and system available plugins' do
19 class Plugin1 < Noosfero::Plugin; end; 17 class Plugin1 < Noosfero::Plugin; end;
@@ -22,6 +20,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase @@ -22,6 +20,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
22 class Plugin4 < Noosfero::Plugin; end; 20 class Plugin4 < Noosfero::Plugin; end;
23 environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) 21 environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s])
24 Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) 22 Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s])
  23 + manager = Noosfero::Plugin::Manager.new(@controller)
25 plugins = manager.enabled_plugins.map { |instance| instance.class.to_s } 24 plugins = manager.enabled_plugins.map { |instance| instance.class.to_s }
26 assert_equal [Plugin1.to_s, Plugin4.to_s], plugins 25 assert_equal [Plugin1.to_s, Plugin4.to_s], plugins
27 end 26 end
@@ -50,6 +49,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase @@ -50,6 +49,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
50 49
51 p1 = Plugin1.new 50 p1 = Plugin1.new
52 p2 = Plugin2.new 51 p2 = Plugin2.new
  52 + manager = Noosfero::Plugin::Manager.new(@controller)
53 53
54 assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event) 54 assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event)
55 end 55 end
test/unit/profile_test.rb
@@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39; @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 class ProfileTest < ActiveSupport::TestCase 3 class ProfileTest < ActiveSupport::TestCase
4 fixtures :profiles, :environments, :users, :roles, :domains 4 fixtures :profiles, :environments, :users, :roles, :domains
5 5
  6 + def teardown
  7 + Thread.current[:enabled_plugins] = nil
  8 + end
  9 +
6 def test_identifier_validation 10 def test_identifier_validation
7 p = Profile.new 11 p = Profile.new
8 p.valid? 12 p.valid?