From: Rolf Pedersen Date: 2010-07-28T04:29:28+09:00 Subject: Re: Module inclusion and class macro problem --001517593660c937f7048c63844f Content-Type: text/plain; charset=ISO-8859-1 Hi Paolo Thanks for answering :o) I understand that the code is executed immediately. (After all, I did read your book! ;o) ) The code you proposed actually matches exactly what I had in the previous iteration. But in this next iteration, instead of defining the methods in the Interface::xxx modules, and thereby repeat code (def...end, and possibly in other cases even the body of the methods), my goal was to use a similar technique to the class macros, only in the modules instead. So is this possible to accomplish? Kind regards, -Rolf On Mon, Jul 26, 2010 at 12:45 AM, Paolo Perrotta < paolo.nusco.perrotta@gmail.com> wrote: > Hello, Rolf. Let's wrap up what happened and why. The issue comes from > these lines: > > > module Interface > > module ILockable > > add_interface_methods :lock, :unlock > > end > > > > # ... > > end > > Coming from C#, you're probably tempted to assume that the code inside > ILockable (and IDrivable) is executed only when a class/module is > "loaded". Actually, that code is executed immediately as Ruby goes > through the definition. > > So, at this point (and independently of all the other code in your > example), Ruby tries to execute add_interface_methods() in the scope > of Interface::ILockable. Inside that scope, the role of self is taken > by Interface::ILockable itself - so that's the implicit receiver of > any method call. So Ruby tries to call > Interface::ILockable.add_interface_methods(), doesn't find that > method, and fails. > > In the real world, I'd go for something simpler (and I'd be a real > prick in questioning the notion of strongly typed interfaces in > Ruby ;) ). However, because this is a great learning exercise, here's > something along your own lines that probably works as you expect: > > --- > module Interface > module Base > def self.included(base) > base.extend ClassMethods > end > module ClassMethods > def implement_interfaces(*interfaces) > interfaces.each do |interface| > @interface_methods = (@interface_methods || []) + > interface.instance_methods > puts "self: " + self.inspect.to_s > end > end > def enforce_interfaces > if not (not_implemented_interface_methods = @interface_methods > - self.instance_methods).empty? > raise RuntimeError, "The following interface methods are not > implemented in class #{self.to_s}:\n " > +not_implemented_interface_methods.inspect > end > end > end > end > end > > module Interface > module ILockable > def lock; end > def unlock; end > end > > module IDrivable > def drive; end > def end; end > end > end > > class MyClass > include Interface::Base > implement_interfaces Interface::ILockable, Interface::IDrivable > # methods and other stuff > enforce_interfaces > end > > > --- > Paolo "Nusco" Perrotta > Metaprogramming Ruby (http://www.pragprog.com/titles/ppmetr) > > --001517593660c937f7048c63844f--