Нет, вы не можете сделать это.
Весь смысл комментариев в том, что они не часть программы! Если вам нужна строка, которая является частью вашей программы, просто используйте вместо нее строку.
В большинстве реализаций Ruby комментарии уже отбрасываются в лексере, что означает, что они даже не достигают парсера , не говоря уже о интерпретаторе или компиляторе. Когда код запускается, комментарии уже давно исчезли & hellip; Фактически, в реализациях, таких как Rubinius или YARV, в которых используется компилятор, просто невозможно сохранить комментарии в скомпилированном исполняемом файле, поэтому, даже если они не были выброшены лексером или парсером, все равно не будет возможности сообщить их среде выполнения.
Итак, в основном ваш единственный шанс - проанализировать исходный файл Ruby для извлечения комментариев. Однако, как я упоминал выше, вы не можете просто взять любой парсер, потому что большинство существующих парсеров выбрасывают комментарии. (Который, опять же, является целым пунктом комментариев, так что нет ничего плохого в том, что парсер выбрасывает их.) Однако, есть парсеры Ruby, которые сохраняют комментарии, особенно те, которые используются в таких инструментах, как RDoc или YARD.
YARD особенно интересен, поскольку он также содержит механизм запросов, который позволяет вам искать и отфильтровывать документацию на основе некоторых мощных предикатов, таких как имя класса, имя метода, теги YARD, версия API, сигнатура типа и т. Д.
Однако, если вы do в конечном итоге используете RDoc или YARD для анализа, то почему бы не использовать их вообще?
Или, как я уже говорил выше, если вы хотите строки, просто используйте строки:
module MethodAddedHook
private
def method_added(meth)
(@__doc__ ||= {})[meth] = @__last_doc__ if @__last_doc__
@__last_doc__ = nil
super
end
end
class Module
private
prepend MethodAddedHook
def doc(meth=nil, str)
return @__doc__[meth] = str if meth
@__last_doc__ = str
end
def defdoc(meth, doc, &block)
@__doc__[meth] = doc
define_method(meth, &block)
end
end
Это дает нам метод Module#doc
, который мы можем использовать для документирования либо уже существующего метода, вызывая его с именем метода и строкой документации, либо вы можете использовать его для документирования следующего определенного вами метода. Он делает это, сохраняя строку документации во временной переменной экземпляра, а затем определяя хук method_added
, который просматривает эту переменную экземпляра и сохраняет ее содержимое в хэше документации.
Существует также метод Module#defdoc
, который определяет и документирует метод за один раз.
module Kernel
private
def get_doc(klass, meth)
klass.instance_variable_get(:@__doc__)[meth]
end
end
Это ваш Kernel#get_doc
метод, который возвращает документацию (или nil
, если метод недокументирован).
class MyClass
doc 'This method tries over and over until it is tired'
def go_go_go(thing_to_try, tries = 10)
puts thing_to_try
go_go_go thing_to_try, tries - 1
end
def some_other_meth; end # Oops, I forgot to document it!
# No problem:
doc :some_other_meth, 'Does some other things'
defdoc(:yet_another_method, 'This method also does something') do |a, b, c|
p a, b, c
end
end
Здесь вы видите три разных способа документирования метода.
О, и это работает:
require 'test/unit'
class TestDocstrings < Test::Unit::TestCase
def test_that_myclass_gogogo_has_a_docstring
doc = 'This method tries over and over until it is tired'
assert_equal doc, get_doc(MyClass, :go_go_go)
end
def test_that_myclass_some_other_meth_has_a_docstring
doc = 'Does some other things'
assert_equal doc, get_doc(MyClass, :some_other_meth)
end
def test_that_myclass_yet_another_method_has_a_docstring
doc = 'This method also does something'
assert_equal doc, get_doc(MyClass, :yet_another_method)
end
def test_that_undocumented_methods_return_nil
assert_nil get_doc(MyClass, :does_not_exist)
end
end
Примечание: это довольно забавно. Например, нет блокировки, поэтому, если два потока определяют методы для одного и того же класса одновременно, документация может быть испорчена. (Т.е.: строка документа может быть приписана неверному методу или потеряна.)
Я считаю, что rake
делает то же самое с его desc
методом, и что кодовая база на намного лучше протестирована, чем эта, поэтому, если вы намереваетесь использовать ее в производстве, я бы укради код Джима вместо моего.