Private module methods in Ruby

2019-01-12 17:14发布

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 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.

9条回答
兄弟一词,经得起流年.
2楼-- · 2019-01-12 17:16

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.

查看更多
戒情不戒烟
3楼-- · 2019-01-12 17:18

Make a private module or class

Constants are never private. However, it's possible to create a module or class without assigning it to a constant.

So an alternative to :private_class_method is to create a private module or class and define public methods on it.

module PublicModule
  def self.do_stuff(input)
    @private_implementation.do_stuff(input)
  end

  @private_implementation = Module.new do
    def self.do_stuff(input)
      input.upcase # or call other methods on module
    end
  end
end

Usage:

PublicModule.do_stuff("whatever") # => "WHATEVER"

See the docs for Module.new and Class.new.

查看更多
乱世女痞
4楼-- · 2019-01-12 17:19

What's about storing methods as lambdas within class variables/constants?

module MyModule
  @@my_secret_method = lambda {
    # ...
  }
  # ...
end

For test:

module A
  @@C = lambda{ puts "C" }
  def self.B ; puts "B"; @@C[] ; end
  private     # yeah, this has no sense, just for experiment
  def self.D ; puts "D"; @@C[] ; end
end

for expr in %w{ A::B A.B A::C A.C A::D A.D }
  eval expr rescue puts expr
end

Here we see that C can be successfully used by B and D, but not from outside.

查看更多
贼婆χ
5楼-- · 2019-01-12 17:20
module Writer
  class << self
    def output(s)
      puts upcase(s)
    end

    private

    def upcase(s)
      s.upcase
    end
  end
end

Writer.output "Hello World"
# -> HELLO WORLD

Writer.upcase "Hello World"
# -> so.rb:16:in `<main>': private method `upcase' called for Writer:Module (NoMethodError)
查看更多
不美不萌又怎样
6楼-- · 2019-01-12 17:36

A nice way is like this

module MyModule
  class << self
    def public_method
      # you may call the private method here
      tmp = private_method
      :public
    end

    private def private_method
      :private
    end
  end
end

# calling from outside the module
puts MyModule::public_method
查看更多
来,给爷笑一个
7楼-- · 2019-01-12 17:37

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
查看更多
登录 后发表回答