yard 0.5.4 → 0.5.5

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 (59) hide show
  1. data/.yardopts +1 -0
  2. data/ChangeLog +181 -0
  3. data/LEGAL +74 -0
  4. data/LICENSE +1 -1
  5. data/README.md +15 -8
  6. data/lib/yard.rb +3 -3
  7. data/lib/yard/cli/yard_graph.rb +10 -10
  8. data/lib/yard/cli/yardoc.rb +29 -9
  9. data/lib/yard/code_objects/base.rb +1 -1
  10. data/lib/yard/code_objects/class_object.rb +1 -1
  11. data/lib/yard/code_objects/module_object.rb +1 -1
  12. data/lib/yard/code_objects/proxy.rb +1 -1
  13. data/lib/yard/docstring.rb +2 -2
  14. data/lib/yard/handlers/ruby/constant_handler.rb +2 -2
  15. data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +64 -1
  16. data/lib/yard/handlers/ruby/legacy/constant_handler.rb +2 -2
  17. data/lib/yard/handlers/ruby/legacy/method_handler.rb +11 -0
  18. data/lib/yard/handlers/ruby/method_handler.rb +11 -0
  19. data/lib/yard/parser/ruby/legacy/statement_list.rb +3 -3
  20. data/lib/yard/parser/source_parser.rb +2 -2
  21. data/lib/yard/tags/default_factory.rb +9 -6
  22. data/lib/yard/templates/helpers/base_helper.rb +14 -4
  23. data/lib/yard/templates/helpers/html_helper.rb +16 -22
  24. data/lib/yard/templates/helpers/method_helper.rb +1 -1
  25. data/lib/yard/templates/helpers/module_helper.rb +1 -2
  26. data/spec/cli/yardoc_spec.rb +1 -1
  27. data/spec/code_objects/class_object_spec.rb +1 -0
  28. data/spec/code_objects/module_object_spec.rb +1 -0
  29. data/spec/docstring_spec.rb +14 -0
  30. data/spec/handlers/class_condition_handler_spec.rb +8 -10
  31. data/spec/handlers/examples/method_handler_001.rb.txt +4 -0
  32. data/spec/handlers/method_handler_spec.rb +7 -0
  33. data/spec/parser/ruby/legacy/statement_list_spec.rb +14 -0
  34. data/spec/parser/source_parser_spec.rb +7 -0
  35. data/spec/tags/default_factory_spec.rb +1 -0
  36. data/spec/templates/examples/class001.html +5 -5
  37. data/spec/templates/examples/method001.html +1 -1
  38. data/spec/templates/examples/module001.html +4 -4
  39. data/spec/templates/helpers/base_helper_spec.rb +18 -1
  40. data/spec/templates/helpers/html_helper_spec.rb +2 -1
  41. data/spec/templates/module_spec.rb +5 -2
  42. data/templates/default/docstring/html/abstract.erb +2 -2
  43. data/templates/default/docstring/html/deprecated.erb +1 -1
  44. data/templates/default/docstring/html/note.erb +2 -2
  45. data/templates/default/docstring/html/private.erb +4 -0
  46. data/templates/default/docstring/html/todo.erb +2 -2
  47. data/templates/default/docstring/setup.rb +6 -1
  48. data/templates/default/docstring/text/private.erb +2 -0
  49. data/templates/default/fulldoc/html/css/style.css +7 -3
  50. data/templates/default/fulldoc/html/js/app.js +27 -0
  51. data/templates/default/fulldoc/html/setup.rb +1 -1
  52. data/templates/default/module/html/attribute_summary.erb +1 -1
  53. data/templates/default/module/html/box_info.erb +1 -1
  54. data/templates/default/module/html/header.erb +2 -1
  55. data/templates/default/module/html/item_summary.erb +1 -0
  56. data/templates/default/module/html/method_summary.erb +4 -1
  57. data/templates/default/module/text/extends.erb +2 -2
  58. data/templates/default/tags/html/see.erb +1 -1
  59. metadata +5 -2
@@ -254,7 +254,7 @@ module YARD
254
254
  super
255
255
  end
256
256
  end
257
-
257
+
258
258
  # Accesses a custom attribute on the object
259
259
  # @param [#to_s] key the name of the custom attribute
260
260
  # @return [Object, nil] the custom attribute or nil if not found.
@@ -45,7 +45,7 @@ module YARD::CodeObjects
45
45
  [self] + list.map do |m|
46
46
  next m unless m.respond_to?(:inheritance_tree)
47
47
  m.inheritance_tree(include_mods)
48
- end.flatten
48
+ end.flatten.uniq
49
49
  end
50
50
 
51
51
  # Returns the list of methods matching the options hash. Returns
@@ -12,7 +12,7 @@ module YARD::CodeObjects
12
12
  next if m == self
13
13
  next m unless m.respond_to?(:inheritance_tree)
14
14
  m.inheritance_tree(true)
15
- end.compact.flatten
15
+ end.compact.flatten.uniq
16
16
  end
17
17
  end
18
18
  end
@@ -127,7 +127,7 @@ module YARD
127
127
  false
128
128
  end
129
129
  end
130
-
130
+
131
131
  # Returns the class name of the object the proxy is mimicking, if
132
132
  # resolved. Otherwise returns +Proxy+.
133
133
  # @return [Class] the resolved object's class or +Proxy+
@@ -149,8 +149,8 @@ module YARD
149
149
  end
150
150
 
151
151
  # Creates a {Tags::RefTag}
152
- def create_ref_tag(tag_name, name, object)
153
- @ref_tags << Tags::RefTagList.new(tag_name, object, name)
152
+ def create_ref_tag(tag_name, name, object_name)
153
+ @ref_tags << Tags::RefTagList.new(tag_name, P(object, object_name), name)
154
154
  end
155
155
 
156
156
  # Creates a tag from the {Tags::DefaultFactory tag factory}.
@@ -39,8 +39,8 @@ class YARD::Handlers::Ruby::ConstantHandler < YARD::Handlers::Ruby::Base
39
39
  name = node.jump(:ident).source
40
40
  klass.attributes[scope][name] = SymbolHash[:read => nil, :write => nil]
41
41
  {read: name, write: "#{name}="}.each do |type, meth|
42
- klass.attributes[scope][name][type] = MethodObject.new(klass, meth, scope)
42
+ klass.attributes[scope][name][type] = register MethodObject.new(klass, meth, scope)
43
43
  end
44
44
  end
45
45
  end
46
- end
46
+ end
@@ -1,8 +1,71 @@
1
1
  class YARD::Handlers::Ruby::Legacy::ClassConditionHandler < YARD::Handlers::Ruby::Legacy::Base
2
2
  namespace_only
3
- handles TkIF, TkELSIF, TkELSE, TkUNLESS
3
+ handles TkIF, TkELSIF, TkUNLESS
4
4
 
5
5
  process do
6
+ condition = parse_condition
7
+ if condition == nil
8
+ # Parse both blocks if we're unsure of the condition
9
+ parse_then_block
10
+ parse_else_block
11
+ elsif condition
12
+ parse_then_block
13
+ else
14
+ parse_else_block
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ # Parses the condition part of the if/unless statement
21
+ #
22
+ # @return [true, false, nil] true if the condition can be definitely
23
+ # parsed to true, false if not, and nil if the condition cannot be
24
+ # parsed with certainty (it's dynamic)
25
+ def parse_condition
26
+ condition = nil
27
+
28
+ # Right now we can handle very simple unary conditions like:
29
+ # if true
30
+ # if false
31
+ # if 0
32
+ # if 100 (not 0)
33
+ # if defined? SOME_CONSTANT
34
+ #
35
+ # The last case will do a lookup in the registry and then one
36
+ # in the Ruby world (using eval).
37
+ case statement.tokens[1..-1].to_s.strip
38
+ when /^(\d+)$/
39
+ condition = $1 != "0"
40
+ when /^defined\?\s*\(?(.+?)\)?$/
41
+ # defined? keyword used, let's see if we can look up the name
42
+ # in the registry, then we'll try using Ruby's powers. eval() is not
43
+ # *too* dangerous here since code is not actually executed.
44
+ name = $1
45
+ obj = YARD::Registry.resolve(namespace, name, true)
46
+ condition = true if obj || Object.instance_eval("defined? #{name}")
47
+ when "true"
48
+ condition = true
49
+ when "false"
50
+ condition = false
51
+ end
52
+
53
+ if TkUNLESS === statement.tokens.first
54
+ condition = !condition if condition != nil
55
+ end
56
+ condition
57
+ end
58
+
59
+ def parse_then_block
6
60
  parse_block
7
61
  end
62
+
63
+ def parse_else_block
64
+ stmtlist = YARD::Parser::Ruby::Legacy::StatementList
65
+ stmtlist.new(statement.block).each do |stmt|
66
+ if TkELSE === stmt.tokens.first
67
+ parser.process(stmtlist.new(stmt.block))
68
+ end
69
+ end
70
+ end
8
71
  end
@@ -25,8 +25,8 @@ class YARD::Handlers::Ruby::Legacy::ConstantHandler < YARD::Handlers::Ruby::Lega
25
25
  tokval_list(YARD::Parser::Ruby::Legacy::TokenList.new(parameters), TkSYMBOL).each do |name|
26
26
  klass.attributes[scope][name] = SymbolHash[:read => nil, :write => nil]
27
27
  {:read => name, :write => "#{name}="}.each do |type, meth|
28
- klass.attributes[scope][name][type] = MethodObject.new(klass, meth, scope)
28
+ klass.attributes[scope][name][type] = register MethodObject.new(klass, meth, scope)
29
29
  end
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -42,6 +42,17 @@ class YARD::Handlers::Ruby::Legacy::MethodHandler < YARD::Handlers::Ruby::Legacy
42
42
  end
43
43
  end
44
44
 
45
+ if obj.has_tag?(:option)
46
+ # create the options parameter if its missing
47
+ obj.tags(:option).each do |option|
48
+ expected_param = option.name
49
+ unless obj.tags(:param).find {|x| x.name == expected_param }
50
+ new_tag = YARD::Tags::Tag.new(:param, "a customizable set of options", "Hash", expected_param)
51
+ obj.docstring.add_tag(new_tag)
52
+ end
53
+ end
54
+ end
55
+
45
56
  if info = obj.attr_info
46
57
  if meth.to_s =~ /=$/ # writer
47
58
  info[:write] = obj if info[:read]
@@ -39,6 +39,17 @@ class YARD::Handlers::Ruby::MethodHandler < YARD::Handlers::Ruby::Base
39
39
  end
40
40
  end
41
41
 
42
+ if obj.has_tag?(:option)
43
+ # create the options parameter if its missing
44
+ obj.tags(:option).each do |option|
45
+ expected_param = option.name
46
+ unless obj.tags(:param).find {|x| x.name == expected_param }
47
+ new_tag = YARD::Tags::Tag.new(:param, "a customizable set of options", "Hash", expected_param)
48
+ obj.docstring.add_tag(new_tag)
49
+ end
50
+ end
51
+ end
52
+
42
53
  if info = obj.attr_info
43
54
  if meth.to_s =~ /=$/ # writer
44
55
  info[:write] = obj if info[:read]
@@ -6,7 +6,7 @@ module YARD
6
6
  # The following list of tokens will require a block to be opened
7
7
  # if used at the beginning of a statement.
8
8
  OPEN_BLOCK_TOKENS = [TkCLASS, TkDEF, TkMODULE, TkUNTIL,
9
- TkIF, TkUNLESS, TkWHILE, TkFOR, TkCASE]
9
+ TkIF, TkELSIF, TkUNLESS, TkWHILE, TkFOR, TkCASE]
10
10
 
11
11
  ##
12
12
  # Creates a new statement list
@@ -215,7 +215,7 @@ module YARD
215
215
  #
216
216
  # @param [RubyToken::Token] tk the token to process
217
217
  def process_simple_block_opener(tk)
218
- return unless [TkLBRACE, TkDO, TkBEGIN].include?(tk.class) &&
218
+ return unless [TkLBRACE, TkDO, TkBEGIN, TkELSE].include?(tk.class) &&
219
219
  # Make sure hashes are parsed as hashes, not as blocks
220
220
  (@last_ns_tk.nil? || @last_ns_tk.lex_state != EXPR_BEG)
221
221
 
@@ -314,7 +314,7 @@ module YARD
314
314
  if [TkLPAREN, TkLBRACK, TkLBRACE, TkDO, TkBEGIN].include?(tk.class)
315
315
  @level += 1
316
316
  elsif OPEN_BLOCK_TOKENS.include?(tk.class)
317
- @level += 1 unless @last_ns_tk.class == TkALIAS
317
+ @level += 1 unless @last_ns_tk.class == TkALIAS || tk.class == TkELSIF
318
318
  elsif [TkRPAREN, TkRBRACK, TkRBRACE, TkEND].include?(tk.class) && @level > 0
319
319
  @level -= 1
320
320
  end
@@ -149,8 +149,8 @@ module YARD
149
149
  def parse(content = __FILE__)
150
150
  case content
151
151
  when String
152
- @file = content
153
- content = convert_encoding(File.read_binary(content))
152
+ @file = File.cleanpath(content)
153
+ content = convert_encoding(File.read_binary(file))
154
154
  checksum = Registry.checksum_for(content)
155
155
  return if Registry.checksums[file] == checksum
156
156
 
@@ -110,20 +110,20 @@ module YARD
110
110
  [title, desc]
111
111
  end
112
112
 
113
- # Parses a [], <>, {} or () block at the beginning of a line of text into a list of
114
- # comma delimited values. Returns the text be
113
+ # Parses a [], <>, {} or () block at the beginning of a line of text
114
+ # into a list of comma delimited values.
115
115
  #
116
116
  # @example
117
117
  # obj.parse_types('[String, Array<Hash, String>, nil]') # => [nil, ['String', 'Array<Hash, String>', 'nil'], ""]
118
118
  # obj.parse_types('b<String> A string') # => ['b', ['String'], 'A string']
119
119
  #
120
- # @return [String, Array<String>] the text before the type list (or nil), followed by the type list parsed
121
- # into an array of strings, followed by the text following the type list.
122
- # @return [nil] if no type list is present.
120
+ # @return [Array(String, Array<String>, String)] the text before the type
121
+ # list (or nil), followed by the type list parsed into an array of
122
+ # strings, followed by the text following the type list.
123
123
  def extract_types_and_name_from_text(text, opening_types = TYPELIST_OPENING_CHARS, closing_types = TYPELIST_CLOSING_CHARS)
124
124
  s, e = 0, 0
125
125
  before = ''
126
- list, level = [''], 0
126
+ list, level, seen_space = [''], 0, false
127
127
  text.split(//).each_with_index do |c, i|
128
128
  if opening_types.include?(c)
129
129
  list.last << c if level > 0
@@ -136,7 +136,10 @@ module YARD
136
136
  elsif c == ',' && level == 1
137
137
  list.push ''
138
138
  elsif c =~ /\S/ && level == 0
139
+ break e = i if seen_space && list == ['']
139
140
  before << c
141
+ elsif c =~ /\s/ && level == 0 && !before.empty?
142
+ seen_space = true
140
143
  elsif level >= 1
141
144
  list.last << c
142
145
  end
@@ -14,9 +14,15 @@ module YARD::Templates::Helpers
14
14
  end
15
15
 
16
16
  def linkify(*args)
17
- # The :// character sequence exists in no valid object path but just about every URL scheme.
18
- if args.first.is_a?(String) && args.first.include?("://")
19
- link_url(*args)
17
+ if args.first.is_a?(String)
18
+ case args.first
19
+ when %r{://}, /^mailto:/
20
+ link_url(args[0], args[1], {:target => '_parent'}.merge(args[2]||{}))
21
+ when /^file:(\S+?)(?:#(\S+))?$/
22
+ link_file($1, args[1] ? args[1] : $1, $2)
23
+ else
24
+ link_object(*args)
25
+ end
20
26
  else
21
27
  link_object(*args)
22
28
  end
@@ -35,10 +41,14 @@ module YARD::Templates::Helpers
35
41
  end
36
42
  end
37
43
 
38
- def link_url(url)
44
+ def link_url(url, title = nil, params = nil)
39
45
  url
40
46
  end
41
47
 
48
+ def link_file(filename, title = nil, anchor = nil)
49
+ filename
50
+ end
51
+
42
52
  def format_types(list, brackets = true)
43
53
  list.nil? || list.empty? ? "" : (brackets ? "(#{list.join(", ")})" : list.join(", "))
44
54
  end
@@ -122,33 +122,27 @@ module YARD
122
122
  def resolve_links(text)
123
123
  code_tags = 0
124
124
  text.gsub(/<(\/)?(pre|code|tt)|\{(\S+?)(?:\s(.*?\S))?\}(?=[\W<]|.+<\/|$)/) do |str|
125
- tag = $2
126
- closed = $1
125
+ closed, tag, name, title = $1, $2, $3, $4
127
126
  if tag
128
127
  code_tags += (closed ? -1 : 1)
129
128
  next str
130
129
  end
131
130
  next str unless code_tags == 0
132
131
 
133
- name = $3
134
- title = $4 || name
135
-
136
- case name
137
- when %r{://}, /^mailto:/
138
- link_url(name, title, :target => '_parent')
139
- when /^file:(\S+?)(?:#(\S+))?$/
140
- link_file($1, title == name ? $1 : title, $2)
132
+ if object.is_a?(String)
133
+ object
141
134
  else
142
- if object.is_a?(String)
143
- obj = name
135
+ link = linkify(name, title)
136
+ if link == name || link == title
137
+ match = text[/(.{0,20}\{.*?#{Regexp.quote name}.*?\}.{0,20})/, 1]
138
+ log.warn "In file `#{object.file}':#{object.line}: Cannot resolve link to #{name} from text" + (match ? ":" : ".")
139
+ log.warn '...' + match.gsub(/\n/,"\n\t") + '...' if match
140
+ end
141
+
142
+ if name =~ %r{://} || name =~ /^(mailto|file):/
143
+ link
144
144
  else
145
- obj = Registry.resolve(object, name, true, true)
146
- if obj.is_a?(CodeObjects::Proxy)
147
- match = text[/(.{0,20}\{.*?#{Regexp.quote name}.*?\}.{0,20})/, 1]
148
- log.warn "In file `#{object.file}':#{object.line}: Cannot resolve link to #{obj.path} from text" + (match ? ":" : ".")
149
- log.warn '...' + match.gsub(/\n/,"\n\t") + '...' if match
150
- end
151
- "<tt>" + linkify(obj, title) + "</tt>"
145
+ "<tt>" + link + "</tt>"
152
146
  end
153
147
  end
154
148
  end
@@ -199,17 +193,17 @@ module YARD
199
193
  title = h(obj.to_s)
200
194
  end
201
195
  return title unless serializer
202
-
203
196
  return title if obj.is_a?(CodeObjects::Proxy)
204
-
197
+
205
198
  link = url_for(obj, anchor, relative)
206
199
  link ? link_url(link, title, :title => "#{obj.path} (#{obj.type})") : title
207
200
  end
208
201
 
209
202
  def link_url(url, title = nil, params = {})
203
+ title ||= url
210
204
  params = SymbolHash.new(false).update(
211
205
  :href => url,
212
- :title => h(title || url)
206
+ :title => h(title)
213
207
  ).update(params)
214
208
  "<a #{tag_attrs(params)}>#{title}</a>"
215
209
  end
@@ -6,7 +6,7 @@ module YARD
6
6
  params = object.parameters
7
7
  if object.has_tag?(:yield) || object.has_tag?(:yieldparam)
8
8
  params.reject! do |param|
9
- param[0][0,1] == "&" &&
9
+ param[0].to_s[0,1] == "&" &&
10
10
  !object.tags(:param).any? {|t| t.name == param[0][1..-1] }
11
11
  end
12
12
  end
@@ -4,7 +4,6 @@ module YARD
4
4
  module ModuleHelper
5
5
  def prune_method_listing(list, hide_attributes = true)
6
6
  list = run_verifier(list)
7
- list = list.reject {|o| !options[:visibilities].include? o.visibility } if options[:visibilities]
8
7
  list = list.reject {|o| o.is_alias? unless CodeObjects::Proxy === o.namespace }
9
8
  list = list.reject {|o| o.is_attribute? unless CodeObjects::Proxy === o.namespace } if hide_attributes
10
9
  list
@@ -12,4 +11,4 @@ module YARD
12
11
  end
13
12
  end
14
13
  end
15
- end
14
+ end
@@ -41,7 +41,7 @@ describe YARD::CLI::Yardoc do
41
41
 
42
42
  it "should use String#shell_split to split .yardopts tokens" do
43
43
  optsdata = "foo bar"
44
- optsdata.should_receive(:shell_split)
44
+ optsdata.should_receive(:shell_split).and_return([optsdata])
45
45
  IO.should_receive(:read).with("test").and_return(optsdata)
46
46
  @yardoc.stub!(:support_rdoc_document_file!).and_return([])
47
47
  @yardoc.options_file = "test"
@@ -6,6 +6,7 @@ describe YARD::CodeObjects::ClassObject do
6
6
  Registry.clear
7
7
  @mixin = ModuleObject.new(:root, :SomeMixin)
8
8
  @mixin2 = ModuleObject.new(:root, :SomeMixin2)
9
+ @mixin2.instance_mixins << @mixin
9
10
  @mixin3 = ModuleObject.new(:root, :SomeMixin3)
10
11
  @mixin4 = ModuleObject.new(:root, :SomeMixin4)
11
12
  @mixin2.instance_mixins << @mixin3
@@ -111,6 +111,7 @@ describe YARD::CodeObjects::ModuleObject do
111
111
 
112
112
  @mod1.instance_mixins << @mod2
113
113
  @mod2.instance_mixins << @mod3
114
+ @mod3.instance_mixins << @mod4
114
115
  @mod1.instance_mixins << @mod4
115
116
 
116
117
  @proxy = P(:SomeProxyClass)
@@ -117,6 +117,20 @@ describe YARD::Docstring do
117
117
  tags = doc.tags('param')
118
118
  tags.size.should == 0
119
119
  end
120
+
121
+ it "resolves references to methods in the same class with #methname" do
122
+ klass = CodeObjects::ClassObject.new(:root, "Foo")
123
+ o = CodeObjects::MethodObject.new(klass, "bar")
124
+ ref = CodeObjects::MethodObject.new(klass, "baz")
125
+ o.docstring.add_tag Tags::Tag.new('param', 'testing', nil, 'arg1')
126
+ ref.docstring = "@param (see #bar)"
127
+
128
+ tags = ref.docstring.tags("param")
129
+ tags.size.should == 1
130
+ tags.first.text.should == "testing"
131
+ tags.first.should be_kind_of(Tags::RefTag)
132
+ tags.first.owner.should == o
133
+ end
120
134
  end
121
135
 
122
136
  describe '#empty?/#blank?' do
@@ -32,17 +32,15 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ClassConditionHandler
32
32
  verify_method :j, :k
33
33
  end
34
34
 
35
- if RUBY19
36
- it "should parse all if/elsif blocks for complex conditions" do
37
- verify_method :a, :b, :c, :d
38
- end
35
+ it "should parse all if/elsif blocks for complex conditions" do
36
+ verify_method :a, :b, :c, :d
37
+ end
39
38
 
40
- it "should only parse else block if condition is literal value `false`" do
41
- verify_method :q
42
- end
39
+ it "should only parse else block if condition is literal value `false`" do
40
+ verify_method :q
41
+ end
43
42
 
44
- it "should only parse else block if condition is literal integer == 0" do
45
- verify_method :n
46
- end
43
+ it "should only parse else block if condition is literal integer == 0" do
44
+ verify_method :n
47
45
  end
48
46
  end