yard 0.9.0 → 0.9.1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/Rakefile +1 -1
  4. data/docs/Tags.md +10 -9
  5. data/lib/rubygems_plugin.rb +7 -3
  6. data/lib/yard.rb +5 -6
  7. data/lib/yard/autoload.rb +12 -9
  8. data/lib/yard/cli/stats.rb +11 -1
  9. data/lib/yard/cli/yri.rb +2 -2
  10. data/lib/yard/code_objects/base.rb +12 -2
  11. data/lib/yard/code_objects/class_object.rb +2 -0
  12. data/lib/yard/code_objects/class_variable_object.rb +2 -0
  13. data/lib/yard/code_objects/constant_object.rb +2 -0
  14. data/lib/yard/code_objects/method_object.rb +3 -0
  15. data/lib/yard/code_objects/module_object.rb +2 -0
  16. data/lib/yard/code_objects/namespace_mapper.rb +113 -0
  17. data/lib/yard/code_objects/namespace_object.rb +3 -0
  18. data/lib/yard/docstring.rb +1 -1
  19. data/lib/yard/docstring_parser.rb +28 -1
  20. data/lib/yard/handlers/c/handler_methods.rb +1 -0
  21. data/lib/yard/handlers/c/mixin_handler.rb +7 -1
  22. data/lib/yard/handlers/ruby/alias_handler.rb +4 -3
  23. data/lib/yard/handlers/ruby/constant_handler.rb +6 -1
  24. data/lib/yard/handlers/ruby/dsl_handler_methods.rb +20 -3
  25. data/lib/yard/parser/c/comment_parser.rb +1 -1
  26. data/lib/yard/parser/ruby/ruby_parser.rb +25 -5
  27. data/lib/yard/parser/source_parser.rb +1 -0
  28. data/lib/yard/registry.rb +22 -43
  29. data/lib/yard/registry_resolver.rb +171 -0
  30. data/lib/yard/rubygems/hook.rb +164 -0
  31. data/lib/yard/server.rb +2 -1
  32. data/lib/yard/server/commands/root_request_command.rb +27 -0
  33. data/lib/yard/server/commands/static_file_command.rb +3 -16
  34. data/lib/yard/server/doc_server_helper.rb +1 -1
  35. data/lib/yard/server/router.rb +16 -6
  36. data/lib/yard/tags/default_factory.rb +3 -1
  37. data/lib/yard/tags/directives.rb +4 -0
  38. data/lib/yard/templates/engine.rb +1 -1
  39. data/lib/yard/templates/helpers/html_helper.rb +7 -2
  40. data/lib/yard/templates/helpers/module_helper.rb +1 -0
  41. data/lib/yard/templates/helpers/text_helper.rb +12 -0
  42. data/lib/yard/templates/template_options.rb +1 -1
  43. data/lib/yard/version.rb +1 -1
  44. data/spec/cli/stats_spec.rb +8 -3
  45. data/spec/code_objects/base_spec.rb +9 -1
  46. data/spec/docstring_parser_spec.rb +36 -1
  47. data/spec/docstring_spec.rb +1 -6
  48. data/spec/handlers/c/mixin_handler_spec.rb +16 -0
  49. data/spec/handlers/constant_handler_spec.rb +9 -0
  50. data/spec/handlers/dsl_handler_spec.rb +18 -0
  51. data/spec/handlers/examples/dsl_handler_001.rb.txt +29 -0
  52. data/spec/parser/ruby/ruby_parser_spec.rb +42 -0
  53. data/spec/registry_spec.rb +46 -3
  54. data/spec/server/router_spec.rb +1 -1
  55. data/spec/server_spec.rb +9 -0
  56. data/spec/tags/default_factory_spec.rb +5 -0
  57. data/spec/templates/engine_spec.rb +10 -0
  58. data/spec/templates/examples/constant001.txt +2 -2
  59. data/spec/templates/helpers/html_helper_spec.rb +8 -1
  60. data/spec/templates/helpers/module_helper_spec.rb +35 -0
  61. data/spec/templates/helpers/text_helper_spec.rb +20 -0
  62. data/templates/default/module/setup.rb +1 -1
  63. metadata +7 -4
  64. data/spec/server/commands/static_file_command_spec.rb +0 -84
data/lib/yard/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module YARD
2
- VERSION = '0.9.0'
2
+ VERSION = '0.9.1'
3
3
  end
@@ -10,6 +10,8 @@ describe YARD::CLI::Stats do
10
10
 
11
11
  def foo; end
12
12
 
13
+ attr_reader :fooattr
14
+
13
15
  # Documented
14
16
  def bar; end
15
17
  end
@@ -21,8 +23,9 @@ describe YARD::CLI::Stats do
21
23
  "Modules: 1 ( 1 undocumented)\n" +
22
24
  "Classes: 1 ( 1 undocumented)\n" +
23
25
  "Constants: 1 ( 1 undocumented)\n" +
26
+ "Attributes: 1 ( 0 undocumented)\n" +
24
27
  "Methods: 2 ( 1 undocumented)\n" +
25
- " 20.00% documented\n"
28
+ " 33.33% documented\n"
26
29
 
27
30
  @output = StringIO.new
28
31
  @stats = CLI::Stats.new(false)
@@ -56,6 +59,7 @@ eof
56
59
  "Modules: 0 ( 0 undocumented)\n" +
57
60
  "Classes: 0 ( 0 undocumented)\n" +
58
61
  "Constants: 0 ( 0 undocumented)\n" +
62
+ "Attributes: 0 ( 0 undocumented)\n" +
59
63
  "Methods: 1 ( 0 undocumented)\n" +
60
64
  " 100.00% documented\n"
61
65
  end
@@ -65,7 +69,7 @@ eof
65
69
  expect(@output.string).to eq <<-eof
66
70
  #{@main_stats}
67
71
  Undocumented Objects:
68
- B ((stdin):9)
72
+ B ((stdin):11)
69
73
  A ((stdin):1)
70
74
  A::CONST ((stdin):2)
71
75
  A#foo ((stdin):4)
@@ -84,7 +88,8 @@ eof
84
88
  "Modules: 0 ( 0 undocumented)\n" +
85
89
  "Classes: 0 ( 0 undocumented)\n" +
86
90
  "Constants: 0 ( 0 undocumented)\n" +
91
+ "Attributes: 0 ( 0 undocumented)\n" +
87
92
  "Methods: 0 ( 0 undocumented)\n" +
88
93
  " 100.00% documented\n")
89
94
  end
90
- end
95
+ end
@@ -223,9 +223,17 @@ describe YARD::CodeObjects::Base do
223
223
  describe "#format" do
224
224
  it "sends object to Templates.render" do
225
225
  object = MethodObject.new(:root, :method)
226
- expect(Templates::Engine).to receive(:render).with(:x => 1, :object => object)
226
+ expect(Templates::Engine).to receive(:render).with(:x => 1, :object => object, :type => object.type)
227
227
  object.format :x => 1
228
228
  end
229
+
230
+ it "does not change options object class" do
231
+ opts = YARD::Templates::TemplateOptions.new
232
+ opts.type = "test"
233
+ object = MethodObject.new(:root, :method)
234
+ expect(Templates::Engine).to receive(:render).with kind_of(YARD::Templates::TemplateOptions)
235
+ object.format(opts)
236
+ end
229
237
  end
230
238
 
231
239
  describe "#source_type" do
@@ -199,7 +199,7 @@ eof
199
199
  end
200
200
  end
201
201
 
202
- describe "after_parse" do
202
+ describe "after_parse (param)" do
203
203
  it "allows specifying of callbacks" do
204
204
  parser = DocstringParser.new
205
205
  the_yielded_obj = nil
@@ -216,6 +216,15 @@ eof
216
216
  eof
217
217
  end
218
218
 
219
+ it "warns about invalid named parameters on @!method directives" do
220
+ expect(log).to receive(:warn).with(/@param tag has unknown parameter name: notaparam/)
221
+ YARD.parse_string <<-eof
222
+ # @!method foo(a)
223
+ # @param notaparam foo
224
+ test
225
+ eof
226
+ end
227
+
219
228
  it "warns about duplicate named parameters" do
220
229
  expect(log).to receive(:warn).with(/@param tag has duplicate parameter name: a/)
221
230
  YARD.parse_string <<-eof
@@ -224,5 +233,31 @@ eof
224
233
  def foo(a) end
225
234
  eof
226
235
  end
236
+
237
+ it "does not warn on aliases" do
238
+ expect(log).to_not receive(:warn)
239
+ YARD.parse_string <<-eof
240
+ # @param a foo
241
+ def foo(a) end
242
+ alias bar foo
243
+ eof
244
+ end
245
+ end
246
+
247
+ describe "after_parse (see)" do
248
+ it "does not warn on valid see tag" do
249
+ expect(log).to_not receive(:warn)
250
+ YARD.parse_string "# @see valid\nclass Foo;end"
251
+ end
252
+
253
+ it "warns if {} wraps single name" do
254
+ expect(log).to receive(:warn).with(/@see tag \(#1\) should not be wrapped in \{\}/)
255
+ YARD.parse_string "# @see {invalid}\nclass Foo;end"
256
+ end
257
+
258
+ it "warns if {} wraps across name and text" do
259
+ expect(log).to receive(:warn).with(/@see tag \(#1\) should not be wrapped in \{\}/)
260
+ YARD.parse_string "# @see {invalid tag}\nclass Foo;end"
261
+ end
227
262
  end
228
263
  end
@@ -52,14 +52,9 @@ describe YARD::Docstring do
52
52
  5.times { expect(o1.summary).to eq "Hello." }
53
53
  end
54
54
 
55
- it "strips HTML before summarizing" do
56
- doc = Docstring.new("<p>Hello <b>world</b></p>.")
57
- expect(doc.summary).to eq 'Hello world.'
58
- end
59
-
60
55
  it "strips newlines in first paragraph before summarizing" do
61
56
  doc = Docstring.new("Foo\n<code>==</code> bar.")
62
- expect(doc.summary).to eq 'Foo == bar.'
57
+ expect(doc.summary).to eq 'Foo <code>==</code> bar.'
63
58
  end
64
59
 
65
60
  it "returns the first sentence" do
@@ -24,4 +24,20 @@ describe YARD::Handlers::C::MixinHandler do
24
24
  foo = Registry.at('Foo')
25
25
  expect(foo.mixins(:instance)).to eq [P('XYZ')]
26
26
  end
27
+
28
+ it "fails if mixin variable cannot be detected" do
29
+ with_parser(:c) do
30
+ undoc_error <<-eof
31
+ void Init_Foo() {
32
+ VALUE noprefix;
33
+
34
+ mFoo = rb_define_module("Foo");
35
+ // YARD doesn't understand this
36
+ noprefix = rb_const_get(rb_cObject, rb_intern("Observable"));
37
+
38
+ rb_include_module(mFoo, noprefix);
39
+ }
40
+ eof
41
+ end
42
+ end
27
43
  end
@@ -64,4 +64,13 @@ describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ConstantHandle
64
64
  it "raises undocumentable error in 1.9 parser for Struct.new assignment to non-const" do
65
65
  undoc_error "nonconst = Struct.new"
66
66
  end unless LEGACY_PARSER
67
+
68
+ %w(module class).each do |type|
69
+ it "does not allow #{type} to be redefined as constant" do
70
+ undoc_error <<-eof
71
+ #{type} Foo; end
72
+ Foo = "value"
73
+ eof
74
+ end
75
+ end unless LEGACY_PARSER
67
76
  end
@@ -193,4 +193,22 @@ describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}DSLHandler" do
193
193
  dsl_method '/foo/bar'
194
194
  eof
195
195
  end
196
+
197
+ # @note Currently unsupported behavior. Overriding a macro on an alias will
198
+ # not work until macro lookups can be done by caller_method directly.
199
+ # @todo optimize MacroObject lookup to work by caller name, not macro name.
200
+ it "cannot attach a macro on alias of attached macro" do
201
+ expect(Registry.at('AliasTest#main_foo1')).not_to be nil
202
+ expect(Registry.at('AliasTest#alt_foo1')).to be nil
203
+ end if HAVE_RIPPER
204
+
205
+ it "searches attached macro's aliases for caller method match" do
206
+ expect(Registry.at('AliasTest#main_foo2')).not_to be nil
207
+ expect(Registry.at('AliasTest#alt_foo2')).to be nil
208
+ end if HAVE_RIPPER
209
+
210
+ it "does not create method object if directive data detected in expanded macro" do
211
+ expect(Registry.at('DirectiveMethods#Bar')).to be nil
212
+ expect(Registry.at('DirectiveMethods').mixins).to include P(:Bar)
213
+ end
196
214
  end
@@ -123,3 +123,32 @@ module DSLMethods
123
123
  dsl_method :foo, String
124
124
  dsl_method :bar, Integer
125
125
  end
126
+
127
+ class AliasTest
128
+ class << self
129
+ # @!macro alias_main
130
+ # @!method main_$1
131
+ # Success main_$1
132
+ def main; end
133
+
134
+ # TODO: currently unsupported behavior
135
+ # @!macro alias_alt
136
+ # @!method alias_$1
137
+ # Success alias_$1
138
+ alias alt main
139
+
140
+ alias alt2 main
141
+ end
142
+
143
+ alt :foo1
144
+ alt2 :foo2
145
+ end
146
+
147
+ class DirectiveMethods
148
+ # @!macro with_directive
149
+ # @!parse
150
+ # include $1
151
+ def self.attach(x) end
152
+
153
+ attach Bar
154
+ end
@@ -381,5 +381,47 @@ eof
381
381
  expect(Registry.at("Foo::CONST1").docstring).to eq "Comment here"
382
382
  expect(Registry.at("Foo::CONST2").docstring).to eq "Another comment here"
383
383
  end
384
+
385
+ %w(if unless).each do |type|
386
+ it "does not get confused by modifier '#{type}' statements" do
387
+ Registry.clear
388
+ ast = YARD.parse_string(<<-eof).enumerator
389
+ module Foo
390
+ #{type} test?
391
+ # Docstring
392
+ class Bar
393
+ # Docstring2
394
+ def foo
395
+ x #{type} true
396
+ end
397
+ end
398
+ end
399
+ end
400
+ eof
401
+
402
+ expect(Registry.at("Foo::Bar").docstring).to eq "Docstring"
403
+ expect(Registry.at("Foo::Bar#foo").docstring).to eq "Docstring2"
404
+ end
405
+
406
+ it "does not add comment blocks to #{type}_mod nodes" do
407
+ Registry.clear
408
+ ast = YARD.parse_string(<<-eof).enumerator
409
+ class Foo
410
+ # Docstring
411
+ def bar; end if true
412
+ end
413
+ eof
414
+
415
+ expect(Registry.at("Foo#bar").docstring).to eq "Docstring"
416
+ end
417
+ end
418
+
419
+ it "removes frozen string line from initial file comments" do
420
+ YARD.parse_string "# frozen_string_literal: true\n# this is a comment\nclass Foo; end"
421
+ YARD.parse_string "# Frozen-string-literal: true\n# this is a comment\nclass Bar; end"
422
+
423
+ expect(Registry.at(:Foo).docstring).to eq "this is a comment"
424
+ expect(Registry.at(:Bar).docstring).to eq "this is a comment"
425
+ end
384
426
  end
385
427
  end if HAVE_RIPPER
@@ -12,6 +12,8 @@ describe YARD::Registry do
12
12
  allow(@gem).to receive(:name).and_return('foo')
13
13
  allow(@gem).to receive(:full_name).and_return('foo-1.0')
14
14
  allow(@gem).to receive(:full_gem_path).and_return('/path/to/foo')
15
+ allow(@gem).to receive(:doc_dir).and_return('/path/to/foo/doc')
16
+ allow(@gem).to receive(:doc_dir).with('.yardoc').and_return('/path/to/foo/doc/.yardoc')
15
17
  end
16
18
 
17
19
  it "returns nil if gem isn't found" do
@@ -25,14 +27,21 @@ describe YARD::Registry do
25
27
  end
26
28
 
27
29
  it "returns existing .yardoc path for gem when for_writing=false" do
28
- expect(File).to receive(:exist?).and_return(false)
30
+ expect(File).to receive(:exist?).twice.and_return(false)
29
31
  expect(File).to receive(:exist?).with('/path/to/foo/.yardoc').and_return(true)
30
32
  expect(Gem.source_index).to receive(:find_name).with('foo', '>= 0').and_return([@gem])
31
33
  expect(Registry.yardoc_file_for_gem('foo')).to eq '/path/to/foo/.yardoc'
32
34
  end
33
35
 
36
+ it "returns new existing .yardoc path for gem when for_writing=false" do
37
+ expect(File).to receive(:exist?).once.and_return(false)
38
+ expect(File).to receive(:exist?).with('/path/to/foo/doc/.yardoc').and_return(true)
39
+ expect(Gem.source_index).to receive(:find_name).with('foo', '>= 0').and_return([@gem])
40
+ expect(Registry.yardoc_file_for_gem('foo')).to eq '/path/to/foo/doc/.yardoc'
41
+ end
42
+
34
43
  it "returns nil if no .yardoc path exists in gem when for_writing=false" do
35
- expect(File).to receive(:exist?).and_return(false)
44
+ expect(File).to receive(:exist?).twice.and_return(false)
36
45
  expect(File).to receive(:exist?).with('/path/to/foo/.yardoc').and_return(false)
37
46
  expect(Gem.source_index).to receive(:find_name).with('foo', '>= 0').and_return([@gem])
38
47
  expect(Registry.yardoc_file_for_gem('foo')).to eq nil
@@ -45,12 +54,20 @@ describe YARD::Registry do
45
54
  end
46
55
 
47
56
  it "returns global .yardoc path for gem if for_writing=true and dir is writable" do
57
+ expect(File).to receive(:writable?).with(@gem.doc_dir).and_return(false)
48
58
  expect(File).to receive(:writable?).with(@gem.full_gem_path).and_return(true)
49
59
  expect(Gem.source_index).to receive(:find_name).with('foo', '>= 0').and_return([@gem])
50
60
  expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to eq '/path/to/foo/.yardoc'
51
61
  end
52
62
 
63
+ it "returns new global .yardoc path for gem if for_writing=true and dir is writable" do
64
+ expect(File).to receive(:writable?).with(@gem.doc_dir).and_return(true)
65
+ expect(Gem.source_index).to receive(:find_name).with('foo', '>= 0').and_return([@gem])
66
+ expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to eq '/path/to/foo/doc/.yardoc'
67
+ end
68
+
53
69
  it "returns local .yardoc path for gem if for_writing=true and dir is not writable" do
70
+ expect(File).to receive(:writable?).with(@gem.doc_dir).and_return(false)
54
71
  expect(File).to receive(:writable?).with(@gem.full_gem_path).and_return(false)
55
72
  expect(Gem.source_index).to receive(:find_name).with('foo', '>= 0').and_return([@gem])
56
73
  expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to match %r{/.yard/gem_index/foo-1.0.yardoc$}
@@ -123,6 +140,18 @@ describe YARD::Registry do
123
140
  expect(Registry.resolve(:root, 'methname')).to eq o
124
141
  end
125
142
 
143
+ it "does lexical lookup on the initial namespace" do
144
+ YARD.parse_string <<-eof
145
+ module A
146
+ module B; module C; end end
147
+ module D; module E; end end
148
+ end
149
+ eof
150
+
151
+ d = Registry.at('A::B::C')
152
+ expect(Registry.resolve(d, 'D::E')).to eq Registry.at('A::D::E')
153
+ end
154
+
126
155
  it "resolves superclass methods when inheritance = true" do
127
156
  superyard = ClassObject.new(:root, :SuperYard)
128
157
  yard = ClassObject.new(:root, :YARD)
@@ -178,6 +207,20 @@ describe YARD::Registry do
178
207
  expect(Registry.resolve(P('MyObject'), '#foo', true)).to be nil
179
208
  end
180
209
 
210
+ it "performs lookups on each individual namespace when inheritance = true" do
211
+ YARD.parse_string <<-eof
212
+ module A
213
+ module B; include A::D end
214
+ module C; extend A::D end
215
+ module D; def bar; end end
216
+ end
217
+ eof
218
+
219
+ r = Registry.root
220
+ expect(Registry.resolve(r, 'A::B#bar', true)).to eq Registry.at('A::D#bar')
221
+ expect(Registry.resolve(r, 'A::C.bar', true)).to eq Registry.at('A::D#bar')
222
+ end
223
+
181
224
  it "allows type=:typename to ensure resolved object is of a certain type" do
182
225
  YARD.parse_string "class Foo; end"
183
226
  expect(Registry.resolve(Registry.root, 'Foo')).to eq Registry.at('Foo')
@@ -191,7 +234,7 @@ describe YARD::Registry do
191
234
  def self.Bar; end
192
235
  end
193
236
  eof
194
- expect(Registry.resolve(P('Foo'), 'Bar')).to eq Registry.at('Foo::Bar')
237
+ expect(Registry.resolve(P('Foo'), 'Bar', false, false, :class)).to eq Registry.at('Foo::Bar')
195
238
  expect(Registry.resolve(P('Foo'), 'Bar', false, false, :method)).to eq(
196
239
  Registry.at('Foo.Bar'))
197
240
  end
@@ -116,7 +116,7 @@ describe YARD::Server::Router do
116
116
  end
117
117
 
118
118
  it "searches static files for non-existent library" do
119
- route_to('/mydocs/foo/notproject', StaticFileCommand)
119
+ route_to('/mydocs/foo/notproject', RootRequestCommand)
120
120
  end
121
121
  end
122
122
  end
data/spec/server_spec.rb CHANGED
@@ -6,5 +6,14 @@ describe YARD::Server do
6
6
  YARD::Server.register_static_path 'foo'
7
7
  expect(YARD::Server::Commands::StaticFileCommand::STATIC_PATHS.last).to eq "foo"
8
8
  end
9
+
10
+ it "does not duplicate paths" do
11
+ paths = YARD::Server::Commands::StaticFileCommand::STATIC_PATHS
12
+ count = paths.size
13
+ YARD::Server.register_static_path 'foo2'
14
+ YARD::Server.register_static_path 'foo2'
15
+ expect(paths.size).to eq(count + 1)
16
+ expect(paths.last).to eq 'foo2'
17
+ end
9
18
  end
10
19
  end
@@ -41,6 +41,11 @@ describe YARD::Tags::DefaultFactory do
41
41
  expect(parse_types('b c <String> description (test)')).to eq [nil, nil, 'b c <String> description (test)']
42
42
  end
43
43
 
44
+ it "does not allow types to start after a newline" do
45
+ v = parse_types(" \n [X]")
46
+ expect(v).to eq [nil, nil, "[X]"]
47
+ end
48
+
44
49
  it "handles a complex list of types" do
45
50
  v = parse_types(' [Test, Array<String, Hash, C>, String]')
46
51
  expect(v).to include(["Test", "Array<String, Hash, C>", "String"])
@@ -1,11 +1,21 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  describe YARD::Templates::Engine do
4
+ before { @paths = Engine.template_paths }
5
+ after { Engine.template_paths = @paths }
6
+
4
7
  describe ".register_template_path" do
5
8
  it "registers a String path" do
6
9
  Engine.register_template_path('.')
7
10
  expect(Engine.template_paths.pop).to eq '.'
8
11
  end
12
+
13
+ it "does not duplicate paths" do
14
+ Engine.template_paths = []
15
+ Engine.register_template_path('foo')
16
+ Engine.register_template_path('foo')
17
+ expect(Engine.template_paths).to eq ['foo']
18
+ end
9
19
  end
10
20
 
11
21
  describe ".template!" do