yard 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of yard might be problematic. Click here for more details.

Files changed (204) hide show
  1. data/LICENSE +1 -1
  2. data/README.markdown +200 -0
  3. data/Rakefile +6 -1
  4. data/benchmarks/format_args.rb +46 -0
  5. data/benchmarks/parsing.rb +13 -1
  6. data/benchmarks/rdoc_vs_yardoc.rb +10 -0
  7. data/benchmarks/ripper_parser.rb +12 -0
  8. data/docs/CODE_OBJECTS.markdown +121 -0
  9. data/docs/FAQ.markdown +34 -0
  10. data/docs/GENERATORS.markdown +211 -0
  11. data/docs/GETTING_STARTED.markdown +263 -0
  12. data/docs/GLOSSARY.markdown +13 -0
  13. data/docs/HANDLERS.markdown +158 -0
  14. data/docs/OVERVIEW.markdown +64 -0
  15. data/docs/PARSER.markdown +180 -0
  16. data/docs/TAGS.markdown +181 -0
  17. data/docs/WHATSNEW.markdown +96 -0
  18. data/docs/images/code-objects-class-diagram.png +0 -0
  19. data/docs/images/handlers-class-diagram.png +0 -0
  20. data/docs/images/overview-class-diagram.png +0 -0
  21. data/docs/images/parser-class-diagram.png +0 -0
  22. data/docs/images/tags-class-diagram.png +0 -0
  23. data/lib/yard.rb +4 -1
  24. data/lib/yard/autoload.rb +79 -31
  25. data/lib/yard/cli/yard_graph.rb +8 -2
  26. data/lib/yard/cli/yardoc.rb +61 -8
  27. data/lib/yard/code_objects/base.rb +78 -135
  28. data/lib/yard/code_objects/class_object.rb +9 -8
  29. data/lib/yard/code_objects/constant_object.rb +1 -0
  30. data/lib/yard/code_objects/extended_method_object.rb +9 -0
  31. data/lib/yard/code_objects/method_object.rb +18 -5
  32. data/lib/yard/code_objects/module_object.rb +8 -1
  33. data/lib/yard/code_objects/namespace_object.rb +25 -16
  34. data/lib/yard/code_objects/proxy.rb +22 -22
  35. data/lib/yard/core_ext/file.rb +1 -1
  36. data/lib/yard/core_ext/string.rb +0 -4
  37. data/lib/yard/core_ext/symbol_hash.rb +3 -2
  38. data/lib/yard/docstring.rb +180 -0
  39. data/lib/yard/generators/base.rb +33 -13
  40. data/lib/yard/generators/class_generator.rb +4 -2
  41. data/lib/yard/generators/constants_generator.rb +3 -2
  42. data/lib/yard/generators/full_doc_generator.rb +76 -9
  43. data/lib/yard/generators/helpers/base_helper.rb +18 -1
  44. data/lib/yard/generators/helpers/filter_helper.rb +2 -2
  45. data/lib/yard/generators/helpers/html_helper.rb +94 -39
  46. data/lib/yard/generators/helpers/html_syntax_highlight_helper.rb +49 -0
  47. data/lib/yard/generators/helpers/markup_helper.rb +86 -0
  48. data/lib/yard/generators/helpers/method_helper.rb +23 -7
  49. data/lib/yard/generators/method_generator.rb +15 -3
  50. data/lib/yard/generators/method_listing_generator.rb +3 -3
  51. data/lib/yard/generators/mixins_generator.rb +8 -2
  52. data/lib/yard/generators/module_generator.rb +3 -2
  53. data/lib/yard/generators/overloads_generator.rb +20 -0
  54. data/lib/yard/generators/quick_doc_generator.rb +3 -9
  55. data/lib/yard/generators/root_generator.rb +32 -0
  56. data/lib/yard/generators/source_generator.rb +2 -17
  57. data/lib/yard/generators/tags_generator.rb +34 -6
  58. data/lib/yard/generators/uml_generator.rb +16 -6
  59. data/lib/yard/handlers/base.rb +88 -253
  60. data/lib/yard/handlers/processor.rb +72 -0
  61. data/lib/yard/handlers/ruby/alias_handler.rb +38 -0
  62. data/lib/yard/handlers/ruby/attribute_handler.rb +69 -0
  63. data/lib/yard/handlers/ruby/base.rb +72 -0
  64. data/lib/yard/handlers/ruby/class_condition_handler.rb +70 -0
  65. data/lib/yard/handlers/ruby/class_handler.rb +74 -0
  66. data/lib/yard/handlers/ruby/class_variable_handler.rb +11 -0
  67. data/lib/yard/handlers/ruby/constant_handler.rb +12 -0
  68. data/lib/yard/handlers/ruby/exception_handler.rb +22 -0
  69. data/lib/yard/handlers/ruby/extend_handler.rb +19 -0
  70. data/lib/yard/handlers/{alias_handler.rb → ruby/legacy/alias_handler.rb} +3 -4
  71. data/lib/yard/handlers/{attribute_handler.rb → ruby/legacy/attribute_handler.rb} +2 -2
  72. data/lib/yard/handlers/ruby/legacy/base.rb +198 -0
  73. data/lib/yard/handlers/{class_handler.rb → ruby/legacy/class_handler.rb} +18 -6
  74. data/lib/yard/handlers/{class_variable_handler.rb → ruby/legacy/class_variable_handler.rb} +1 -1
  75. data/lib/yard/handlers/{constant_handler.rb → ruby/legacy/constant_handler.rb} +2 -2
  76. data/lib/yard/handlers/{exception_handler.rb → ruby/legacy/exception_handler.rb} +3 -3
  77. data/lib/yard/handlers/ruby/legacy/extend_handler.rb +18 -0
  78. data/lib/yard/handlers/ruby/legacy/method_handler.rb +31 -0
  79. data/lib/yard/handlers/ruby/legacy/mixin_handler.rb +28 -0
  80. data/lib/yard/handlers/{module_handler.rb → ruby/legacy/module_handler.rb} +1 -1
  81. data/lib/yard/handlers/{visibility_handler.rb → ruby/legacy/visibility_handler.rb} +1 -1
  82. data/lib/yard/handlers/{yield_handler.rb → ruby/legacy/yield_handler.rb} +4 -4
  83. data/lib/yard/handlers/ruby/method_condition_handler.rb +7 -0
  84. data/lib/yard/handlers/ruby/method_handler.rb +48 -0
  85. data/lib/yard/handlers/ruby/mixin_handler.rb +25 -0
  86. data/lib/yard/handlers/ruby/module_handler.rb +9 -0
  87. data/lib/yard/handlers/ruby/visibility_handler.rb +18 -0
  88. data/lib/yard/handlers/ruby/yield_handler.rb +28 -0
  89. data/lib/yard/parser/ruby/ast_node.rb +263 -0
  90. data/lib/yard/parser/{ruby_lex.rb → ruby/legacy/ruby_lex.rb} +258 -259
  91. data/lib/yard/parser/{statement.rb → ruby/legacy/statement.rb} +8 -4
  92. data/lib/yard/parser/ruby/legacy/statement_list.rb +262 -0
  93. data/lib/yard/parser/{token_list.rb → ruby/legacy/token_list.rb} +1 -1
  94. data/lib/yard/parser/ruby/ruby_parser.rb +307 -0
  95. data/lib/yard/parser/source_parser.rb +76 -45
  96. data/lib/yard/rake/yardoc_task.rb +6 -1
  97. data/lib/yard/registry.rb +45 -19
  98. data/lib/yard/serializers/file_system_serializer.rb +8 -3
  99. data/lib/yard/tags/default_factory.rb +70 -10
  100. data/lib/yard/tags/default_tag.rb +12 -0
  101. data/lib/yard/tags/library.rb +65 -26
  102. data/lib/yard/tags/option_tag.rb +12 -0
  103. data/lib/yard/tags/overload_tag.rb +62 -0
  104. data/lib/yard/tags/ref_tag.rb +7 -0
  105. data/lib/yard/tags/ref_tag_list.rb +27 -0
  106. data/lib/yard/tags/tag.rb +1 -0
  107. data/lib/yard/tags/tag_format_error.rb +6 -0
  108. data/spec/cli/yardoc_spec.rb +43 -0
  109. data/spec/code_objects/base_spec.rb +56 -68
  110. data/spec/code_objects/class_object_spec.rb +18 -6
  111. data/spec/code_objects/constants_spec.rb +2 -0
  112. data/spec/code_objects/method_object_spec.rb +33 -5
  113. data/spec/code_objects/module_object_spec.rb +66 -8
  114. data/spec/code_objects/namespace_object_spec.rb +37 -17
  115. data/spec/code_objects/proxy_spec.rb +13 -2
  116. data/spec/core_ext/string_spec.rb +14 -2
  117. data/spec/core_ext/symbol_hash_spec.rb +9 -3
  118. data/spec/docstring_spec.rb +139 -0
  119. data/spec/generators/full_doc_generator_spec.rb +29 -0
  120. data/spec/generators/helpers/html_helper_spec.rb +74 -0
  121. data/spec/generators/helpers/markup_helper_spec.rb +95 -0
  122. data/spec/handlers/alias_handler_spec.rb +16 -3
  123. data/spec/handlers/attribute_handler_spec.rb +1 -1
  124. data/spec/handlers/base_spec.rb +15 -141
  125. data/spec/handlers/class_condition_handler_spec.rb +49 -0
  126. data/spec/handlers/class_handler_spec.rb +44 -3
  127. data/spec/handlers/class_variable_handler_spec.rb +1 -1
  128. data/spec/handlers/constant_handler_spec.rb +1 -1
  129. data/spec/handlers/examples/alias_handler_001.rb.txt +7 -3
  130. data/spec/handlers/examples/class_condition_handler_001.rb.txt +61 -0
  131. data/spec/handlers/examples/class_handler_001.rb.txt +33 -0
  132. data/spec/handlers/examples/exception_handler_001.rb.txt +1 -1
  133. data/spec/handlers/examples/extend_handler_001.rb.txt +8 -0
  134. data/spec/handlers/examples/method_condition_handler_001.rb.txt +10 -0
  135. data/spec/handlers/examples/method_handler_001.rb.txt +16 -4
  136. data/spec/handlers/examples/mixin_handler_001.rb.txt +10 -2
  137. data/spec/handlers/examples/module_handler_001.rb.txt +4 -0
  138. data/spec/handlers/examples/visibility_handler_001.rb.txt +1 -1
  139. data/spec/handlers/exception_handler_spec.rb +2 -2
  140. data/spec/handlers/extend_handler_spec.rb +15 -0
  141. data/spec/handlers/legacy_base_spec.rb +128 -0
  142. data/spec/handlers/method_condition_handler_spec.rb +14 -0
  143. data/spec/handlers/method_handler_spec.rb +38 -5
  144. data/spec/handlers/mixin_handler_spec.rb +15 -7
  145. data/spec/handlers/module_handler_spec.rb +5 -1
  146. data/spec/handlers/processor_spec.rb +19 -0
  147. data/spec/handlers/ruby/base_spec.rb +90 -0
  148. data/spec/handlers/ruby/legacy/base_spec.rb +53 -0
  149. data/spec/handlers/spec_helper.rb +22 -16
  150. data/spec/handlers/visibility_handler_spec.rb +4 -4
  151. data/spec/handlers/yield_handler_spec.rb +1 -1
  152. data/spec/parser/ruby/ast_node_spec.rb +15 -0
  153. data/spec/parser/ruby/legacy/statement_list_spec.rb +145 -0
  154. data/spec/parser/{token_list_spec.rb → ruby/legacy/token_list_spec.rb} +4 -4
  155. data/spec/parser/source_parser_spec.rb +0 -15
  156. data/spec/rake/yardoc_task_spec.rb +48 -0
  157. data/spec/registry_spec.rb +28 -2
  158. data/spec/serializers/file_system_serializer_spec.rb +7 -1
  159. data/spec/spec_helper.rb +1 -1
  160. data/spec/tags/default_factory_spec.rb +135 -0
  161. data/spec/tags/default_tag_spec.rb +11 -0
  162. data/spec/tags/overload_tag_spec.rb +35 -0
  163. data/spec/tags/ref_tag_list_spec.rb +53 -0
  164. data/templates/default/attributes/html/header.erb +17 -5
  165. data/templates/default/attributes/text/header.erb +1 -1
  166. data/templates/default/fulldoc/html/all_files.erb +19 -0
  167. data/templates/default/fulldoc/html/all_methods.erb +8 -7
  168. data/templates/default/fulldoc/html/all_namespaces.erb +4 -1
  169. data/templates/default/fulldoc/html/app.js +1 -1
  170. data/templates/default/fulldoc/html/{readme.erb → file.erb} +2 -2
  171. data/templates/default/fulldoc/html/header.erb +1 -1
  172. data/templates/default/fulldoc/html/index.erb +4 -3
  173. data/templates/default/fulldoc/html/style.css +13 -3
  174. data/templates/default/fulldoc/html/syntax_highlight.css +8 -5
  175. data/templates/default/method/text/header.erb +1 -0
  176. data/templates/default/method/text/title.erb +1 -0
  177. data/templates/default/methodsignature/html/main.erb +10 -8
  178. data/templates/default/methodsignature/text/main.erb +4 -1
  179. data/templates/default/methodsummary/html/summary.erb +8 -4
  180. data/templates/default/methodsummary/text/summary.erb +4 -1
  181. data/templates/default/mixins/html/header.erb +3 -3
  182. data/templates/default/overloads/html/header.erb +8 -0
  183. data/templates/default/overloads/text/header.erb +8 -0
  184. data/templates/default/root/html/header.erb +4 -0
  185. data/templates/default/tags/html/example.erb +20 -0
  186. data/templates/default/tags/html/option.erb +27 -0
  187. data/templates/default/tags/html/param.erb +21 -0
  188. data/templates/default/tags/html/tags.erb +4 -1
  189. data/templates/default/tags/html/todo.erb +8 -0
  190. data/templates/default/tags/text/example.erb +14 -0
  191. data/templates/default/tags/text/header.erb +3 -3
  192. data/templates/default/tags/text/option.erb +5 -0
  193. data/templates/default/tags/text/param.erb +9 -0
  194. data/templates/default/uml/dot/dependencies.erb +1 -1
  195. data/templates/default/uml/dot/info.erb +1 -1
  196. data/templates/default/uml/dot/superclasses.erb +2 -2
  197. data/templates/javadoc/methodsummary/html/summary.erb +2 -2
  198. data/templates/javadoc/mixins/html/header.erb +3 -3
  199. metadata +108 -139
  200. data/README +0 -211
  201. data/lib/yard/handlers/method_handler.rb +0 -27
  202. data/lib/yard/handlers/mixin_handler.rb +0 -16
  203. data/lib/yard/parser/statement_list.rb +0 -167
  204. data/lib/yard/tags/merbdoc_factory.rb +0 -47
@@ -0,0 +1,13 @@
1
+ Glossary
2
+ ========
3
+
4
+ * **Code Object**: Any explicitly defined Ruby source that describes a feature
5
+ of the code. By default, this refers to classes, modules, methods, constants
6
+ and class variables, though it can be extended to refer to custom functionality
7
+ defined by a DSL (like a spec, for instance).
8
+
9
+ * **Domain Specific Language (DSL)**: In the context of Ruby, a DSL is a languge
10
+ optimized for a specific domain (problem) but represented using Ruby syntax.
11
+
12
+ * **Docstring (Documentation String)**: Comments associated with a code object
13
+ used for documentation purposes.
@@ -0,0 +1,158 @@
1
+ Handlers Architecture
2
+ =====================
3
+
4
+ Handlers allow the processing of parsed source code. Handling is done after
5
+ parsing to abstract away the implementation details of lexical and semantic
6
+ analysis on source and to only deal with the logic regarding recognizing
7
+ source statements as {file:CODE_OBJECTS.markdown code objects}.
8
+
9
+ ![Handlers Architecture Class Diagram](images/handlers-class-diagram.png)
10
+
11
+ The Pipeline
12
+ ------------
13
+
14
+ After the {file:PARSER.markdown parser component} finishes analyzing the
15
+ source, it is handed off for post-processing to the {YARD::Handlers::Processor}
16
+ class, which is responsible for traversing the set of statements given by
17
+ the parser and delegating them to matching handlers. Handlers match when the
18
+ {YARD::Handlers::Base.handles?} method returns true for a given statement.
19
+ The handler can then perform any action after being invoked by the `process`
20
+ method.
21
+
22
+ The Processor Class
23
+ -------------------
24
+
25
+ The main purpose of the processor, as mentioned above, is to traverse through
26
+ the list of statements given to it by the parser. The processor also keeps
27
+ state about what is being processed. For instance, the processor is what keeps
28
+ track of the current namespace (the module or class an object is being defined
29
+ in), scope (class or instance), file and owner. The owner refers to the object
30
+ that is most directly responsible for the source statement being processed. This
31
+ is most often the same as the namespace, except when parsing the body of a method,
32
+ where the namespace would be the class/module the method is defined in and the
33
+ owner would be the method object itself.
34
+
35
+ Implementing a Handler
36
+ ======================
37
+
38
+ This section covers the basics of implementing a *new-style* Ruby handler. For
39
+ details on implementing a legacy handler, see the "API Differences" section below.
40
+
41
+ a Ruby handler can be implemented simply by subclassing the {YARD::Handlers::Ruby::Base}
42
+ class and declaring what node types or source to process with the {YARD::Handlers::Base.handles handles}
43
+ class method. A very simple handler that handles a module definition would be:
44
+
45
+ class MyModuleHandler < YARD::Handlers::Ruby::Base
46
+ handles :module
47
+
48
+ def process
49
+ puts "Handling a module named #{statement[0].source}"
50
+ end
51
+ end
52
+
53
+ For details on what nodes are, and what node types are, see the
54
+ {file:PARSER.markdown parser architecture document}.
55
+
56
+ In this case the node type being handled is the `:module` type. More than one
57
+ node type or `handles` declarations may describe a single handler, for instance,
58
+ a handler that handles class definitions should handle the `:class` and `:sclass`
59
+ node types respectively (the latter refers to classes defined as `class << Something`).
60
+ The {YARD::Handlers::Base#statement statement} attribute refers to the current
61
+ node (or statement) that is being handled by the handler.
62
+
63
+ Handling a Method Call
64
+ ----------------------
65
+
66
+ In some cases, a developer might need to handle a method call. The parser can
67
+ express a method call in many AST forms, so to simplify this process, a method
68
+ call can be handled by declaring the following in a `handles` statement:
69
+
70
+ class MyHandler < YARD::Handlers::Ruby::Base
71
+ handles method_call(:describe)
72
+
73
+ def process
74
+ # Process the method call
75
+ end
76
+ end
77
+
78
+ In this case we handle any of the method calls to method name `describe` with
79
+ the following syntaxes:
80
+
81
+ describe(something)
82
+ describe arg1, arg2, arg3
83
+ describe(something) { perform_a_block }
84
+ describe "Something" do
85
+ a_block
86
+ end
87
+
88
+ Creating a new Code Object
89
+ --------------------------
90
+
91
+ Usually (but not always) handling is performed to create new code objects to add
92
+ to the registry (for information about code objects, see {file:CODE_OBJECTS.markdown this document}).
93
+ Code objects should simply be created and added to the existing `namespace`. This
94
+ will be enough to add them to the registry. There is also a convenience
95
+ {YARD::Handlers::Base#register register} method which quickly sets standard attributed
96
+ on the newly created object, such as the file, line, source and docstring of the
97
+ object. This method will be seen in the next example.
98
+
99
+ Handling an Inner Block
100
+ -----------------------
101
+
102
+ By default, the parser gives the processor class a list of all the top level
103
+ statements and the processor parses only those top level statements. If an inner
104
+ block of a module, class, method declaration or even a block passed to a method call
105
+ needs to be handled, the {YARD::Handlers::Base#parse_block parse_block} method must be called on the list of statements
106
+ to parse. This will send the list to the processor to continue processing on that
107
+ statement list. The source tree can be selectively parsed in this manner by parsing
108
+ only the inner blocks that are relevant to documentation.
109
+
110
+ For example, the module handler parses the inner body of a module by performing
111
+ the following commands:
112
+
113
+ class YARD::Handlers::Ruby::ModuleHandler < YARD::Handlers::Ruby::Base
114
+ handles :module
115
+
116
+ def process
117
+ modname = statement[0].source
118
+ mod = register ModuleObject.new(namespace, modname)
119
+ parse_block(statement[1], :namespace => mod)
120
+ end
121
+ end
122
+
123
+ In this case `statement[1]` refers to a list of extra statements, the block we
124
+ wish to parse. Note here that when parsing objects like modules and classes,
125
+ we set the namespace for the duration of the block parsing by setting options
126
+ on the `parse_block` method.
127
+
128
+ API Differences for Legacy Handler
129
+ ----------------------------------
130
+
131
+ Because the legacy handler uses the legacy parser and therefore a different kind
132
+ of AST, there are subtle differences in the handler API. Most importantly, the
133
+ `handles` method usually deals with either lexical tokens or source code as a string
134
+ or RegExp object. The statement object, similarly, is made up of lexical tokens instead
135
+ of semantically parsed nodes (this is described in the {file:PARSER.markdown parser document}).
136
+
137
+ The module example above can be rewritten as a legacy handler as follows:
138
+
139
+ class YARD::Handlers::Ruby::Legacy::ModuleHandler < YARD::Handlers::Ruby::Legacy::Base
140
+ handles TkMODULE
141
+
142
+ def process
143
+ modname = statement.tokens.to_s[/^module\s+(#{NAMESPACEMATCH})/, 1]
144
+ mod = register ModuleObject.new(namespace, modname)
145
+ parse_block(:namespace => mod)
146
+ end
147
+ end
148
+
149
+ A few notes on the differences:
150
+
151
+ * We inherit from `Legacy::Base` instead of the standard Ruby Base handler class.
152
+ * We exchange node type `:module` for `TkMODULE`, which represents the
153
+ first token in the statement.
154
+ * We perform direct string manipulation to get the module name.
155
+ * `parse_block` does not take a list of statements. In the old parser API,
156
+ each statement has a `block` attribute which defines the list of
157
+ statements within that statement, if any. Therefore, `parse_block` will
158
+ always parse the `statement.block` if it exists.
@@ -0,0 +1,64 @@
1
+ Architecture Overview
2
+ =====================
3
+
4
+ YARD is separated in three major components, each of which allows YARD to be
5
+ extended for a separate purpose. The split also emphasizes YARD's design choice
6
+ to explicitly separate data gathering from HTML document generation, something
7
+ that tools like RDoc do not do. These components are:
8
+
9
+ * [Code Parsing & Processing Component](#parsing)
10
+ * [Data Storage Component](#storage)
11
+ * [Post Processing & Output Generation Component](#generators)
12
+
13
+ This separation is a major goal of the project, and means that YARD is not *just*
14
+ a tool to generate HTML output. The expectation is that any subset of YARD's
15
+ major components may be used, extended or modified independently. YARD may be
16
+ used just as a data gathering tool (to parse and audit code), just as as a data
17
+ source (a webserver containing raw unformatted data about code), or just as a
18
+ conventional HTML documentation generation tool (like RDoc).
19
+
20
+ The important classes and dependencies of these components are shown in the
21
+ following class diagram:
22
+
23
+ ![Overview Class Diagram](images/overview-class-diagram.png)
24
+
25
+ <a name="parsing"></a>
26
+ Code Parsing & Processing Component
27
+ -----------------------------------
28
+
29
+ This component is made up of four sub-components, each of which have separate
30
+ tasks during the data gathering process (*note: the tag architecture is not*
31
+ *shown in the class diagram*). These sub-components are:
32
+
33
+ * {file:PARSER.markdown Parser Architecture}
34
+ * {file:HANDLERS.markdown Handler Architecture}
35
+ * {file:CODE_OBJECTS.markdown Code Object Architecture}
36
+ * {file:TAGS.markdown Tag Architecture}
37
+
38
+ The parser component reads source files and converts it into a set of statements
39
+ which the handlers then process, creating code objects which in turn create tags
40
+ (meta-data) attached to the objects. These objects are all added to the {YARD::Registry},
41
+ the data store component.
42
+
43
+ <a name="storage"></a>
44
+ Data Storage Component
45
+ ----------------------
46
+
47
+ This component is currently implemented as a simple Ruby marshalled flat namespace
48
+ of object. The implementation is found in the single class {YARD::Registry}, which
49
+ is the centralized repository for all data being parsed, stored and accessed. There
50
+ are future plans to improve this storage mechanism to be backend agnostic and allow
51
+ for more robust storage.
52
+
53
+ <a name="generators"></a>
54
+ Post Processing & Output Generation Component
55
+ ---------------------------------------------
56
+
57
+ This component handles processing of objects from the registry through a templating
58
+ engine that allows output to a variety of formats. Practically speaking, this is
59
+ where templates can be implemented to change the design, output or structure of
60
+ the data. The next release, 0.2.4, will see a significant change in the design of
61
+ this component, so documentation might be sparse for now.
62
+
63
+ The current design is documented in the {file:GENERATORS.markdown Generators Architecture}
64
+ document.
@@ -0,0 +1,180 @@
1
+ Parser Architecture
2
+ ===================
3
+
4
+ The parser component of YARD is the first component in the data processing pipeline
5
+ that runs before any handling is done on the source. The parser is meant to translate
6
+ the source into a set of statements that can be understood by the {file:HANDLERS.markdown Handlers}
7
+ that run immediately afterwards.
8
+
9
+ The important classes are described in the class diagram of the entire parser
10
+ system below:
11
+
12
+ ![Parser Class Diagram](images/parser-class-diagram.png)
13
+
14
+ (Note: the RubyToken classes are omitted from the diagram)
15
+
16
+ SourceParser
17
+ ------------
18
+
19
+ The main class {YARD::Parser::SourceParser} acts as a factory class, instantiating
20
+ the correct parser class given the source type being parsed. This usually involves
21
+ a file extension check, though this can be overriden. Currently, only a Ruby source
22
+ parser is implemented, though future plans include a C parser for Ruby extensions.
23
+
24
+ This factory class should always be used when parsing source files rather than
25
+ the individual parser classes since it initiates the pipeline that runs the
26
+ handlers on the parsed source. The parser used must also match the handlers,
27
+ and this is coordinated by the `SourceParser` class as well.
28
+
29
+ Using the SourceParser Class
30
+ ----------------------------
31
+
32
+ The `SourceParser` class API is optimized for parsing globs of files. As such,
33
+ the main method to use the class is the `parse` class method, which takes an
34
+ array of file globs or a single file glob.
35
+
36
+ YARD::Parser::SourceParser.parse('spec_*.rb')
37
+ YARD::Parser::SourceParser.parse(['spec_*.rb', '*_helper.rb'])
38
+
39
+ This is equivalent to the convenience method {YARD.parse}:
40
+
41
+ YARD.parse('lib/**/*.rb')
42
+
43
+ In some cases (ie. for testing), it may be more helpful to parse a string of input
44
+ directly. In such a case, the method {YARD::Parser::SourceParser.parse_string} should be
45
+ used:
46
+
47
+ YARD::Parser::SourceParser.parse_string("def method(a, b) end")
48
+
49
+ Because no filename information is given, this method allows the setting of the
50
+ parser type as an argument:
51
+
52
+ # Parses a string of C (not implemented)
53
+ YARD::Parser::SourceParser.parse_string("int main() { }", :c)
54
+
55
+ The Two Ruby Parser Types
56
+ -------------------------
57
+
58
+ When parsing Ruby, the SourceParser can either instantiate the new {YARD::Parser::Ruby::RubyParser}
59
+ class or the {YARD::Parser::Ruby::Legacy::StatementList} class. The first of the
60
+ two, although faster, more robust and more efficient, is only available for
61
+ Ruby 1.9. The legacy parser parser is available in both 1.8.x and 1.9, if
62
+ compatibility is required. The choice of parser will affect which handlers
63
+ ultimately get used, since new handlers can only use the new parser and the
64
+ same requirement applies to the legacy parser & handlers.
65
+
66
+ Switching to Legacy Parser
67
+ --------------------------
68
+
69
+ By default, running YARD under Ruby 1.9 will automatically select the new parser
70
+ and new handlers by extension. Although YARD supports both handler styles, plugins
71
+ may choose to only implement one of the two (though this is not recommended). If
72
+ only the legacy handlers are implemented, the `SourceParser` class should force
73
+ the use of the legacy parser by setting the `parser_type` attribute as such:
74
+
75
+ YARD::Parser::SourceParser.parser_type = :ruby18
76
+
77
+ The default value is `:ruby`. Note that this cannot be forced the other way around,
78
+ a parser type of `:ruby` cannot be set under Ruby 1.8.x as the new parser is not
79
+ supported under 1.8.
80
+
81
+ RubyParser (the New Parser)
82
+ ===========================
83
+
84
+ The new Ruby parser uses the Ripper library that is packaged as part of stdlib
85
+ in Ruby 1.9. Because of this, it can generate an AST from a string of Ruby input
86
+ that is similar to the style of other sexp libraries (such as ParseTree). Each
87
+ node generated in the tree is of the base type {YARD::Parser::Ruby::AstNode},
88
+ which has some subclasses for common node types.
89
+
90
+ AstNode Basics
91
+ --------------
92
+
93
+ The `AstNode` class behaves like a standard Array class in which all of its data
94
+ make up the list of elements in the array. Unlike other sexp style libraries, however,
95
+ the node type is not the first element of the list. Instead, the node type is defined
96
+ by the `#type` method. The following examples show some of the basic uses of `AstNode`:
97
+
98
+ # The sexp defines the statement `hello if 1`
99
+ node = s(:if_mod, s(:int, "1"), s(:var_ref, s(:ident, "hello")))
100
+ node.type #=> :if_mod
101
+ node[0] #=> s(:int, "1")
102
+ node[0][0] #=> "1"
103
+
104
+ (Note the `s()` syntax is shorthand for `AstNode.new(...)`. `s()` with no type
105
+ is shorthand for a node of type `:list`)
106
+
107
+ As shown, not all of the elements are AstNodes in themselves, some are String
108
+ objects containing values. A list of only the AstNodes within a node can be
109
+ accessed via the {YARD::Parser::Ruby::AstNode#children #children} method. Using
110
+ the sexp declared above, we can do:
111
+
112
+ node.children #=> [s(:int, "1"), s(:var_ref, s(:ident, "hello"))]
113
+
114
+ AstNode#source and #line
115
+ ------------------------
116
+
117
+ Every node defines the `#source` method which returns the source code that the
118
+ node represents. One of the most common things to do with a node is to grab its
119
+ source. The following example shows how this can be done:
120
+
121
+ source = "if 1 == 1 then\n raise Exception\n end"
122
+ ast = YARD::Parser::Ruby::RubyParser.parse(source).root
123
+ ast[0].condition.source #=> "1 == 1"
124
+ ast[0].then_block.source #=> "raise Exception"
125
+
126
+ Note that this only works on source parsed from the RubyParser, not sexps
127
+ declared using the `s()` syntax. This is because no source code is generated
128
+ or stored by nodes. Instead, only the character ranges are stored, which are
129
+ then looked up in the original full source string object. For example:
130
+
131
+ # Following the code snippet above
132
+ ast[0].then_block.source_range #=> 17..31
133
+
134
+ We can also get the line and line ranges in a similar fashion:
135
+
136
+ ast[0].type #=> :if
137
+ ast[0].line #=> 1
138
+ ast[0].line_range #=> 1..3 (note the newlines in the source)
139
+
140
+ AstNode#jump
141
+ ------------
142
+
143
+ Often the AST will be such that the node we care about might be buried arbitrarily
144
+ deep in a node's hierarchy. The {YARD::Parser::Ruby::AstNode#jump} method exists
145
+ to quickly get at a node of a specific type in such a situation:
146
+
147
+ # Get the first identifier in the statement
148
+ ast = s(s(:int, "1"), s(s(:var_ref, s(:ident, "hello"))))
149
+ ast.jump(:ident)[0] #=> "hello"
150
+
151
+ Multiple types can be searched for at once. If none are found, the original root
152
+ node is returned so that it may be chained.
153
+
154
+ The Legacy Parser
155
+ =================
156
+
157
+ The goal of the legacy parser is much the same as the new parser, but it is far
158
+ more simplistic. Instead of a full-blown AST, the legacy parser simply groups
159
+ together lists of "statements" called a {YARD::Parser::Ruby::Legacy::StatementList}.
160
+ These statement lists are made up of {YARD::Parser::Ruby::Legacy::Statement} objects.
161
+ A statement is any method call condition, loop, or declaration. Each statement
162
+ may or may not have a block. In the case of a condition or loop, the block is
163
+ the inner list of statements; in the case of a method call, the block is a do
164
+ block (if provided). The statements themselves are made up of tokens, so instead
165
+ of being semantic in nature like the new parser, statements are tied directly
166
+ to the lexical tokens that make them up. To convert a statement into source, you
167
+ simply join all the tokens together (this is done through the use of `#to_s`).
168
+
169
+ Note that because there is little semantic parsing, the legacy parser is less
170
+ able to deal with certain Ruby syntaxes. Specifically, the `:if_mod` syntax
171
+ seen above ("hello if 1") would be considered two statements with the new parser,
172
+ but using the legacy parser it is only one statement:
173
+
174
+ stmts = ARD::Parser::Ruby::Legacy::StatementList.new("hello if 1")
175
+ stmts[0].block #=> nil
176
+ stmts[0].tokens.to_s #=> "hello if 1"
177
+
178
+ In addition, this means that most handling still needs to be done via string
179
+ manipulation and regular expression matching, making it considerably more
180
+ difficult to use in edge case scenarios.
@@ -0,0 +1,181 @@
1
+ Tags Architecture
2
+ =================
3
+
4
+ Tags represent the metadata that can be added to documentation through the `@tag`
5
+ style syntax:
6
+
7
+ # @tagname some data
8
+ class Foo
9
+ end
10
+
11
+ The above example adds metadata under the name `tagname` to the Foo class object.
12
+
13
+ Tags are the best way to add arbitrary metadata when documenting an object in a
14
+ way to access it later without having to parse the entire comment string. The
15
+ rest of the document will describe how to access the tag metadata and how to extend
16
+ YARD to support custom tags or override existing tags to the {YARD::Tags::Library}
17
+ class.
18
+
19
+ Accessing Tag Information
20
+ -------------------------
21
+
22
+ Tag metadata is added when a {YARD::Docstring} is added to a {file:CODE_OBJECTS.markdown code object}
23
+ using the {YARD::CodeObjects::Base#docstring=} attribute. In addition to adding
24
+ conventional comments, tags are parsed and associated with the object. The easiest
25
+ way to access tags on an object is to use the {YARD::CodeObjects::Base#tag} and `#tags`
26
+ methods, for example:
27
+
28
+ # Using the Foo class object from above
29
+ obj.tags(:tagname).first.text #=> "some data"
30
+
31
+ Because multiple tags can be stored with the same name, they are stored as a list
32
+ of tags. The `#tag` method is an alias for the first item in the list of tags.
33
+ Also note that the `#tag`, `#tags` and `#has_tag?` methods are all convenience
34
+ methods that delegate to the {YARD::Docstring} object described above.
35
+
36
+ Adding Custom Tags
37
+ ------------------
38
+
39
+ The `@tagname` tag used in the above examples is clearly not part of the tags
40
+ that come with YARD. If such a tag would actually be part of documentation under
41
+ a default install, YARD would raise a warning that the tag does not exist. It is,
42
+ however, trivial to add this tag to be recognized by YARD.
43
+
44
+ All tags in YARD are added to the {YARD::Tags::Library tag library} which makes
45
+ use of a tag factory class to parse the data inside the tags. To simply add a
46
+ tag that stores simple text like our `@tagname` tag above, use:
47
+
48
+ YARD::Tags::Library.define_tag("A Sample Tag", :tagname)
49
+
50
+ This will now allow YARD to add the metadata from `@tagname` to the docstring.
51
+
52
+ The Tag Factory Architecture
53
+ ============================
54
+
55
+ Recognizing a tag is one part of the process. Parsing the tag contents is the
56
+ second step. YARD has a tag architecture that allows developers to add or completely
57
+ change the way tags contents can be parsed.
58
+
59
+ The separation of registration and tag creation can be seen in the following
60
+ class diagram:
61
+
62
+ ![Tags Architecture Class Diagram](images/tags-class-diagram.png)
63
+
64
+ DefaultFactory
65
+ --------------
66
+
67
+ By default, YARD has a few standard syntaxes that can be parsed for tags. These
68
+ are all implemented by the {YARD::Tags::DefaultFactory} class. These syntaxes
69
+ are:
70
+
71
+ * Standard text: no parsing is done, but text is stripped of newlines and
72
+ multiple spaces.
73
+
74
+ * Raw text: does no parsing at all, no stripping of newlines or spaces. This
75
+ is best used for code snippets.
76
+
77
+ * Raw text with title: does no parsing on the text but extracts the first line
78
+ of the metadata as the "title", useful for tags such as `@example`:
79
+
80
+ # @example Inspect an element
81
+ # myobj.inspect #=> #<Object:0x123525>
82
+
83
+ * Text with types: parses a list of types at the beginning of the text. Types
84
+ are optional. The standard syntax is in the form `[type1, type2, ...]`,
85
+ for example:
86
+
87
+ # @return [String, Symbol] a description here
88
+ # @return description here with no types
89
+
90
+ * Text with types and a name: parses a list of types at the beginning of text
91
+ followed by a name and extra descriptive text. For example:
92
+
93
+ # @param [String] str the string to reverse
94
+ def reverse(str) '...' end
95
+
96
+ As mentioned above, this syntax is implemented by the `DefaultFactory` which can
97
+ be swapped out for any factory. In some cases, a developer may want to change
98
+ the type declaration syntax to be in the form:
99
+
100
+ # @tagname name <Types, here> description
101
+
102
+ This can be done by simply implementing a new factory that parses the data in
103
+ this form.
104
+
105
+ Implementing a Factory
106
+ ----------------------
107
+
108
+ Factories should implement the method `parse_tag` as well as any `parse_tag_SUFFIX`
109
+ method where SUFFIX refers to the suffix added when declaring the tag. For example,
110
+ a tag can also be declared as follows:
111
+
112
+ YARD::Tags::Library.define_tag "Parameter", :param, :with_types
113
+
114
+ In such a case, the factory will be called with method `parse_tag_with_types`. In
115
+ all cases, the method should return a new {YARD::Tags::Tag} object. Generally,
116
+ the `parse_tag` methods take 2 or 3 parameters. A simple tag can be implemented
117
+ as:
118
+
119
+ def parse_tag(tag_name, text)
120
+ Tag.new(tag_name, text)
121
+ end
122
+
123
+ The text parameter contains pre-parsed text with extra spaces and newlines removed.
124
+ If required, the method could also be declared with a third parameter containing
125
+ unmodified raw text:
126
+
127
+ def parse_tag_with_raw_text(tag_name, text, raw_text)
128
+ Tag.new(tag_name, raw_text)
129
+ end
130
+
131
+ Note that this method would be invoked for a tag declared with the `:with_raw_text`
132
+ suffix.
133
+
134
+ Changing the Factory
135
+ --------------------
136
+
137
+ To change the factory, set the {YARD::Tags::Library.default_factory} attribute:
138
+
139
+ YARD::Tags::Library.default_factory = MyFactory
140
+
141
+ This must be done before any parsing is done, or the factory will not be used.
142
+
143
+ <a name="reftags"></a>
144
+ Reference Tags
145
+ --------------
146
+
147
+ Although attempt is made in YARD to leave as many of the syntax details as
148
+ possible to the factory provider, there is a special tag syntax for referencing
149
+ tags created in other objects so that they can be reused again. This is common
150
+ when an object describes a return type or parameters that are passed through to
151
+ other methods. In such a case, it is more manageable to use the reference tag
152
+ syntax. Consider the following example:
153
+
154
+ class User
155
+ # @param [String] username the nam of the user to add
156
+ # @param [Number] uid the user ID
157
+ # @param [Number] gid the group ID
158
+ def initialize(username, uid, gid)
159
+ end
160
+ end
161
+
162
+ module UserHelper
163
+ # @param (see User#initialize)
164
+ def add_user(username, uid, gid)
165
+ User.new(username, uid, gid)
166
+ end
167
+
168
+ # @param username (see User#initialize)
169
+ def add_root_user(username)
170
+ User.new(username, 0, 0)
171
+ end
172
+ end
173
+
174
+ Because the UserHelper module methods delegate directly to `User.new`, copying
175
+ the documentation details would be unmaintainable. In this case, the (see METHODNAME)
176
+ syntax is used to reference the tags from the User constructor to the helper methods.
177
+ For the first method, all `@param` tags are referenced in one shot, but the second
178
+ method only references one of the tags by adding `username` before the reference.
179
+
180
+ Reference tags are represented by the {YARD::Tags::RefTag} class and are created
181
+ directly during parsing by {YARD::Docstring}.