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 1 class ApplicationController < ActionController::Base
2 2  
3 3 before_filter :change_pg_schema
  4 + before_filter :detect_stuff_by_domain
  5 + before_filter :init_noosfero_plugins
4 6  
5 7 include ApplicationHelper
6 8 layout :get_layout
... ... @@ -51,8 +53,6 @@ class ApplicationController &lt; ActionController::Base
51 53  
52 54 include NeedsProfile
53 55  
54   - before_filter :detect_stuff_by_domain
55   - before_filter :init_noosfero_plugins
56 56 attr_reader :environment
57 57  
58 58 before_filter :load_terminology
... ...
config/initializers/plugins.rb
1 1 require 'noosfero/plugin'
  2 +require 'noosfero/plugin/acts_as_having_hotspots'
2 3 require 'noosfero/plugin/manager'
3 4 require 'noosfero/plugin/context'
4 5 require 'noosfero/plugin/active_record'
... ...
lib/noosfero/plugin/acts_as_having_hotspots.rb 0 → 100644
... ... @@ -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 2 # controller that can be accessed by plugins
3 3 class Noosfero::Plugin::Context
4 4  
5   - def initialize(controller)
  5 + def initialize(controller = ApplicationController.new)
6 6 @controller = controller
7 7 end
8 8  
... ...
lib/noosfero/plugin/manager.rb
1 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 9 delegate :each, :to => :enabled_plugins
10 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 18 end
30 19 end
31 20  
... ...
test/unit/person_test.rb
... ... @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 3 class PersonTest < ActiveSupport::TestCase
4 4 fixtures :profiles, :users, :environments
5 5  
  6 + def teardown
  7 + Thread.current[:enabled_plugins] = nil
  8 + end
  9 +
6 10 def test_person_must_come_form_the_cration_of_an_user
7 11 p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john')
8 12 assert !p.valid?
... ...
test/unit/plugin_manager_test.rb
... ... @@ -10,10 +10,8 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
10 10 @controller.stubs(:response).returns()
11 11 @controller.stubs(:environment).returns(@environment)
12 12 @controller.stubs(:params).returns()
13   - @manager = Noosfero::Plugin::Manager.new(@controller)
14 13 end
15 14 attr_reader :environment
16   - attr_reader :manager
17 15  
18 16 should 'return the intersection between environment\'s enabled plugins and system available plugins' do
19 17 class Plugin1 < Noosfero::Plugin; end;
... ... @@ -22,6 +20,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
22 20 class Plugin4 < Noosfero::Plugin; end;
23 21 environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s])
24 22 Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s])
  23 + manager = Noosfero::Plugin::Manager.new(@controller)
25 24 plugins = manager.enabled_plugins.map { |instance| instance.class.to_s }
26 25 assert_equal [Plugin1.to_s, Plugin4.to_s], plugins
27 26 end
... ... @@ -50,6 +49,7 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
50 49  
51 50 p1 = Plugin1.new
52 51 p2 = Plugin2.new
  52 + manager = Noosfero::Plugin::Manager.new(@controller)
53 53  
54 54 assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event)
55 55 end
... ...
test/unit/profile_test.rb
... ... @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 3 class ProfileTest < ActiveSupport::TestCase
4 4 fixtures :profiles, :environments, :users, :roles, :domains
5 5  
  6 + def teardown
  7 + Thread.current[:enabled_plugins] = nil
  8 + end
  9 +
6 10 def test_identifier_validation
7 11 p = Profile.new
8 12 p.valid?
... ...