Let's say I have the following function:
#param foo [Array<String>]
def recursive_split(foo)
bar = []
foo.each do |elem|
bar.append(elem.split(''))
end
bar
end
How do I document with the yard #return tag that my return value is an array of arrays of strings ? Is #return [Array<Array<String>>] the right way to do it ?
The docs aren't that specific but types specifiers are recursive so the X in Array<X> can be any list of valid types so these:
Array<String>
Array<String, Symbol>
Array<Array<String, Symbol, #m>>
Array<String, Array<#m>>
...
are all valid.
The online type parser is probably the easiest way to check. That says that Array<Array<String>> is:
an Array of (an Array of (Strings))
Related
Lets say I have following code
let(:document) { FactoryBot.create :document }
let(:mail) do
# #type [User]
celebrated_user = FactoryBot.create :user
# #type [Rule]
rule = FactoryBot.create :rule, document: document
CelebrationMailer.birthday celebrated_user, document, rule
end
CelebrationMailer#birthday is documented as follows
# #param [User] celebrated_user
# #param [Document] document
# #param [Rule] rule
In the let(:mail) RubyMine (and probably some other tools with types) recognize document variable as type Object.
How can I document the let, so tools recognize document let/variable as Document type?
I've tried #type, #return, #attr_reader.
Well, what does let do? It creates a method whose name is given by the symbol argument and whose return value is given by the return value of the block.
So, if you wanted to write a type for that, you would have to
take the symbol and turn it into a method name
take the return type of the block and turn it into the return type of the method
I am pretty sure that is not possible with RDoc or YARD type notation.
So, the best thing you can do is a synthetic attribute reader:
# #!attribute [r] document
# #return [Document] a fake document
let(:document) { FactoryBot.create :document }
Note that YARD does support macros, but macros obviously only have access to what is in the source code, and the return type of the block is not part of the source code. In fact, the documentation block you showed looks like it was generated by a macro that looks somewhat like this:
# Defines a memoized method
# #param [Symbol] name the method name
# #param block how to compute the value
# #!macro [attach] let
# #!attribute [r] $1
# #return the value defined by the block
def let(name, &block) end
This will tell YARD that wherever it sees a call to let, it should insert a synthetic documentation block for an attribute reader whose name is the first argument to let.
However, it will not allow you to use the type of the block. These are the only interpolation variables that exist:
$0 - the method name being called
$1, $2, $3, … - the Nth argument in the method call
$& - the full source line
What would work, is if let took a second argument that is the type, then you could write a macro like this:
# Defines a memoized method
# #param [Symbol] name the method name
# #param [Module] type the type of the memoized value
# #param block how to compute the value
# #!macro [attach] let
# #!attribute [r] $1
# #return [${-1}] the value defined by the block
def let(name, type, &block) end
And then you would call it like this:
let(:document, Document) { FactoryBot.create :document }
But, that is not how RSpec is designed, so the best you can do is the synthetic attribute reader from my first suggestion.
I have a method that optionally takes a block.
It either returns an array of the parameters it would have supplied to an absent block, or transparently returns the result of yield.
I know I can use #overload to treat the block/no-block causes differently, but how can I tell it that #return for the block clause is whatever the block handed me? If this were Kotlin, I'd use a type parameter with_build_parameters(...) or whatever.
# #overload with_build_parameters
# #return [Array] if no block is given
# #overload with_build_parameters(&block)
# #yieldparam [Hash<String, String>] config_props
# #yieldparam [Hash<String, String>] build_props
# #yieldreturn [T] whatever you like
# #return [T] whatever the block said
I'm mainly interested in getting this to work with RubyMine's type checking.
I have an impure function like so:
# Impure function: Sets the status for a report_schedule, uses last_sent to
# calculate status
# #param report_schedule [Hash]
# #return [String] Non-useful: value of last_sent that was set
def self.set_report_schedule_status(report_schedule)
# Some logic that calculates status of report_schedule
report_schedule['status'] = status
report_schedule['last_sent'] = Time.now.to_s
end
What I want this function to do is set status and last_sent, but the side effect here is that it returns Time.now.to_s. Is there a proper way to document this?
Alternatively is my function definition wrong or should I just end with a return nil.
Should be just adding return nil
Ruby automatically appends return to the last thing executed in a method
I'm new to vim and vimscript and getting my head with all this.
I'm trying to write a plugin that replicates the behaviour of VVDocumenter for ruby code, so, if the cursor is over a method for example and activates the plugin, it should build a skeleton to document it.
For example this code:
def method1(obj1, obj2)
// Code
end
should generate this comments:
#
#
# #param [] obj1
# #param [] obj2
# #return []
def method1(obj1, obj2)
// Code
end
I'am having trouble inserting the completion in the correct column, at the same level where def is defined.
Any help will be great!
Thanks
You can work around range and ex insert in normal mode, something like below:
1 def foo(params)
2 // code
3 end
When in normal mode:
:0,4:normal O# #param [] obj1
Vim do:
1 # #param [] obj1
2 # #param [] obj1
3 # #param [] obj1
4 # #param [] obj1
5 # #param [] obj1
6 def foo(params)
7 // code
8 end
Explain :0,4:normal O# #param [] obj1 - from 0 to 4 line, insert in normal mode O(puts before 0 line) this text # #param [] obj1.
Put this in function(not sure, can't test now):
function! PutComments()
for lineno in range(a:firstline, a:lastline)
exec ":normal O# #param [] obj1"
endfor
endfunction
For a basic Ruby method, I would provide YARD style doc for parameters in the following format.
# #param query [String] The search string to query.
# #param options [Hash] Optional search preferences.
def search(query, options = {})
# ...
end
With Ruby 2.0, keywords arguments can now be used. However, I'm not sure how to approach that in terms of the YARD documentation.
def search(query, exact_match: false, results_per_page: 10)
# ...
end
How would I document for exact_match and results_per_page in the second scenario? Should I just continue to use the #param keyword, or is there something better?
Should I just continue to use the #param keyword?
Yes.
YARD recognizes keyword arguments. Use #param to document a single method parameter (either regular or keyword) with a given name, type and optional description:
# #param query [String] The search string
# #param exact_match [Boolean] whether to do an exact match
# #param results_per_page [Integer] number of results
def search(query, exact_match: false, results_per_page: 10)
# ...
end
Source: YARD Tags #param at rubydoc.info