Private modular methods in Ruby

I have a two-part question

Best practice

  • I have an algorithm that performs some operation on a data structure using an open interface
  • Currently, it is a module with many static methods, all private, with the exception of one open interface method.
  • There is one instance variable that must be shared between all methods.

These are the options that I see which is better ?:

  • Module with static ('module' in ruby) methods
  • Class with static methods
  • Mixin module for inclusion in the data structure
  • Refactoring from the part of the algorithm that changes this data structure (very small) and makes it mixin, which calls the static methods of the algorithm module

Technical part

Is there a 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 

private there seems to have no effect , I can still call Thing.priv without any problems.

+78
ruby access-specifier
Nov 25 '08 at 21:01
source share
9 answers

I think the best way (and basically how existing libraries are written) is to do this by making a class in a module that deals with all the logic, and the module just provides a convenient method, for example.

 module GTranslate class Translator def perform( text ); 'hola munda'; end end def self.translate( text ) t = Translator.new t.perform( text ) end end 
+76
Jan 08 '09 at 15:11
source share

There's also Module.private_class_method , which perhaps expresses more intentions.

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

For the code in question:

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

Ruby 2.1 or later:

 module Thing def self.pub; puts "Public method"; end private_class_method def self.priv; puts "Private method"; end end 
+58
Jan 6 '09 at 21:48
source share

You can use the on method to do fancy things when the module mixes. This is 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 
+25
Nov 26 '08 at 16:58
source share
 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) 
+15
Jan 26 '16 at 11:15
source share

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 did not play with this in the modules.

+11
Nov 25 '08 at 21:15
source share

Good way:

 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 
+1
Jun 15 '15 at 20:21
source share

What about storing methods like lambdas in class variables / constants?

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

For the 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 AB A::C AC A::D AD } eval expr rescue puts expr end 

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

0
Oct 17
source share

The best sample I've found doing this in Rails is to drop modules that want private methods and use the Singleton class instead. It doesnโ€™t feel good, but it works and seems cleaner than other examples that I saw in this question.

I would like to hear other opinions on this matter.

Example:

 ErrorService.notify("Something bad happened") class ErrorService include Singleton class << self delegate :notify, to: :instance end def notify(message, severity: :error) send_exception_notification(message) log_message(message, severity) end private def send_exception_notification(message) # ... end def log_message(message, severity) # ... end end 
0
Nov 09 '16 at 6:54
source share

Make a private module or class

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

Thus, an alternative :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 

Using:

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

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

0
Nov 10 '16 at 15:56
source share



All Articles