Module nesting and module vs. instance methods

Discussion in 'Ruby' started by gga, Feb 19, 2005.

  1. gga

    gga Guest

    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).
    gga, Feb 19, 2005
    #1
    1. Advertising

  2. gga

    Csaba Henk Guest

    On 2005-02-19, gga <> 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).


    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
    Csaba Henk, Feb 19, 2005
    #2
    1. Advertising

  3. On Sat, 19 Feb 2005 10:09:48 +0900, gga <> wrote:
    [...]
    > 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
    +
    > 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 *
    * Alternate:
    Austin Ziegler, Feb 19, 2005
    #3
  4. 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 <>
    William Morgan, Feb 19, 2005
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John M. Gabriele
    Replies:
    18
    Views:
    1,141
    Steven Bethard
    Feb 18, 2005
  2. Trans
    Replies:
    10
    Views:
    286
    Sean O'Halpin
    Sep 16, 2005
  3. Replies:
    1
    Views:
    135
    Trans
    Feb 5, 2007
  4. Leon Bogaert
    Replies:
    19
    Views:
    315
    Robert Klemme
    Mar 23, 2008
  5. Kenneth McDonald
    Replies:
    5
    Views:
    298
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page