yard 0.5.8 → 0.6.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 (211) hide show
  1. data/.yardopts +2 -0
  2. data/ChangeLog +1064 -0
  3. data/README.md +103 -42
  4. data/Rakefile +3 -2
  5. data/benchmarks/parsing.rb +2 -1
  6. data/bin/yard +4 -0
  7. data/bin/yard-graph +1 -1
  8. data/bin/yard-server +4 -0
  9. data/docs/GettingStarted.md +8 -8
  10. data/docs/Handlers.md +5 -5
  11. data/docs/Overview.md +5 -5
  12. data/docs/Parser.md +1 -1
  13. data/docs/Tags.md +1 -1
  14. data/docs/Templates.md +27 -6
  15. data/docs/WhatsNew.md +222 -2
  16. data/lib/rubygems_plugin.rb +1 -0
  17. data/lib/yard.rb +7 -1
  18. data/lib/yard/autoload.rb +46 -6
  19. data/lib/yard/cli/{base.rb → command.rb} +20 -6
  20. data/lib/yard/cli/command_parser.rb +87 -0
  21. data/lib/yard/cli/diff.rb +176 -0
  22. data/lib/yard/cli/gems.rb +74 -0
  23. data/lib/yard/cli/{yard_graph.rb → graph.rb} +9 -8
  24. data/lib/yard/cli/help.rb +18 -0
  25. data/lib/yard/cli/server.rb +137 -0
  26. data/lib/yard/cli/stats.rb +210 -0
  27. data/lib/yard/cli/yardoc.rb +315 -116
  28. data/lib/yard/cli/yri.rb +45 -4
  29. data/lib/yard/code_objects/base.rb +73 -30
  30. data/lib/yard/code_objects/class_object.rb +9 -1
  31. data/lib/yard/code_objects/method_object.rb +11 -0
  32. data/lib/yard/code_objects/namespace_object.rb +8 -2
  33. data/lib/yard/code_objects/proxy.rb +2 -2
  34. data/lib/yard/core_ext/array.rb +3 -49
  35. data/lib/yard/core_ext/file.rb +7 -0
  36. data/lib/yard/core_ext/insertion.rb +60 -0
  37. data/lib/yard/docstring.rb +34 -7
  38. data/lib/yard/globals.rb +2 -2
  39. data/lib/yard/handlers/base.rb +101 -20
  40. data/lib/yard/handlers/processor.rb +23 -7
  41. data/lib/yard/handlers/ruby/alias_handler.rb +1 -0
  42. data/lib/yard/handlers/ruby/attribute_handler.rb +8 -0
  43. data/lib/yard/handlers/ruby/base.rb +71 -2
  44. data/lib/yard/handlers/ruby/class_condition_handler.rb +10 -0
  45. data/lib/yard/handlers/ruby/class_handler.rb +7 -4
  46. data/lib/yard/handlers/ruby/class_variable_handler.rb +1 -0
  47. data/lib/yard/handlers/ruby/constant_handler.rb +1 -0
  48. data/lib/yard/handlers/ruby/exception_handler.rb +1 -0
  49. data/lib/yard/handlers/ruby/extend_handler.rb +2 -3
  50. data/lib/yard/handlers/ruby/legacy/alias_handler.rb +1 -0
  51. data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +2 -0
  52. data/lib/yard/handlers/ruby/legacy/base.rb +15 -2
  53. data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +5 -0
  54. data/lib/yard/handlers/ruby/legacy/class_handler.rb +7 -4
  55. data/lib/yard/handlers/ruby/legacy/class_variable_handler.rb +1 -0
  56. data/lib/yard/handlers/ruby/legacy/constant_handler.rb +1 -0
  57. data/lib/yard/handlers/ruby/legacy/exception_handler.rb +1 -0
  58. data/lib/yard/handlers/ruby/legacy/extend_handler.rb +1 -3
  59. data/lib/yard/handlers/ruby/legacy/method_handler.rb +7 -3
  60. data/lib/yard/handlers/ruby/legacy/mixin_handler.rb +2 -1
  61. data/lib/yard/handlers/ruby/legacy/module_handler.rb +1 -0
  62. data/lib/yard/handlers/ruby/legacy/process_handler.rb +1 -0
  63. data/lib/yard/handlers/ruby/legacy/visibility_handler.rb +1 -0
  64. data/lib/yard/handlers/ruby/legacy/yield_handler.rb +1 -0
  65. data/lib/yard/handlers/ruby/method_condition_handler.rb +1 -0
  66. data/lib/yard/handlers/ruby/method_handler.rb +5 -1
  67. data/lib/yard/handlers/ruby/mixin_handler.rb +2 -1
  68. data/lib/yard/handlers/ruby/module_handler.rb +1 -0
  69. data/lib/yard/handlers/ruby/process_handler.rb +7 -1
  70. data/lib/yard/handlers/ruby/struct_handler_methods.rb +3 -0
  71. data/lib/yard/handlers/ruby/visibility_handler.rb +8 -2
  72. data/lib/yard/handlers/ruby/yield_handler.rb +1 -0
  73. data/lib/yard/logging.rb +7 -1
  74. data/lib/yard/parser/base.rb +1 -0
  75. data/lib/yard/parser/c_parser.rb +2 -0
  76. data/lib/yard/parser/ruby/ast_node.rb +82 -63
  77. data/lib/yard/parser/ruby/legacy/ruby_lex.rb +36 -10
  78. data/lib/yard/parser/ruby/legacy/ruby_parser.rb +1 -0
  79. data/lib/yard/parser/ruby/legacy/statement.rb +9 -5
  80. data/lib/yard/parser/ruby/legacy/statement_list.rb +20 -11
  81. data/lib/yard/parser/ruby/ruby_parser.rb +18 -1
  82. data/lib/yard/parser/source_parser.rb +6 -1
  83. data/lib/yard/registry.rb +284 -278
  84. data/lib/yard/registry_store.rb +4 -2
  85. data/lib/yard/serializers/base.rb +30 -13
  86. data/lib/yard/serializers/file_system_serializer.rb +10 -1
  87. data/lib/yard/server/adapter.rb +51 -0
  88. data/lib/yard/server/commands/base.rb +98 -0
  89. data/lib/yard/server/commands/display_file_command.rb +20 -0
  90. data/lib/yard/server/commands/display_object_command.rb +50 -0
  91. data/lib/yard/server/commands/frames_command.rb +31 -0
  92. data/lib/yard/server/commands/library_command.rb +83 -0
  93. data/lib/yard/server/commands/library_index_command.rb +23 -0
  94. data/lib/yard/server/commands/list_command.rb +44 -0
  95. data/lib/yard/server/commands/search_command.rb +67 -0
  96. data/lib/yard/server/commands/static_file_command.rb +45 -0
  97. data/lib/yard/server/doc_server_helper.rb +22 -0
  98. data/lib/yard/server/doc_server_serializer.rb +29 -0
  99. data/lib/yard/server/library_version.rb +86 -0
  100. data/lib/yard/server/rack_adapter.rb +38 -0
  101. data/lib/yard/server/router.rb +110 -0
  102. data/lib/yard/server/static_caching.rb +16 -0
  103. data/lib/yard/server/templates/default/fulldoc/html/css/custom.css +78 -0
  104. data/lib/yard/server/templates/default/fulldoc/html/images/processing.gif +0 -0
  105. data/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js +12 -0
  106. data/lib/yard/server/templates/default/fulldoc/html/js/live.js +32 -0
  107. data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +46 -0
  108. data/lib/yard/server/templates/default/layout/html/headers.erb +11 -0
  109. data/lib/yard/server/templates/doc_server/frames/html/frames.erb +13 -0
  110. data/lib/yard/server/templates/doc_server/frames/html/setup.rb +3 -0
  111. data/lib/yard/server/templates/doc_server/full_list/html/full_list.erb +34 -0
  112. data/lib/yard/server/templates/doc_server/full_list/html/setup.rb +10 -0
  113. data/lib/yard/server/templates/doc_server/library_list/html/contents.erb +13 -0
  114. data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +26 -0
  115. data/lib/yard/server/templates/doc_server/library_list/html/library_list.erb +12 -0
  116. data/lib/yard/server/templates/doc_server/library_list/html/setup.rb +3 -0
  117. data/lib/yard/server/templates/doc_server/library_list/html/title.erb +2 -0
  118. data/lib/yard/server/templates/doc_server/processing/html/processing.erb +51 -0
  119. data/lib/yard/server/templates/doc_server/processing/html/setup.rb +3 -0
  120. data/lib/yard/server/templates/doc_server/search/html/search.erb +19 -0
  121. data/lib/yard/server/templates/doc_server/search/html/setup.rb +8 -0
  122. data/lib/yard/server/webrick_adapter.rb +38 -0
  123. data/lib/yard/tags/default_factory.rb +0 -5
  124. data/lib/yard/tags/library.rb +61 -22
  125. data/lib/yard/tags/tag.rb +26 -4
  126. data/lib/yard/templates/engine.rb +12 -1
  127. data/lib/yard/templates/erb_cache.rb +2 -1
  128. data/lib/yard/templates/helpers/base_helper.rb +96 -3
  129. data/lib/yard/templates/helpers/filter_helper.rb +5 -0
  130. data/lib/yard/templates/helpers/html_helper.rb +204 -94
  131. data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +4 -0
  132. data/lib/yard/templates/helpers/markup_helper.rb +58 -3
  133. data/lib/yard/templates/helpers/method_helper.rb +7 -0
  134. data/lib/yard/templates/helpers/module_helper.rb +5 -0
  135. data/lib/yard/templates/helpers/text_helper.rb +10 -1
  136. data/lib/yard/templates/helpers/uml_helper.rb +13 -0
  137. data/lib/yard/templates/section.rb +106 -0
  138. data/lib/yard/templates/template.rb +20 -19
  139. data/lib/yard/verifier.rb +21 -2
  140. data/spec/cli/command_parser_spec.rb +43 -0
  141. data/spec/cli/diff_spec.rb +170 -0
  142. data/spec/cli/help_spec.rb +22 -0
  143. data/spec/cli/server_spec.rb +140 -0
  144. data/spec/cli/stats_spec.rb +75 -0
  145. data/spec/cli/yardoc_spec.rb +438 -182
  146. data/spec/cli/yri_spec.rb +13 -1
  147. data/spec/code_objects/base_spec.rb +51 -6
  148. data/spec/code_objects/class_object_spec.rb +15 -1
  149. data/spec/code_objects/method_object_spec.rb +29 -0
  150. data/spec/code_objects/namespace_object_spec.rb +150 -129
  151. data/spec/core_ext/array_spec.rb +4 -23
  152. data/spec/core_ext/insertion_spec.rb +37 -0
  153. data/spec/docstring_spec.rb +63 -0
  154. data/spec/handlers/attribute_handler_spec.rb +4 -0
  155. data/spec/handlers/base_spec.rb +98 -26
  156. data/spec/handlers/class_handler_spec.rb +5 -1
  157. data/spec/handlers/examples/attribute_handler_001.rb.txt +5 -0
  158. data/spec/handlers/examples/class_handler_001.rb.txt +4 -0
  159. data/spec/handlers/examples/module_handler_001.rb.txt +6 -1
  160. data/spec/handlers/examples/visibility_handler_001.rb.txt +4 -0
  161. data/spec/handlers/method_handler_spec.rb +5 -0
  162. data/spec/handlers/module_handler_spec.rb +4 -0
  163. data/spec/handlers/visibility_handler_spec.rb +6 -0
  164. data/spec/parser/source_parser_spec.rb +24 -0
  165. data/spec/registry_spec.rb +44 -8
  166. data/spec/server/adapter_spec.rb +38 -0
  167. data/spec/server/commands/base_spec.rb +87 -0
  168. data/spec/server/commands/static_file_command_spec.rb +67 -0
  169. data/spec/server/doc_server_serializer_spec.rb +58 -0
  170. data/spec/server/router_spec.rb +115 -0
  171. data/spec/server/spec_helper.rb +17 -0
  172. data/spec/server/static_caching_spec.rb +39 -0
  173. data/spec/server/webrick_servlet_spec.rb +20 -0
  174. data/spec/templates/constant_spec.rb +40 -0
  175. data/spec/templates/engine_spec.rb +9 -5
  176. data/spec/templates/examples/class002.html +1 -3
  177. data/spec/templates/examples/constant001.txt +25 -0
  178. data/spec/templates/examples/constant002.txt +7 -0
  179. data/spec/templates/examples/constant003.txt +11 -0
  180. data/spec/templates/examples/module001.txt +1 -1
  181. data/spec/templates/examples/module002.html +319 -0
  182. data/spec/templates/helpers/base_helper_spec.rb +2 -2
  183. data/spec/templates/helpers/html_helper_spec.rb +93 -3
  184. data/spec/templates/helpers/html_syntax_highlight_helper_spec.rb +5 -0
  185. data/spec/templates/helpers/markup_helper_spec.rb +94 -67
  186. data/spec/templates/helpers/shared_signature_examples.rb +9 -0
  187. data/spec/templates/helpers/text_helper_spec.rb +12 -0
  188. data/spec/templates/module_spec.rb +21 -4
  189. data/spec/templates/section_spec.rb +146 -0
  190. data/spec/templates/template_spec.rb +9 -20
  191. data/templates/default/class/setup.rb +5 -5
  192. data/templates/default/constant/text/header.erb +11 -0
  193. data/templates/default/constant/text/setup.rb +3 -0
  194. data/templates/default/fulldoc/html/css/style.css +29 -3
  195. data/templates/default/fulldoc/html/js/app.js +67 -1
  196. data/templates/default/fulldoc/html/js/full_list.js +3 -8
  197. data/templates/default/fulldoc/html/js/jquery.js +150 -15
  198. data/templates/default/fulldoc/html/setup.rb +9 -0
  199. data/templates/default/layout/html/footer.erb +1 -1
  200. data/templates/default/layout/html/setup.rb +7 -25
  201. data/templates/default/method_details/html/source.erb +1 -1
  202. data/templates/default/module/html/attribute_summary.erb +2 -2
  203. data/templates/default/module/html/method_summary.erb +2 -2
  204. data/templates/default/module/setup.rb +27 -4
  205. data/templates/default/onefile/html/files.erb +5 -0
  206. data/templates/default/onefile/html/layout.erb +22 -0
  207. data/templates/default/onefile/html/readme.erb +3 -0
  208. data/templates/default/onefile/html/setup.rb +40 -0
  209. data/templates/default/root/html/setup.rb +1 -0
  210. data/templates/default/tags/setup.rb +26 -33
  211. metadata +80 -10
@@ -0,0 +1,210 @@
1
+ module YARD
2
+ module CLI
3
+ # @since 0.6.0
4
+ class Stats < Yardoc
5
+ include Templates::Helpers::BaseHelper
6
+
7
+ # Maintains the order in which +stats_for_+ statistics methods should be
8
+ # printed.
9
+ #
10
+ # @see #print_statistics
11
+ STATS_ORDER = [:files, :modules, :classes, :constants, :methods]
12
+
13
+ # @return [Boolean] whether to parse and load registry
14
+ attr_accessor :parse
15
+
16
+ # @param [Boolean] parse whether to parse and load registry (see {#parse})
17
+ def initialize(parse = true)
18
+ super()
19
+ @parse = parse
20
+ @undoc_list = nil
21
+ @compact = false
22
+ end
23
+
24
+ def description
25
+ "Prints documentation statistics on a set of files"
26
+ end
27
+
28
+ # Runs the commandline utility, parsing arguments and generating
29
+ # output if set.
30
+ #
31
+ # @param [Array<String>] args the list of arguments
32
+ # @return [void]
33
+ def run(*args)
34
+ parse_arguments(*args)
35
+
36
+ if parse
37
+ if use_cache
38
+ Registry.load!
39
+ checksums = Registry.checksums.dup
40
+ end
41
+ YARD.parse(files, excluded)
42
+ Registry.save(use_cache) if save_yardoc
43
+ end
44
+
45
+ print_statistics
46
+ print_undocumented_objects
47
+ end
48
+
49
+ # Prints statistics for different object types
50
+ #
51
+ # To add statistics for a specific type, add a method +#stats_for_TYPE+
52
+ # to this class that calls {#output}.
53
+ def print_statistics
54
+ @total, @undocumented = 0, 0
55
+ meths = methods.map {|m| m.to_s }.grep(/^stats_for_/)
56
+ STATS_ORDER.each do |meth|
57
+ mname = "stats_for_#{meth}"
58
+ if meths.include?(mname)
59
+ send(mname)
60
+ meths.delete(mname)
61
+ end
62
+ end
63
+ meths.each {|m| send(m) }
64
+ total = (@total - @undocumented).to_f / @total.to_f * 100
65
+ puts("% 3.2f%% documented" % total)
66
+ end
67
+
68
+ # Prints list of undocumented objects
69
+ def print_undocumented_objects
70
+ return unless @undoc_list
71
+ puts
72
+ puts "Undocumented Objects:"
73
+
74
+ objects = @undoc_list.sort_by {|o| o.file }
75
+ max = objects.sort_by {|o| o.path.length }.last.path.length
76
+ if @compact
77
+ objects.each do |object|
78
+ puts("%-#{max}s (%s)" % [object.path, object.file])
79
+ end
80
+ else
81
+ last_file = nil
82
+ objects.each do |object|
83
+ if object.file != last_file
84
+ puts
85
+ puts "(in file: #{object.file})"
86
+ end
87
+ puts object.path
88
+ last_file = object.file
89
+ end
90
+ end
91
+ end
92
+
93
+ # @return [Array<CodeObjects::Base>] all the parsed objects in the registry,
94
+ # removing any objects that are not visible (private, protected) depending
95
+ # on the arguments passed to the command.
96
+ def all_objects
97
+ @all_objects ||= run_verifier Registry.all
98
+ end
99
+
100
+ # Statistics for files
101
+ def stats_for_files
102
+ files = []
103
+ all_objects.each {|o| files |= [o.file] }
104
+ output "Files", files.size
105
+ end
106
+
107
+ # Statistics for modules
108
+ def stats_for_modules
109
+ output "Modules", *type_statistics(:module)
110
+ end
111
+
112
+ # Statistics for classes
113
+ def stats_for_classes
114
+ output "Classes", *type_statistics(:class)
115
+ end
116
+
117
+ # Statistics for constants
118
+ def stats_for_constants
119
+ output "Constants", *type_statistics(:constant)
120
+ end
121
+
122
+ # Statistics for methods
123
+ def stats_for_methods
124
+ objs = all_objects.select {|m| m.type == :method }
125
+ objs.reject! {|m| m.is_alias? || !m.is_explicit? }
126
+ undoc = objs.select {|m| m.docstring.blank? && !m.overridden_method }
127
+ @undoc_list |= undoc if @undoc_list
128
+ output "Methods", objs.size, undoc.size
129
+ end
130
+
131
+ # Prints a statistic to standard out. This method is optimized for
132
+ # getting Integer values, though it allows any data to be printed.
133
+ #
134
+ # @param [String] name the statistic name
135
+ # @param [Integer, String] data the numeric (or any) data representing
136
+ # the statistic. If +data+ is an Integer, it should represent the
137
+ # total objects of a type.
138
+ # @param [Integer, nil] undoc number of undocumented objects for the type
139
+ # @return [void]
140
+ def output(name, data, undoc = nil)
141
+ @total += data if data.is_a?(Integer) && undoc
142
+ @undocumented += undoc if undoc.is_a?(Integer)
143
+ if undoc
144
+ data = ("% 5s (% 5d undocumented)" % [data, undoc])
145
+ else
146
+ data = "% 5s" % data
147
+ end
148
+ puts("%-12s %s" % [name + ":", data])
149
+ end
150
+
151
+ private
152
+
153
+ def type_statistics(type)
154
+ objs = all_objects.select {|m| m.type == type }
155
+ undoc = objs.find_all {|m| m.docstring.blank? }
156
+ @undoc_list |= undoc if @undoc_list
157
+ [objs.size, undoc.size]
158
+ end
159
+
160
+ # Parses commandline options.
161
+ # @param [Array<String>] args each tokenized argument
162
+ def optparse(*args)
163
+ opts = OptionParser.new
164
+ opts.banner = "Usage: yard stats [options] [source_files]"
165
+
166
+ opts.separator "(if a list of source files is omitted, lib/**/*.rb ext/**/*.c is used.)"
167
+
168
+ general_options(opts)
169
+ output_options(opts)
170
+ tag_options(opts)
171
+ common_options(opts)
172
+ parse_options(opts, args)
173
+ parse_files(*args) unless args.empty?
174
+ end
175
+
176
+ def general_options(opts)
177
+ super(opts)
178
+
179
+ opts.on('--list-undoc', 'List all undocumented objects') do
180
+ @undoc_list = []
181
+ end
182
+
183
+ opts.on('--compact', 'Compact undocumented objects listing') do
184
+ @compact = true
185
+ end
186
+
187
+ opts.on('--no-public', "Don't include public methods in statistics.") do
188
+ visibilities.delete(:public)
189
+ end
190
+
191
+ opts.on('--protected', "Include protected methods in statistics.") do
192
+ visibilities.push(:protected)
193
+ end
194
+
195
+ opts.on('--private', "Include private methods in statistics.") do
196
+ visibilities.push(:private)
197
+ end
198
+
199
+ opts.on('--no-private', "Don't include objects with @private tag in statistics.") do
200
+ options[:verifier].add_expressions '!object.tag(:private) &&
201
+ (object.namespace.type == :proxy || !object.namespace.tag(:private))'
202
+ end
203
+
204
+ opts.on('--query QUERY', "Only includes objects that match a specific query") do |query|
205
+ options[:verifier].add_expressions(query.taint)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -3,7 +3,98 @@ require 'fileutils'
3
3
 
4
4
  module YARD
5
5
  module CLI
6
- class Yardoc < Base
6
+ # Yardoc is the default YARD CLI command (+yard doc+ and historic +yardoc+
7
+ # executable) used to generate and output (mainly) HTML documentation given
8
+ # a set of source files.
9
+ #
10
+ # == Usage
11
+ #
12
+ # Main usage for this command is:
13
+ #
14
+ # $ yardoc [options] [source_files [- extra_files]]
15
+ #
16
+ # See +yardoc --help+ for details on valid options.
17
+ #
18
+ # == Options File (+.yardopts+)
19
+ #
20
+ # If a +.yardopts+ file is found in the source directory being processed,
21
+ # YARD will use the contents of the file as arguments to the command,
22
+ # treating newlines as spaces. You can use shell-style quotations to
23
+ # group space delimited arguments, just like on the command line.
24
+ #
25
+ # A valid +.yardopts+ file might look like:
26
+ #
27
+ # --no-private
28
+ # --title "My Title"
29
+ # --exclude foo --exclude bar
30
+ # lib/**/*.erb
31
+ # lib/**/*.rb -
32
+ # HACKING.rdoc LEGAL COPYRIGHT
33
+ #
34
+ # Note that Yardoc also supports the legacy RDoc style +.document+ file,
35
+ # though this file can only specify source globs to parse, not options.
36
+ #
37
+ # == Queries (+--query+)
38
+ #
39
+ # Yardoc supports queries to select specific code objects for which to
40
+ # generate documentation. For example, you might want to generate
41
+ # documentation only for your public API. If you've documented your public
42
+ # methods with +@api public+, you can use the following query to select
43
+ # all of these objects:
44
+ #
45
+ # --query '@api.text == "public"'
46
+ #
47
+ # Note that the syntax for queries is mostly Ruby with a few syntactic
48
+ # simplifications for meta-data tags. See the {Verifier} class for an
49
+ # overview of this syntax.
50
+ #
51
+ # == Adding Custom Ad-Hoc Meta-data Tags (+--tag+)
52
+ #
53
+ # YARD allows specification of {file:docs/Tags.md meta-data tags}
54
+ # programmatically via the {YARD::Tags::Library} class, but often this is not
55
+ # practical for users writing documentation. To make adding custom tags
56
+ # easier, Yardoc has a few command-line switches for creating basic tags
57
+ # and displaying them in generated HTML output.
58
+ #
59
+ # To specify a custom tag to be displayed in output, use any of the
60
+ # following:
61
+ #
62
+ # * +--tag+ TAG:TITLE
63
+ # * +--name-tag+ TAG:TITLE
64
+ # * +--type-tag+ TAG:TITLE
65
+ # * +--type-name-tag+ TAG:TITLE
66
+ # * +--title-tag+ TAG:TITLE
67
+ #
68
+ # "TAG:TITLE" is of the form: name:"Display Title", for example:
69
+ #
70
+ # --tag overload:"Overloaded Method"
71
+ #
72
+ # See +yardoc --help+ for a description of the various options.
73
+ #
74
+ # Tags added in this way are automatically displayed in output. To add
75
+ # a meta-data tag that does not show up in output, use +--hide-tag TAG+.
76
+ # Note that you can also use this option on existing tags to hide
77
+ # builtin tags, for instance.
78
+ #
79
+ # == Processed Data Storage (+.yardoc+ directory)
80
+ #
81
+ # When Yardoc parses a source directory, it creates a +.yardoc+ directory
82
+ # (by default, override with +-b+) at the root of the project. This directory
83
+ # contains marshal dumps for all raw object data in the source, so that
84
+ # you can access it later for various commands (+stats+, +graph+, etc.).
85
+ # This directory is also used as a cache for any future calls to +yardoc+
86
+ # so as to process only the files which have changed since the last call.
87
+ #
88
+ # When Yardoc uses the cache in subsequent calls to +yardoc+, methods
89
+ # or classes that have been deleted from source since the last parsing
90
+ # will not be erased from the cache (YARD never deletes objects). In such
91
+ # a case, you should wipe the cache and do a clean parsing of the source tree.
92
+ # You can do this by deleting the +.yardoc+ directory manually, or running
93
+ # Yardoc without +--use-cache+ (+-c+).
94
+ #
95
+ # @since 0.2.1
96
+ # @see Verifier
97
+ class Yardoc < Command
7
98
  # The configuration filename to load extra options from
8
99
  DEFAULT_YARDOPTS_FILE = ".yardopts"
9
100
 
@@ -15,6 +106,7 @@ module YARD
15
106
  attr_accessor :files
16
107
 
17
108
  # @return [Array<String>] list of excluded paths (regexp matches)
109
+ # @since 0.5.3
18
110
  attr_accessor :excluded
19
111
 
20
112
  # @return [Boolean] whether to use the existing yardoc db if the
@@ -22,14 +114,20 @@ module YARD
22
114
  # parse only changed files.
23
115
  attr_accessor :use_cache
24
116
 
25
- # @return [Boolean] whether to generate output incrementally (
26
- # implies use_cache and generate)
27
- attr_accessor :incremental
117
+ # @return [Boolean] whether to parse options from .yardopts
118
+ attr_accessor :use_yardopts_file
119
+
120
+ # @return [Boolean] whether to parse options from .document
121
+ attr_accessor :use_document_file
122
+
123
+ # @return [Boolean] whether objects should be serialized to .yardoc db
124
+ attr_accessor :save_yardoc
28
125
 
29
126
  # @return [Boolean] whether to generate output
30
127
  attr_accessor :generate
31
128
 
32
129
  # @return [Boolean] whether to print a list of objects
130
+ # @since 0.5.5
33
131
  attr_accessor :list
34
132
 
35
133
  # The options file name (defaults to {DEFAULT_YARDOPTS_FILE})
@@ -38,14 +136,20 @@ module YARD
38
136
 
39
137
  # Keep track of which visibilities are to be shown
40
138
  # @return [Array<Symbol>] a list of visibilities
139
+ # @since 0.5.6
41
140
  attr_accessor :visibilities
141
+
142
+ # @return [Array<Symbol>] a list of tags to hide from templates
143
+ # @since 0.6.0
144
+ attr_accessor :hidden_tags
42
145
 
43
- # @return [Boolean] whether to build or rebuild gems
44
- attr_accessor :build_gems, :rebuild_gems
146
+ # @return [Boolean] whether to print statistics after parsing
147
+ # @since 0.6.0
148
+ attr_accessor :statistics
45
149
 
46
- # Helper method to create an instance and run the utility
47
- # @see #run
48
- def self.run(*args) new.run(*args) end
150
+ # @return [Array<String>] a list of assets to copy after generation
151
+ # @since 0.6.0
152
+ attr_accessor :assets
49
153
 
50
154
  # Creates a new instance of the commandline utility
51
155
  def initialize
@@ -63,16 +167,28 @@ module YARD
63
167
  :verifier => Verifier.new
64
168
  )
65
169
  @visibilities = [:public]
170
+ @assets = {}
66
171
  @excluded = []
67
172
  @files = []
173
+ @hidden_tags = []
68
174
  @use_cache = false
69
- @build_gems = false
70
- @rebuild_gems = false
175
+ @use_yardopts_file = true
176
+ @use_document_file = true
71
177
  @generate = true
72
- @incremental = false
73
178
  @options_file = DEFAULT_YARDOPTS_FILE
179
+ @statistics = true
180
+ @list = false
181
+ @save_yardoc = true
182
+
183
+ if defined?(Encoding)
184
+ Encoding.default_external, Encoding.default_internal = 'utf-8', 'utf-8'
185
+ end
74
186
  end
75
187
 
188
+ def description
189
+ "Generates documentation"
190
+ end
191
+
76
192
  # Runs the commandline utility, parsing arguments and generating
77
193
  # output if set.
78
194
  #
@@ -81,55 +197,72 @@ module YARD
81
197
  def run(*args)
82
198
  parse_arguments(*args)
83
199
 
200
+ checksums = nil
84
201
  if use_cache
85
202
  Registry.load
86
203
  checksums = Registry.checksums.dup
87
204
  end
88
205
  YARD.parse(files, excluded)
89
- Registry.save(use_cache)
206
+ Registry.save(use_cache) if save_yardoc
90
207
 
91
-
92
- if build_gems
93
- do_build_gems(rebuild_gems)
94
- elsif generate
95
- if incremental
96
- generate_with_cache(checksums)
97
- else
98
- Registry.load_all if use_cache
99
- Templates::Engine.generate(all_objects, options)
100
- end
208
+ if generate
209
+ run_generate(checksums)
210
+ copy_assets
101
211
  elsif list
102
212
  print_list
103
213
  end
104
-
214
+
215
+ if !list && statistics && log.level < Logger::ERROR
216
+ Registry.load_all
217
+ log.enter_level(Logger::ERROR) do
218
+ Stats.new(false).run(*args)
219
+ end
220
+ end
221
+
105
222
  true
106
223
  end
107
224
 
108
225
  # Parses commandline arguments
109
226
  # @param [Array<String>] args the list of arguments
110
227
  # @return [void]
228
+ # @since 0.5.6
111
229
  def parse_arguments(*args)
112
- optparse(*support_rdoc_document_file!)
113
- optparse(*yardopts)
230
+ # Hack: parse out --no-yardopts, --no-document before parsing files
231
+ ['document', 'yardopts'].each do |file|
232
+ without, with = args.index("--no-#{file}") || 0, args.index("--#{file}") || 0
233
+ send("use_#{file}_file=", false) if without > with
234
+ end
235
+
236
+ # Parse files and then command line arguments
237
+ optparse(*support_rdoc_document_file!) if use_document_file
238
+ optparse(*yardopts) if use_yardopts_file
114
239
  optparse(*args)
115
240
 
116
241
  # Last minute modifications
117
242
  self.files = ['lib/**/*.rb', 'ext/**/*.c'] if self.files.empty?
243
+ self.files.delete_if {|x| x =~ /\A\s*\Z/ } # remove empty ones
118
244
  options[:readme] ||= Dir.glob('README*').first
245
+ if options[:onefile]
246
+ options[:files] << options[:readme] if options[:readme]
247
+ options[:readme] = Dir.glob(files.first).first
248
+ end
249
+ Tags::Library.visible_tags -= hidden_tags
119
250
  add_visibility_verifier
120
251
  end
121
252
 
122
253
  # The list of all objects to process. Override this method to change
123
254
  # which objects YARD should generate documentation for.
124
255
  #
256
+ # @deprecated To hide methods use the +@private+ tag instead.
125
257
  # @return [Array<CodeObjects::Base>] a list of code objects to process
126
258
  def all_objects
127
259
  Registry.all(:root, :module, :class)
128
260
  end
129
261
 
130
262
  # Parses the .yardopts file for default yard options
131
- # @return [void]
263
+ # @return [Array<String>] an array of options parsed from .yardopts
132
264
  def yardopts
265
+ return [] unless use_yardopts_file
133
266
  File.read_binary(options_file).shell_split
134
267
  rescue Errno::ENOENT
135
268
  []
@@ -137,38 +270,59 @@ module YARD
137
270
 
138
271
  private
139
272
 
140
- # Generates output for changed objects in cache
273
+ # Generates output for objects
274
+ # @param [Hash, nil] checksums if supplied, a list of checkums for files.
141
275
  # @return [void]
142
- def generate_with_cache(checksums)
143
- changed_files = []
144
- Registry.checksums.each do |file, hash|
145
- changed_files << file if checksums[file] != hash
276
+ # @since 0.5.1
277
+ def run_generate(checksums)
278
+ if checksums
279
+ changed_files = []
280
+ Registry.checksums.each do |file, hash|
281
+ changed_files << file if checksums[file] != hash
282
+ end
146
283
  end
147
- Registry.load_all
148
- all_objects.each do |object|
149
- if object.files.any? {|f, line| changed_files.include?(f) }
284
+ Registry.load_all if use_cache
285
+ objects = run_verifier(all_objects).reject do |object|
286
+ serialized = !options[:serializer] || options[:serializer].exists?(object)
287
+ if checksums && serialized && !object.files.any? {|f, line| changed_files.include?(f) }
288
+ true
289
+ else
150
290
  log.info "Re-generating object #{object.path}..."
151
- opts = options.merge(:object => object, :type => :layout)
152
- Templates::Engine.render(opts)
291
+ false
153
292
  end
154
293
  end
294
+ Templates::Engine.generate(objects, options)
295
+ end
296
+
297
+ # Copies any assets to the output directory
298
+ # @return [void]
299
+ # @since 0.6.0
300
+ def copy_assets
301
+ return unless options[:serializer]
302
+ outpath = options[:serializer].basepath
303
+ assets.each do |from, to|
304
+ to = File.join(outpath, to)
305
+ log.debug "Copying asset '#{from}' to '#{to}'"
306
+ FileUtils.cp_r(from, to)
307
+ end
155
308
  end
156
309
 
157
310
  # Prints a list of all objects
158
311
  # @return [void]
312
+ # @since 0.5.5
159
313
  def print_list
160
314
  Registry.load_all
161
- Registry.all.
162
- reject {|item| options[:verifier].call(item).is_a?(FalseClass) }.
315
+ run_verifier(Registry.all).
163
316
  sort_by {|item| [item.file, item.line]}.each do |item|
164
317
  puts "#{item.file}:#{item.line}: #{item}"
165
318
  end
166
319
  end
167
320
 
168
321
  # Reads a .document file in the directory to get source file globs
169
- # @return [void]
322
+ # @return [Array<String>] an array of files parsed from .document
170
323
  def support_rdoc_document_file!
171
- IO.read(".document").gsub(/^[ \t]*#.+/m, '').split(/\s+/)
324
+ return [] unless use_document_file
325
+ File.read(".document").gsub(/^[ \t]*#.+/m, '').split(/\s+/)
172
326
  rescue Errno::ENOENT
173
327
  []
174
328
  end
@@ -212,40 +366,31 @@ module YARD
212
366
  end
213
367
  end
214
368
 
215
- # Builds .yardoc files for all non-existing gems
216
- # @param [Boolean] rebuild Forces rebuild of all gems
217
- def do_build_gems(rebuild = false)
218
- require 'rubygems'
219
- Gem.source_index.find_name('').each do |spec|
220
- reload = true
221
- dir = Registry.yardoc_file_for_gem(spec.name)
222
- if dir && File.directory?(dir) && !rebuild
223
- log.debug "#{spec.name} index already exists at '#{dir}'"
224
- else
225
- yfile = Registry.yardoc_file_for_gem(spec.name, ">= 0", true)
226
- next unless yfile
227
- Registry.clear
228
- Dir.chdir(spec.full_gem_path)
229
- log.info "Building yardoc index for gem: #{spec.full_name}"
230
- Yardoc.run('-n', '-b', yfile)
231
- reload = false
232
- end
233
- end
234
- exit(0)
235
- end
236
-
237
369
  # Adds verifier rule for visibilities
238
370
  # @return [void]
371
+ # @since 0.5.6
239
372
  def add_visibility_verifier
240
373
  vis_expr = "object.type != :method || #{visibilities.uniq.inspect}.include?(object.visibility)"
241
374
  options[:verifier].add_expressions(vis_expr)
242
375
  end
243
376
 
377
+ # (see Templates::Helpers::BaseHelper#run_verifier)
378
+ def run_verifier(list)
379
+ options[:verifier] ? options[:verifier].run(list) : list
380
+ end
381
+
382
+ # @since 0.6.0
383
+ def add_tag(tag_data, factory_method = nil)
384
+ tag, title = *tag_data.split(':')
385
+ Tags::Library.define_tag(title, tag.to_sym, factory_method)
386
+ Tags::Library.visible_tags |= [tag.to_sym]
387
+ end
388
+
244
389
  # Parses commandline options.
245
390
  # @param [Array<String>] args each tokenized argument
246
391
  def optparse(*args)
247
392
  opts = OptionParser.new
248
- opts.banner = "Usage: yardoc [options] [source_files [- extra_files]]"
393
+ opts.banner = "Usage: yard doc [options] [source_files [- extra_files]]"
249
394
 
250
395
  opts.separator "(if a list of source files is omitted, lib/**/*.rb ext/**/*.c is used.)"
251
396
  opts.separator ""
@@ -257,94 +402,102 @@ module YARD
257
402
  opts.separator "A base set of options can be specified by adding a .yardopts"
258
403
  opts.separator "file to your base path containing all extra options separated"
259
404
  opts.separator "by whitespace."
405
+
406
+ general_options(opts)
407
+ output_options(opts)
408
+ tag_options(opts)
409
+ common_options(opts)
410
+ parse_options(opts, args)
411
+ parse_files(*args) unless args.empty?
412
+ end
413
+
414
+ # Adds general options
415
+ def general_options(opts)
260
416
  opts.separator ""
261
417
  opts.separator "General Options:"
262
418
 
263
- opts.on('-c', '--use-cache [FILE]',
264
- "Use the cached .yardoc db to generate documentation. (defaults to no cache)") do |file|
265
- YARD::Registry.yardoc_file = file if file
266
- self.use_cache = true
267
- end
268
-
269
419
  opts.on('-b', '--db FILE', 'Use a specified .yardoc db to load from or save to. (defaults to .yardoc)') do |yfile|
270
420
  YARD::Registry.yardoc_file = yfile
271
421
  end
272
-
422
+
273
423
  opts.on('-n', '--no-output', 'Only generate .yardoc database, no documentation.') do
274
424
  self.generate = false
275
425
  end
276
-
277
- opts.on('-e', '--load FILE', 'A Ruby script to load before the source tree is parsed.') do |file|
278
- if !require(file.gsub(/\.rb$/, ''))
279
- log.error "The file `#{file}' was already loaded, perhaps you need to specify the absolute path to avoid name collisions."
280
- exit
281
- end
282
- end
283
-
284
- opts.on('--incremental', 'Generates output for changed files only (implies -c)') do
285
- self.incremental = true
286
- self.generate = true
426
+
427
+ opts.on('-c', '--use-cache [FILE]',
428
+ "Use the cached .yardoc db to generate documentation. (defaults to no cache)") do |file|
429
+ YARD::Registry.yardoc_file = file if file
287
430
  self.use_cache = true
288
431
  end
289
432
 
290
- opts.on('--exclude REGEXP', 'Ignores a file if it matches path match (regexp)') do |path|
291
- self.excluded << path
433
+ opts.on('--no-cache', "Clear .yardoc db before parsing source.") do
434
+ self.use_cache = false
292
435
  end
293
436
 
294
- opts.on('--legacy', 'Use old style parser and handlers. Unavailable under Ruby 1.8.x') do
295
- YARD::Parser::SourceParser.parser_type = :ruby18
437
+ opts.on('--[no-]yardopts', "If arguments should be read from .yardopts file. (defaults to yes)") do |use_yardopts|
438
+ self.use_yardopts_file = use_yardopts
439
+ end
440
+
441
+ opts.on('--[no-]document', "If arguments should be read from .document file. (defaults to yes)") do |use_document|
442
+ self.use_document_file = use_document
296
443
  end
297
444
 
298
- opts.on('--build-gems', 'Builds .yardoc files for all gems (implies -n)') do
299
- self.build_gems = true
445
+ opts.on('--no-save', 'Do not save the parsed data to the yardoc db') do
446
+ self.save_yardoc = false
300
447
  end
301
448
 
302
- opts.on('--re-build-gems', 'Forces building .yardoc files for all gems (implies -n)') do
303
- self.build_gems = true
304
- self.rebuild_gems = true
449
+ opts.on('--exclude REGEXP', 'Ignores a file if it matches path match (regexp)') do |path|
450
+ self.excluded << path
305
451
  end
452
+ end
306
453
 
454
+ # Adds output options
455
+ def output_options(opts)
307
456
  opts.separator ""
308
457
  opts.separator "Output options:"
309
-
458
+
459
+ opts.on('--one-file', 'Generates output as a single file') do
460
+ options[:onefile] = true
461
+ end
462
+
463
+ opts.on('--list', 'List objects to standard out (implies -n)') do |format|
464
+ self.generate = false
465
+ self.list = true
466
+ end
467
+
310
468
  opts.on('--no-public', "Don't show public methods. (default shows public)") do
311
469
  visibilities.delete(:public)
312
470
  end
313
471
 
314
- opts.on('--protected', "Show or don't show protected methods. (default hides protected)") do
472
+ opts.on('--protected', "Show protected methods. (default hides protected)") do
315
473
  visibilities.push(:protected)
316
474
  end
317
475
 
318
- opts.on('--private', "Show or don't show private methods. (default hides private)") do
476
+ opts.on('--private', "Show private methods. (default hides private)") do
319
477
  visibilities.push(:private)
320
478
  end
321
-
479
+
322
480
  opts.on('--no-private', "Hide objects with @private tag") do
323
481
  options[:verifier].add_expressions '!object.tag(:private) &&
324
482
  (object.namespace.type == :proxy || !object.namespace.tag(:private))'
325
483
  end
326
484
 
327
- opts.on('--no-highlight', "Don't highlight code in docs as Ruby.") do
485
+ opts.on('--no-highlight', "Don't highlight code blocks in output.") do
328
486
  options[:no_highlight] = true
329
487
  end
330
-
488
+
331
489
  opts.on('--default-return TYPE', "Shown if method has no return type. Defaults to 'Object'") do |type|
332
490
  options[:default_return] = type
333
491
  end
334
-
492
+
335
493
  opts.on('--hide-void-return', "Hides return types specified as 'void'. Default is shown.") do
336
494
  options[:hide_void_return] = true
337
495
  end
338
-
496
+
339
497
  opts.on('--query QUERY', "Only show objects that match a specific query") do |query|
340
498
  options[:verifier].add_expressions(query.taint)
341
499
  end
342
500
 
343
- opts.on('--list', 'List objects to standard out (implies -n)') do |format|
344
- self.generate = false
345
- self.list = true
346
- end
347
-
348
501
  opts.on('--title TITLE', 'Add a specific title to HTML documents') do |title|
349
502
  options[:title] = title
350
503
  end
@@ -356,11 +509,27 @@ module YARD
356
509
  log.warn "Could not find readme file: #{readme}"
357
510
  end
358
511
  end
359
-
512
+
360
513
  opts.on('--files FILE1,FILE2,...', 'Any extra comma separated static files to be included (eg. FAQ)') do |files|
361
514
  add_extra_files(*files.split(","))
362
515
  end
363
516
 
517
+ opts.on('--asset FROM[:TO]', 'A file or directory to copy over to output directory after generating') do |asset|
518
+ re = /^(?:\.\.\/|\/)/
519
+ from, to = *asset.split(':').map {|f| File.cleanpath(f) }
520
+ to ||= from
521
+ if from =~ re || to =~ re
522
+ log.warn "Invalid file '#{asset}'"
523
+ else
524
+ assets[from] = to
525
+ end
526
+ end
527
+
528
+ opts.on('-o', '--output-dir PATH',
529
+ 'The output directory. (defaults to ./doc)') do |dir|
530
+ options[:serializer].basepath = dir
531
+ end
532
+
364
533
  opts.on('-m', '--markup MARKUP',
365
534
  'Markup style used in documentation, like textile, markdown or rdoc. (defaults to rdoc)') do |markup|
366
535
  options[:markup] = markup.to_sym
@@ -370,15 +539,10 @@ module YARD
370
539
  'Overrides the library used to process markup formatting (specify the gem name)') do |markup_provider|
371
540
  options[:markup_provider] = markup_provider.to_sym
372
541
  end
373
-
374
- opts.on('-o', '--output-dir PATH',
375
- 'The output directory. (defaults to ./doc)') do |dir|
376
- options[:serializer].basepath = dir
377
- end
378
-
542
+
379
543
  opts.on('--charset ENC', 'Character set to use for HTML output (default is system locale)') do |encoding|
380
544
  begin
381
- Encoding.default_external = encoding
545
+ Encoding.default_external, Encoding.default_internal = encoding, encoding
382
546
  rescue ArgumentError => e
383
547
  raise OptionParser::InvalidOption, e
384
548
  end
@@ -393,15 +557,50 @@ module YARD
393
557
  'The template path to look for templates in. (used with -t).') do |path|
394
558
  YARD::Templates::Engine.register_template_path(path)
395
559
  end
396
-
560
+
397
561
  opts.on('-f', '--format FORMAT',
398
562
  'The output format for the template. (defaults to html)') do |format|
399
563
  options[:format] = format.to_sym
400
564
  end
565
+
566
+ opts.on('--no-stats', 'Don\'t print statistics') do
567
+ self.statistics = false
568
+ end
569
+ end
401
570
 
402
- common_options(opts)
403
- parse_options(opts, args)
404
- parse_files(*args) unless args.empty?
571
+ # Adds tag options
572
+ # @since 0.6.0
573
+ def tag_options(opts)
574
+ opts.separator ""
575
+ opts.separator "Tag options: (TAG:TITLE looks like: 'overload:Overloaded Method')"
576
+
577
+ opts.on('--tag TAG:TITLE', 'Registers a new free-form metadata @tag') do |tag|
578
+ add_tag(tag)
579
+ end
580
+
581
+ opts.on('--type-tag TAG:TITLE', 'Tag with an optional types field') do |tag|
582
+ add_tag(tag, :with_types)
583
+ end
584
+
585
+ opts.on('--type-name-tag TAG:TITLE', 'Tag with optional types and a name field') do |tag|
586
+ add_tag(tag, :with_types_and_name)
587
+ end
588
+
589
+ opts.on('--name-tag TAG:TITLE', 'Tag with a name field') do |tag|
590
+ add_tag(tag, :with_name)
591
+ end
592
+
593
+ opts.on('--title-tag TAG:TITLE', 'Tag with first line as title field') do |tag|
594
+ add_tag(tag, :with_title_and_text)
595
+ end
596
+
597
+ opts.on('--hide-tag TAG', 'Hides a previously defined tag from templates') do |tag|
598
+ self.hidden_tags |= [tag.to_sym]
599
+ end
600
+
601
+ opts.on('--transitive-tag TAG', 'Adds a transitive tag') do |tag|
602
+ Tags::Library.transitive_tags += [tag.to_sym]
603
+ end
405
604
  end
406
605
  end
407
606
  end