yard 0.6.8 → 0.7.0

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 (224) hide show
  1. data/.yardopts +1 -0
  2. data/ChangeLog +723 -0
  3. data/README.md +16 -6
  4. data/docs/CodeObjects.md +10 -16
  5. data/docs/GettingStarted.md +232 -32
  6. data/docs/Glossary.md +1 -2
  7. data/docs/Handlers.md +10 -16
  8. data/docs/Overview.md +14 -13
  9. data/docs/Parser.md +13 -22
  10. data/docs/Tags.md +209 -16
  11. data/docs/Templates.md +237 -26
  12. data/docs/WhatsNew.md +178 -2
  13. data/lib/yard.rb +13 -10
  14. data/lib/yard/autoload.rb +22 -18
  15. data/lib/yard/cli/command.rb +13 -12
  16. data/lib/yard/cli/command_parser.rb +20 -19
  17. data/lib/yard/cli/config.rb +19 -19
  18. data/lib/yard/cli/diff.rb +46 -21
  19. data/lib/yard/cli/gems.rb +11 -11
  20. data/lib/yard/cli/graph.rb +13 -13
  21. data/lib/yard/cli/help.rb +1 -1
  22. data/lib/yard/cli/list.rb +22 -0
  23. data/lib/yard/cli/server.rb +17 -17
  24. data/lib/yard/cli/stats.rb +32 -32
  25. data/lib/yard/cli/yardoc.rb +181 -135
  26. data/lib/yard/cli/yri.rb +29 -29
  27. data/lib/yard/code_objects/base.rb +101 -101
  28. data/lib/yard/code_objects/class_object.rb +20 -20
  29. data/lib/yard/code_objects/constant_object.rb +1 -1
  30. data/lib/yard/code_objects/extended_method_object.rb +5 -5
  31. data/lib/yard/code_objects/extra_file_object.rb +89 -0
  32. data/lib/yard/code_objects/macro_object.rb +215 -0
  33. data/lib/yard/code_objects/method_object.rb +30 -30
  34. data/lib/yard/code_objects/module_object.rb +1 -1
  35. data/lib/yard/code_objects/namespace_object.rb +39 -39
  36. data/lib/yard/code_objects/proxy.rb +38 -38
  37. data/lib/yard/code_objects/root_object.rb +1 -1
  38. data/lib/yard/config.rb +40 -40
  39. data/lib/yard/core_ext/array.rb +2 -2
  40. data/lib/yard/core_ext/file.rb +11 -11
  41. data/lib/yard/core_ext/insertion.rb +10 -10
  42. data/lib/yard/core_ext/module.rb +2 -2
  43. data/lib/yard/core_ext/string.rb +2 -2
  44. data/lib/yard/core_ext/symbol_hash.rb +14 -14
  45. data/lib/yard/docstring.rb +122 -54
  46. data/lib/yard/globals.rb +2 -2
  47. data/lib/yard/handlers/base.rb +216 -127
  48. data/lib/yard/handlers/processor.rb +65 -27
  49. data/lib/yard/handlers/ruby/alias_handler.rb +6 -3
  50. data/lib/yard/handlers/ruby/attribute_handler.rb +7 -6
  51. data/lib/yard/handlers/ruby/base.rb +50 -31
  52. data/lib/yard/handlers/ruby/class_condition_handler.rb +11 -11
  53. data/lib/yard/handlers/ruby/class_handler.rb +10 -10
  54. data/lib/yard/handlers/ruby/class_variable_handler.rb +3 -3
  55. data/lib/yard/handlers/ruby/constant_handler.rb +7 -7
  56. data/lib/yard/handlers/ruby/exception_handler.rb +2 -2
  57. data/lib/yard/handlers/ruby/extend_handler.rb +1 -1
  58. data/lib/yard/handlers/ruby/legacy/alias_handler.rb +8 -5
  59. data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +6 -5
  60. data/lib/yard/handlers/ruby/legacy/base.rb +42 -27
  61. data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +9 -9
  62. data/lib/yard/handlers/ruby/legacy/class_handler.rb +13 -12
  63. data/lib/yard/handlers/ruby/legacy/class_variable_handler.rb +3 -6
  64. data/lib/yard/handlers/ruby/legacy/constant_handler.rb +5 -8
  65. data/lib/yard/handlers/ruby/legacy/exception_handler.rb +1 -1
  66. data/lib/yard/handlers/ruby/legacy/extend_handler.rb +1 -0
  67. data/lib/yard/handlers/ruby/legacy/macro_handler.rb +40 -0
  68. data/lib/yard/handlers/ruby/legacy/method_handler.rb +10 -10
  69. data/lib/yard/handlers/ruby/legacy/mixin_handler.rb +4 -3
  70. data/lib/yard/handlers/ruby/legacy/module_handler.rb +2 -1
  71. data/lib/yard/handlers/ruby/legacy/private_constant_handler.rb +4 -4
  72. data/lib/yard/handlers/ruby/legacy/visibility_handler.rb +2 -1
  73. data/lib/yard/handlers/ruby/legacy/yield_handler.rb +3 -3
  74. data/lib/yard/handlers/ruby/macro_handler.rb +41 -0
  75. data/lib/yard/handlers/ruby/macro_handler_methods.rb +130 -0
  76. data/lib/yard/handlers/ruby/method_condition_handler.rb +1 -1
  77. data/lib/yard/handlers/ruby/method_handler.rb +13 -13
  78. data/lib/yard/handlers/ruby/mixin_handler.rb +4 -4
  79. data/lib/yard/handlers/ruby/module_handler.rb +2 -1
  80. data/lib/yard/handlers/ruby/private_constant_handler.rb +4 -4
  81. data/lib/yard/handlers/ruby/struct_handler_methods.rb +11 -11
  82. data/lib/yard/handlers/ruby/visibility_handler.rb +1 -1
  83. data/lib/yard/handlers/ruby/yield_handler.rb +5 -5
  84. data/lib/yard/logging.rb +11 -11
  85. data/lib/yard/parser/base.rb +8 -8
  86. data/lib/yard/parser/c_parser.rb +42 -33
  87. data/lib/yard/parser/ruby/ast_node.rb +62 -61
  88. data/lib/yard/parser/ruby/legacy/ruby_lex.rb +66 -66
  89. data/lib/yard/parser/ruby/legacy/ruby_parser.rb +4 -4
  90. data/lib/yard/parser/ruby/legacy/statement.rb +11 -11
  91. data/lib/yard/parser/ruby/legacy/statement_list.rb +15 -15
  92. data/lib/yard/parser/ruby/legacy/token_list.rb +9 -9
  93. data/lib/yard/parser/ruby/ruby_parser.rb +51 -37
  94. data/lib/yard/parser/source_parser.rb +271 -46
  95. data/lib/yard/rake/yardoc_task.rb +18 -17
  96. data/lib/yard/registry.rb +64 -64
  97. data/lib/yard/registry_store.rb +34 -34
  98. data/lib/yard/rubygems/backports.rb +8 -0
  99. data/lib/yard/rubygems/backports/LICENSE.txt +57 -0
  100. data/lib/yard/rubygems/backports/MIT.txt +20 -0
  101. data/lib/yard/rubygems/backports/gem.rb +8 -0
  102. data/lib/yard/rubygems/backports/source_index.rb +353 -0
  103. data/lib/yard/rubygems/specification.rb +2 -2
  104. data/lib/yard/serializers/base.rb +20 -20
  105. data/lib/yard/serializers/file_system_serializer.rb +28 -24
  106. data/lib/yard/serializers/process_serializer.rb +3 -3
  107. data/lib/yard/serializers/stdout_serializer.rb +6 -6
  108. data/lib/yard/serializers/yardoc_serializer.rb +17 -17
  109. data/lib/yard/server/adapter.rb +12 -12
  110. data/lib/yard/server/commands/base.rb +26 -26
  111. data/lib/yard/server/commands/display_file_command.rb +3 -2
  112. data/lib/yard/server/commands/display_object_command.rb +5 -5
  113. data/lib/yard/server/commands/frames_command.rb +1 -1
  114. data/lib/yard/server/commands/library_command.rb +7 -7
  115. data/lib/yard/server/commands/library_index_command.rb +2 -2
  116. data/lib/yard/server/commands/list_command.rb +8 -8
  117. data/lib/yard/server/commands/search_command.rb +8 -8
  118. data/lib/yard/server/commands/static_file_command.rb +3 -3
  119. data/lib/yard/server/doc_server_helper.rb +6 -3
  120. data/lib/yard/server/doc_server_serializer.rb +1 -1
  121. data/lib/yard/server/library_version.rb +45 -45
  122. data/lib/yard/server/rack_adapter.rb +10 -10
  123. data/lib/yard/server/router.rb +28 -28
  124. data/lib/yard/server/static_caching.rb +5 -5
  125. data/lib/yard/server/templates/default/fulldoc/html/css/custom.css +3 -3
  126. data/lib/yard/server/templates/default/fulldoc/html/js/live.js +1 -1
  127. data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +2 -2
  128. data/lib/yard/server/templates/default/layout/html/headers.erb +13 -8
  129. data/lib/yard/server/templates/default/layout/html/setup.rb +7 -0
  130. data/lib/yard/server/templates/doc_server/full_list/html/full_list.erb +2 -2
  131. data/lib/yard/server/templates/doc_server/full_list/html/setup.rb +14 -4
  132. data/lib/yard/server/templates/doc_server/library_list/html/contents.erb +2 -2
  133. data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +2 -2
  134. data/lib/yard/server/templates/doc_server/processing/html/processing.erb +1 -1
  135. data/lib/yard/server/templates/doc_server/search/html/search.erb +1 -1
  136. data/lib/yard/server/webrick_adapter.rb +2 -2
  137. data/lib/yard/tags/default_factory.rb +19 -19
  138. data/lib/yard/tags/default_tag.rb +1 -1
  139. data/lib/yard/tags/library.rb +68 -63
  140. data/lib/yard/tags/option_tag.rb +1 -1
  141. data/lib/yard/tags/overload_tag.rb +9 -9
  142. data/lib/yard/tags/ref_tag_list.rb +2 -2
  143. data/lib/yard/tags/tag.rb +7 -7
  144. data/lib/yard/templates/engine.rb +31 -31
  145. data/lib/yard/templates/erb_cache.rb +1 -1
  146. data/lib/yard/templates/helpers/base_helper.rb +46 -32
  147. data/lib/yard/templates/helpers/filter_helper.rb +2 -2
  148. data/lib/yard/templates/helpers/html_helper.rb +120 -81
  149. data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +4 -4
  150. data/lib/yard/templates/helpers/markup/rdoc_markup.rb +9 -9
  151. data/lib/yard/templates/helpers/markup_helper.rb +37 -30
  152. data/lib/yard/templates/helpers/method_helper.rb +7 -7
  153. data/lib/yard/templates/helpers/text_helper.rb +7 -7
  154. data/lib/yard/templates/helpers/uml_helper.rb +3 -3
  155. data/lib/yard/templates/section.rb +14 -14
  156. data/lib/yard/templates/template.rb +54 -54
  157. data/lib/yard/verifier.rb +27 -27
  158. data/spec/cli/list_spec.rb +8 -0
  159. data/spec/cli/yardoc_spec.rb +58 -10
  160. data/spec/code_objects/extra_file_object_spec.rb +132 -0
  161. data/spec/code_objects/macro_object_spec.rb +154 -0
  162. data/spec/docstring_spec.rb +90 -0
  163. data/spec/handlers/base_spec.rb +22 -0
  164. data/spec/handlers/examples/macro_handler_001.rb.txt +73 -0
  165. data/spec/handlers/examples/method_handler_001.rb.txt +17 -0
  166. data/spec/handlers/macro_handler_spec.rb +140 -0
  167. data/spec/handlers/method_handler_spec.rb +28 -0
  168. data/spec/handlers/processor_spec.rb +4 -0
  169. data/spec/handlers/spec_helper.rb +1 -1
  170. data/spec/parser/c_parser_spec.rb +47 -16
  171. data/spec/parser/examples/extrafile.c.txt +8 -0
  172. data/spec/parser/examples/multifile.c.txt +6 -0
  173. data/spec/parser/ruby/ruby_parser_spec.rb +5 -0
  174. data/spec/parser/source_parser_spec.rb +235 -0
  175. data/spec/rake/yardoc_task_spec.rb +22 -17
  176. data/spec/serializers/file_system_serializer_spec.rb +6 -0
  177. data/spec/server/commands/library_command_spec.rb +39 -0
  178. data/spec/spec_helper.rb +14 -0
  179. data/spec/templates/examples/method001.html +6 -6
  180. data/spec/templates/examples/method002.html +4 -4
  181. data/spec/templates/examples/method003.html +10 -10
  182. data/spec/templates/examples/method005.html +2 -2
  183. data/spec/templates/examples/module001.dot +2 -0
  184. data/spec/templates/examples/module001.html +76 -37
  185. data/spec/templates/examples/module001.txt +1 -1
  186. data/spec/templates/helpers/base_helper_spec.rb +7 -2
  187. data/spec/templates/helpers/html_helper_spec.rb +49 -5
  188. data/spec/templates/helpers/markup_helper_spec.rb +9 -8
  189. data/spec/templates/module_spec.rb +7 -0
  190. data/spec/templates/onefile_spec.rb +47 -0
  191. data/templates/default/fulldoc/html/css/style.css +7 -5
  192. data/templates/default/fulldoc/html/full_list.erb +13 -10
  193. data/templates/default/fulldoc/html/full_list_files.erb +1 -1
  194. data/templates/default/fulldoc/html/js/app.js +16 -14
  195. data/templates/default/fulldoc/html/js/full_list.js +7 -6
  196. data/templates/default/fulldoc/html/setup.rb +78 -17
  197. data/templates/default/layout/html/files.erb +1 -1
  198. data/templates/default/layout/html/headers.erb +11 -7
  199. data/templates/default/layout/html/search.erb +4 -4
  200. data/templates/default/layout/html/setup.rb +28 -8
  201. data/templates/default/module/html/inherited_attributes.erb +17 -0
  202. data/templates/default/module/setup.rb +1 -1
  203. data/templates/default/onefile/html/files.erb +2 -2
  204. data/templates/default/onefile/html/layout.erb +1 -1
  205. data/templates/default/onefile/html/setup.rb +7 -5
  206. data/templates/default/tags/html/option.erb +1 -1
  207. data/templates/default/tags/html/tag.erb +3 -3
  208. data/templates/guide/class/html/setup.rb +1 -0
  209. data/templates/guide/docstring/html/setup.rb +1 -0
  210. data/templates/guide/fulldoc/html/css/style.css +91 -0
  211. data/templates/guide/fulldoc/html/js/app.js +33 -0
  212. data/templates/guide/fulldoc/html/setup.rb +54 -0
  213. data/templates/guide/layout/html/layout.erb +81 -0
  214. data/templates/guide/layout/html/setup.rb +24 -0
  215. data/templates/guide/method/html/header.erb +18 -0
  216. data/templates/guide/method/html/setup.rb +21 -0
  217. data/templates/guide/module/html/header.erb +7 -0
  218. data/templates/guide/module/html/method_list.erb +5 -0
  219. data/templates/guide/module/html/setup.rb +26 -0
  220. data/templates/guide/tags/html/setup.rb +8 -0
  221. metadata +40 -7
  222. data/lib/yard/handlers/ruby/legacy/process_handler.rb +0 -13
  223. data/lib/yard/handlers/ruby/process_handler.rb +0 -18
  224. data/spec/handlers/process_handler_spec.rb +0 -17
@@ -1,45 +1,45 @@
1
1
  module YARD
2
- # A documentation string, or "docstring" for short, encapsulates the
2
+ # A documentation string, or "docstring" for short, encapsulates the
3
3
  # comments and metadata, or "tags", of an object. Meta-data is expressed
4
4
  # in the form +@tag VALUE+, where VALUE can span over multiple lines as
5
5
  # long as they are indented. The following +@example+ tag shows how tags
6
6
  # can be indented:
7
- #
7
+ #
8
8
  # # @example My example
9
9
  # # a = "hello world"
10
10
  # # a.reverse
11
11
  # # @version 1.0
12
- #
13
- # Tags can be nested in a documentation string, though the {Tags::Tag}
12
+ #
13
+ # Tags can be nested in a documentation string, though the {Tags::Tag}
14
14
  # itself is responsible for parsing the inner tags.
15
15
  class Docstring < String
16
16
  # @return [Array<Tags::RefTag>] the list of reference tags
17
17
  attr_reader :ref_tags
18
-
18
+
19
19
  # @return [CodeObjects::Base] the object that owns the docstring.
20
20
  attr_accessor :object
21
-
21
+
22
22
  # @return [Range] line range in the {#object}'s file where the docstring was parsed from
23
23
  attr_accessor :line_range
24
-
24
+
25
25
  # @return [String] the raw documentation (including raw tag text)
26
26
  attr_reader :all
27
-
27
+
28
28
  # @return [Boolean] whether the docstring was started with "##"
29
29
  attr_reader :hash_flag
30
30
  def hash_flag=(v) @hash_flag = v == nil ? false : v end
31
31
 
32
32
  # Matches a tag at the start of a comment line
33
33
  META_MATCH = /^@([a-z_0-9]+)(?:\s+(.*))?$/i
34
-
34
+
35
35
  # @group Creating a Docstring Object
36
36
 
37
37
  # Creates a new docstring with the raw contents attached to an optional
38
38
  # object.
39
- #
39
+ #
40
40
  # @example
41
41
  # Docstring.new("hello world\n@return Object return", someobj)
42
- #
42
+ #
43
43
  # @param [String] content the raw comments to be parsed into a docstring
44
44
  # and associated meta-data.
45
45
  # @param [CodeObjects::Base] object an object to associate the docstring
@@ -48,12 +48,12 @@ module YARD
48
48
  @object = object
49
49
  @summary = nil
50
50
  @hash_flag = false
51
-
51
+
52
52
  self.all = content
53
53
  end
54
-
54
+
55
55
  # Adds another {Docstring}, copying over tags.
56
- #
56
+ #
57
57
  # @param [Docstring, String] other the other docstring (or string) to
58
58
  # add.
59
59
  # @return [Docstring] a new docstring with both docstrings combines
@@ -65,23 +65,41 @@ module YARD
65
65
  super
66
66
  end
67
67
  end
68
-
68
+
69
69
  # Replaces the docstring with new raw content. Called by {#all=}.
70
70
  # @param [String] content the raw comments to be parsed
71
71
  def replace(content)
72
+ content = content.join("\n") if content.is_a?(Array)
72
73
  @tags, @ref_tags = [], []
73
74
  @all = content
74
75
  super parse_comments(content)
75
76
  end
76
77
  alias all= replace
78
+
79
+ # Deep-copies a docstring
80
+ #
81
+ # @note This method creates a new docstring with new tag lists, but does
82
+ # not create new individual tags. Modifying the tag objects will still
83
+ # affect the original tags.
84
+ # @return [Docstring] a new copied docstring
85
+ # @since 0.7.0
86
+ def dup
87
+ obj = super
88
+ %w(all summary tags ref_tags).each do |name|
89
+ val = instance_variable_get("@#{name}")
90
+ obj.instance_variable_set("@#{name}", val ? val.dup : nil)
91
+ end
92
+ obj
93
+ end
77
94
 
78
95
  # @endgroup
79
-
80
- # @return [Fixnum] the first line of the {#line_range}.
96
+
97
+ # @return [Fixnum] the first line of the {#line_range}
98
+ # @return [nil] if there is no associated {#line_range}
81
99
  def line
82
- line_range.first
100
+ line_range ? line_range.first : nil
83
101
  end
84
-
102
+
85
103
  # Gets the first line of a docstring to the period or the first paragraph.
86
104
  # @return [String] The first line or paragraph of the docstring; always ends with a period.
87
105
  def summary
@@ -106,11 +124,64 @@ module YARD
106
124
  @summary += '.' unless @summary.empty?
107
125
  @summary
108
126
  end
127
+
128
+ # Reformats and returns a raw representation of the tag data using the
129
+ # current tag and docstring data, not the original text.
130
+ #
131
+ # @return [String] the updated raw formatted docstring data
132
+ # @since 0.7.0
133
+ # @todo Add Tags::Tag#to_raw and refactor
134
+ def to_raw
135
+ tag_data = tags.sort_by {|t| t.tag_name }.map do |tag|
136
+ case tag
137
+ when Tags::OverloadTag
138
+ tag_text = "@#{tag.tag_name} #{tag.signature}\n"
139
+ unless tag.docstring.blank?
140
+ tag_text += "\n" + tag.docstring.all.gsub(/\r?\n/, "\n ")
141
+ end
142
+ else
143
+ tag_text = '@' + tag.tag_name
144
+ tag_text += ' [' + tag.types.join(', ') + ']' if tag.types
145
+ tag_text += ' ' + tag.name.to_s if tag.name
146
+ tag_text += "\n " if tag.name && tag.text
147
+ tag_text += ' ' + tag.text.strip.gsub(/\n/, "\n ") if tag.text
148
+ end
149
+ tag_text
150
+ end
151
+ [strip, tag_data.join("\n")].reject {|l| l.empty? }.compact.join("\n")
152
+ end
109
153
 
110
154
  # @group Creating and Accessing Meta-data
111
-
112
- # Adds a tag or reftag object to the tag list
155
+
156
+ # Creates a tag from the {Tags::DefaultFactory tag factory}.
157
+ #
158
+ # To add an already created tag object, use {#add_tag}
159
+ #
160
+ # @param [String] tag_name the tag name
161
+ # @param [String] tag_buf the text attached to the tag with newlines removed.
162
+ # @return [Tags::Tag, Tags::RefTag] a tag
163
+ def create_tag(tag_name, tag_buf)
164
+ if tag_buf =~ /\A\s*(?:(\S+)\s+)?\(\s*see\s+(\S+)\s*\)\s*\Z/
165
+ return create_ref_tag(tag_name, $1, $2)
166
+ end
167
+
168
+ tag_factory = Tags::Library.instance
169
+ tag_method = "#{tag_name}_tag"
170
+ if tag_name && tag_factory.respond_to?(tag_method)
171
+ add_tag(*[tag_factory.send(tag_method, tag_buf)].flatten)
172
+ else
173
+ log.warn "Unknown tag @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "")
174
+ end
175
+ rescue Tags::TagFormatError
176
+ log.warn "Invalid tag format for @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "")
177
+ end
178
+
179
+ # Adds a tag or reftag object to the tag list. If you want to parse
180
+ # tag data based on the {Tags::DefaultFactory} tag factory, use {#create_tag}
181
+ # instead.
182
+ #
113
183
  # @param [Tags::Tag, Tags::RefTag] tags list of tag objects to add
184
+ # @return [void]
114
185
  def add_tag(*tags)
115
186
  tags.each_with_index do |tag, i|
116
187
  case tag
@@ -124,7 +195,7 @@ module YARD
124
195
  end
125
196
  end
126
197
  end
127
-
198
+
128
199
  # Convenience method to return the first tag
129
200
  # object in the list of tag objects of that name
130
201
  #
@@ -155,6 +226,24 @@ module YARD
155
226
  def has_tag?(name)
156
227
  tags.any? {|tag| tag.tag_name.to_s == name.to_s }
157
228
  end
229
+
230
+ # Delete all tags with +name+
231
+ # @param [String] name the tag name
232
+ # @return [void]
233
+ # @since 0.7.0
234
+ def delete_tags(name)
235
+ delete_tag_if {|tag| tag.tag_name.to_s == name.to_s }
236
+ end
237
+
238
+ # Deletes all tags where the block returns true
239
+ # @yieldparam [Tags::Tag] tag the tag that is being tested
240
+ # @yieldreturn [Boolean] true if the tag should be deleted
241
+ # @return [void]
242
+ # @since 0.7.0
243
+ def delete_tag_if(&block)
244
+ @tags.delete_if(&block)
245
+ @ref_tags.delete_if(&block)
246
+ end
158
247
 
159
248
  # Returns true if the docstring has no content that is visible to a template.
160
249
  #
@@ -168,51 +257,30 @@ module YARD
168
257
  empty? && @tags.empty? && @ref_tags.empty?
169
258
  end
170
259
  end
171
-
260
+
172
261
  # @endgroup
173
262
 
174
263
  private
175
-
264
+
176
265
  # Maps valid reference tags
177
- #
266
+ #
178
267
  # @return [Array<Tags::RefTag>] the list of valid reference tags
179
268
  def convert_ref_tags
180
269
  list = @ref_tags.reject {|t| CodeObjects::Proxy === t.owner }
181
270
  list.map {|t| t.tags }.flatten
182
271
  end
183
-
272
+
184
273
  # Creates a {Tags::RefTag}
185
274
  def create_ref_tag(tag_name, name, object_name)
186
275
  @ref_tags << Tags::RefTagList.new(tag_name, P(object, object_name), name)
187
276
  end
188
-
189
- # Creates a tag from the {Tags::DefaultFactory tag factory}.
190
- #
191
- # @param [String] tag_name the tag name
192
- # @param [String] tag_buf the text attached to the tag with newlines removed.
193
- # @return [Tags::Tag, Tags::RefTag] a tag
194
- def create_tag(tag_name, tag_buf)
195
- if tag_buf =~ /\A\s*(?:(\S+)\s+)?\(\s*see\s+(\S+)\s*\)\s*\Z/
196
- return create_ref_tag(tag_name, $1, $2)
197
- end
198
-
199
- tag_factory = Tags::Library.instance
200
- tag_method = "#{tag_name}_tag"
201
- if tag_name && tag_factory.respond_to?(tag_method)
202
- add_tag(*[tag_factory.send(tag_method, tag_buf)].flatten)
203
- else
204
- log.warn "Unknown tag @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "")
205
- end
206
- rescue Tags::TagFormatError
207
- log.warn "Invalid tag format for @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "")
208
- end
209
277
 
210
278
  # Parses out comments split by newlines into a new code object
211
279
  #
212
- # @param [String] comments
280
+ # @param [String] comments
213
281
  # the newline delimited array of comments. If the comments
214
- # are passed as a String, they will be split by newlines.
215
- #
282
+ # are passed as a String, they will be split by newlines.
283
+ #
216
284
  # @return [String] the non-metadata portion of the comments to
217
285
  # be used as a docstring
218
286
  def parse_comments(comments)
@@ -226,11 +294,11 @@ module YARD
226
294
  tag_name, tag_klass, tag_buf = nil, nil, []
227
295
 
228
296
  (comments+['']).each_with_index do |line, index|
229
- indent = line[/^\s*/].length
297
+ indent = line[/^\s*/].length
230
298
  empty = (line =~ /^\s*$/ ? true : false)
231
299
  done = comments.size == index
232
300
 
233
- if tag_name && (((indent < orig_indent && !empty) || done ||
301
+ if tag_name && (((indent < orig_indent && !empty) || done ||
234
302
  (indent == 0 && !empty)) || (indent <= last_indent && line =~ META_MATCH))
235
303
  create_tag(tag_name, tag_buf.join("\n"))
236
304
  tag_name, tag_buf, = nil, []
@@ -244,12 +312,12 @@ module YARD
244
312
  orig_indent = indent if orig_indent == 0
245
313
  # Extra data added to the tag on the next line
246
314
  last_empty = last_line =~ /^[ \t]*$/ ? true : false
247
-
315
+
248
316
  tag_buf << '' if last_empty
249
317
  tag_buf << line.gsub(/^[ \t]{#{orig_indent}}/, '')
250
318
  elsif !tag_name
251
319
  # Regular docstring text
252
- docstring << line << "\n"
320
+ docstring << line << "\n"
253
321
  end
254
322
 
255
323
  last_indent = indent
data/lib/yard/globals.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # @group Global Convenience Methods
2
2
 
3
3
  # Shortcut for creating a YARD::CodeObjects::Proxy via a path
4
- #
4
+ #
5
5
  # @see YARD::CodeObjects::Proxy
6
6
  # @see YARD::Registry.resolve
7
7
  def P(namespace, name = nil)
@@ -10,7 +10,7 @@ def P(namespace, name = nil)
10
10
  end
11
11
 
12
12
  # The global {YARD::Logger} instance
13
- #
13
+ #
14
14
  # @return [YARD::Logger] the global {YARD::Logger} instance
15
15
  # @see YARD::Logger
16
16
  def log
@@ -7,12 +7,12 @@ module YARD
7
7
  # The object the error occurred on
8
8
  # @return [CodeObjects::Base] a code object
9
9
  attr_accessor :object
10
-
10
+
11
11
  def initialize(object) @object = object end
12
12
  end
13
-
14
- # Handlers are pluggable semantic parsers for YARD's code generation
15
- # phase. They allow developers to control what information gets
13
+
14
+ # Handlers are pluggable semantic parsers for YARD's code generation
15
+ # phase. They allow developers to control what information gets
16
16
  # generated by YARD, giving them the ability to, for instance, document
17
17
  # any Ruby DSLs that a customized framework may use. A good example
18
18
  # of this would be the ability to document and generate meta data for
@@ -21,45 +21,45 @@ module YARD
21
21
  # takes advantage of class level declarations could add these to the
22
22
  # documentation in a very explicit format by treating them as first-
23
23
  # class objects in any outputted documentation.
24
- #
25
- # == Overview of a Typical Handler Scenario
26
- #
24
+ #
25
+ # == Overview of a Typical Handler Scenario
26
+ #
27
27
  # Generally, a handler class will declare a set of statements which
28
28
  # it will handle using the {handles} class declaration. It will then
29
29
  # implement the {#process} method to do the work. The processing would
30
- # usually involve the manipulation of the {#namespace}, {#owner}
31
- # {CodeObjects::Base code objects} or the creation of new ones, in
32
- # which case they should be registered by {#register}, a method that
30
+ # usually involve the manipulation of the {#namespace}, {#owner}
31
+ # {CodeObjects::Base code objects} or the creation of new ones, in
32
+ # which case they should be registered by {#register}, a method that
33
33
  # sets some basic attributes for the new objects.
34
- #
34
+ #
35
35
  # Handlers are usually simple and take up to a page of code to process
36
36
  # and register a new object or add new attributes to the current +namespace+.
37
- #
38
- # == Setting up a Handler for Use
39
- #
37
+ #
38
+ # == Setting up a Handler for Use
39
+ #
40
40
  # A Handler is automatically registered when it is subclassed from the
41
41
  # base class. The only other thing that needs to be done is to specify
42
42
  # which statement the handler will process. This is done with the +handles+
43
43
  # declaration, taking either a {Parser::Ruby::Legacy::RubyToken}, {String} or `Regexp`.
44
44
  # Here is a simple example which processes module statements.
45
- #
45
+ #
46
46
  # class MyModuleHandler < YARD::Handlers::Base
47
47
  # handles TkMODULE
48
- #
48
+ #
49
49
  # def process
50
50
  # # do something
51
51
  # end
52
52
  # end
53
- #
54
- # == Processing Handler Data
55
- #
56
- # The goal of a specific handler is really up to the developer, and as
53
+ #
54
+ # == Processing Handler Data
55
+ #
56
+ # The goal of a specific handler is really up to the developer, and as
57
57
  # such there is no real guideline on how to process the data. However,
58
58
  # it is important to know where the data is coming from to be able to use
59
59
  # it.
60
- #
61
- # === +statement+ Attribute
62
- #
60
+ #
61
+ # === +statement+ Attribute
62
+ #
63
63
  # The +statement+ attribute pertains to the {Parser::Ruby::Legacy::Statement} object
64
64
  # containing a set of tokens parsed in by the parser. This is the main set
65
65
  # of data to be analyzed and processed. The comments attached to the statement
@@ -67,71 +67,71 @@ module YARD
67
67
  # the data to be processed will live in the +tokens+ attribute. This list
68
68
  # can be converted to a +String+ using +#to_s+ to parse the data with
69
69
  # regular expressions (or other text processing mechanisms), if needed.
70
- #
71
- # === +namespace+ Attribute
72
- #
73
- # The +namespace+ attribute is a {CodeObjects::NamespaceObject namespace object}
70
+ #
71
+ # === +namespace+ Attribute
72
+ #
73
+ # The +namespace+ attribute is a {CodeObjects::NamespaceObject namespace object}
74
74
  # which represents the current namespace that the parser is in. For instance:
75
- #
75
+ #
76
76
  # module SomeModule
77
77
  # class MyClass
78
78
  # def mymethod; end
79
79
  # end
80
80
  # end
81
- #
81
+ #
82
82
  # If a handler was to parse the 'class MyClass' statement, it would
83
83
  # be necessary to know that it belonged inside the SomeModule module.
84
84
  # This is the value that +namespace+ would return when processing such
85
85
  # a statement. If the class was then entered and another handler was
86
86
  # called on the method, the +namespace+ would be set to the 'MyClass'
87
87
  # code object.
88
- #
89
- # === +owner+ Attribute
90
- #
88
+ #
89
+ # === +owner+ Attribute
90
+ #
91
91
  # The +owner+ attribute is similar to the +namespace+ attribute in that
92
92
  # it also follows the scope of the code during parsing. However, a namespace
93
93
  # object is loosely defined as a module or class and YARD has the ability
94
94
  # to parse beyond module and class blocks (inside methods, for instance),
95
- # so the +owner+ attribute would not be limited to modules and classes.
96
- #
95
+ # so the +owner+ attribute would not be limited to modules and classes.
96
+ #
97
97
  # To put this into context, the example from above will be used. If a method
98
98
  # handler was added to the mix and decided to parse inside the method body,
99
99
  # the +owner+ would be set to the method object but the namespace would remain
100
100
  # set to the class. This would allow the developer to process any method
101
101
  # definitions set inside a method (def x; def y; 2 end end) by adding them
102
102
  # to the correct namespace (the class, not the method).
103
- #
103
+ #
104
104
  # In summary, the distinction between +namespace+ and +owner+ can be thought
105
105
  # of as the difference between first-class Ruby objects (namespaces) and
106
106
  # second-class Ruby objects (methods).
107
- #
108
- # === +visibility+ and +scope+ Attributes
109
- #
107
+ #
108
+ # === +visibility+ and +scope+ Attributes
109
+ #
110
110
  # Mainly needed for parsing methods, the +visibility+ and +scope+ attributes
111
111
  # refer to the public/protected/private and class/instance values (respectively)
112
112
  # of the current parsing position.
113
- #
114
- # == Parsing Blocks in Statements
115
- #
113
+ #
114
+ # == Parsing Blocks in Statements
115
+ #
116
116
  # In addition to parsing a statement and creating new objects, some
117
117
  # handlers may wish to continue parsing the code inside the statement's
118
118
  # block (if there is one). In this context, a block means the inside
119
119
  # of any statement, be it class definition, module definition, if
120
- # statement or classic 'Ruby block'.
121
- #
122
- # For example, a class statement would be "class MyClass" and the block
123
- # would be a list of statements including the method definitions inside
124
- # the class. For a class handler, the programmer would execute the
125
- # {#parse_block} method to continue parsing code inside the block, with
126
- # the +namespace+ now pointing to the class object the handler created.
127
- #
128
- # YARD has the ability to continue into any block: class, module, method,
129
- # even if statements. For this reason, the block parsing method must be
120
+ # statement or classic 'Ruby block'.
121
+ #
122
+ # For example, a class statement would be "class MyClass" and the block
123
+ # would be a list of statements including the method definitions inside
124
+ # the class. For a class handler, the programmer would execute the
125
+ # {#parse_block} method to continue parsing code inside the block, with
126
+ # the +namespace+ now pointing to the class object the handler created.
127
+ #
128
+ # YARD has the ability to continue into any block: class, module, method,
129
+ # even if statements. For this reason, the block parsing method must be
130
130
  # invoked explicitly out of efficiency sake.
131
- #
131
+ #
132
132
  # @abstract Subclass this class to provide a handler for YARD to use
133
133
  # during the processing phase.
134
- #
134
+ #
135
135
  # @see CodeObjects::Base
136
136
  # @see CodeObjects::NamespaceObject
137
137
  # @see handles
@@ -139,20 +139,20 @@ module YARD
139
139
  # @see #owner
140
140
  # @see #register
141
141
  # @see #parse_block
142
- class Base
143
- # For accessing convenience, eg. "MethodObject"
142
+ class Base
143
+ # For accessing convenience, eg. "MethodObject"
144
144
  # instead of the full qualified namespace
145
145
  include YARD::CodeObjects
146
-
146
+
147
147
  include Parser
148
-
148
+
149
149
  class << self
150
150
  # Clear all registered subclasses. Testing purposes only
151
- # @return [void]
151
+ # @return [void]
152
152
  def clear_subclasses
153
153
  @@subclasses = []
154
154
  end
155
-
155
+
156
156
  # Returns all registered handler subclasses.
157
157
  # @return [Array<Base>] a list of handlers
158
158
  def subclasses
@@ -165,70 +165,70 @@ module YARD
165
165
  end
166
166
 
167
167
  # Declares the statement type which will be processed
168
- # by this handler.
169
- #
168
+ # by this handler.
169
+ #
170
170
  # A match need not be unique to a handler. Multiple
171
171
  # handlers can process the same statement. However,
172
172
  # in this case, care should be taken to make sure that
173
173
  # {#parse_block} would only be executed by one of
174
174
  # the handlers, otherwise the same code will be parsed
175
175
  # multiple times and slow YARD down.
176
- #
176
+ #
177
177
  # @param [Parser::RubyToken, Symbol, String, Regexp] matches
178
178
  # statements that match the declaration will be
179
- # processed by this handler. A {String} match is
180
- # equivalent to a +/\Astring/+ regular expression
181
- # (match from the beginning of the line), and all
179
+ # processed by this handler. A {String} match is
180
+ # equivalent to a +/\Astring/+ regular expression
181
+ # (match from the beginning of the line), and all
182
182
  # token matches match only the first token of the
183
183
  # statement.
184
- #
184
+ #
185
185
  def handles(*matches)
186
186
  (@handlers ||= []).push(*matches)
187
187
  end
188
-
188
+
189
189
  # This class is implemented by {Ruby::Base} and {Ruby::Legacy::Base}.
190
190
  # To implement a base handler class for another language, implement
191
191
  # this method to return true if the handler should process the given
192
192
  # statement object. Use {handlers} to enumerate the matchers declared
193
193
  # for the handler class.
194
- #
194
+ #
195
195
  # @param statement a statement object or node (depends on language type)
196
196
  # @return [Boolean] whether or not this handler object should process
197
197
  # the given statement
198
198
  def handles?(statement)
199
199
  raise NotImplementedError, "override #handles? in a subclass"
200
200
  end
201
-
201
+
202
202
  # @return [Array] a list of matchers for the handler object.
203
203
  # @see handles?
204
204
  def handlers
205
205
  @handlers ||= []
206
206
  end
207
-
207
+
208
208
  # Declares that the handler should only be called when inside a
209
209
  # {CodeObjects::NamespaceObject}, not a method body.
210
- #
210
+ #
211
211
  # @return [void]
212
212
  def namespace_only
213
213
  @namespace_only = true
214
214
  end
215
-
215
+
216
216
  # @return [Boolean] whether the handler should only be processed inside
217
217
  # a namespace.
218
218
  def namespace_only?
219
219
  (@namespace_only ||= false) ? true : false
220
220
  end
221
-
221
+
222
222
  # Declares that a handler should only be called when inside a filename
223
223
  # by its basename or a regex match for the full path.
224
- #
224
+ #
225
225
  # @param [String, Regexp] filename a matching filename or regex
226
226
  # @return [void]
227
227
  # @since 0.6.2
228
228
  def in_file(filename)
229
229
  (@in_files ||= []) << filename
230
230
  end
231
-
231
+
232
232
  # @return [Boolean] whether the filename matches the declared file
233
233
  # match for a handler. If no file match is specified, returns true.
234
234
  # @since 0.6.2
@@ -245,12 +245,16 @@ module YARD
245
245
  end
246
246
  end
247
247
  end
248
-
248
+
249
249
  # Generates a +process+ method, equivalent to +def process; ... end+.
250
250
  # Blocks defined with this syntax will be wrapped inside an anonymous
251
251
  # module so that the handler class can be extended with mixins that
252
252
  # override the +process+ method without alias chaining.
253
- #
253
+ #
254
+ # @macro yard.handlers.process
255
+ # @method process
256
+ # Main processing callback
257
+ # @return [void]
254
258
  # @see #process
255
259
  # @return [void]
256
260
  # @since 0.5.4
@@ -268,57 +272,63 @@ module YARD
268
272
 
269
273
  # The main handler method called by the parser on a statement
270
274
  # that matches the {handles} declaration.
271
- #
275
+ #
272
276
  # Subclasses should override this method to provide the handling
273
- # functionality for the class.
274
- #
277
+ # functionality for the class.
278
+ #
275
279
  # @return [Array<CodeObjects::Base>, CodeObjects::Base, Object]
276
280
  # If this method returns a code object (or a list of them),
277
281
  # they are passed to the +#register+ method which adds basic
278
282
  # attributes. It is not necessary to return any objects and in
279
283
  # some cases you may want to explicitly avoid the returning of
280
284
  # any objects for post-processing by the register method.
281
- #
285
+ #
282
286
  # @see handles
283
287
  # @see #register
284
- #
288
+ #
285
289
  def process
286
290
  raise NotImplementedError, "#{self} did not implement a #process method for handling."
287
291
  end
288
-
292
+
289
293
  # Parses the semantic "block" contained in the statement node.
290
- #
294
+ #
291
295
  # @abstract Subclasses should call {Processor#process parser.process}
292
296
  def parse_block(*args)
293
297
  raise NotImplementedError, "#{self} did not implement a #parse_block method for handling"
294
298
  end
295
-
299
+
296
300
  protected
297
-
298
- # @return [Processor] the processor object that manages all global state
301
+
302
+ # @return [Processor] the processor object that manages all global state
299
303
  # during handling.
300
304
  attr_reader :parser
301
-
305
+
302
306
  # @return [Object] the statement object currently being processed. Usually
303
307
  # refers to one semantic language statement, though the strict definition
304
308
  # depends on the parser used.
305
309
  attr_reader :statement
306
-
310
+
307
311
  # (see Processor#owner)
308
312
  attr_accessor :owner
309
-
313
+
310
314
  # (see Processor#namespace)
311
315
  attr_accessor :namespace
312
-
316
+
313
317
  # (see Processor#visibility)
314
318
  attr_accessor :visibility
315
-
319
+
316
320
  # (see Processor#scope)
317
321
  attr_accessor :scope
322
+
323
+ # (see Processor#globals)
324
+ attr_reader :globals
325
+
326
+ # (see Processor#extra_state)
327
+ attr_reader :extra_state
318
328
 
319
329
  undef owner, owner=, namespace, namespace=
320
330
  undef visibility, visibility=, scope, scope=
321
-
331
+
322
332
  def owner; parser.owner end
323
333
  def owner=(v) parser.owner=(v) end
324
334
  def namespace; parser.namespace end
@@ -327,17 +337,19 @@ module YARD
327
337
  def visibility=(v); parser.visibility=(v) end
328
338
  def scope; parser.scope end
329
339
  def scope=(v); parser.scope=(v) end
330
-
340
+ def globals; parser.globals end
341
+ def extra_state; parser.extra_state end
342
+
331
343
  # Executes a given block with specific state values for {#owner},
332
344
  # {#namespace} and {#scope}.
333
- #
345
+ #
334
346
  # @param [Proc] block the block to execute with specific state
335
- # @option opts [CodeObjects::NamespaceObject] :namespace (value of #namespace)
347
+ # @option opts [CodeObjects::NamespaceObject] :namespace (value of #namespace)
336
348
  # the namespace object that {#namespace} will be equal to for the
337
- # duration of the block.
338
- # @option opts [Symbol] :scope (:instance)
349
+ # duration of the block.
350
+ # @option opts [Symbol] :scope (:instance)
339
351
  # the scope for the duration of the block.
340
- # @option opts [CodeObjects::Base] :owner (value of #owner)
352
+ # @option opts [CodeObjects::Base] :owner (value of #owner)
341
353
  # the owner object (method) for the duration of the block
342
354
  # @yield a block to execute with the given state values.
343
355
  def push_state(opts = {}, &block)
@@ -360,43 +372,52 @@ module YARD
360
372
  self.scope = sc
361
373
  self.owner = oo
362
374
  end
363
-
364
- # Do some post processing on a list of code objects.
365
- # Adds basic attributes to the list of objects like
375
+
376
+ # Do some post processing on a list of code objects.
377
+ # Adds basic attributes to the list of objects like
366
378
  # the filename, line number, {CodeObjects::Base#dynamic},
367
379
  # source code and {CodeObjects::Base#docstring},
368
380
  # but only if they don't exist.
369
- #
381
+ #
370
382
  # @param [Array<CodeObjects::Base>] objects
371
383
  # the list of objects to post-process.
372
- #
384
+ #
373
385
  # @return [CodeObjects::Base, Array<CodeObjects::Base>]
374
386
  # returns whatever is passed in, for chainability.
375
- #
387
+ #
376
388
  def register(*objects)
377
389
  objects.flatten.each do |object|
378
390
  next unless object.is_a?(CodeObjects::Base)
379
-
391
+
380
392
  begin
381
393
  ensure_loaded!(object.namespace)
382
394
  object.namespace.children << object
383
395
  rescue NamespaceMissingError
384
396
  end
385
-
397
+
386
398
  # Yield the object to the calling block because ruby will parse the syntax
387
- #
399
+ #
388
400
  # register obj = ClassObject.new {|o| ... }
389
- #
401
+ #
390
402
  # as the block for #register. We need to make sure this gets to the object.
391
- yield(object) if block_given?
392
-
403
+ yield(object) if block_given?
404
+
393
405
  object.add_file(parser.file, statement.line, statement.comments)
394
406
 
395
407
  # Add docstring if there is one.
396
- object.docstring = statement.comments if statement.comments
397
- object.docstring.hash_flag = statement.comments_hash_flag
398
- object.docstring.line_range = statement.comments_range
399
-
408
+ if statement.comments
409
+ object.docstring = Docstring.new(statement.comments, object)
410
+ end
411
+
412
+ # Expand/create any @macro tags
413
+ expand_macro(object, find_or_create_macro(object))
414
+
415
+ # Add hash_flag/line_range
416
+ if statement.comments
417
+ object.docstring.hash_flag = statement.comments_hash_flag
418
+ object.docstring.line_range = statement.comments_range
419
+ end
420
+
400
421
  # Add group information
401
422
  if statement.group
402
423
  unless object.namespace.is_a?(Proxy)
@@ -404,7 +425,7 @@ module YARD
404
425
  end
405
426
  object.group = statement.group
406
427
  end
407
-
428
+
408
429
  # Add transitive tags
409
430
  Tags::Library.transitive_tags.each do |tag|
410
431
  next if object.namespace.is_a?(Proxy)
@@ -412,12 +433,12 @@ module YARD
412
433
  next if object.has_tag?(tag)
413
434
  object.docstring.add_tag(*object.namespace.tags(tag))
414
435
  end
415
-
436
+
416
437
  # Add source only to non-class non-module objects
417
438
  unless object.is_a?(NamespaceObject)
418
439
  object.source ||= statement
419
440
  end
420
-
441
+
421
442
  # Make it dynamic if its owner is not its namespace.
422
443
  # This generally means it was defined in a method (or block of some sort)
423
444
  object.dynamic = true if owner != namespace
@@ -428,17 +449,17 @@ module YARD
428
449
  # Ensures that a specific +object+ has been parsed and loaded into the
429
450
  # registry. This is necessary when adding data to a namespace, for instance,
430
451
  # since the namespace may not have been processed yet (it can be located
431
- # in a file that has not been handled).
432
- #
433
- # Calling this method defers the handler until all other files have been
452
+ # in a file that has not been handled).
453
+ #
454
+ # Calling this method defers the handler until all other files have been
434
455
  # processed. If the object gets resolved, the rest of the handler continues,
435
456
  # otherwise an exception is raised.
436
- #
457
+ #
437
458
  # @example Adding a mixin to the String class programmatically
438
459
  # ensure_loaded! P('String')
439
460
  # # "String" is now guaranteed to be loaded
440
461
  # P('String').mixins << P('MyMixin')
441
- #
462
+ #
442
463
  # @param [Proxy, CodeObjects::Base] object the object to resolve.
443
464
  # @param [Integer] max_retries the number of times to defer the handler
444
465
  # before raising a +NamespaceMissingError+.
@@ -455,7 +476,7 @@ module YARD
455
476
  nil
456
477
  end
457
478
  end
458
-
479
+
459
480
  unless CONTINUATIONS_SUPPORTED
460
481
  unless $NO_CONTINUATION_WARNING
461
482
  $NO_CONTINUATION_WARNING = true
@@ -464,11 +485,11 @@ module YARD
464
485
  end
465
486
  raise NamespaceMissingError, object
466
487
  end
467
-
488
+
468
489
  retries = 0
469
490
  context = callcc {|c| c }
470
- retries += 1
471
-
491
+ retries += 1
492
+
472
493
  if object.is_a?(Proxy)
473
494
  if retries <= max_retries
474
495
  log.debug "Missing object #{object} in file `#{parser.file}', moving it to the back of the line."
@@ -479,6 +500,74 @@ module YARD
479
500
  end
480
501
  object
481
502
  end
503
+
504
+ # @group Macro Support
505
+
506
+ # @abstract Implement this method to return the parameters in a method call
507
+ # statement. It should return an empty list if the statement is not a
508
+ # method call.
509
+ # @return [Array<String>] a list of argument names
510
+ def call_params
511
+ raise NotImplementedError
512
+ end
513
+
514
+ # @abstract Implement this method to return the method being called in
515
+ # a method call. It should return nil if the statement is not a method
516
+ # call.
517
+ # @return [String] the method name being called
518
+ # @return [nil] if the statement is not a method call
519
+ def caller_method
520
+ raise NotImplementedError
521
+ end
522
+
523
+ # Attempts to find or create a macro if a +@macro+ tag is found in the
524
+ # docstring (or the object's docstring).
525
+ #
526
+ # @param [Docstring, CodeObjects::Base] object_or_docstring the docstring
527
+ # or it's object with which to check for a macro
528
+ # @return [CodeObjects::MacroObject] the newly created macro
529
+ # @return [nil] if the docstring does not create or reference a macro
530
+ def find_or_create_macro(object_or_docstring)
531
+ if object_or_docstring.is_a?(Docstring)
532
+ object, docstring = nil, object_or_docstring
533
+ else
534
+ object, docstring = object_or_docstring, object_or_docstring.docstring
535
+ end
536
+ return unless macro_tag = docstring.tag(:macro)
537
+ unless macro_tag.name
538
+ if object
539
+ log.warn "Invalid/missing macro name for #{object.path} (#{parser.file}:#{statement.line})"
540
+ return nil
541
+ else
542
+ raise UndocumentableError, 'method/attribute, missing macro name'
543
+ end
544
+ end
545
+ caller_obj = caller_method ? P(namespace, caller_method) : nil
546
+ if macro = MacroObject.find_or_create(docstring, caller_obj)
547
+ attached_method_name = caller_method
548
+ if object && object.is_a?(MethodObject) && object.scope == :class
549
+ macro.method_object = object
550
+ attached_method_name = object.name.to_s
551
+ end
552
+ if macro.attached?
553
+ globals.__attached_macros ||= {}
554
+ globals.__attached_macros[attached_method_name] ||= []
555
+ globals.__attached_macros[attached_method_name] |= [macro]
556
+ end
557
+ end
558
+ macro
559
+ end
560
+
561
+ # Sets the docstring on +object+ to the expanded macro.
562
+ # @param [CodeObjects::Base] object the object to expand the macro on
563
+ # @param [CodeObjects::MacroObject] macro the macro object to expand
564
+ # @return [void]
565
+ def expand_macro(object, macro)
566
+ return unless macro
567
+ all_params = ([caller_method] + call_params).compact
568
+ data = MacroObject.apply_macro(macro, object.docstring, all_params, statement.source)
569
+ object.docstring = Docstring.new(data, object)
570
+ end
482
571
  end
483
572
  end
484
573
  end