为什么我们要在Ruby中的类中放置一个模块?

Nat*_*ong 37 ruby namespaces

在Ruby中,我发现为了命名空间而将类放在模块中会很有用.我也看到可以将模块放在类中.但我不明白你为什么那样做.

模块通常混合成类,对吧?那么,在类中定义模块的目的是什么?

Jos*_*ein 53

我们可以在编写像这样的类似猿的代码时使用它:

class DrugDealer
  module Drug
    def happy?; true; end
  end

  def approach(victim)
    victim.extend Drug
  end
end

o = Object.new
DrugDealer.new.approach(o)
o.happy? # => true
Run Code Online (Sandbox Code Playgroud)

在现实世界中更实用的另一个例子是具有仅由子类应用的mixin.

当一些这是有用的方面的东西应用到一些子类和其他方面适用于其他子类,而不存在于这些方面的应用让位给一个明确的类层次结构(树)的方式足够的订单.想多重继承!一个简化的例子:

class Person
  def handshake
    :sloppy
  end

  def mind_contents
    :spam
  end

  module Proper
    def handshake
      :firm
    end
  end

  module Clever
    def mind_contents
      :theories
    end
  end
end

class Professor < Person
  include Proper
  include Clever

  # ...
end
Run Code Online (Sandbox Code Playgroud)

等等.有点好,当合理使用时.即使是超级调用和构造函数(我之前没有定义任何内容)也会按照我希望的方式遍历所有的mixin和类.


Nat*_*ong 8

我已经遇到了一个具有复杂命名空间的大型Rails应用程序中的用例.一个简化的例子:

# app/models/invoice/dependents/item.rb
class Invoice
  module Dependents
    class Item
      # Define invoice item
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

Invoice是一个自己的类,但也是其依赖项的一个很好的命名空间.我们不能说module Invoice因为该常量已经被定义为一个类,但我们仍然可以将它用作命名空间.

巨人警告

如果您使用类作为命名空间,并且您正在使用Rails,请确保您不会在其他地方意外地声明该类.自动加载会破坏你的一天.例如:

# app/helpers/invoice/dependents/items_helper.rb
class Invoice       # This line will cause you grief
  module Dependents
    module ItemsHelper
      # view helper methods
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

class Invoice此文件中声明的事实会创建加载顺序依赖项; 如果class Invoice在预期的类定义之前执行此文件的行,则您的预期类定义可能无法正常工作.在这个例子中,我不能声明Invoicesublcasses ActiveRecord::Baseif Invoice已经声明没有父类.

可能需要在另一个文件的顶部使用"真正的"类定义文件,但至少在Rails自动加载方案中,如果您执行此操作,则可以进行更少的争论:

# app/helpers/invoice/dependents/items_helper.rb
module Invoice:Dependents::ItemsHelper  
  # view helper methods
end
Run Code Online (Sandbox Code Playgroud)

使用这种语法,Rails将看到Invoice常量并使用自动加载查找,在模型文件中找到它并按照您的预期方式定义它.

  • 对警告的很好解释——我也刚好。但是如果你采用建议的方法(`module Invoice::Dependents::ItemsHelper`),如果你想引用 `Invoice::Dependents` 范围内的其他类怎么办?我发现我必须包含完整的类名(`Invoice::Dependents::OtherClass.method`),这很烦人。 (2认同)
  • 我相信随着 Zeitwerk 自动装载机的推出,这个问题已经得到解决。经典自动加载器的弃用周期将从 Rails 6.1 开始 (2认同)

hor*_*guy 6

class Image
    module Colors
        Red = ...
        Blue = ...
    end
    include Colors
end

include Image::Colors

Image.new.set_pixel x, y, Red 
Run Code Online (Sandbox Code Playgroud)