способы определения глобального метода в ruby - PullRequest
7 голосов
/ 25 августа 2011

Я пишу маленький гем и хочу определить DSL-подобный метод, почти такой же, как методы desc и task в Rake .

Rake определяет их как закрытые методы в модуле Rake::DSL, а затем

self.extend Rake::DSL

, чтобы смешать модуль с основным объектом?(Я новичок и продолжайте смеяться, если я ошибаюсь)

Каковы преимущества от этого?это потому, что закрытие этих методов может помешать другим объектам использовать их (то есть, предотвратить что-то вроде some_obj.desc)?

что если я определю методы в Kernel

module Kernel
  private

  include Rake::DSL
end

Есть ли разница?

Ответы [ 2 ]

5 голосов
/ 25 августа 2011

Если вы определите приватный метод в модуле Kernel, он будет доступен во всем проекте.Вы также перепишете метод desc, который используется в проекте для определения граблей.Но если вы пишете свои методы в своем подмодуле, а затем расширяете его в суперклассе или каком-либо модуле - вы можете легко написать любой тип DSL-языка, который вы могли бы видеть в Rake или RSpec.PS Создание методов private предотвращает их использование другими moludes или классами (но не подклассами) (но не owerwrite) - я имею в виду иерархию вложений модулей.

3 голосов
/ 25 августа 2011

Просто чтобы расширить ответ, данный bor1s, о приватных методах:

В ruby ​​у вас есть "приватный" и "защищенный" методы. То, что говорит bor1s, верно, когда речь идет о «защищенных» методах. Объявление метода "private" дополнительно запрещает другим экземплярам того же класса использовать метод.

Когда вы вызываете «закрытый» метод, вы не можете использовать точку перед ним - вы даже не можете использовать self., даже если использование или пропуск self обычно имеет тот же эффект.

class Xyzzy
  private
  def foo
    puts "Foo called"
  end

  public
  def do_it
    foo       # <= Is OK
    self.foo  # <= raises NoMethodError
  end
end

Xyzzy.new.do_it

Если вы измените 'private' на 'protected' в приведенном выше коде, ошибка не возникнет.

А по поводу модулей:

Окончательный результат определения метода в Kernel и расширения Kernel методом, определенным в некотором модуле, одинаков: в обоих случаях метод является глобальным.

Использование модуля немного более элегантно, поскольку оно группирует ваши изменения в одном месте, но я бы сказал, что это вопрос личного вкуса.

Обычно вы не включаете методы в ядро ​​или объект (как это может быть немного опасно), но вы включаете (или расширяете) определенный класс или объект, который нуждается в этих методах, и в этом случае вам нужен ваши методы сгруппированы в модуле.

Даже Rake в версии 0.9.0 остановлен, включая команды DSL в Object:

== Версия 0.9.0

  • Несовместимо * change *: Команды Rake DSL («задача», «файл» и т. Д.) больше не частные методы в Object. Если вам нужно вызвать 'task: xzy' внутри ваш класс, включите Rake :: DSL в класс. DSL все еще доступен на область верхнего уровня (через объект верхнего уровня, который расширяет Rake :: DSL).
...