Ruby模块中的私有类(非类方法)?

时间:2022-06-13 11:00:59

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"?)

我是Ruby新手(有过Python、c++和C的经验),我需要创建一个只供模块中其他类和方法使用的类。在Python中,我只叫它__classname。我将在c++中使用一个空的typedef。我如何在Ruby中做这件事(或者我是在错误的树中做这件事,而不是用“Ruby方式”做这件事?)

3 个解决方案

#1


4  

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

到目前为止我还没有见过这样的概念在Ruby中,但是我想你可以模拟,通过创建私有方法将返回一个类创建一个局部变量(记住,在Ruby中,一个类是一个对象就像任何其他,和可以实例化一个方法,返回的)。

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.

顺便说一句,即使Ruby中的私有方法也不像其他语言中的私有方法那样—您总是可以使用send方法访问它们。但这样做意味着你知道你在做什么。

#2


27  

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. 将它们嵌套在一个名称空间(即模块)中。在Ruby中,人们普遍预期,图书馆的所有模块和类同名的生活在一个名称空间作为图书馆(即my_awesome_library→MyAwesomeLibrary),但总的来说,这一切都是嵌套低于该名称空间,被认为是私有的。实际上,除了Test::Unit::TestCase之外,我想不出客户机代码实际希望使用的三层深度名称空间的单个示例。
  3. same as 1., but name it something obvious, like MyAwesomeLibrary::Internal::FfiStruct
  4. 与1相同。,但请说出一些显而易见的东西,比如MyAwesomeLibrary::Internal:::FfiStruct
  5. same as 1. or 2., and mark it with the :nodoc: RDoc tag.
  6. 与1相同。或2。,并使用:nodoc: RDoc标记。
  7. similar to 3., but use a more modern documentation system like YARD, which actually lets you explicitly mark up private APIs.
  8. 类似于3。,但是使用更现代的文档系统,比如YARD,它实际上允许您显式地标记私有api。
  9. 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.)
  10. 用方法代替常数。方法可以变得私有。(为了保持一致性,您可以让方法名以大写字母开头,使其类似于常量。没有什么可以阻止的,snake_case公约就是这样的:一个约定。
  11. 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.
  12. 用一个实例变量。他们总是私人。注意,可以使用反射对私有方法和实例变量进行简单访问。发送似乎比instance_variable_get更广泛地使用,这也是为什么我认为实例变量比方法具有更高的隐私级别。
  13. 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.
  14. 实际上,获得实际隐私或封装的唯一方法是使用本地变量和闭包。但是请注意,这可能会阻止您使用Ruby的模块、类或方法定义语法,因为这些语法创建了新的作用域。在所有需要访问类的情况下,都需要使用模块。新的类。#使用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.

是的,这是在Ruby中实现真正100%信息隐藏和封装的唯一方法。

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

然而,通常的Ruby方法是简单地将这些内容记录为私有(可能会将其推入名称空间级别),并信任您的开发伙伴。在Ruby社区中,有时会在Python的口号“我们都是自愿的成年人”下进行总结。

#3


10  

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:

直接从这篇博文中获取这些信息,但是由于Ruby 1.9.3,您可以使用private_constant在模块中创建一个私有类:

class Person
  class Secret
    def to_s
      "1234vW74X&"
    end
  end
  private_constant :Secret

  def show_secret
    Secret.new.to_s
  end
end

#1


4  

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

到目前为止我还没有见过这样的概念在Ruby中,但是我想你可以模拟,通过创建私有方法将返回一个类创建一个局部变量(记住,在Ruby中,一个类是一个对象就像任何其他,和可以实例化一个方法,返回的)。

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.

顺便说一句,即使Ruby中的私有方法也不像其他语言中的私有方法那样—您总是可以使用send方法访问它们。但这样做意味着你知道你在做什么。

#2


27  

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. 将它们嵌套在一个名称空间(即模块)中。在Ruby中,人们普遍预期,图书馆的所有模块和类同名的生活在一个名称空间作为图书馆(即my_awesome_library→MyAwesomeLibrary),但总的来说,这一切都是嵌套低于该名称空间,被认为是私有的。实际上,除了Test::Unit::TestCase之外,我想不出客户机代码实际希望使用的三层深度名称空间的单个示例。
  3. same as 1., but name it something obvious, like MyAwesomeLibrary::Internal::FfiStruct
  4. 与1相同。,但请说出一些显而易见的东西,比如MyAwesomeLibrary::Internal:::FfiStruct
  5. same as 1. or 2., and mark it with the :nodoc: RDoc tag.
  6. 与1相同。或2。,并使用:nodoc: RDoc标记。
  7. similar to 3., but use a more modern documentation system like YARD, which actually lets you explicitly mark up private APIs.
  8. 类似于3。,但是使用更现代的文档系统,比如YARD,它实际上允许您显式地标记私有api。
  9. 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.)
  10. 用方法代替常数。方法可以变得私有。(为了保持一致性,您可以让方法名以大写字母开头,使其类似于常量。没有什么可以阻止的,snake_case公约就是这样的:一个约定。
  11. 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.
  12. 用一个实例变量。他们总是私人。注意,可以使用反射对私有方法和实例变量进行简单访问。发送似乎比instance_variable_get更广泛地使用,这也是为什么我认为实例变量比方法具有更高的隐私级别。
  13. 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.
  14. 实际上,获得实际隐私或封装的唯一方法是使用本地变量和闭包。但是请注意,这可能会阻止您使用Ruby的模块、类或方法定义语法,因为这些语法创建了新的作用域。在所有需要访问类的情况下,都需要使用模块。新的类。#使用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.

是的,这是在Ruby中实现真正100%信息隐藏和封装的唯一方法。

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

然而,通常的Ruby方法是简单地将这些内容记录为私有(可能会将其推入名称空间级别),并信任您的开发伙伴。在Ruby社区中,有时会在Python的口号“我们都是自愿的成年人”下进行总结。

#3


10  

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:

直接从这篇博文中获取这些信息,但是由于Ruby 1.9.3,您可以使用private_constant在模块中创建一个私有类:

class Person
  class Secret
    def to_s
      "1234vW74X&"
    end
  end
  private_constant :Secret

  def show_secret
    Secret.new.to_s
  end
end