Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Private class (not class method) in a Ruby module?

I'm new to Ruby (experienced with Python, C++ and C). I need to create a class that is only to be used by other classes and methods in a module. In Python, I'd just call it __classname. I'd use an empty typedef in C++. How do I do this in Ruby (or am I barking up the wrong tree and not doing this the "Ruby way"?)

like image 265
c4757p Avatar asked Aug 16 '10 18:08

c4757p


People also ask

Can a Ruby module have private methods?

Understanding Private Methods in RubyYou can only use a private method by itself. It's the same method, but you have to call it like this. Private methods are always called within the context of self .

Can a class method be private Ruby?

there's no such thing as "a private section" in Ruby. To define private instance methods, you call private on the instance's class to set the default visibility for subsequently defined methods to private... and hence it makes perfect sense to define private class methods by calling private on the class's class, ie.

Can you call a private method outside a Ruby class using its object?

Private methods can't be called outside the class. Private methods can be called inside a class inside other methods.

CAN modules have private methods?

Private instance/class methods for modulesDefining a private instance method in a module works just like in a class, you use the private keyword. You can define private class methods using the private_class_method method.


1 Answers

The most important thing to realize is that a class is nothing special. It's just an object. Per convention, classes are assigned to constants, but there is nothing that says they have to be.

And since classes are just objects like any other object, you make them private the same way that you make any other object private.

Here are the possibilities I can think of, in the order of increasing privateness:

  1. Just nest them inside a namespace (i.e. module). In Ruby, it is generally expected that all of a library's modules and classes live inside a namespace with the same name as the library (i.e. my_awesome_libraryMyAwesomeLibrary), but in general, everything which is nested below that namespace, is considered private. In fact, besides Test::Unit::TestCase, I cannot think of a single example of a three-level deep namespace that is actually expected to be used by client code.
  2. same as 1., but name it something obvious, like MyAwesomeLibrary::Internal::FfiStruct
  3. same as 1. or 2., and mark it with the :nodoc: RDoc tag.
  4. similar to 3., but use a more modern documentation system like YARD, which actually lets you explicitly mark up private APIs.
  5. Use a method instead of a constant. Methods can be made private. (For consistency's sake, you can have the method name start with an uppercase letter, to make it resemble a constant. There's nothing to prevent that, the snake_case convention is just that: a convention.)
  6. Use an instance variable. They are always private. Note that both private methods and instance variables can be trivially accessed using reflection. send seems to be in more widespread use than instance_variable_get, though, which is why I consider instance variables to have a higher level of privacy than methods.
  7. Really the only way to get actual privacy or encapsulation is using local variables and closures, though. Note however that this might preclude you from using Ruby's module, class or method definition syntax, because those create new scopes. In all cases where you need access to the class, you need to use Module.new, Class.new or Module#define_method.

Ex.:

module MyAwesomeLibrary
  struct = Class.new(FFI::Struct) do
    # ...
  end

  PublicInterface = Class.new do
    define_method(:initialize) do |bar|
      @foo = struct.new(bar)
    end
  end
end

And yes, this is the only way of achieving true 100% information hiding and encapsulation in Ruby.

However, the normal Ruby way would be to simply document the stuff as being private (maybe push it down a level of namespacing) and trust your fellow developers. In the Ruby community, this is sometimes summarized under the Python slogan "We are all consenting adults".

like image 105
Jörg W Mittag Avatar answered Sep 18 '22 12:09

Jörg W Mittag