yard 0.8.7.6 → 0.9.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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -1
  3. data/LICENSE +2 -2
  4. data/README.md +2 -2
  5. data/Rakefile +1 -1
  6. data/bin/yard +0 -0
  7. data/bin/yardoc +0 -0
  8. data/bin/yri +0 -0
  9. data/docs/GettingStarted.md +88 -6
  10. data/docs/images/handlers-class-diagram.png +0 -0
  11. data/docs/images/overview-class-diagram.png +0 -0
  12. data/docs/images/parser-class-diagram.png +0 -0
  13. data/docs/templates/default/fulldoc/html/full_list_tag.erb +6 -4
  14. data/lib/yard/autoload.rb +3 -0
  15. data/lib/yard/cli/yardoc.rb +1 -1
  16. data/lib/yard/code_objects/base.rb +4 -1
  17. data/lib/yard/code_objects/extra_file_object.rb +3 -1
  18. data/lib/yard/code_objects/proxy.rb +2 -2
  19. data/lib/yard/docstring.rb +11 -6
  20. data/lib/yard/handlers/base.rb +1 -2
  21. data/lib/yard/handlers/c/base.rb +19 -0
  22. data/lib/yard/handlers/c/handler_methods.rb +42 -8
  23. data/lib/yard/handlers/c/init_handler.rb +1 -1
  24. data/lib/yard/handlers/c/method_handler.rb +3 -3
  25. data/lib/yard/handlers/ruby/decorator_handler_methods.rb +132 -0
  26. data/lib/yard/handlers/ruby/legacy/private_class_method_handler.rb +1 -1
  27. data/lib/yard/handlers/ruby/private_class_method_handler.rb +6 -39
  28. data/lib/yard/handlers/ruby/private_constant_handler.rb +36 -30
  29. data/lib/yard/handlers/ruby/public_class_method_handler.rb +13 -0
  30. data/lib/yard/handlers/ruby/struct_handler_methods.rb +1 -0
  31. data/lib/yard/handlers/ruby/visibility_handler.rb +5 -8
  32. data/lib/yard/logging.rb +1 -0
  33. data/lib/yard/parser/ruby/ruby_parser.rb +2 -2
  34. data/lib/yard/parser/source_parser.rb +6 -6
  35. data/lib/yard/rake/yardoc_task.rb +2 -2
  36. data/lib/yard/serializers/file_system_serializer.rb +33 -1
  37. data/lib/yard/server/commands/display_file_command.rb +8 -3
  38. data/lib/yard/server/commands/display_object_command.rb +7 -3
  39. data/lib/yard/server/doc_server_helper.rb +2 -8
  40. data/lib/yard/server/doc_server_serializer.rb +2 -4
  41. data/lib/yard/server/router.rb +1 -1
  42. data/lib/yard/server/templates/default/fulldoc/html/css/custom.css +57 -8
  43. data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +2 -10
  44. data/lib/yard/server/templates/default/layout/html/script_setup.erb +1 -2
  45. data/lib/yard/server/templates/default/method_details/html/permalink.erb +3 -3
  46. data/lib/yard/server/templates/doc_server/processing/html/processing.erb +4 -4
  47. data/lib/yard/tags/directives.rb +1 -0
  48. data/lib/yard/tags/library.rb +9 -7
  49. data/lib/yard/tags/overload_tag.rb +4 -1
  50. data/lib/yard/templates/helpers/html_helper.rb +4 -3
  51. data/lib/yard/templates/template_options.rb +3 -0
  52. data/lib/yard/version.rb +1 -1
  53. data/spec/cli/command_parser_spec.rb +14 -14
  54. data/spec/cli/command_spec.rb +11 -11
  55. data/spec/cli/config_spec.rb +32 -32
  56. data/spec/cli/diff_spec.rb +86 -90
  57. data/spec/cli/display_spec.rb +6 -6
  58. data/spec/cli/gems_spec.rb +28 -28
  59. data/spec/cli/graph_spec.rb +8 -8
  60. data/spec/cli/help_spec.rb +8 -8
  61. data/spec/cli/i18n_spec.rb +33 -37
  62. data/spec/cli/list_spec.rb +2 -2
  63. data/spec/cli/markup_types_spec.rb +3 -3
  64. data/spec/cli/server_spec.rb +74 -88
  65. data/spec/cli/stats_spec.rb +14 -14
  66. data/spec/cli/yardoc_spec.rb +316 -321
  67. data/spec/cli/yri_spec.rb +45 -45
  68. data/spec/code_objects/base_spec.rb +174 -173
  69. data/spec/code_objects/class_object_spec.rb +65 -65
  70. data/spec/code_objects/code_object_list_spec.rb +13 -11
  71. data/spec/code_objects/constants_spec.rb +68 -58
  72. data/spec/code_objects/extra_file_object_spec.rb +71 -59
  73. data/spec/code_objects/macro_object_spec.rb +64 -64
  74. data/spec/code_objects/method_object_spec.rb +80 -72
  75. data/spec/code_objects/module_object_spec.rb +47 -47
  76. data/spec/code_objects/namespace_object_spec.rb +51 -51
  77. data/spec/code_objects/proxy_spec.rb +54 -54
  78. data/spec/config_spec.rb +104 -104
  79. data/spec/core_ext/array_spec.rb +5 -5
  80. data/spec/core_ext/file_spec.rb +33 -33
  81. data/spec/core_ext/hash_spec.rb +5 -5
  82. data/spec/core_ext/insertion_spec.rb +18 -18
  83. data/spec/core_ext/module_spec.rb +6 -6
  84. data/spec/core_ext/string_spec.rb +17 -17
  85. data/spec/core_ext/symbol_hash_spec.rb +42 -39
  86. data/spec/docstring_parser_spec.rb +65 -65
  87. data/spec/docstring_spec.rb +137 -130
  88. data/spec/handlers/alias_handler_spec.rb +39 -39
  89. data/spec/handlers/attribute_handler_spec.rb +35 -35
  90. data/spec/handlers/base_spec.rb +60 -51
  91. data/spec/handlers/c/alias_handler_spec.rb +6 -6
  92. data/spec/handlers/c/attribute_handler_spec.rb +12 -12
  93. data/spec/handlers/c/class_handler_spec.rb +35 -22
  94. data/spec/handlers/c/constant_handler_spec.rb +24 -22
  95. data/spec/handlers/c/init_handler_spec.rb +10 -10
  96. data/spec/handlers/c/method_handler_spec.rb +150 -65
  97. data/spec/handlers/c/mixin_handler_spec.rb +5 -5
  98. data/spec/handlers/c/module_handler_spec.rb +27 -15
  99. data/spec/handlers/c/override_comment_handler_spec.rb +14 -14
  100. data/spec/handlers/c/path_handler_spec.rb +8 -8
  101. data/spec/handlers/c/spec_helper.rb +10 -0
  102. data/spec/handlers/c/struct_handler_spec.rb +3 -3
  103. data/spec/handlers/class_condition_handler_spec.rb +18 -18
  104. data/spec/handlers/class_handler_spec.rb +97 -97
  105. data/spec/handlers/class_method_handler_shared_examples.rb +132 -0
  106. data/spec/handlers/class_variable_handler_spec.rb +3 -3
  107. data/spec/handlers/constant_handler_spec.rb +32 -29
  108. data/spec/handlers/decorator_handler_methods_spec.rb +405 -0
  109. data/spec/handlers/dsl_handler_spec.rb +108 -109
  110. data/spec/handlers/examples/constant_handler_001.rb.txt +4 -1
  111. data/spec/handlers/examples/visibility_handler_001.rb.txt +4 -0
  112. data/spec/handlers/exception_handler_spec.rb +23 -23
  113. data/spec/handlers/extend_handler_spec.rb +9 -9
  114. data/spec/handlers/legacy_base_spec.rb +60 -60
  115. data/spec/handlers/method_condition_handler_spec.rb +5 -5
  116. data/spec/handlers/method_handler_spec.rb +92 -92
  117. data/spec/handlers/mixin_handler_spec.rb +25 -25
  118. data/spec/handlers/module_function_handler_spec.rb +24 -24
  119. data/spec/handlers/module_handler_spec.rb +15 -15
  120. data/spec/handlers/private_class_method_handler_spec.rb +4 -48
  121. data/spec/handlers/private_constant_handler_spec.rb +8 -8
  122. data/spec/handlers/processor_spec.rb +12 -12
  123. data/spec/handlers/public_class_method_handler_spec.rb +10 -0
  124. data/spec/handlers/ruby/base_spec.rb +16 -16
  125. data/spec/handlers/ruby/legacy/base_spec.rb +20 -18
  126. data/spec/handlers/spec_helper.rb +1 -1
  127. data/spec/handlers/visibility_handler_spec.rb +25 -21
  128. data/spec/handlers/yield_handler_spec.rb +28 -28
  129. data/spec/i18n/locale_spec.rb +16 -16
  130. data/spec/i18n/message_spec.rb +8 -8
  131. data/spec/i18n/messages_spec.rb +14 -14
  132. data/spec/i18n/pot_generator_spec.rb +32 -32
  133. data/spec/i18n/text_spec.rb +22 -22
  134. data/spec/logging_spec.rb +12 -12
  135. data/spec/options_spec.rb +56 -56
  136. data/spec/parser/base_spec.rb +9 -9
  137. data/spec/parser/c_parser_spec.rb +50 -50
  138. data/spec/parser/ruby/ast_node_spec.rb +7 -7
  139. data/spec/parser/ruby/legacy/statement_list_spec.rb +106 -106
  140. data/spec/parser/ruby/legacy/token_list_spec.rb +27 -27
  141. data/spec/parser/ruby/ruby_parser_spec.rb +123 -113
  142. data/spec/parser/source_parser_spec.rb +224 -224
  143. data/spec/parser/tag_parsing_spec.rb +6 -7
  144. data/spec/rake/yardoc_task_spec.rb +38 -48
  145. data/spec/registry_spec.rb +143 -143
  146. data/spec/registry_store_spec.rb +165 -165
  147. data/spec/rubygems/doc_manager_spec.rb +38 -38
  148. data/spec/serializers/file_system_serializer_spec.rb +53 -33
  149. data/spec/serializers/yardoc_serializer_spec.rb +15 -15
  150. data/spec/server/adapter_spec.rb +15 -15
  151. data/spec/server/commands/base_spec.rb +29 -29
  152. data/spec/server/commands/library_command_spec.rb +12 -12
  153. data/spec/server/commands/static_file_command_spec.rb +28 -28
  154. data/spec/server/doc_server_helper_spec.rb +8 -8
  155. data/spec/server/doc_server_serializer_spec.rb +23 -18
  156. data/spec/server/rack_adapter_spec.rb +6 -6
  157. data/spec/server/router_spec.rb +39 -39
  158. data/spec/server/static_caching_spec.rb +16 -16
  159. data/spec/server/webrick_servlet_spec.rb +6 -7
  160. data/spec/server_spec.rb +3 -3
  161. data/spec/spec_helper.rb +11 -2
  162. data/spec/tags/default_factory_spec.rb +64 -64
  163. data/spec/tags/default_tag_spec.rb +5 -5
  164. data/spec/tags/directives_spec.rb +121 -121
  165. data/spec/tags/library_spec.rb +14 -14
  166. data/spec/tags/overload_tag_spec.rb +24 -24
  167. data/spec/tags/ref_tag_list_spec.rb +12 -12
  168. data/spec/templates/class_spec.rb +3 -3
  169. data/spec/templates/constant_spec.rb +4 -4
  170. data/spec/templates/engine_spec.rb +47 -48
  171. data/spec/templates/examples/class001.html +129 -101
  172. data/spec/templates/examples/class002.html +31 -27
  173. data/spec/templates/examples/method001.html +54 -47
  174. data/spec/templates/examples/method002.html +33 -28
  175. data/spec/templates/examples/method003.html +70 -64
  176. data/spec/templates/examples/method004.html +13 -9
  177. data/spec/templates/examples/method005.html +38 -32
  178. data/spec/templates/examples/module001.html +343 -339
  179. data/spec/templates/examples/module002.html +147 -124
  180. data/spec/templates/examples/module003.html +94 -81
  181. data/spec/templates/examples/module004.html +40 -33
  182. data/spec/templates/helpers/base_helper_spec.rb +91 -95
  183. data/spec/templates/helpers/html_helper_spec.rb +276 -279
  184. data/spec/templates/helpers/html_syntax_highlight_helper_spec.rb +16 -15
  185. data/spec/templates/helpers/markup/rdoc_markup_spec.rb +27 -34
  186. data/spec/templates/helpers/markup_helper_spec.rb +57 -57
  187. data/spec/templates/helpers/method_helper_spec.rb +20 -20
  188. data/spec/templates/helpers/shared_signature_examples.rb +33 -31
  189. data/spec/templates/helpers/text_helper_spec.rb +6 -6
  190. data/spec/templates/method_spec.rb +7 -7
  191. data/spec/templates/module_spec.rb +7 -7
  192. data/spec/templates/onefile_spec.rb +7 -7
  193. data/spec/templates/section_spec.rb +66 -69
  194. data/spec/templates/spec_helper.rb +1 -1
  195. data/spec/templates/tag_spec.rb +5 -5
  196. data/spec/templates/template_spec.rb +158 -158
  197. data/spec/verifier_spec.rb +52 -52
  198. data/templates/default/fulldoc/html/css/full_list.css +32 -31
  199. data/templates/default/fulldoc/html/css/style.css +212 -77
  200. data/templates/default/fulldoc/html/frames.erb +6 -15
  201. data/templates/default/fulldoc/html/full_list.erb +14 -21
  202. data/templates/default/fulldoc/html/full_list_class.erb +1 -1
  203. data/templates/default/fulldoc/html/full_list_file.erb +6 -4
  204. data/templates/default/fulldoc/html/full_list_method.erb +8 -6
  205. data/templates/default/fulldoc/html/js/app.js +100 -76
  206. data/templates/default/fulldoc/html/js/full_list.js +170 -135
  207. data/templates/default/fulldoc/html/setup.rb +50 -7
  208. data/templates/default/layout/html/breadcrumb.erb +0 -2
  209. data/templates/default/layout/html/headers.erb +2 -1
  210. data/templates/default/layout/html/layout.erb +16 -10
  211. data/templates/default/layout/html/script_setup.erb +1 -2
  212. data/templates/default/layout/html/search.erb +7 -2
  213. data/templates/default/layout/html/setup.rb +16 -0
  214. data/templates/default/method/html/header.erb +7 -6
  215. data/templates/default/module/html/attribute_summary.erb +1 -1
  216. data/templates/default/module/html/box_info.erb +24 -18
  217. data/templates/default/module/html/constant_summary.erb +9 -11
  218. data/templates/default/module/html/item_summary.erb +1 -1
  219. data/templates/default/module/html/method_summary.erb +1 -1
  220. data/templates/guide/fulldoc/html/setup.rb +1 -1
  221. data/yard.gemspec +1 -2
  222. metadata +10 -7
  223. data/spec/handlers/examples/private_class_method_handler_001.rb.txt +0 -9
  224. data/spec/handlers/examples/private_class_method_handler_002.rb.txt +0 -18
  225. data/spec/handlers/examples/private_class_method_handler_003.rb.txt +0 -11
@@ -0,0 +1,132 @@
1
+ shared_examples "class method visibility decorator" do
2
+ # Use let(:visibility) to specify the name of the x_class_method
3
+ # visibility decorator to test.
4
+
5
+ describe do
6
+ before {
7
+ StubbedSourceParser.parse_string <<-CODE
8
+ class A
9
+ def self.b; end
10
+ def self.c; end
11
+ def self.d; end
12
+ def self.e; end
13
+
14
+ #{visibility}_class_method(:c, :d)
15
+ #{visibility}_class_method("e")
16
+ end
17
+ CODE
18
+ }
19
+
20
+ it "handles private_class_method statement" do
21
+ expect(Registry.at('A.c').visibility).to eq visibility
22
+ expect(Registry.at('A.d').visibility).to eq visibility
23
+ expect(Registry.at('A.e').visibility).to eq visibility
24
+ end
25
+
26
+ # Issue #760
27
+ # https://github.com/lsegal/yard/issues/760
28
+ it "handles singleton classes" do
29
+ # Note: It's important to def a method within the singleton class or
30
+ # the bug may not trigger.
31
+ code = <<-CODE
32
+ class SingletonClass
33
+ private_class_method :new
34
+ def self.foo
35
+ "foo"
36
+ end
37
+ end
38
+ CODE
39
+
40
+ StubbedSourceParser.parse_string(code) # Should be successful.
41
+ end unless LEGACY_PARSER
42
+ end
43
+
44
+ describe "handles reopened class" do
45
+ before {
46
+ StubbedSourceParser.parse_string <<-CODE
47
+ class SingletonClass
48
+
49
+ #{'private' unless visibility.to_sym == :private}
50
+
51
+ # != visibility
52
+ def self.foo
53
+ 'foo'
54
+ end
55
+
56
+ # == visibility
57
+ def self.bar
58
+ end
59
+
60
+ # == visibility from reopening class.
61
+ def self.baz
62
+ end
63
+
64
+ #{visibility}_class_method :new, :bar
65
+
66
+ end
67
+ CODE
68
+
69
+ StubbedSourceParser.parse_string <<-CODE
70
+ # Reopening singleton class.
71
+ class SingletonClass
72
+ #{visibility}_class_method :baz
73
+
74
+ #{'private' unless visibility.to_sym == :private}
75
+ # != visibility from reopened class. (Verifies class was reopened.)
76
+ def self.bat
77
+ end
78
+
79
+ end
80
+ CODE
81
+ }
82
+
83
+ specify do
84
+ expect(Registry.at('SingletonClass.foo').visibility).not_to eq visibility
85
+ expect(Registry.at('SingletonClass.bar').visibility).to eq visibility
86
+ expect(Registry.at('SingletonClass.baz').visibility).to eq visibility
87
+ expect(Registry.at('SingletonClass.bat').visibility).not_to eq visibility
88
+ end
89
+ end unless LEGACY_PARSER # reopened class
90
+
91
+ describe "as method definition decorator" do
92
+ subject { Registry.at('SingletonClass.foo') }
93
+
94
+ # Valid as of Ruby 2.1.0:
95
+ # private_class_method def self.foo; end
96
+
97
+ let(:code) {
98
+ <<-CODE
99
+ class SingletonClass
100
+ # Valid Ruby 2.1.0 syntax.
101
+ #{method_def}
102
+ 'it works'
103
+ end
104
+ end
105
+ CODE
106
+ }
107
+
108
+ let(:method_def) { "#{visibility}_class_method def self.foo param1, param2" }
109
+
110
+ before { StubbedSourceParser.parse_string code }
111
+
112
+ it "handles self.foo" do
113
+ expect(subject.visibility).to eq visibility
114
+ end
115
+
116
+ it "handles parameters correctly" do
117
+ expect(subject.parameters.map { |p| p.first }).to eq ['param1', 'param2']
118
+ end
119
+
120
+ it "attaches documentation to method definition" do
121
+ expect(subject.docstring).to eq "Valid Ruby 2.1.0 syntax."
122
+ end
123
+
124
+ describe "handles SingletonClass.foo" do
125
+ let(:method_def) { "#{visibility}_class_method def SingletonClass.foo" }
126
+
127
+ specify do
128
+ expect(subject.visibility).to eq visibility
129
+ end
130
+ end
131
+ end unless LEGACY_PARSER
132
+ end
@@ -3,9 +3,9 @@ require File.dirname(__FILE__) + '/spec_helper'
3
3
  describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ClassVariableHandler" do
4
4
  before(:all) { parse_file :class_variable_handler_001, __FILE__ }
5
5
 
6
- it "should not parse class variables inside methods" do
6
+ it "does not parse class variables inside methods" do
7
7
  obj = Registry.at("A::B::@@somevar")
8
- obj.source.should == "@@somevar = \"hello\""
9
- obj.value.should == '"hello"'
8
+ expect(obj.source).to eq "@@somevar = \"hello\""
9
+ expect(obj.value).to eq '"hello"'
10
10
  end
11
11
  end
@@ -3,62 +3,65 @@ require File.dirname(__FILE__) + '/spec_helper'
3
3
  describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ConstantHandler" do
4
4
  before(:all) { parse_file :constant_handler_001, __FILE__ }
5
5
 
6
- it "should not parse constants inside methods" do
7
- Registry.at("A::B::SOMECONSTANT").source.should == "SOMECONSTANT= \"hello\""
6
+ it "does not parse constants inside methods" do
7
+ expect(Registry.at("A::B::SOMECONSTANT").source).to eq "SOMECONSTANT= \"hello\""
8
8
  end
9
9
 
10
- it "should only parse valid constants" do
11
- Registry.at("A::B::notaconstant").should be_nil
10
+ it "only parses valid constants" do
11
+ expect(Registry.at("A::B::notaconstant")).to be nil
12
12
  end
13
13
 
14
- it "should maintain newlines" do
15
- Registry.at("A::B::MYCONSTANT").value.gsub("\r", "").should == "A +\nB +\nC +\nD"
14
+ it "maintains newlines" do
15
+ expect(Registry.at("A::B::MYCONSTANT").value.gsub("\r", "")).to eq "A +\nB +\nC +\nD"
16
16
  end
17
17
 
18
- it "should turn Const = Struct.new(:sym) into class Const with attr :sym" do
18
+ it "turns Const = Struct.new(:sym) into class Const with attr :sym" do
19
19
  obj = Registry.at("MyClass")
20
- obj.should be_kind_of(CodeObjects::ClassObject)
20
+ expect(obj).to be_kind_of(CodeObjects::ClassObject)
21
21
  attrs = obj.attributes[:instance]
22
22
  [:a, :b, :c].each do |key|
23
- attrs.should have_key(key)
24
- attrs[key][:read].should_not be_nil
25
- attrs[key][:write].should_not be_nil
23
+ expect(attrs).to have_key(key)
24
+ expect(attrs[key][:read]).not_to be nil
25
+ expect(attrs[key][:write]).not_to be nil
26
26
  end
27
27
  end
28
28
 
29
- it "should turn Const = Struct.new('Name', :sym) into class Const with attr :sym" do
29
+ it "turns Const = Struct.new('Name', :sym) into class Const with attr :sym" do
30
30
  obj = Registry.at("NotMyClass")
31
- obj.should be_kind_of(CodeObjects::ClassObject)
31
+ expect(obj).to be_kind_of(CodeObjects::ClassObject)
32
32
  attrs = obj.attributes[:instance]
33
33
  [:b, :c].each do |key|
34
- attrs.should have_key(key)
35
- attrs[key][:read].should_not be_nil
36
- attrs[key][:write].should_not be_nil
34
+ expect(attrs).to have_key(key)
35
+ expect(attrs[key][:read]).not_to be nil
36
+ expect(attrs[key][:write]).not_to be nil
37
37
  end
38
38
 
39
- Registry.at("NotMyClass2").should be_nil
39
+ expect(Registry.at("NotMyClass2")).to be nil
40
40
  end
41
41
 
42
- it "should turn Const = Struct.new into empty struct" do
42
+ it "turns Const = Struct.new into empty struct" do
43
43
  obj = Registry.at("MyEmptyStruct")
44
- obj.should_not be_nil
45
- obj.attributes[:instance].should be_empty
44
+ expect(obj).not_to be nil
45
+ expect(obj.attributes[:instance]).to be_empty
46
46
  end
47
47
 
48
- it "should maintain docstrings on structs defined via constants" do
48
+ it "maintains docstrings on structs defined via constants" do
49
49
  obj = Registry.at("DocstringStruct")
50
- obj.should_not be_nil
51
- obj.docstring.should == "A crazy struct."
52
- obj.attributes[:instance].should_not be_empty
50
+ expect(obj).not_to be nil
51
+ expect(obj.docstring).to eq "A crazy struct."
52
+ expect(obj.attributes[:instance]).not_to be_empty
53
53
  a1 = Registry.at("DocstringStruct#bar")
54
54
  a2 = Registry.at("DocstringStruct#baz")
55
- a1.docstring.should == "An attr"
56
- a1.tag(:return).types.should == ["String"]
57
- a2.docstring.should == "Another attr"
58
- a2.tag(:return).types.should == ["Number"]
55
+ expect(a1.docstring).to eq "An attr"
56
+ expect(a1.tag(:return).types).to eq ["String"]
57
+ expect(a2.docstring).to eq "Another attr"
58
+ expect(a2.tag(:return).types).to eq ["Number"]
59
+ a3 = Registry.at("DocstringStruct#new_syntax")
60
+ expect(a3.docstring).to eq "Attribute defined with the new syntax"
61
+ expect(a3.tag(:return).types).to eq ["Symbol"]
59
62
  end
60
63
 
61
- it "should raise undocumentable error in 1.9 parser for Struct.new assignment to non-const" do
64
+ it "raises undocumentable error in 1.9 parser for Struct.new assignment to non-const" do
62
65
  undoc_error "nonconst = Struct.new"
63
66
  end unless LEGACY_PARSER
64
67
  end
@@ -0,0 +1,405 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "YARD::Handlers::Ruby::DecoratorHandlerMethods" do
4
+ describe "#process_decorator" do
5
+
6
+ # Create a YARD decorator handler.
7
+ # @param name [Symbol] name of the mock decorator
8
+ def create_test_handler(name)
9
+ data[name] = {}
10
+
11
+ local_mock_handler_opts = mock_handler_opts
12
+ local_nodes = nodes
13
+ local_data = data[name]
14
+
15
+ Class.new YARD::Handlers::Ruby::Base do
16
+ include YARD::Handlers::Ruby::DecoratorHandlerMethods
17
+
18
+ handles method_call(:"#{name}_decorator")
19
+ namespace_only
20
+
21
+ process do
22
+ # process_decorator params written like this due to Ruby 1.8.
23
+ # A modern handler should splat local_nodes.
24
+ local_data[:return] =
25
+ process_decorator *(local_nodes + [local_mock_handler_opts]) do |method, node, name|
26
+ local_data[:method] = method
27
+ local_data[:node] = node
28
+ local_data[:name] = name
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ # Generate method definition.
35
+ # @param symbols [Symbol] method names
36
+ # @return [String] method definition code
37
+ def make_defs(*symbols)
38
+ symbols.map { |s|
39
+ s = "self.#{s}" if mock_handler_opts[:scope] == :class
40
+ "def #{s}; end"
41
+ }.join("\n")
42
+ end
43
+
44
+ # Generate an AST for the given source code string.
45
+ def make_ast(code)
46
+ YARD::Parser::Ruby::RubyParser.new(code, nil).parse.ast
47
+ end
48
+
49
+ subject { data[:mock] }
50
+
51
+ let(:data) { Hash.new }
52
+ let(:nodes) { [] }
53
+ let(:mock_handler_opts) { {:scope => :instance} }
54
+ let(:class_name) { 'DecoratorTest' }
55
+ let(:docstring) { 'the foo method' }
56
+ let(:param_string) { 'def foo param1, param2; end' }
57
+ let(:method_defs) { [] }
58
+ let(:method_string) { "#{class_name}#foo" }
59
+ let(:code) {"
60
+ class #{class_name}
61
+ #{make_defs *method_defs}
62
+ # #{docstring}
63
+ mock_decorator #{param_string}
64
+ end
65
+ "}
66
+
67
+ before {
68
+ Registry.clear
69
+ YARD::Handlers::Base.clear_subclasses
70
+
71
+ create_test_handler :mock
72
+ create_test_handler :first
73
+ create_test_handler :second
74
+ create_test_handler :third
75
+
76
+ StubbedSourceParser.parse_string code
77
+ }
78
+
79
+ it "returns an array of hashes containing the method proxy, node, and name" do
80
+ expect(subject[:return]).to be_an Array
81
+ expect(subject[:return].first[:name].to_s).to eq 'foo'
82
+ expect(subject[:return].first[:method].to_s).to eq method_string
83
+ expect(subject[:return].first[:node]).to be_a YARD::Parser::Ruby::AstNode
84
+ end
85
+
86
+ describe "method is a MethodObject if the method has been defined" do
87
+ let(:code) {"class DecoratorTest; mock_decorator def foo; end; end"}
88
+
89
+ specify do
90
+ expect(subject[:return].first[:method]) \
91
+ .to be_a YARD::CodeObjects::MethodObject
92
+ end
93
+ end
94
+
95
+ describe "method is a Proxy if the method has not been defined" do
96
+ let(:code) {"class DecoratorTest; mock_decorator :foo; end"}
97
+
98
+ specify do
99
+ expect(subject[:return].first[:method]).to be_a YARD::CodeObjects::Proxy
100
+ end
101
+ end
102
+
103
+ specify "block yields method proxy, node, name" do
104
+ expect(subject[:name]).to be_a Symbol
105
+ expect(subject[:name]).to eq :foo
106
+
107
+ expect(subject[:method]).to be_a YARD::CodeObjects::MethodObject
108
+ expect(subject[:method].to_s).to eq method_string
109
+
110
+ expect(subject[:node]).to be_a YARD::Parser::Ruby::AstNode
111
+ end
112
+
113
+ describe "capitalized method names" do
114
+ let(:method_defs) { [:Foo] }
115
+ let(:param_string) { 'def Foo param1, param2; end' }
116
+
117
+ specify do
118
+ expect(subject[:method].to_s).to eq "#{class_name}#Foo"
119
+ end
120
+ end
121
+
122
+ describe "nodes argument" do
123
+ subject { data[:mock][:return].map { |h| h[:method].to_s } }
124
+
125
+ describe "assumes all params refer to methods by default" do
126
+ let(:method_defs) { [:foo, :bar] }
127
+ let(:param_string) { method_defs.map(&:inspect).join(',') }
128
+ let(:nodes) { [] }
129
+
130
+ specify do
131
+ expect(subject).to eq ["#{class_name}#foo", "#{class_name}#bar"]
132
+ end
133
+ end
134
+
135
+ describe "can specify which params to capture as methods" do
136
+ let(:method_defs) { [:foo, :bar, :baz, :bat] }
137
+ let(:parameters) {
138
+ [:option_1, :baz, :bat, :option_2, :foo, :bar].map do |s|
139
+ make_ast s.inspect
140
+ end
141
+ }
142
+
143
+ describe "as a single param" do
144
+ let(:nodes) { parameters[4] }
145
+
146
+ specify do
147
+ expect(subject).to eq ["#{class_name}#foo"]
148
+ end
149
+ end
150
+
151
+ describe "as a list of params" do
152
+ let(:nodes) { [parameters[4], parameters[5]] }
153
+
154
+ specify do
155
+ expect(subject).to eq ["#{class_name}#foo", "#{class_name}#bar"]
156
+ end
157
+ end
158
+
159
+ describe "as a range" do
160
+ let(:nodes) { parameters[4..-1] }
161
+
162
+ specify do
163
+ expect(subject).to eq ["#{class_name}#foo", "#{class_name}#bar"]
164
+ end
165
+ end
166
+
167
+ describe "as multiple ranges" do
168
+ # Written like this due to Ruby 1.8. Can also splat the ranges as
169
+ # separate params:
170
+ # *parameters[1..2], *parameters[4..-1]
171
+ let(:nodes) { parameters[1..2] + parameters[4..-1] }
172
+
173
+ specify do
174
+ expect(subject).to eq [
175
+ "#{class_name}#baz",
176
+ "#{class_name}#bat",
177
+ "#{class_name}#foo",
178
+ "#{class_name}#bar"
179
+ ]
180
+ end
181
+ end
182
+ end
183
+
184
+ describe "can select no nodes by passing nil" do
185
+ let(:nodes) { [nil] }
186
+
187
+ specify do
188
+ expect(subject).to eq []
189
+ end
190
+ end
191
+ end
192
+
193
+ describe "scope option" do
194
+ describe "defaults to :instance" do
195
+ let(:mock_handler_opts) { {} }
196
+
197
+ specify do
198
+ expect(subject[:return].first[:method].to_s).to eq method_string
199
+ end
200
+ end
201
+
202
+ describe "creates method proxies" do
203
+
204
+ shared_examples "decorator helper scope" do
205
+ let(:param_string) { decorator_params.map(&:inspect).join(',') }
206
+
207
+ describe "for symbols" do
208
+ let(:decorator_params) { [:foo, :bar] }
209
+
210
+ specify do
211
+ expect(subject.count).to eq decorator_params.count
212
+
213
+ subject.each_with_index do |_, i|
214
+ expect(subject[i]).to be_a YARD::CodeObjects::MethodObject
215
+ expect(subject[i].to_s).to eq \
216
+ "#{class_name}#{mock_handler_opts[:scope] == :class ? '.' : '#'}#{decorator_params[i]}"
217
+ end
218
+ end
219
+ end
220
+
221
+ describe "for string literals" do
222
+ let(:decorator_params) { ['foo', 'bar'] }
223
+
224
+ specify do
225
+ expect(subject.count).to eq decorator_params.count
226
+
227
+ subject.each_with_index do |_, i|
228
+ expect(subject[i]).to be_a YARD::CodeObjects::MethodObject
229
+ expect(subject[i].to_s).to eq \
230
+ "#{class_name}#{mock_handler_opts[:scope] == :class ? '.' : '#'}#{decorator_params[i]}"
231
+ end
232
+ end
233
+ end
234
+
235
+ describe "for methods" do
236
+ let(:param_string) { decorator_params.join(',') }
237
+ let(:decorator_params) {[
238
+ "def #{'self.' if mock_handler_opts[:scope] == :class}foo f1, f2; end",
239
+ "def #{'self.' if mock_handler_opts[:scope] == :class}bar b1, b2; end"
240
+ ]}
241
+
242
+ specify do
243
+ expect(subject.count).to eq decorator_params.count
244
+
245
+ subject.each_with_index do |_, i|
246
+ expect(subject[i]).to be_a YARD::CodeObjects::MethodObject
247
+ expect(subject[i].to_s).to eq \
248
+ class_name +
249
+ (mock_handler_opts[:scope] == :class ? '.' : '#') +
250
+ decorator_params[i].split(' ')[1][/\w+$/]
251
+ end
252
+ end
253
+ end
254
+ end # decorator helper scope shared examples
255
+
256
+ subject { data[:mock][:return].map { |h| h[:method] } }
257
+
258
+ let(:docstring) { 'the foo method' }
259
+ let(:method_defs) { [:foo, :bar] }
260
+
261
+ describe "for :instance" do
262
+ let(:mock_handler_opts) { {:scope => :instance} }
263
+
264
+ include_examples "decorator helper scope"
265
+ end
266
+
267
+ describe "for :class" do
268
+ let(:mock_handler_opts) { {:scope => :class} }
269
+
270
+ include_examples "decorator helper scope"
271
+ end
272
+ end
273
+ end
274
+
275
+ describe "docstring from decorator" do
276
+ subject { Registry.at method_string }
277
+
278
+ specify "attaches to method definitions as decorator parameters" do
279
+ expect(subject.docstring).to eq docstring
280
+ end
281
+
282
+ describe "does not attach" do
283
+ describe "to undefined methods" do
284
+ let(:code) {"
285
+ class #{class_name}
286
+ # #{docstring}
287
+ mock_decorator :foo
288
+ end
289
+ "}
290
+
291
+ specify do
292
+ expect(subject).not_to respond_to :docstring
293
+ end
294
+ end
295
+
296
+ describe "to methods with existing docstring" do
297
+ let(:code) {"
298
+ class #{class_name}
299
+
300
+ # original docstring
301
+ def foo; end
302
+
303
+ # #{docstring}
304
+ mock_decorator :foo
305
+ end
306
+ "}
307
+
308
+ specify do
309
+ expect(subject.docstring).to eq 'original docstring'
310
+ end
311
+ end
312
+ end
313
+ end
314
+
315
+ describe "chained decorators" do
316
+ subject { Registry.at method_string }
317
+
318
+ let(:param_string) { 'def foo param1, param2; end' }
319
+ let(:code) {"
320
+ class #{class_name}
321
+ #{make_defs *method_defs}
322
+ # #{docstring}
323
+ first_decorator second_decorator third_decorator #{param_string}
324
+ end
325
+ "}
326
+
327
+ specify "register nested method defs" do
328
+ expect(subject).to be_a YARD::CodeObjects::MethodObject
329
+ end
330
+
331
+ describe "transfer docstring to decorated method defs" do
332
+ specify do
333
+ expect(subject.docstring).to eq docstring
334
+ end
335
+
336
+ describe "unless opt-out param is set" do
337
+ let(:mock_handler_opts) { {:transfer_docstring => false} }
338
+
339
+ specify do
340
+ expect(subject.docstring.empty?).to be true
341
+ end
342
+ end
343
+ end
344
+
345
+ describe "don't transfer docstring to referenced methods" do
346
+ let(:method_defs) { [:foo] }
347
+ let(:param_string) { ':foo' }
348
+
349
+ specify do
350
+ expect(subject.docstring.empty?).to be true
351
+ end
352
+ end
353
+
354
+ specify "don't transfer docstring to other decorators" do
355
+ expect(Registry.at("#{class_name}#second_decorator")) \
356
+ .not_to respond_to :docstring
357
+
358
+ expect(Registry.at("#{class_name}#third_decorator")) \
359
+ .not_to respond_to :docstring
360
+ end
361
+
362
+ describe "transfer source to decorated method defs" do
363
+ specify do
364
+ expect(subject.source).to eq code.lines.to_a[-3].strip
365
+ end
366
+
367
+ describe "unless opt-out param is set" do
368
+ let(:mock_handler_opts) { {:transfer_source => false} }
369
+
370
+ specify do
371
+ expect(subject.source).to eq param_string
372
+ end
373
+ end
374
+ end
375
+
376
+ describe "don't transfer source to referenced methods" do
377
+ let(:method_defs) { [:foo] }
378
+ let(:param_string) { ':foo' }
379
+
380
+ specify do
381
+ expect(subject.source).to eq make_defs(*method_defs)
382
+ end
383
+ end
384
+
385
+ describe "are tagged" do
386
+ let(:method_defs) { [:foo, :bar] }
387
+ let(:param_string) { method_defs.map(&:inspect).join(',') }
388
+
389
+ specify do
390
+ expect(subject.tags.count).to eq 3
391
+
392
+ subject.tags.each do |tag|
393
+ expect(tag.tag_name).to eq 'decorator'
394
+ end
395
+
396
+ expect(subject.tags.map(&:text)).to eq [
397
+ 'third_decorator',
398
+ 'second_decorator',
399
+ 'first_decorator'
400
+ ]
401
+ end
402
+ end
403
+ end
404
+ end # process_decorator
405
+ end unless LEGACY_PARSER