Module nesting and module vs. instance methods

Having made the commitment to ruby, I am now finding myself building
bigger frameworks and ruby's limited namespace rules with modules are
potentially showing some issues that I want to either prepare for or
avoid.
Or perhaps it is not entirely clear to me what's the proper Ruby way of
doing it. Basically I am building some libraries and I am trying to be
careful about name pollution.

I have a bunch of functions that, currently, have no particular class
location. Currently, I am placing them in modules.
As I have a bunch of them that are somewhat unrelated, I have been
creating modules following the standard procedure I've used in other
languages. That is, I'm using:

module MyCompany
    module Module
         def self.func1
         end
         def func2
         end
    end
end

Now... the problems I am facing are...

1) Ruby's name pollution on includes.

--- B ---
module B
   def bfunc
      puts "bfunc"
   end
end
--- A ---
require 'B'

module A
   def afunc
      puts "afunc"
      bfunc
   end
end
---- some other code
require "A"
class X
   def initialize
      afunc # this should work
      bfunc # this should fail
   end
end

···

===============================
I want to have code that includes A, but does not include B. However,
class X should not have access to functions in module B, which it never
included.

How can I safely work around this? I want to avoid behaviors or
anything like that.

2) I also would like to have some modules that work either as include
modules or as modules with stand-alone methods. Problem is that ruby
will not "include" class methods.
That is, say I have a funcion called runcmd() to run a shell command
and do stdin/out/err piping. This function is rather common, so I
would like to have:

module Shell
    def self.runcmd(cmd)
       # ....do tons of stuff
    end
    def runcmd(cmd)
       Shell.runcmd(cmd)
    end
end

So I can do:

Shell.runcmd("ls")

or:

class Backup
     include Shell
     def doit
        runcmd("ls")
        runcmd("cmd2")
     end
....etc..
end

The above works but it seems kind of silly and wasteful for something
that to me seems pretty common (not to mention that the instance method
access will likely be slower, too).

[...]

I have a bunch of functions that, currently, have no particular
class location. Currently, I am placing them in modules. As I have
a bunch of them that are somewhat unrelated, I have been creating
modules following the standard procedure I've used in other
languages. That is, I'm using:

module MyCompany
  module Module
    def self.func1
    end
    def func2
    end
  end
end

Now... the problems I am facing are...
1) Ruby's name pollution on includes.

--- B ---
module B
  def bfunc
    puts "bfunc"
  end
end

--- A ---
require 'B'

module A

+ include B

···

On Sat, 19 Feb 2005 10:09:48 +0900, gga <GGarramuno@aol.com> wrote:
+

  def afunc
    puts "afunc"
    bfunc
  end
end

---- some other code
require "A"
class X

+ include A
+

  def initialize
    afunc # this should work
    bfunc # this should fail
  end
end

I presume that you mean the include statements I placed above.

I want to have code that includes A, but does not include B.
However, class X should not have access to functions in module B,
which it never included.

This is not possible without doing some tricks. If you want A to
have access to B, but not allow X (which included A) to have access
to B, then you need to figure out some other way. Perhaps:

  module B
    def self.bfunc; end
  end

  module A
    def afunc; B.bfunc end
  end

  class X
    include A

    def xfunc; afunc; end
  end

But if A has included B, then when you include A, you'll get
everything that it knows about mixed into your class. This is the
fundamental capability of Ruby's mix-ins: the mix-in essentially
becomes a private part of the class into which it is mixed.

2) I also would like to have some modules that work either as
include modules or as modules with stand-alone methods. Problem is
that ruby will not "include" class methods.

try:

  module Shell
    def runcmd(command); ...; end
    module_functtion :runcmd
  end

  class Backup
    include Shell
  end

It does the same thing as you did, except nicer.

-austin
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

I've faced this problem too, and I find out a workaround which may be
not very elegant, but results in only a contstant number of extra code
lines (not like the trivial solution shown above, which uses extra code
lines in a linear rate to the number of class methods in Shell).

module Shell
  # what would be module methods are rather collected in a separate
  # module
  module Addons
    def runcmd(cmd)
       # ....do tons of stuff
    end
  end

  # a custom inclusion method
  def useme aMod
    aMod.send :include, self
    aMod.extend Addons
  end
end

class Backup
  Shell.useme self
  ...
end

Backup.runcmd "ls"
#works

If you want instances of Backup to have direct access to runcmd, you can
include Addon in Shell. I don't see though the purpose of turning
class/module methods into instance methods (yeah, you save a few
characters of code by doing that, but it seems to be a bad design,
unless you are about breaking out of the class based object model).

Csaba

···

On 2005-02-19, gga <GGarramuno@aol.com> wrote:

2) I also would like to have some modules that work either as include
modules or as modules with stand-alone methods. Problem is that ruby
will not "include" class methods.
That is, say I have a funcion called runcmd() to run a shell command
and do stdin/out/err piping. This function is rather common, so I
would like to have:

module Shell
    def self.runcmd(cmd)
       # ....do tons of stuff
    end
    def runcmd(cmd)
       Shell.runcmd(cmd)
    end
end

So I can do:

Shell.runcmd("ls")

or:

class Backup
     include Shell
     def doit
        runcmd("ls")
        runcmd("cmd2")
     end
...etc..
end

The above works but it seems kind of silly and wasteful for something
that to me seems pretty common (not to mention that the instance method
access will likely be slower, too).

Excerpts from Csaba Henk's mail of 18 Feb 2005 (EST):

module Shell
  # what would be module methods are rather collected in a separate
  # module
  module Addons
    def runcmd(cmd)
       # ....do tons of stuff
    end
  end

  # a custom inclusion method
  def useme aMod
    aMod.send :include, self
    aMod.extend Addons
  end
end
#works

Use 'append_features' rather than 'useme'. See e.g. [ruby-talk:20021].
Then you can automatically create both class and instance methods.

Or, if the module's methods are all to be class methods, you can extend
rather than include it in the first place.

···

--
William <wmorgan-ruby-talk@masanjin.net>