Зачем нам помещать модуль в класс в Ruby? - PullRequest
37 голосов
/ 23 августа 2010

В Ruby я вижу, что может быть полезно поместить классы в модули для пространства имен. Я также вижу, что можно размещать модули внутри классов. Но я не понимаю, почему ты это сделал.

Модули обычно смешиваются в классы, верно? Итак, какова цель определения модуля внутри класса?

Ответы [ 4 ]

53 голосов
/ 25 марта 2011

Мы могли бы использовать его при написании обезьяноподобного кода, подобного этому:

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

Другой пример, который был бы более практичным в реальном мире, - это иметь миксины, которые применяются только подклассами.

Это полезно, когда некоторые грани вещи применяются к некоторым подклассам, а другие фасеты применяются к другим подклассам, без достаточного порядка, в котором эти аспекты применяются, чтобы освободить место для четкой иерархии классов дерево). Подумайте о множественном наследовании! Упрощенный пример:

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

И так далее. Вид приятно, когда используется разумно. Даже супер-вызовы и конструкторы (я не определил их здесь) проходят через все миксины и классы так, как я хочу.

7 голосов
/ 07 июня 2012

С тех пор я столкнулся с вариантом использования в большом приложении Rails со сложным пространством имен.Упрощенный пример:

# app/models/invoice/dependents/item.rb
class Invoice
  module Dependents
    class Item
      # Define invoice item
    end
  end
end

Здесь Invoice является собственным классом, но также является хорошим пространством имен для его зависимых элементов.Мы не можем сказать module Invoice, потому что эта константа уже определена как класс, но мы все равно можем использовать ее в качестве пространства имен.

Giant Caveat

Если вы используете класс в качестве пространства имени вы используете 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

Тот факт, что в этом файле указано class Invoice, создает зависимость порядка загрузки;если строка class Invoice этого файла выполняется до определения вашего предполагаемого класса, определение предполагаемого класса может работать неправильно .В этом примере я не могу объявить, что Invoice sublcasses ActiveRecord::Base, если Invoice уже был объявлен без родительского класса.

Вы могли бы требовать вашего "истинного" классафайл определения в верхней части другого файла, но, по крайней мере, в сценарии автозагрузки Rails вам придется меньше спорить, если вы сделаете это вместо этого:

# app/helpers/invoice/dependents/items_helper.rb
module Invoice:Dependents::ItemsHelper  
  # view helper methods
end

С этим синтаксисом Rails увидит Invoice константа и используйте автозагрузку, чтобы найти ее, найти в файле модели и определить, как вы хотели.

6 голосов
/ 24 августа 2010
class Image
    module Colors
        Red = ...
        Blue = ...
    end
    include Colors
end

include Image::Colors

Image.new.set_pixel x, y, Red 
3 голосов
/ 23 августа 2010

Полагаю, на самом деле это просто использование класса в качестве пространства имен, что иногда просто удобнее, чем помещать все в модуль.Я никогда не видел этого на практике, но в любом случае это совершенно правильный код Ruby.

Единственный реальный сценарий, о котором я могу подумать, - это использование EventMachine в классе:

class Api
  def initialize
    EM.start_server "0.0.0.0", 8080, Server
  end

  module Server
    def receive_data (data)
      # do stuff
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...