如何在Ruby中创建层次结构类名?

4
在Ruby中,命名为Foo的类可以使用class Foo进行定义,通过require 'foo'进行使用,并位于$:[0]/foo.rb或类似位置。
但是对于Foo::Bar呢?它是否可以使用require 'foo/bar'进行调用?它是否位于$:[0]/foo/bar.rb中?它该如何定义?
我很习惯使用Perl,在个人项目中我会创建嵌套类,例如Project::UserProject::Text::IndexProject::Text::Search等。然后我会创建一个像Project/Text/Index.pm这样的文件,其中会以package Project::Text::Index开始,并通过use Project::Text::Index;进行调用。
现在我正在Ruby中启动一个项目,不知道该如何做。出于某种原因,我阅读过的所有Ruby书籍和文档都没有提到perl风格的层次化类命名。当他们提到继承时,通常是通过一个类似于class Foo < Bar的微不足道的例子,这并没有真正帮助我。但我认为我尝试的事情一定是可能的,因为Rails(只是举一个例子)有像ActionView::Helpers::ActiveModelFormBuilder这样的类。
2个回答

6
您在这里把几个概念混合在了一起,它们并不相关,即加载路径、继承和作用域解析运算符。
当需要(或加载)文件时,require 关键字的参数只是被视为文件路径,并附加到加载搜索路径上(对于 require.rb 扩展名是可选的)。在这里,继承和嵌套并不起作用,任何文件都可以定义任何内容,例如:
require 'foo' # Looks for "foo.rb" in each of $:
require 'foo/bar' # Looks for "foo/bar.rb" in each of $:

嵌套的类(以及模块、变量等)按预期进行定义,但是需要使用作用域解析运算符来确定其解析方式,例如:

class Foo
  def foo; 'foo'; end
  class Bar
    def bar; 'bar'; end
  end
end
Foo.new.foo # => "foo"
Foo::Bar.new.bar # => "bar"

请注意,类嵌套和继承与加载它们的文件的位置无关。对于类/模块结构似乎没有明确的约定,所以你可以自由地按照适合你的方式进行。《Programming Ruby》书中的Ruby语言页面可能也会有所帮助。

3

你需要模块。如果你想要一个在Funthing/Text/Index.rb中被标识为Funthing::Text::Index的类,并且可以通过require 'Funthing/Text/Index'进行引用,那么你需要这样做:

# file Funthing/Text/Index.rb
module Funthing
  module Text
    class Index
      def do_the_twist()
        puts "Let's twist again!"
      end
    end
  end
end

然后像这样使用它:
require "Funthing/Text/Index"
c = Funthing::Text::Index.new

注意:文件层次结构不是必需的,但(在我看来)是最佳实践。


2
很好的答案,但是文件名(和 require)应该用小写字母:funthing/text/index.rb。 - tokland
关于将类嵌套在模块内和嵌套在类内的区别,您有什么评论吗?似乎这个模块示例可以只使用类定义来实现。 - Don Park

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接