YARD ⇒ how to add custom output to several methods descriptions basing on one DSL statement in YARD plugin

StackOverflow https://stackoverflow.com/questions/15336962

  •  23-03-2022
  •  | 
  •  

Вопрос

I have the problem writing YARD plugin for the following DSL:

class MyClass
  my_dsl :do_it, :do_other
  def do_it
    # do it
  end
  def do_other
    # do other
  end
  def do_unrelated
    # do unrelated
  end
end

Now I want to add notes to those methods’ documentation snippets, which are “influenced” by DSL my_dsl. Within my_dsl handler the scope is totally different (I don’t want to add some new docs, I want to extend already existing for methods.)

So I decided to use Proxy code object inside MyDSLHandler#process to mark the needed methods for delayed future postprocessing (which is to occur within built-in MethodHandler on def do_it ; … ; end.) It looks like:

class MyDSLHandler < YARD::Handlers::Ruby::DSLHandler
  handles method_call(:my_dsl)
  namespace_only

  def process
    statement.parameters.each { |astnode|
      mthd = astnode.jump(:string_content).source if astnode.respond_to? :jump
      obj = YARD::CodeObjects::Proxy.new(namespace, "\##{mthd}", :method)
      register(obj)
      obj[:my_dsl_params] << {
        name: mthd,
        file: statement.file, line: statement.line # I need this!
      }
    }
  end
end

Now the problem is that the Proxy object is derived from plain Object, not from YARD::CodeObjects::Base and therefore has no []= method defined:

[warn]: Load Order / Name Resolution Problem on MyClass#do_it:
[warn]: -
[warn]: Something is trying to call [] on object MyClass#do_it before it has been recognized.
[warn]: This error usually means that you need to modify the order in which you parse files
[warn]: so that MyClass#do_it is parsed before methods or other objects attempt to access it.
[warn]: -
[warn]: YARD will recover from this error and continue to parse but you *may* have problems
[warn]: with your generated documentation. You should probably fix this.
[warn]: -
[error]: Unhandled exception in Yard::Handlers::MyDSLHandler:
[error]:   in `example_mydsl.rb`:5:

    5: my_dsl :do_it, :do_other

[error]: ProxyMethodError: Proxy cannot call method #[] on object 'MyClass#do_it'

How am I supposed to store some values from current context to Proxy object, so that they would be available during object real instantiation?

Это было полезно?

Решение

Well, I was able to resolve it.

The use of Proxy here is not supposed. The CodeObjects have a pretty peculiarity: they are “silent” singletons. Hence, as you have defined an object via CodeObject.new, all the forthcoming calls to new on the same object (according to Registry) will be re-mapped to the existing one.

Therefore in my case I simply create the MethodObject:

m = "#{astnode.jump(:string_content).source[1..-1]}";
obj = YARD::CodeObjects::MethodObject.new(namespace, "#{m}")

and then I do what I want on the newly created object:

obj.my_dsl_params = { :win => true, :mthd => "#{m}", … }

The object within method definition parse will merge these properties with it’s own. The only need is either to register an object with register(obj) or to return it from process method for system registering.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top