Remove debug code from Plugin.
[mailshears.git] / lib / common / plugin.rb
index ed4ea004041a8986a151783707ffec1ff939815f..1178e2fb9a238293b22e72c3620d03b44b6e8782 100644 (file)
-# All plugins should include this module. It defines the basic
-# operations that all plugins are supposed to support.
+require 'common/domain'
+require 'common/user'
+
+# Methods that all plugins must provide. Certain operations -- for
+# example, user listing -- must be supported by all plugins. These
+# operations are defined here, often with naive default
+# implementations, but it is up to each individual plugin to ensure
+# that they are in fact implemented (well).
+#
 module Plugin
 
-  def Plugin.included(c)
-    # Callback, called whenever another class or module includes this
-    # one. The parameter given is the name of the class or module
-    # that included us.
-    @includers ||= []
-    @includers << c
-  end
+  # These are class methods for runnable plugins, meant to be
+  # _extended_. Those runnable plugins get a magic *run* method but
+  # need to define their own *runner* and *dummy_runner* to make it
+  # work.
+  #
+  module Run
 
-  def Plugin.includers
-    return @includers
-  end
+    # A callback function, called whenever another class or module
+    # includes this one. This is used to build a list of all things
+    # that inherited this class. Having such a list lets us run a
+    # collection of plugins without knowing in advance what they are.
+    #
+    # @param c [Class,Module] the name of the class or module that
+    #   included us.
+    #
+    def included(c)
+      @includers ||= []
+      @includers << c
+    end
 
-  def runner()
-    # The Runner associated with this plugin.
-    raise NotImplementedError
+
+    # Obtain the list of classes and modules that have included this one.
+    #
+    # @return [Array<Class,Module>] the list of classes and modules
+    #   that have included this one.
+    #
+    def includers()
+      @includers ||= []
+      return @includers
+    end
+
+
+    # The runner class associated with this plugin. This method must
+    # be supplied by the child class, since they will all have
+    # different runners.
+    #
+    # @return [Class] the runner class associated with this plugin.
+    #
+    def runner()
+      raise NotImplementedError
+    end
+
+
+    # The "dummy" runner class associated with this plugin. This method
+    # must be supplied by the child class, since they will all have
+    # different dummy runners.
+    #
+    # @return [Class] the dummy runner class associated with this
+    #   plugin.
+    #
+    def dummy_runner()
+      raise NotImplementedError
+    end
+
+
+    # Run all of the plugins that have included this module.
+    #
+    # @param cfg [Configuration] the configuration options to pass to
+    #   each of the plugins.
+    #
+    # @param args [Array<Object>] a variable number of additional
+    #   arguments to be passed to the plugins we're running.
+    #
+    def run(cfg, *args)
+      includers().each do |includer|
+        plugin = includer.new(cfg)
+
+        if cfg.i_mean_business then
+          runner = runner().new()
+        else
+          runner = dummy_runner().new()
+        end
+
+        # The splat passes the correct (we hope) number of arguments to the
+        # appropriate runner. The Rm(Dummy)Runner have splats on their
+        # *target arguments as well, to turn ARGV back into an array.
+        runner.run(cfg, plugin, *args)
+      end
+    end
   end
 
-  def dummy_runner()
-    # The RummyRunner associated with this plugin.
-    raise NotImplementedError
+
+  # A generic version of {#describe_user}/{#describe_domain} that
+  # dispatches base on the class of the target.
+  #
+  # @param target [User,Domain] either a user or a domain to describe.
+  #
+  # @return [String] a string describing the *target*. The contents of
+  #   the string depend on the plugin.
+  #
+  def describe(target)
+    if target.is_a?(User)
+      if user_exists(target) then
+        return describe_user(target)
+      else
+        return 'User not found'
+      end
+    elsif target.is_a?(Domain)
+      if domain_exists(target) then
+        return describe_domain(target)
+      else
+        return 'Domain not found'
+      end
+    else
+      raise NotImplementedError
+    end
   end
 
+
+  # Provide a description of the given *domain*. This is output along
+  # with the domain name and can be anything of use to the system
+  # administrator. The default doesn't do anything useful and should
+  # be overridden if possible.
+  #
+  # @param domain [Domain] the domain to describe.
+  #
+  # @return [String] a string description of *domain*.
+  #
   def describe_domain(domain)
-    # Provide a "description" of the domain. This is output along
-    # with the domain name and can be anything of use to the system
-    # administrator.
-    raise NotImplementedError
+    return domain.to_s()
   end
 
+
+  # Provide a description of the given *user*. This is output along
+  # with the username and can be anything of use to the system
+  # administrator. The default doesn't do anything useful and should
+  # be overridden if possible.
+  #
+  # @param user [User] the domain to describe.
+  #
+  # @return [String] a string description of *user*.
+  #
   def describe_user(user)
-    # Provide a "description" of the user. This is output along
-    # with the domain name and can be anything of use to the system
-    # administrator.
-    raise NotImplementedError
+    return user.to_s()
   end
 
+
+  # Return a list of all users managed by this plugin. This must be
+  # supplied by the individual plugins (who know how to find their
+  # users).
+  #
+  # @return [Array<User>] a list of the users that this plugin knows
+  #   about.
+  #
   def list_users()
-    # Return a list of all users managed by this plugin.
     raise NotImplementedError
   end
 
-  def user_exists(username)
-    # Does the given username exist for this plugin? We use a naive
-    # implementation here based on list_users() which is required to
-    # exist above. Plugins can override this with something fast.
+
+  # Return a list of all domains managed by this plugin. This must be
+  # supplied by the individual plugins (who know how to find their
+  # domains). Many plugins will not have a separate concept of
+  # "domain", so the default implementation constructs a list of
+  # domains resulting from {#list_users}.
+  #
+  # For plugins that do know about domains, smarter implementations
+  # are surely possible.
+  #
+  # @return [Array<Domain>] a list of the domains that this plugin knows
+  #   about.
+  #
+  def list_domains()
+    users = list_users()
+    domains = users.map{ |u| u.domain() }
+    return domains.uniq()
+  end
+
+
+  # Does the given *user* exist for this plugin? We use a naive
+  # implementation here based on {#list_users}. Plugins should override
+  # this with something faster.
+  #
+  # @param user [User] the user whose existence is in question.
+  #
+  # @return [Boolean] true if *user* exists for this plugin, and
+  #   false otherwise.
+  #
+  def user_exists(user)
     users = list_users()
-    return users.include?(username)
+    return users.include?(user)
+  end
+
+
+  # Does the given *domain* exist for this plugin? We use a naive
+  # implementation here based on {#list_domains}. Plugins that know
+  # about domains should override this with something fast.
+  #
+  # @param domain [Domain] the domain whose existence is in question.
+  #
+  # @return [Boolean] true if *domain* exists for this plugin, and
+  #   false otherwise.
+  #
+  def domain_exists(domain)
+    domains = list_domains()
+    return domains.include?(domain)
   end
 
+
+  # List all users belonging to the given domains. We say that a user
+  # belongs to a domain "example.com" if the domain part of the user's
+  # email address is "example.com".
+  #
+  # This uses a naive loop, but relies only on the existence of
+  # {#list_users}. Plugins that know about domains should provide a
+  # more efficient implementation.
+  #
+  # @param domains [Array<Domain>] the domains whose users we want.
+  #
+  # @return [Array<User>] a list of {User} objects belonging to
+  #   *domains* for this plugin.
+  #
   def list_domains_users(domains)
-    # Get all usernames belonging to the given domains. If a username
-    # ends in @example.com, it belongs to the domain example.com
-    #
-    # This uses a naive loop, but relies only on the existence of a
-    # list_users() method which is guaranteed above. More efficient
-    # implementations can usually be made within the plugin.
     domains_users = []
 
-    usernames = list_users();
+    users = list_users();
     domains.each do |d|
-      matches = usernames.select do |username|
-        username =~ /@#{d}$/
+      matches = users.select do |user|
+        user.domainpart() == d.to_s()
       end
 
       domains_users += matches