Documenting iterative metprogrammed methods

232 views
Skip to first unread message

mfo...@mdsol.com

unread,
Apr 11, 2013, 4:22:15 PM4/11/13
to yar...@googlegroups.com
Hi,

Been poking around to see how to do something like:

class MyClass

   ATTRIBUTES = %w(name type)

   ATTRIBUTES.each do | attribute |
     # @!macro attr
     #   @!attribute [r] $1
     #   Returns the $1 of the underlying ivar.
     #   @return [String] The ivar $1.
     define_method(attribute) do
        @my_ivar[attribute]
     end
  end
end

I have seen some comments on custom handlers, but would they work in a case like this? Thanks.

Mark

Loren Segal

unread,
Apr 11, 2013, 5:38:33 PM4/11/13
to yar...@googlegroups.com
Hi,
This isn't a case where custom handlers would not be applicable, and
the macro as defined above would not work.

It looks like you just want to document attributes though, and that can
be done fairly easily in a number of ways.

Just FYI, before I show any examples, some IMPORTANT NOTES!

1. YARD already generates standard documentation for attributes that
look almost exactly like how you are documenting them. If all you're
doing is the above-- don't do it. It doesn't provide anything YARD
doesn't do already.

2. If you're not providing ANY extra documentation, you're not really
providing any usable benefit to your users here except listing method
names. You can do this by just creating attrs: attr_reader :name, :type,
...

3. Adding a docstring of "Returns ___" and a @return tag is redundant.
Your @return tag is the Returns sentence, and YARD will generate this
docstring for you.

Okay, now the examples:

1. Regular macros on attrs:

# @!macro [new] attr
# @return [String] the ivar $1

# @!macro attr
attr_reader :name

# @!macro attr
attr_reader :type

2. Define a mini-DSL:

If you're doing something more complicated than *just* attrs, you can
define a mini DSL and document that with attached macros:

class MyClass
# @!macro [attach]
# @!attribute [r] $1
# @return [String] the ivar $1
def self.myattr(attr)
define_method(attr) { @my_ivar[attr] }
end

myattr :name
myattr :type
end

Hope that helps,

Loren

Mark Foster

unread,
Apr 11, 2013, 5:49:50 PM4/11/13
to yar...@googlegroups.com
Hi Loren,

Thanks. I probably should have given a better example than simple accessors as your solution is one I had played with. However, I am really interested in the the more generic case where I can iterate over an array of method names ( possibly hashes where I use key and value) and have the documentation generate per the parmaters passed into the iterator block. 

These may be more than simple accessors, so I am interested to know how I might actually recurse the iteration to generate docs for each value of the enumerable. 

Does that clarify? Thanks.

Mark




--

--- You received this message because you are subscribed to a topic in the Google Groups "YARD" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/yardoc/HIUoeATOjWA/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to yardoc+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Loren Segal

unread,
Apr 11, 2013, 6:13:05 PM4/11/13
to yar...@googlegroups.com
On 2013-04-11 14:49, Mark Foster wrote:
> Hi Loren,
>
> I am really interested in the the more generic case where I can
> iterate
> over an array of method names ( possibly hashes where I use key and
> value) and have the documentation generate per the parmaters passed
> into the iterator block.

Without runtime introspection, you can't. Taking your original example:

class MyClass
ATTRIBUTES = %w(name type)
ATTRIBUTES.each do |attribute|

# docs here?
define_method(attribute) do |some_params|
# complex implementation
end
end
end

It's [near] impossible for you to statically know at "docs here?" what
"attribute" is unless you evaluated Ruby code. Even with a handler, this
would be non-trivial.

If you're going to write a plugin with handlers, you'll be much better
off starting with a DSL that can declaratively identify your dynamically
generated methods like:

mymethods :name, :type, :foo, :bar, :baz

Then you can write a handler to loop through arguments of a mymethods
call and generate attributes. This is not only more declarative, but
also more readable in source. The second you start obscuring that code
with dynamic looping constructs, you've lost the ability to easily
analyze it.

I would start with one of the macro-based examples provided in the last
email though. They are much easier to manage than the above, since
macros don't require any custom code.

Loren

Mark Foster

unread,
Apr 11, 2013, 6:39:22 PM4/11/13
to yar...@googlegroups.com
Ok. That is what I expected, but having hacked at it a bit, I thought I would double check if someone had an idea. Thanks.




Loren

Reply all
Reply to author
Forward
0 new messages