0

I'm trying to clean up our namespaces. Basically our setup is somewhat like

class myClass
 include myModule1
 include myModule2

 @important_var   #critical instance variable

Basically @important_var is a telnet handler that almost all methods need to get at. This works fine with the way it is setup right now. Unfortunately myModule1 & myModule2 are getting huge. So I keep running into namespace collisions for the methods.

I'd love to access methods with a module wrapper eg:

myClass_instance.myModule1.a_method

But I can't figure out how to do this or some other cleaner name spacing idea?

  • classes and modules must begin with capitals. In your case: myClass -> MyClass, myModule1 -> MyModule1... – knut Sep 27 '11 at 19:30
  • You could start each method of MyModule1 with `m1_` – knut Sep 27 '11 at 19:35
  • Hard to say without seeing the code, but just from your description it sounds like some refactoring is needed. - Can you split your methods into lower-level plumbing that need @important_var directly, and isolate the others from it? - Does the class really have a single responsibility or could you split it? etc. – Eric G Sep 27 '11 at 20:34
  • @knut thanks..yea i mucked up the capitals in the names – carpe_noctum Sep 27 '11 at 20:40
  • It's a bit late, but this sounds like an ideal moment to learn about object aggregation and composition. It helps greatly with keeping things organized without cluttering up your namespace and if your components are inheriting from an interface, your code becomes less tightly coupled... –  May 01 '14 at 18:14

1 Answers1

2

Based on the idea to build a naming convention for the methods inside the modules I prepared a automated version:

module MyModule1
  def m;  "M1#m  <#{@important_var }>";  end
  #method according naming convention
  def m1_action;  "M1#m1 <#{@important_var }>";  end
end

module MyModule2
  def m;  "M2#m  <#{@important_var }>";  end
  #method according naming convention
  def m2_action;  "M2#m2 <#{@important_var }>";  end
end

class MyClass
  #add prefix to each method of the included module.
  def self.myinclude( mod, prefix )
    include mod
    #alias each method with selected prefix
    mod.instance_methods.each{|meth|      
      if meth.to_s[0..prefix.size-1] == prefix
        #ok, method follows naming convention
      else #store method as alias
        rename = "#{prefix}#{meth}".to_sym
        alias_method(rename, meth)
        puts "Wrong name for #{mod}##{meth} -> #{rename}" 
      end
    }
    #define a method '<<prefix>> to call the methods
    define_method(prefix){ |meth, *args, &block | send "#{prefix}#{meth}".to_sym *args, &block }
  end
  myinclude MyModule1, 'm1_'
  myinclude MyModule2, 'm2_'
  def initialize
    @important_var   = 'important variable' #critical instance variable
  end
end

###################
puts "-------Test method calls--------"

m = MyClass.new
p m.m1_action
p m.m2_action

p m.m #last include wins

puts "Use renamed methods"
p m.m1_m
p m.m2_m
puts "Use 'moduled' methods"
p m.m1_(:m)
p m.m2_(:m)

myinclude includes the module and checks, if each method begins with a defined prefix. If not the method is defined (via alias). In addition you get a method called like the prefix. This method forwards the call to the original module-method. See example in the code end.

knut
  • 27,320
  • 6
  • 84
  • 112