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"?)
I haven't seen such concept so far in Ruby, but I guess you could simulate that by creating private method which would return a class created as a local variable (remember that in Ruby, a class is an object just like any other, and can be instantiated in a method and returned by it).
BTW, even private methods in Ruby aren't as private as in other languages - you can always access them using send
method. But doing that implies you know what you are doing.
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:
- 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_library
→MyAwesomeLibrary
), but in general, everything which is nested below that namespace, is considered private. In fact, besidesTest::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. - same as 1., but name it something obvious, like
MyAwesomeLibrary::Internal::FfiStruct
- same as 1. or 2., and mark it with the
:nodoc:
RDoc tag. - similar to 3., but use a more modern documentation system like YARD, which actually lets you explicitly mark up private APIs.
- 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.) - 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 thaninstance_variable_get
, though, which is why I consider instance variables to have a higher level of privacy than methods. - 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
orModule#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".
Taking this information straight from this blog post, but since Ruby 1.9.3 you can create a private class within a module using private_constant
:
class Person
class Secret
def to_s
"1234vW74X&"
end
end
private_constant :Secret
def show_secret
Secret.new.to_s
end
end
来源:https://stackoverflow.com/questions/3496291/private-class-not-class-method-in-a-ruby-module