1

メタプログラミングを使って docstring 機能を Ruby 言語に導入したいと考えています。

これは、私がこれまでに書いたコードの非常に初期のプロトタイプです。

module Docstrings
  def doc(docstring)
    @docstrings ||= {}
    if docstring.is_a? String
      # Ruby 2.0 trick to get a caller of the method
      method_caller = caller_locations(1,1)[0].label.to_sym

      @docstrings[method_caller] ||= docstring
    else
      @docstrings[docstring]
    end
  end
end

# lets include it temporarily to see how it works
include Docstrings

class Method
   include Docstrings
end

doc "Hello"
puts doc :"<main>" # => "Hello"

できます。しかし、悲しいことに:

def square(x)
  doc """This method returns square of x"""

  x * x
end

doc(:square) # => nil

これは私が期待したように機能していません。

square(2)
doc(:square) # => """This method returns square of x"""

明らかなように、メソッド square が少なくとも 1 回呼び出された場合にのみ、docstring が追加されます。

私の質問は、そのメソッドの呼び出しではなく、メソッドに docstring を追加する方法で実装することは可能ですか? 解決策ではないヒントを探しています。どこを見ればよいか教えてください:)

4

2 に答える 2

2

これは機能しているようです: (ただし、実際にはメタプログラミングではなく、単なるハックです)

これが欲しいとしましょう:

  def add_these(a, b)
    doc "This function adds two numbers"
    a + b
  end

whatsthedocdoc?(:add_these) # => "This function adds two numbers"

class Object
  def whatsthedocdoc?(method)
    meth = method(method.to_sym)
    sours = meth.source
    puts sours.lines.grep(/doc/).join.gsub(/doc|\"/, "").strip
  end
end

しかし、それはそれほど単純ではありません。上記のスニペットは、メソッドがmainオブジェクト空間で定義されていることを前提としています。例を考えてみましょう:

class A
  def add_these(a, b)
    doc "This method adds two numbers."
  end
end

whatsthedocdoc?この例では、メソッド内のコードを次のように変更する必要があります。

def whatsthedocdoc?(string)
  receiver, meth = string.split(/\#/)
  meth_instance = receiver.method(meth.to_sym)
  sours = meth_instance.source
  # rest is the same as above
end

ドキュメントは次のように表示できます。

whatsthedocdoc?("A#add_these") # => This method adds two numbers.

今はかなりきれいではありませんか?


おー!さらに別のエッジケースがあります: クラスメソッド

class A
  def self.add_these(a, b)
    doc "This too, adds two numbers"
  end
end

あなたはアイデアを得る...

于 2013-08-11T16:47:57.960 に答える