What is the preferred way (better style) to name a namespace in Ruby? Singular or Plural?

14,711

Solution 1

Use:

module FooLib end
module FooLib::Plugins end
class  FooLib::Plugins::Plugin; end #the base for plugins
class  FooLib::Plugins::Bar < FooLib::Plugins::Plugin; end
class  FooLib::Plugins::Bar2 < FooLib::Plugins::Plugin; end

or in a different words:

module FooLib
  module Plugins
    class Plugin; end #the base for plugins
    class Bar < Plugin; end
    class Bar2 < Plugin; end
  end
end

Also arrange the files like this:

- foo_lib/
  - plugins/
    - plugin.rb
    - bar.rb
    - bar2.rb

This is how Rails does it (so this is the Rails Way). I.e. look at the Associations namespace and the Associations::Association class from which all of the classes form the Associations namespace inherits (i.e. Associations::SingularAssociation).

Solution 2

To me FooLib::Plugins appears like a module, used as a namespace which various plugin classes are kept in. FooLib::Plugin looks like a superclass for FooLib plugins.

In FooLib::Plugins::Bar, Bar definitely seems like the name of a plugin. With FooLib::Plugin::Bar, I would be doubtful whether Bar was a helper class used by Foo::Plugin, or the name of a plugin.

Solution 3

Assuming Plugin is a base class:

  • class FooLib::Plugin::Bar < FooLib::Plugin

    This is the one I use and recommend. Bar is a Plugin in FooLib and it inherits from FooLib::Plugin. It also keeps the plugins provided by the FooLib library nested under the namespace of the general class, which reads naturally:

    # Assign the Bar Plugin of the FooLib library to p.
    p = FooLib::Plugin::Bar
    

    If I were to develop a third party plugin for your library, I would create the following structure:

    # Baz is a Plugin for the FooLib library provided by BarLib.
    class BarLib::FooLib::Plugin::Baz < ::FooLib::Plugin
    

    Note that I mirror the FooLib hierarchy, but under BarLib's namespace. I would not extend it directly.

  • class FooLib::Plugins::Bar < FooLib::Plugin

    I have also used this one, and I think it makes the most sense. Bar extends FooLib::Plugin and is one of the Plugins provided by FooLib. However, it creates a potentially needless module.

    I think this would be a great choice if Plugins was a central plugin repository that implements methods like Plugins.add, Plugins.all and Plugins.loaded.

    Use it if you can justify the extra module.

  • class FooLib::Plugins::Bar < FooLib::Plugins

    Doesn't make a lot of sense to me. Bar is one of the Plugins in FooLib, that part looks fine. However, it inherits from Plugins. Is it inheriting from more than one plugin? It sounds strange to me; the class name shouldn't suggest something that is impossible.

Solution 4

I would second the approach outlined by @jtrim.

Given that the module (i.e. Plugin) is being used for namespacing only, I typically override the new method in the module:

module Foo
  module Plugin

    def self.included(base)
      raise "cannot be included"
    end

    def self.extended(base)
      raise "cannot extend"
    end

    def self.new(*args)
      Base.new(*args)
    end

    class Base;end
  end
end


base_plugin_obj = Foo::Plugin.new(...)

Solution 5

Generally, the approach I tend to take is:

module Foo
  module Plugin
    class Base; end
  end
end

class Foo::Plugin::Bar < Foo::Plugin::Base; end

The Base class for plugins is a convention found all over the place in the RubyOnRails codebase as well as many others. (e.g. ActiveRecord::Base, ActionController::Base, etc.)

I disagree with @Matheus Moreira's approach where Foo::Plugin is used both as the base class and the namespace for plugins.

The only functional reason why this shouldn't be done has to do with convention - in the Ruby community one will find many less instances of classes as namespaces than modules. The only time I really see classes used as a namespace for another class is when the purpose of said class is private to the namespace class and is not used externally.

Share:
14,711
Szymon Jeż
Author by

Szymon Jeż

Providing programming services

Updated on June 14, 2022

Comments

  • Szymon Jeż
    Szymon Jeż about 2 years

    What are for you the pros and cons of using:

    FooLib::Plugins
    FooLib::Plugins::Bar
    

    vs.

    FooLib::Plugin
    FooLib::Plugin::Bar
    

    naming conventions? And what would you use or what are you using? What is more commonly used in the comunity?

  • Szymon Jeż
    Szymon Jeż over 12 years
    This is a general question. Not attached to what I'm doing. I have some thoughts on this topic and I wanted to see what others think about it all.
  • Szymon Jeż
    Szymon Jeż over 12 years
    What about FooLib::Plugins::Bar vs FooLib::Plugin::Bar? - the second looks to me more like an object name -> Bar is a Plugin in the FooLib, the first fits less this reasoning.
  • Matheus Moreira
    Matheus Moreira over 12 years
    I personally use FooLib::Plugin as the superclass of plugins, and also keep all subclasses under it: class FooLib::Plugin::Bar < FooLib::Plugin. It feels natural to read: Bar is a Plugin in FooLib. I think a general class containing its specific subclasses in its own namespace makes a lot of sense. I use this nesting system in all of my code.
  • Alex D
    Alex D over 12 years
    Many good points made, +1. If the plugins don't inherit from a common base class, FooLib::Plugins seems very attractive.