How to document a YARD parameter that could be of any type possible?
Is there a convention for it?
This is similar to Any type in TypeScript
# #param [?] var1
def create_foo(var1)
# var1 could be anything
end
Since almost every object in Ruby inherits behavior from the class Object, # #param [Object] var1 seems like an appropriate choice.
A few examples from rubygems/rubygems and lostisland/faraday
Related
How can I document a method that a subclass overrides without being redundant? For example...
class Parent
# Is this the parent?
# #return [Boolean]
def parent?
true
end
end
class Child < Parent
def parent?
false
end
end
YARD generates something like this.
Class: Parent
Instance Method Summary
#parent? ⇒ Boolean
Is this the parent?.
Class: Child
Instance Method Summary
#parent? ⇒ Boolean
The generated YARD documentation will not include "Is this the parent?" in the docs for Child#parent?, nor will it indicate that it is an override.
I would like to see something like this:
Class: Parent
Instance Method Summary
#parent? ⇒ Boolean
Is this the parent?.
Class: Child
Instance Method Summary
#parent? ⇒ Boolean
Is this the parent?.
Methods inherited from Parent
#parent?
I would prefer not to have to copy the documentation into every subclass.
Simple Answer
The correct way to document this is to place a free-form description after the return type, and maybe document the method itself. For example:
class Parent
# True when a passed argument has Parent
# as an ancestor.
#
# #return [Boolean] ancestor of subclass
def parent?
true
end
end
A More Comprehensive Example
You can also provide examples of usage and more detailed documentation by leveraging the free-form parts of the tag syntax and your markup language (RDoc by default).
class Parent
# True when passed argument includes
# +Parent+ as an ancestor.
#
# #example Cousin isn't subclass of Parent
# parent? Cousin.new #=> false
# #example Child is a subclass of Parent
# parent? Child.new #=> true
# #param obj [Class, #ancestors] Class,
# instance, or other object that can
# #respond_to?(:ancestors)
# #return [Boolean] ancestors of _obj_
# includes +Parent+ class
def parent? obj
obj.class.ancestors.include? self.class
end
end
There may be more elegant ways to do this, and I'm typing on a phone so caveat emptor with the code as I haven't actually tested the code or validated the formatting of the YARD output. Still, the general approach is sound and I use this type of formatting routinely.
Core Ideas
Basically, the core ideas are that one should:
Place your description of each tagged item in-line if you want it associated with that item. Most tags support free-form descriptions or titles which will be formatted in a way that visually associates them with the tagged element.
Use tags and formatting for classes, methods, arguments, examples, and so on. You don't have to cram it all into a single tag, although in your specific example you probably want to do so to keep things visually associated.
You can wrap long free-form text with indentation in most cases.
There are a few exceptions to wrapping (e.g. example titles vs. indented code blocks is illustrative) but you can often work around that with RDoc or Markdown syntax.
If you can't get what you want, refer to item four for some alternative approaches or find a different tag or markup to represent your intent.
Macros, custom tags, and directives will let you do weird and wonderful things if you can't get what you want out of the box. NB: I've almost never needed to resort to this, but the features are there if you need them.
In most cases, simpler is better. Understanding how and when YARD can't succinctly represent your authorial intent is admittedly a bit of an art form, but code that's hard to tag or render as expected may indicate a need to refactor the code rather than just modifying the YARD tags.
Keep YARD's Main Purpose in Mind
Just remember that YARD is primarily for ** elements of your documentation, and providing hints to a rendering engine or document reader, It's not a full-fledged markup language by itself, can't validate signatures like RBS with Steep, and doesn't enforce any sort of caller/callee contract.
It's all just comments. Make your code as self-explanatory as possible, then treat YARD as just one way to improve necessary comments by tagging documentation elements so the markup language generates better output.
You can use a reference tag on each individual method to refer to the Parent methods.
class Child < Parent
# (see Parent#parent?)
def parent?
false
end
end
Child#parent? will have the same documentation as Parent::parent?
I'm migrating and documenting an old Ruby (specifically Sketchup) code base but I'm not very familiar with the ecosystem. Since I'm more used to TypeScript, I'm asking what is the equivalent documentation of this in Ruby:
function get_definition(instance: ComponentInstance | Group | Image)
I've tried this:
# #param [ComponentInstance | Group | Image] instance
def self.get_definition(instance)
but I'm unsure if this is correct.
Some Possible YARD Tag Examples for Your Code
def self.get_definition(instance)
There really isn't enough of your code to be sure what the real programmer intent is, so you'll have to adapt a bit as needed. Additionally, it's important to understand that YARD tags are really just documentation, not enforced contracts or even type definitions in the sense of RBS, which can be used to create typed signatures that can be checked with various external utilities.
Since you are defining your own objects, you probably want to use the Class or Module Types tag, with or without sub-types. For example, assuming the instance argument can be any of three completely different classes:
# Class or module method to return the definition of an
# object.
#
# #param instance [ComponentInstance, Group, Image] a single
# injected object of one of the listed classes
# #return [Array<String>] components that define _instance_
def self.get_definition(instance)
end
On the other hand, if Group and Image classes inherit from ComponentInstance, or perhaps are contained by one, then you might use the following instead:
# Class or module method that uses a ComponentInstance to create
# side effects.
#
# #param instance [ComponentInstance<Group, Image>] an injected
# ComponentInstance object holding one or more Group or Image
# objects
# #return [void] because we don't care about the return value,
# just the side effects
def self.get_definition(instance)
end
You might also benefit from duck-typing, where you don't care what the instance object actually is, so long as it conforms to a given API. For example:
# Class or module method to return the definition of a
# serialized object.
#
# #param instance [#define, #inspect, #ancestors] object that
# will #respond_to? one of the listed methods
# #return [String<JSON>] a definition String that has been
# serialized as JSON for consumption by an API
def self.get_definition(instance)
end
There are certainly other tags and macros you might use, depending on the semantics you want to convey, but that should get you started. You might also want to look at RBS or TypeProf if you need real signature delcarations, or if you're planning to use some sort of third-party typing system with your code, e.g. Steep or Sorbet. For documentation, though, plain RDoc or YARD tags with RDoc or Markdown are generally your best bets.
Do SerializerMethodFields accept the source= kwarg?
I have been running to a bug where I've been consistently passing in a value to the source=in SerializerMethodFields but it is always ignored. That is, the argument passed as obj to my SerializerMethodField is always the instance I am trying to serialize itself (e.g. source='*').
The DRF Documentation says there are certain core arguments that all field types should accept include the source=argument.
With that said, the DRF Documentation says this about SerializerMethodField:
SerializerMethodField
This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.
Signature: SerializerMethodField(method_name=None)
method_name - The name of the method on the serializer to be called. If not included this defaults to get_<field_name>.
The serializer method referred to by the method_name argument should accept a single argument (in addition to self), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object.
Which did not leave me with a convincing answer as to what the expected behavior should be like for source= since it does not say that no other core kwargs are applicable.
Any insight with respect to what the expected behavior is for the source= in SerializerMethodField would be greatly appreciated!
I did a bit of snooping into the source code for SerializerMethodField and saw this
class SerializerMethodField(Field):
# ...ignoring useful docstrings for brevity...
def __init__(self, method_name=None, **kwargs):
self.method_name = method_name
kwargs['source'] = '*' # <-- and here's our answer
kwargs['read_only'] = True
super().__init__(**kwargs)
I would have been nice if the DRF documentation for SerializerMethodField was more explicit in saying that none of the other core arguments applied here but such is life.
Answer: No, the source= is not a respected argument.
Is there any way to protect an instance variable from being written to/modified in Ruby?
Say I do this:
class Test
def initialize(var)
#var = var
end
def modify
#var = "test" # This would raise an error, saying '#var' is just readable.
end
end
Is there any way to make instance variable to be read-only? If not, which kind of attribute am I looking for?
You can virtually protect instance variables with freezing a wrapping object:
t=Test.new "example"
p t.var
# "example"
t.freeze
t.modify
# :in `modify': can't modify frozen Test (RuntimeError)
p t.var
# t.var is still equal to "example" if exception won't terminate app
See Object#freeze method for details.
There is no way to do that. First of all, there should not be a reason that a class would need to write-protect an attribute against itself. Secondly, all access protection rules in Ruby, such as it exists, are really only suggestions - ultimately, using introspection, you can access anything you wish, including redefining core methods like Fixnum#+. Try this:
class Fixnum
def +(other)
self - other
end
end
It will mess up your code more than writing to #var ever could.
No, there is no way to do this. The closest thing Ruby has to non-writable variables are constants which can exist within a class or module and begin with a capital letter (typically all caps). Ruby will not prevent these variables from being written, but will issue a warning if they are redefined.
With strings one can do this:
a = "hello"
a.upcase!
p a #=> "HELLO"
But how would I write my own method like that?
Something like (although that doesn't work obviously):
class MyClass
def positify!
self = [0, self].max
end
end
I know there are some tricks one can use on String but what if I'm trying to do something like this for Object?
Many classes are immutable (e.g. Numeric, Symbol, ...), so have no method allowing you to change their value.
On the other hand, any Object can have instance variables and these can be modified.
There is an easy way to delegate the behavior to a known object (say 42) and be able to change, later on, to another object, using SimpleDelegator. In the example below, quacks_like_an_int behaves like an Integer:
require 'delegate'
quacks_like_an_int = SimpleDelegator.new(42)
quacks_like_an_int.round(-1) # => 40
quacks_like_an_int.__setobj__(666)
quacks_like_an_int.round(-1) # => 670
You can use it to design a class too, for example:
require 'delegate'
class MutableInteger < SimpleDelegator
def plus_plus!
__setobj__(self + 1)
self
end
def positify!
__setobj__(0) if self < 0
self
end
end
i = MutableInteger.new(-42)
i.plus_plus! # => -41
i.positify! # => 0
Well, the upcase! method doesn't change the object identity, it only changes its internal structure (s.object_id == s.upcase!.object_id).
On the other hand, numbers are immutable objects and therefore, you can't change their value without changing their identity. AFAIK, there's no way for an object to self-change its identity, but, of course, you may implement positify! method that changes properties of its object - and this would be an analogue of what upcase! does for strings.
Assignment, or binding of local variables (using the = operator) is built-in to the core language and there is no way to override or customize it. You could run a preprocessor over your Ruby code which would convert your own, custom syntax to valid Ruby, though. You could also pass a Binding in to a custom method, which could redefine variables dynamically. This wouldn't achieve the effect you are looking for, though.
Understand that self = could never work, because when you say a = "string"; a = "another string" you are not modifying any objects; you are rebinding a local variable to a different object. Inside your custom method, you are in a different scope, and any local variables which you bind will only exist in that scope; it won't have any effect on the scope which you called the method from.
You cannot change self to point to anything other than its current object. You can make changes to instance variables, such as in the case string which is changing the underlying characters to upper case.
As pointed out in this answer:
Ruby and modifying self for a Float instance
There is a trick mentioned here that is a work around, which is to write you class as a wrapper around the other object. Then your wrapper class can replace the wrapped object at will. I'm hesitant on saying this is a good idea though.