From: trans Date: 2009-02-20T23:12:02+09:00 Subject: Re: module include class/instance methods confusion!! On Feb 20, 8:42 am, "David A. Black" wrote: > Hi -- > > > > On Fri, 20 Feb 2009, Adam Wilson wrote: > > I have been having trouble today with a module include in a Rails app. > > The module file sits in the /lib folder. > > > My problem, I worked out (which I have noticed before) is that I cannot > > seem to access defined class methods in the module via the including > > class. It seems that only instance methods are available. Let me > > explain: > > > module MyModule > >  def self.test > >    "class" > >  end > > >  def test > >    "instance" > >  end > > end > > > class MyClass > >  include MyModule > > end > > > class MyController > >  my_class = MyClass.new > > >  test1 = MyClass.test #=> gives an NoMethodError > >  test2 = my_class.test #=> works > > end > > > Is there something I am missing here? Please note I just wrote this code > > quickly to show the idea, have not tested! > > Its not essential but seems a bit silly that I need to use an instance > > method in a situation when a class method would be much neater. > > > Any pointers much appreciated! > > If you have a spare six months, you can look through the previous > discussions of this topic on this list :-) > > Basically, the module and the class that includes it are independent > agents, when it comes to their own singleton/class methods. The > include operation is for the benefit of the objects that already > consult the class for methods: it adds the module to the method lookup > path of those objects. The class object itself is unaffected. > > You can intercept the include event, though, and manipulate the lookup > path of the class object itself. A very common pattern is: > >    module M >      def x >        puts "Instance method" >      end > >      module ClassMethods >        def y >          puts "Class method" >        end >      end > >      def self.included(c) >        c.extend(ClassMethods) >      end >    end > >    class C >      include M >    end > >    C.new.x       # Instance method >    C.y           # Class method > > The idea here is to extend (i.e., do a per-object include) the class > object itself with a specialized module, M::ClassMethods, at the same > time that the module M is included in the class. > > The name "ClassMethods", of course, is arbitrary; the methods defined > in that module are instance methods of the M::ClassMethods module. > They only become "class methods" by virtue of the extend operation. > > I know it probably seems like a lot of work for something that you > might think should be automatic, but it's actually good that it isn't > automatic, because that would remove the ability to keep the singleton > (class) methods of a given module and a given class separate. This > way, with the out-of-the-box behavior being the more basic, there's > nothing you can't do. I think that's a fallacious argument. First, I would like to see an example where it would really be a problem. I've heard plenty of opinion on this, I've yet to see any hard examples where it is actually a problematic limitation. But besides that, why can't there be both? Let #include do it's thing and have another method provide the other. My argument for having the capability is that it provides single encapsulation of concerns. I have come across plenty of situations where the meta and instance level need to communicate. This works fine if your need fits the profile of a subclass. But if you need a mixin, then you are forced to encapsulate the two parts as separate modules, even though they represent a single cohesive unit of logic. We end up with extraneous separations of code with non-descriptive names, like "ClassMethods", which is neither intuitive or naturally documenting. T.