{"action":"created","issue":{"url":"https://api.github.com/repos/lsegal/yard/issues/917","labels_url":"https://api.github.com/repos/lsegal/yard/issues/917/labels{/name}","comments_url":"https://api.github.com/repos/lsegal/yard/issues/917/comments","events_url":"https://api.github.com/repos/lsegal/yard/issues/917/events","html_url":"https://github.com/lsegal/yard/issues/917","id":120052090,"number":917,"title":"@!attribute completely broken","user":{"login":"paddor","id":8876,"avatar_url":"https://avatars.githubusercontent.com/u/8876?v=3","gravatar_id":"","url":"https://api.github.com/users/paddor","html_url":"https://github.com/paddor","followers_url":"https://api.github.com/users/paddor/followers","following_url":"https://api.github.com/users/paddor/following{/other_user}","gists_url":"https://api.github.com/users/paddor/gists{/gist_id}","starred_url":"https://api.github.com/users/paddor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paddor/subscriptions","organizations_url":"https://api.github.com/users/paddor/orgs","repos_url":"https://api.github.com/users/paddor/repos","events_url":"https://api.github.com/users/paddor/events{/privacy}","received_events_url":"https://api.github.com/users/paddor/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-12-02T22:39:41Z","updated_at":"2015-12-02T23:11:28Z","closed_at":null,"body":"Maybe this is related to #874.\r\n\r\nConsider this code:\r\n\r\n```ruby\r\n    # @!attribute [rw] name\r\n    #   Name of the item.\r\n    # @return [String] name of the item\r\n    def name\r\n      ffi_delegate.name.read_string\r\n    end\r\n\r\n    def name=(new_name)\r\n      ffi_delegate.set_name(new_name)\r\n    end\r\n```\r\n\r\nGood things:\r\n\r\n* it does document `name` as an instance attribute, including its type\r\n* it does not document the method `#name` and `#name=` themselves\r\n\r\n\r\nProblems:\r\n\r\n* changing from `rw` to `r` makes no difference\r\n  * it does not mark it as read-only\r\n  * it still doesn't document the method `#name=`\r\n* return type is only recognized if unindented\r\n  * even though documentation of `@!attribute` shows it indented (see [1])\r\n* no source code is made accessible in the documentation\r\n  * even though the documentation of `@!attribute` claims that (see [1])\r\n\r\n\r\n[[1]](http://www.rubydoc.info/gems/yard/file/docs/Tags.md#attribute)\r\n"},"comment":{"url":"https://api.github.com/repos/lsegal/yard/issues/comments/161463150","html_url":"https://github.com/lsegal/yard/issues/917#issuecomment-161463150","issue_url":"https://api.github.com/repos/lsegal/yard/issues/917","id":161463150,"user":{"login":"lsegal","id":686,"avatar_url":"https://avatars.githubusercontent.com/u/686?v=3","gravatar_id":"","url":"https://api.github.com/users/lsegal","html_url":"https://github.com/lsegal","followers_url":"https://api.github.com/users/lsegal/followers","following_url":"https://api.github.com/users/lsegal/following{/other_user}","gists_url":"https://api.github.com/users/lsegal/gists{/gist_id}","starred_url":"https://api.github.com/users/lsegal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsegal/subscriptions","organizations_url":"https://api.github.com/users/lsegal/orgs","repos_url":"https://api.github.com/users/lsegal/repos","events_url":"https://api.github.com/users/lsegal/events{/privacy}","received_events_url":"https://api.github.com/users/lsegal/received_events","type":"User","site_admin":false},"created_at":"2015-12-02T23:11:28Z","updated_at":"2015-12-02T23:11:28Z","body":"I wouldn't say \"completely broken\".\r\n\r\n> changing from rw to r makes no difference\r\n\r\nIt's *not* read-only, you've defined a writer method, so by definition (literally), it's parsed as readwrite. `@!attribute` is primarily meant for scenarios where there is no explicit method declaration, like a DSL method, eval, or native code. If you have direct code, you should be documenting directly on the method.\r\n\r\nBasically, you're confusing YARD by using a declaration to fake a method declaration followed by YARD actually parsing a real method declaration. See the docs on directives for more context:\r\n\r\n> Directives are similar to meta-data tags in the way they are specified, but they do not add meta-data to the object directly. Instead, they affect the parsing context and objects themselves, allowing a developer to create objects (like methods) outright, rather than simply add text to an existing object.\r\n\r\nYou don't need to affect parsing in order to add a docstring to #name, you simply need a directive to mark is as an attribute, which can be done as a *separate* comment line:\r\n\r\n```ruby\r\n## @!attribute name\r\n\r\n# @return [String] name\r\ndef name; end\r\n\r\n...\r\n```\r\n\r\nOr, alternatively, document ONLY the directive, not the method definition itself:\r\n\r\n```ruby\r\n# @!attribute name\r\n#   @return [String] name\r\n\r\n\r\ndef name; end\r\n# note multiple spaces of separation\r\n```\r\n\r\nBasically, never mix a directive that creates a code object with an explicit code definition of a code object in the same docstring. Otherwise YARD will parse your directive, then see a regular (empty) docstring defined on the same object and overwrite all your hard work with the empty docstring. The last parsed docstring always wins.\r\n\r\n> return type is only recognized if unindented\r\n\r\nThe above explanation applies to this point as well. By attaching the directive to #name's docstring, you're effectively causing YARD to overwrite the docstring with empty text after it parses the directive, wiping out your return tag. If you unindent the tag, it sticks around because it's being parsed after the directive's docstring additions.\r\n\r\nIt's debatable whether YARD should omit overwriting an existing docstring with an empty docstring, but changing this may break assumptions that other docs might be relying on so it would have to be investigated further. This is something we *could* improve on.\r\n\r\n> no source code is made accessible in the documentation\r\n\r\ntl;dr no attributes display source code in YARD's default HTML template-- this is not specific to the directive usage.\r\n\r\nI think this might be a misunderstanding of the verbiage here. Source *is* added to the YARD database for the code object. In other words, YARD is storing that information internally. The issue here is that the default HTML template that YARD uses will *never* expose source for attributes, whether there is source attached or not. The parser parses it-- the *default* template is omitting it  (custom templating could display it, if needed).\r\n\r\nThis is an explicit decision in the templating layer due to the fact that the implementation for an attribute is typically irrelevant. Implementation details are usually only needed in documentation if the implementation itself is \"doing something\"-- in an attribute's case, you are only accessing other properties, and, typically, internal properties that are not relevant to documentation. If you think the implementation for your attribute is important, i.e., it \"does something\"-- consider the fact that it might not be an \"attribute\"-- especially if you also believe that it should be considered readonly."}}