Module methods acting like instance methods in extension module

I'm working with an extension module (written in C) that is a wrapper
of another C library. The extension module makes one big Ruby module
with a bunch of module methods. That is, the calls in the extension
module C code are all rb_define_module_function(...).

If I build and 'require' this module, I can see

irb:> TheModule.instance_methods
==> []

which is expected.

I do:

irb:> TheModule.methods - Object.methods

and get all the ones I expect to see. Ok.

What's confusing is, in my Ruby code, when I use this module, I'm able
to do this:

require 'the_module'
include TheModule

and then call the supposed module methods in TheModule without
prefixing them with "TheModule.". That is, I can call "foo123" instead
of "TheModule.foo123" and it works.

Am I not understanding correctly how "include" works? Can anyone tell
me why this works? I tried it with some simple example code (pure
Ruby):

----------------- code -------------------
module TheModule
    def self.foo123
        puts "Doing stuff..."
    end
end

include TheModule
foo123
----------------- /code -------------------

but it fails, as expected (seemingly in conflict with how the
extension module is behaving). BTW, if I try:

----------------- code -------------------
module TheModule
    def self.foo123
        puts "Doing stuff..."
    end
end

TheModule.foo123

p TheModule.methods - Object.methods
----------------- /code -------------------

I get:

$ ./foo.rb
Doing stuff...
["foo123"]

as expected.

Looking at README.EXT, it has this to say on the matter:

------------------------------- 8< --------------------------------
The other [way to define methods] is to define module functions, which
are private AND singleton
methods of the module. For example, sqrt is the module function
defined in Math module. It can be call in the form like:

  Math.sqrt(4)

or

  include Math
  sqrt(4)

To define module functions, use:

  void rb_define_module_function(VALUE module, const char *name,
         VALUE (*func)(), int argc)
------------------------------- 8< --------------------------------

I don't understand why it says that they're private -- I'm calling
them from my Ruby code and it seems they're being accessed, so they
don't seem private... What does the author of the README mean by
"private" here?

Thanks for any insights.

---John

Am I not understanding correctly how "include" works? Can anyone tell
me why this works? I tried it with some simple example code (pure
Ruby):

Well try this

moulon% cat b.rb
#!/usr/bin/ruby

module TheModule
   def self.foo123
      puts "Doing stuff..."
   end

   private
   def foo123
      puts "I'm the private method doing stuff..."
   end
end

include TheModule
TheModule.foo123
foo123
self.foo123 # will give an error because it's a private method
moulon%

moulon% ./b.rb
Doing stuff...
I'm the private method doing stuff...
./b.rb:17: private method `foo123' called for main:Object (NoMethodError)
moulon%

module_function define a public singleton method and a private method.

Guy Decoux

Thanks for the reply Guy.

So, rb_define_module_function does *both*? Ah. Interesting.

Now, I've always read that a "singleton method" is one that you add to
your own instance of something -- such that, other instances don't
have the method; just yours. In the code above, I see a public module
method... why do you refer to it as a public "singleton" method?

Also, I see that the reason we can call foo123 like that (after doing
the include) is because it's an instance method and we're getting it
when we do the include. It may be private, but since we've included
the module, it's like it's a private method in our own class (which we
can of course access). The difference between calling 'foo123' and
'self.foo123' seems more subtle... possibly having to do with how the
mixin feature is implemented? (the PickAxe 2nd ed. mentions an
"anonymous proxy class", p. 383)

Your comment "# will give an error because it's a private method"
doesn't make sense to me, since just calling 'foo123' does in fact
work, and foo123 is private.

---John

···

On 7/5/06, ts <decoux@moulon.inra.fr> wrote:

> Am I not understanding correctly how "include" works? Can anyone tell
> me why this works? I tried it with some simple example code (pure
> Ruby):

Well try this

moulon% cat b.rb
#!/usr/bin/ruby

module TheModule
   def self.foo123
      puts "Doing stuff..."
   end

   private
   def foo123
      puts "I'm the private method doing stuff..."
   end
end

include TheModule
TheModule.foo123
foo123
self.foo123 # will give an error because it's a private method
moulon%

moulon% ./b.rb
Doing stuff...
I'm the private method doing stuff...
./b.rb:17: private method `foo123' called for main:Object (NoMethodError)
moulon%

module_function define a public singleton method and a private method.

So, rb_define_module_function does *both*? Ah. Interesting.

rb_define_module_function() do the same thing than Module#module_function

moulon% ri module_function
------------------------------------------------- Module#module_function
     module_function(symbol, ...) => self

···

------------------------------------------------------------------------
     Creates module functions for the named methods. These functions may
     be called with the module as a receiver, and also become available
     as instance methods to classes that mix in the module. Module
     functions are copies of the original, and so may be changed
     independently. The instance-method versions are made private. If
     used with no arguments, subsequently defined methods become module
     functions.

        module Mod
          def one
            "This is one"
          end
          module_function :one
        end
        class Cls
          include Mod
          def callOne
            one
          end
        end
        Mod.one #=> "This is one"
        c = Cls.new
        c.callOne #=> "This is one"
        module Mod
          def one
            "This is the new one"
          end
        end
        Mod.one #=> "This is one"
        c.callOne #=> "This is the new one"
moulon%

Your comment "# will give an error because it's a private method"
doesn't make sense to me, since just calling 'foo123' does in fact
work, and foo123 is private.

Well, in ruby a private method is a method that you can only call "like a
function" (see the thread send/funcall "About 1.9 #__method__ feature"),
i.e. without a receiver.

In this case

   foo123 # will work, the method is called without a receiver
   self.foo123 # will give an error because ruby will try to call
                # TheModule#foo123 which is private

   TheModule.foo123 # will work because ruby will call the
                    # singleton method TheModule::foo123, which is
                    # public

Guy Decoux