tags:

views:

2280

answers:

4

I have a two part question

Best-Practice

  • I have an algorithm that performs some operation on a data structure using the public interface
  • It is currently a module with numerous static methods, all private except for the one public interface method.
  • There is one instance instance variable that needs to be shared among all the methods.

These are the options I can see, which is the best?:

  • Module with static ('module' in ruby) methods
  • Class with static methods
  • Mixin module for inclusion into the data structure
  • Refactor out the part of the algorithm that modifies that data structure (very small) and make that a mixin that calls the static methods of the algorithm module

Technical part

Is there any way to make a private Module method?

module Thing
  def self.pub; puts "Public method"; end
  private
  def self.priv; puts "Private method"; end
end

The private in there doesn't seem to have any effect, I can still call Thing.priv without issue.

+2  A: 

Unfortunately, private only applies to instance methods. The general way to get private "static" methods in a class is to do something like:

class << self
  private

  def foo()
   ....
  end
end

Admittedly I haven't played with doing this in modules.

J Cooper
+2  A: 

You can use the "included" method to do fancy things when a module is mixed in. This does about what you want I think:

module Foo
  def self.included(base)
    class << base 
      def public_method
        puts "public method"
      end
      def call_private
        private_method
      end
      private
      def private_method
        puts "private"
      end
    end
  end
end

class Bar
  include Foo
end

Bar.public_method

begin
  Bar.private_method
rescue
  puts "couldn't call private method"
end

Bar.call_private
Cameron Price
That's clever. So it's possible, but probably not worth it.
Daniel Beardsley
+1  A: 

There's also Module.private_class_method, which arguably expresses more intent.

module Foo
  def self.included(base)
    base.instance_eval do
      def method_name
        # ...
      end
      private_class_method :method_name
    end
  end
end
+1  A: 

I think the best way (and mostly how existing libs are written) do this by making a class within the module that deals with all the logic, and the module just provides a convenient method, e.g.

module GTranslate
  class Translator
    def perform( text ); 'hola munda'; end
  end

  def self.translate( text )
    t = Translator.new
    t.perform( text )
  end
end

just my .02

ucron
This makes sense.
Daniel Beardsley