6

Namespacing in Perl is pretty straight forward, but I can't seem to find a solution for translating this very simple Perl class hierarchy to Ruby.

Perl

lib/Foo.pm

package Foo;

use Foo::Bar;

sub bar {
    return Foo::Bar->new()
}

lib/Foo/Bar.pm

package Foo::Bar

sub baz {}

main.pl

use Foo;
my $foo = Foo->new();
my $bar = $foo->bar();
$bar->baz()

Ruby

Modules can't be instantiated, so this code obviously won't work:

lib/foo.rb

require 'foo/bar.rb'

module Foo    
  def bar
    Foo::Bar.new
  end
end

lib/foo/bar.rb

module Foo
  class Bar
    def baz
    end
  end
end

main.rb

require 'lib/foo.rb'
foo = Foo.new
bar = foo.bar
bar.baz

But trying to declare Foo as a class instead doesn't work either, because there's already a module by that name:

lib/foo.rb:3:in `<top (required)>': Foo is not a class (TypeError)

So I end up with:

lib/foo.rb

module Foo
  class Foo
    ...
  end
end

main.rb

foo = Foo::Foo.new

Which is just not what I want. I have the feeling that I'm missing something very fundamental. :) Thanks for shedding some light on this.

daskraken
  • 83
  • 4

1 Answers1

4

In Ruby, both modules and classes can be used to provide namespace separation. In fact Class is a subclass of Module, and most things you can do with a Module you can also do with a Class

If Foo needs to be a class, declare it as a class, don't declare it as a module.

E.g.

lib/foo.rb

require 'foo/bar.rb'

class Foo    
  def bar
    Foo::Bar.new
  end
end

lib/foo/bar.rb

class Foo
  class Bar
    def baz
    end
  end
end

main.rb

require 'lib/foo.rb'
foo = Foo.new
bar = foo.bar
bar.baz
Neil Slater
  • 26,512
  • 6
  • 76
  • 94
  • Ok, that was easy! Thanks! :) I'm wondering if this re-opens the class Foo (aka monkey-patching) to add another class to it, which would be something different than just putting Bar into the namespace Foo? – daskraken Apr 23 '15 at 22:28
  • 1
    Yes as written it re-opens the class, although you don't do anything with that in this case. It's not considered monkey-patching unless it over-writes some existing method (perhaps to fix or remove some side effect). If you changed the order of requires so that `Foo` is already defined, you could also use the full namespace e.g. `class Foo::Bar` - Ruby needs `Foo` to exist before it lets you do that – Neil Slater Apr 23 '15 at 22:31
  • Cool! I didn't come across any Ruby code which builds such a hierarchy in that way, so I considered it bad style. – daskraken Apr 23 '15 at 22:37
  • 2
    Elaborating a little bit on what @NeilSlater was saying, it is a common practice to use Modules to namespace, even though you could namespace with either Module or Class, it is clearer to see the intention of doing so when you use Modules. If namespacing is not a concern, i.e. there's no chance of a gem or another piece of code to declare a class with the same name as the one you are trying to create, then you can simply stick to classes. – JeanLescure Apr 23 '15 at 22:45