yard 0.7.1 → 0.7.2

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 (44) hide show
  1. data/ChangeLog +180 -0
  2. data/README.md +12 -3
  3. data/docs/GettingStarted.md +2 -2
  4. data/lib/yard.rb +1 -1
  5. data/lib/yard/autoload.rb +2 -1
  6. data/lib/yard/cli/command.rb +4 -2
  7. data/lib/yard/cli/server.rb +4 -3
  8. data/lib/yard/cli/stats.rb +2 -2
  9. data/lib/yard/cli/yardoc.rb +11 -9
  10. data/lib/yard/code_objects/macro_object.rb +2 -2
  11. data/lib/yard/config.rb +35 -1
  12. data/lib/yard/handlers/base.rb +1 -5
  13. data/lib/yard/handlers/ruby/legacy/macro_handler.rb +0 -1
  14. data/lib/yard/handlers/ruby/macro_handler.rb +0 -1
  15. data/lib/yard/handlers/ruby/macro_handler_methods.rb +1 -1
  16. data/lib/yard/logging.rb +13 -0
  17. data/lib/yard/parser/c_parser.rb +4 -8
  18. data/lib/yard/parser/ruby/legacy/statement_list.rb +1 -1
  19. data/lib/yard/parser/ruby/ruby_parser.rb +3 -3
  20. data/lib/yard/parser/source_parser.rb +1 -1
  21. data/lib/yard/server/commands/frames_command.rb +1 -1
  22. data/lib/yard/server/commands/library_command.rb +2 -1
  23. data/lib/yard/tags/library.rb +1 -1
  24. data/lib/yard/templates/helpers/html_helper.rb +13 -2
  25. data/lib/yard/templates/helpers/text_helper.rb +6 -2
  26. data/spec/cli/command_spec.rb +36 -0
  27. data/spec/cli/diff_spec.rb +2 -0
  28. data/spec/cli/server_spec.rb +7 -7
  29. data/spec/cli/yardoc_spec.rb +20 -4
  30. data/spec/handlers/examples/macro_handler_001.rb.txt +10 -0
  31. data/spec/handlers/examples/method_handler_001.rb.txt +12 -0
  32. data/spec/handlers/macro_handler_spec.rb +17 -0
  33. data/spec/handlers/method_handler_spec.rb +8 -0
  34. data/spec/parser/base_spec.rb +2 -1
  35. data/spec/parser/c_parser_spec.rb +30 -2
  36. data/spec/parser/ruby/ruby_parser_spec.rb +9 -0
  37. data/spec/registry_spec.rb +23 -11
  38. data/spec/templates/helpers/html_helper_spec.rb +39 -3
  39. data/spec/templates/helpers/shared_signature_examples.rb +10 -0
  40. data/spec/templates/helpers/text_helper_spec.rb +2 -1
  41. data/spec/templates/onefile_spec.rb +3 -3
  42. data/templates/default/fulldoc/html/setup.rb +0 -2
  43. data/templates/default/onefile/html/setup.rb +1 -0
  44. metadata +4 -3
@@ -10,7 +10,6 @@ module YARD
10
10
  namespace_only
11
11
 
12
12
  process do
13
- return if namespace == Registry.root
14
13
  globals.__attached_macros ||= {}
15
14
  if !globals.__attached_macros[caller_method]
16
15
  return if Ruby::MacroHandler::IGNORE_METHODS[caller_method]
@@ -13,7 +13,6 @@ module YARD
13
13
  private_constant).map {|n| [n, true] }.flatten]
14
14
 
15
15
  process do
16
- return if namespace == Registry.root
17
16
  globals.__attached_macros ||= {}
18
17
  if !globals.__attached_macros[caller_method]
19
18
  return if IGNORE_METHODS[caller_method]
@@ -71,7 +71,7 @@ module YARD
71
71
  name = nil
72
72
  [:method, :attribute, :overload].each do |tag_name|
73
73
  if tag = @docstring.tag(tag_name)
74
- name = tag.send(tag == :overload ? :text : :name).to_s
74
+ name = tag.send(tag_name == :attribute ? :text : :name).to_s
75
75
  if tag_name == :method && name =~ /\(|\s/
76
76
  overload = Tags::OverloadTag.new(:overload, name)
77
77
  @docstring.add_tag(overload)
data/lib/yard/logging.rb CHANGED
@@ -38,6 +38,19 @@ module YARD
38
38
  error "Stack trace:" +
39
39
  exc.backtrace[0..5].map {|x| "\n\t#{x}" }.join + "\n"
40
40
  end
41
+
42
+ # Warns that the Ruby environment does not support continuations. Applies
43
+ # to JRuby, Rubinius and MacRuby. This warning will only display once
44
+ # per Ruby process.
45
+ #
46
+ # @return [void]
47
+ def warn_no_continuations
48
+ return if CONTINUATIONS_SUPPORTED
49
+ return if $NO_CONTINUATION_WARNING
50
+ $NO_CONTINUATION_WARNING = true
51
+ warn "JRuby/MacRuby/Rubinius do not implement Kernel#callcc and cannot " +
52
+ "load files in order. You must specify the correct order manually."
53
+ end
41
54
 
42
55
  # Sets the logger level for the duration of the block
43
56
  #
@@ -34,12 +34,8 @@ module YARD
34
34
  def ensure_loaded!(object, max_retries = 1)
35
35
  return if object.is_a?(CodeObjects::RootObject)
36
36
  unless CONTINUATIONS_SUPPORTED
37
- unless $NO_CONTINUATION_WARNING
38
- $NO_CONTINUATION_WARNING = true
39
- log.warn "JRuby/MacRuby/Rubinius do not implement Kernel#callcc and cannot " +
40
- "load files in order. You must specify the correct order manually."
41
- end
42
- raise NamespaceMissingError, object
37
+ log.warn_no_continuations
38
+ raise Handlers::NamespaceMissingError, object
43
39
  end
44
40
 
45
41
  retries = 0
@@ -162,7 +158,7 @@ module YARD
162
158
 
163
159
  # see if we can find the whole body
164
160
 
165
- re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
161
+ re = Regexp.escape(body_text) + '[^(]*\{.*?\}'
166
162
  body_text = $& if /#{re}/m =~ content
167
163
 
168
164
  # The comment block may have been overridden with a 'Document-method'
@@ -175,7 +171,7 @@ module YARD
175
171
  comment = override_comment if override_comment
176
172
 
177
173
  object.docstring = parse_comments(object, comment) if comment
178
- object.source = body_text
174
+ object.source = body_text.gsub(/\A#{Regexp.quote comment}/, '')
179
175
  when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{func_name}\s+(\w+)}m
180
176
  comment = $1
181
177
  find_method_body(object, $2, content)
@@ -356,7 +356,7 @@ module YARD
356
356
  # @return [Boolean] whether or not the current statement's parentheses and blocks
357
357
  # are balanced after +tk+
358
358
  def balances?(tk)
359
- unless @last_ns_tk.class == TkALIAS || @before_last_ns_tk.class == TkALIAS
359
+ unless [TkALIAS, TkDEF].include?(@last_ns_tk.class) || @before_last_ns_tk.class == TkALIAS
360
360
  if [TkLPAREN, TkLBRACK, TkLBRACE, TkDO, TkBEGIN].include?(tk.class)
361
361
  @level += 1
362
362
  elsif OPEN_BLOCK_TOKENS.include?(tk.class)
@@ -331,15 +331,15 @@ module YARD
331
331
  def on_qwords_new(*args)
332
332
  node = LiteralNode.new(:qwords_literal, args)
333
333
  if @map[:qwords_beg]
334
- sstart, lstart = *@map[:qwords_beg].pop
335
- node.source_range = Range.new(sstart-1, @ns_charno)
334
+ lstart, sstart = *@map[:qwords_beg].pop
335
+ node.source_range = Range.new(sstart, @ns_charno-1)
336
336
  node.line_range = Range.new(lstart, lineno)
337
337
  end
338
338
  node
339
339
  end
340
340
 
341
341
  def on_qwords_add(list, item)
342
- list.source_range = (list.source_range.first..@ns_charno)
342
+ list.source_range = (list.source_range.first..@ns_charno-1)
343
343
  list.line_range = (list.line_range.first..lineno)
344
344
  list.push(item)
345
345
  list
@@ -62,7 +62,7 @@ module YARD
62
62
  # @param [Array<String, Regexp>] excluded a list of excluded path matchers
63
63
  # @param [Fixnum] level the logger level to use during parsing. See
64
64
  # {YARD::Logger}
65
- # @return the parser object that was used to parse the source.
65
+ # @return [void]
66
66
  def parse(paths = ["{lib,app}/**/*.rb", "ext/**/*.c"], excluded = [], level = log.level)
67
67
  log.debug("Parsing #{paths.inspect} with `#{parser_type}` parser")
68
68
  excluded = excluded.map do |path|
@@ -12,7 +12,7 @@ module YARD
12
12
  elsif !path.empty?
13
13
  page_title = "Object: #{object_path}"
14
14
  elsif options[:files] && options[:files].size > 0
15
- page_title = "File: #{options[:files].first.sub(/^#{library.source_path}\/?/, '')}"
15
+ page_title = "File: #{File.basename(options[:files].first.path)}"
16
16
  main_url = url_for_file(options[:files].first)
17
17
  elsif !path || path.empty?
18
18
  page_title = "Documentation for #{library.name} #{library.version ? '(' + library.version + ')' : ''}"
@@ -1,3 +1,5 @@
1
+ require 'thread'
2
+
1
3
  module YARD
2
4
  module Server
3
5
  module Commands
@@ -68,7 +70,6 @@ module YARD
68
70
  yardoc.parse_arguments
69
71
  end
70
72
  yardoc.options.delete(:serializer)
71
- yardoc.options[:files].unshift(*Dir.glob('README*'))
72
73
  options.update(yardoc.options.to_hash)
73
74
  end
74
75
  end
@@ -95,7 +95,7 @@ module YARD
95
95
 
96
96
  # Sets the list of tags that should apply to any children inside the
97
97
  # namespace they are defined in. For instance, a "@since" tag should
98
- # apply to all methods inside a module is it defined in. Transitive
98
+ # apply to all methods inside a module it is defined in. Transitive
99
99
  # tags can be overridden by directly defining a tag on the child object.
100
100
  #
101
101
  # @return [Array<Symbol>] a list of transitive tags
@@ -180,6 +180,12 @@ module YARD
180
180
  next(match[1..-1]) if escape
181
181
 
182
182
  next(match) if name[0,1] == '|'
183
+
184
+ if name == '<a' && title =~ /href=["'](.+?)["'].*>.*<\/a>\s*(.*)\Z/
185
+ name, title = $1, $2
186
+ title = nil if title.empty?
187
+ end
188
+
183
189
  if object.is_a?(String)
184
190
  object
185
191
  else
@@ -371,6 +377,9 @@ module YARD
371
377
  # @since 0.5.3
372
378
  def signature_types(meth, link = true)
373
379
  meth = convert_method_to_overload(meth)
380
+ if meth.respond_to?(:object) && !meth.has_tag?(:return)
381
+ meth = meth.object
382
+ end
374
383
 
375
384
  type = options[:default_return] || ""
376
385
  if meth.tag(:return) && meth.tag(:return).types
@@ -429,7 +438,8 @@ module YARD
429
438
  else
430
439
  link_title = "#{h name} (#{meth.type})"
431
440
  end
432
- link_url(url_for(meth), title, :title => link_title) + extras_text
441
+ obj = meth.respond_to?(:object) ? meth.object : meth
442
+ link_url(url_for(obj), title, :title => link_title) + extras_text
433
443
  else
434
444
  title + extras_text
435
445
  end
@@ -450,13 +460,14 @@ module YARD
450
460
  else
451
461
  return 'utf-8' unless RUBY19 || lang = ENV['LANG']
452
462
  if RUBY19
453
- lang = Encoding.default_external.name.downcase
463
+ lang = ::Encoding.default_external.name.downcase
454
464
  else
455
465
  lang = lang.downcase.split('.').last
456
466
  end
457
467
  end
458
468
  case lang
459
469
  when "ascii-8bit", "us-ascii", "ascii-7bit"; 'iso-8859-1'
470
+ when "utf8"; 'utf-8'
460
471
  else; lang
461
472
  end
462
473
  end
@@ -52,8 +52,12 @@ module YARD
52
52
  end
53
53
 
54
54
  type = options[:default_return] || ""
55
- if meth.tag(:return) && meth.tag(:return).types
56
- types = meth.tags(:return).map {|t| t.types ? t.types : [] }.flatten.uniq
55
+ rmeth = meth
56
+ if !rmeth.has_tag?(:return) && rmeth.respond_to?(:object)
57
+ rmeth = meth.object
58
+ end
59
+ if rmeth.tag(:return) && rmeth.tag(:return).types
60
+ types = rmeth.tags(:return).map {|t| t.types ? t.types : [] }.flatten.uniq
57
61
  first = types.first
58
62
  if types.size == 2 && types.last == 'nil'
59
63
  type = first + '?'
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'optparse'
3
+
4
+ describe YARD::CLI::Command do
5
+ describe '#parse_options' do
6
+ before do
7
+ @options = OptionParser.new
8
+ @saw_foo = false
9
+ @options.on('--foo') { @saw_foo = true }
10
+ end
11
+
12
+ def parse(*args)
13
+ CLI::Command.new.send(:parse_options, @options, args)
14
+ args
15
+ end
16
+
17
+ it "should skip unrecognized options but continue to next option" do
18
+ log.should_receive(:warn).with(/Unrecognized.*--list/)
19
+ log.should_receive(:warn).with(/Unrecognized.*--list2/)
20
+ parse('--list', '--list2', '--foo')
21
+ @saw_foo.should be_true
22
+ end
23
+
24
+ it "should skip unrecognized options and any extra non-option arg that follows" do
25
+ log.should_receive(:warn).with(/Unrecognized.*--list/)
26
+ parse('--list', 'foo', '--foo')
27
+ @saw_foo.should be_true
28
+ end
29
+
30
+ it "should stop retrying to parse at non-switch argument" do
31
+ log.should_receive(:warn).with(/Unrecognized.*--list/)
32
+ args = parse('--list', 'foo', 'foo', 'foo')
33
+ args.should == %w(foo foo)
34
+ end
35
+ end
36
+ end
@@ -135,6 +135,7 @@ eof
135
135
  File.should_receive(:directory?).any_number_of_times
136
136
  File.should_receive(:exist?).with('gem1.gem').and_return(true)
137
137
  File.should_receive(:exist?).with('gem2.gem').and_return(true)
138
+ File.should_receive(:exist?).any_number_of_times
138
139
  File.should_receive(:open).with('gem1.gem', 'rb').and_yield(iomock)
139
140
  File.should_receive(:open).with('gem2.gem', 'rb')
140
141
  FileUtils.should_receive(:mkdir_p)
@@ -152,6 +153,7 @@ eof
152
153
  File.should_receive(:directory?).any_number_of_times
153
154
  File.should_receive(:exist?).with('gem1.gem').and_return(false)
154
155
  File.should_receive(:exist?).with('gem2.gem').and_return(false)
156
+ File.should_receive(:exist?).any_number_of_times
155
157
  @diff.should_receive(:open).with('http://rubygems.org/downloads/gem1.gem').and_yield(iomock)
156
158
  @diff.should_receive(:open).with('http://rubygems.org/downloads/gem2.gem')
157
159
  FileUtils.should_receive(:mkdir_p)
@@ -24,11 +24,11 @@ describe YARD::CLI::Server do
24
24
 
25
25
  def run(*args)
26
26
  if @libraries.empty?
27
- library = Server::LibraryVersion.new(File.basename(Dir.pwd), nil, '.yardoc')
27
+ library = Server::LibraryVersion.new(File.basename(Dir.pwd), nil, File.expand_path('.yardoc'))
28
28
  @libraries = {library.name => [library]}
29
29
  end
30
30
  unless @no_verify_libraries
31
- @libraries.values.each {|libs| libs.each {|lib| File.should_receive(:exist?).at_least(1).times.with(lib.yardoc_file).and_return(true) } }
31
+ @libraries.values.each {|libs| libs.each {|lib| File.should_receive(:exist?).at_least(1).times.with(File.expand_path(lib.yardoc_file)).and_return(true) } }
32
32
  end
33
33
  unless @no_adapter_mock
34
34
  @cli.stub!(:adapter).and_return(@adapter)
@@ -40,19 +40,19 @@ describe YARD::CLI::Server do
40
40
 
41
41
  it "should default to current dir if no library is specified" do
42
42
  Dir.should_receive(:pwd).and_return('/path/to/foo')
43
- @libraries['foo'] = [Server::LibraryVersion.new('foo', nil, '.yardoc')]
43
+ @libraries['foo'] = [Server::LibraryVersion.new('foo', nil, File.expand_path('.yardoc'))]
44
44
  run
45
45
  end
46
46
 
47
47
  it "should use .yardoc as yardoc file is library list is odd" do
48
- @libraries['a'] = [Server::LibraryVersion.new('a', nil,'.yardoc')]
48
+ @libraries['a'] = [Server::LibraryVersion.new('a', nil, File.expand_path('.yardoc'))]
49
49
  run 'a'
50
50
  end
51
51
 
52
52
  it "should force multi library if more than one library is listed" do
53
53
  @options[:single_library] = false
54
- @libraries['a'] = [Server::LibraryVersion.new('a', nil, 'b')]
55
- @libraries['c'] = [Server::LibraryVersion.new('c', nil, '.yardoc')]
54
+ @libraries['a'] = [Server::LibraryVersion.new('a', nil, File.expand_path('b'))]
55
+ @libraries['c'] = [Server::LibraryVersion.new('c', nil, File.expand_path('.yardoc'))]
56
56
  run %w(a b c)
57
57
  end
58
58
 
@@ -167,4 +167,4 @@ describe YARD::CLI::Server do
167
167
  end
168
168
  end
169
169
  end
170
- end
170
+ end
@@ -416,6 +416,7 @@ describe YARD::CLI::Yardoc do
416
416
  end
417
417
 
418
418
  it "should accept files section only containing extra files" do
419
+ Dir.should_receive(:glob).with('README*').and_return([])
419
420
  @yardoc.parse_arguments *%w( - LICENSE )
420
421
  @yardoc.files.should == %w( {lib,app}/**/*.rb ext/**/*.c )
421
422
  @yardoc.options[:files].should == [CodeObjects::ExtraFileObject.new('LICENSE', '')]
@@ -444,6 +445,21 @@ describe YARD::CLI::Yardoc do
444
445
  log.should_receive(:warn).with(/Could not find readme file: UNKNOWN/)
445
446
  @yardoc.parse_arguments *%w( -r UNKNOWN )
446
447
  end
448
+
449
+ it "should use first file as readme if no readme is specified when using --one-file" do
450
+ Dir.should_receive(:glob).with('README*').and_return []
451
+ Dir.should_receive(:glob).with('lib/*.rb').and_return(['lib/foo.rb'])
452
+ File.should_receive(:read).with('lib/foo.rb').and_return('')
453
+ @yardoc.parse_arguments *%w( --one-file lib/*.rb )
454
+ @yardoc.options[:readme].should == CodeObjects::ExtraFileObject.new('lib/foo.rb', '')
455
+ end
456
+
457
+ it "should use readme it exists when using --one-file" do
458
+ Dir.should_receive(:glob).with('README*').and_return ['README']
459
+ File.should_receive(:read).with('README').and_return('')
460
+ @yardoc.parse_arguments *%w( --one-file lib/*.rb )
461
+ @yardoc.options[:readme].should == CodeObjects::ExtraFileObject.new('README', '')
462
+ end
447
463
  end
448
464
 
449
465
  describe 'Source file arguments' do
@@ -458,7 +474,7 @@ describe YARD::CLI::Yardoc do
458
474
  visible_tags = mock(:visible_tags)
459
475
  visible_tags.should_receive(:|).ordered.with([:foo])
460
476
  visible_tags.should_receive(:-).ordered.with([]).and_return(visible_tags)
461
- Tags::Library.should_receive(:define_tag).with(nil, :foo, factory_method)
477
+ Tags::Library.should_receive(:define_tag).with('Foo', :foo, factory_method)
462
478
  Tags::Library.stub!(:visible_tags=)
463
479
  Tags::Library.should_receive(:visible_tags).at_least(1).times.and_return(visible_tags)
464
480
  @yardoc.parse_arguments("--#{switch}-tag", 'foo')
@@ -468,7 +484,7 @@ describe YARD::CLI::Yardoc do
468
484
  visible_tags = mock(:visible_tags)
469
485
  visible_tags.should_receive(:|).ordered.with([tag])
470
486
  visible_tags.should_receive(:-).ordered.with([tag]).and_return([])
471
- Tags::Library.should_receive(:define_tag).with(nil, tag, nil)
487
+ Tags::Library.should_receive(:define_tag).with(tag.to_s.capitalize, tag, nil)
472
488
  Tags::Library.stub!(:visible_tags=)
473
489
  Tags::Library.should_receive(:visible_tags).at_least(1).times.and_return(visible_tags)
474
490
  end
@@ -478,8 +494,8 @@ describe YARD::CLI::Yardoc do
478
494
  @yardoc.parse_arguments('--tag', 'foo:Title of Foo')
479
495
  end
480
496
 
481
- it "should accept --tag without title" do
482
- Tags::Library.should_receive(:define_tag).with(nil, :foo, nil)
497
+ it "should accept --tag without title (and default to captialized tag name)" do
498
+ Tags::Library.should_receive(:define_tag).with('Foo', :foo, nil)
483
499
  @yardoc.parse_arguments('--tag', 'foo')
484
500
  end
485
501
 
@@ -26,6 +26,9 @@ class Foo
26
26
  # @attribute
27
27
  default_attribute :attr3
28
28
 
29
+ # @attribute custom
30
+ default_attribute :attr4
31
+
29
32
  # @method xyz(a, b, c)
30
33
  # The foo method
31
34
  # @param [String] a
@@ -71,3 +74,10 @@ class Baz < Foo
71
74
  parser :y_parser
72
75
  none { }
73
76
  end
77
+
78
+ # @method my_other_method
79
+ # Docstring for method
80
+ method_that_makes_a_method
81
+
82
+ # @macro something
83
+ foobarbaz :beep
@@ -108,3 +108,15 @@ class E
108
108
 
109
109
  xyz :a
110
110
  end
111
+
112
+ module F
113
+ class A
114
+ def foo; end
115
+
116
+ def end
117
+ end
118
+
119
+ # PASS
120
+ def bar; end
121
+ end
122
+ end
@@ -27,6 +27,11 @@ describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MacroHandler"
27
27
  obj.should_not be_nil
28
28
  obj.should be_writer
29
29
  end
30
+
31
+ it "should allow @attribute to define alternate method name" do
32
+ Registry.at('Foo#attr4').should be_nil
33
+ Registry.at('Foo#custom').should_not be_nil
34
+ end
30
35
 
31
36
  it "should default to creating an instance method for any DSL method with tags" do
32
37
  obj = Registry.at('Foo#implicit0')
@@ -137,4 +142,16 @@ describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MacroHandler"
137
142
  Registry.at('Bar#x_parser').should be_nil
138
143
  Registry.at('Baz#y_parser').should_not be_nil
139
144
  end
145
+
146
+ it "should handle top-level DSL methods" do
147
+ obj = Registry.at('#my_other_method')
148
+ obj.should_not be_nil
149
+ obj.docstring.should == "Docstring for method"
150
+ end
151
+
152
+ it "should handle Constant.foo syntax" do
153
+ obj = Registry.at('#beep')
154
+ obj.should_not be_nil
155
+ obj.signature.should == 'def beep(a, b, c)'
156
+ end
140
157
  end