yard 0.7.2 → 0.7.3

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 (43) hide show
  1. data/ChangeLog +205 -0
  2. data/README.md +52 -73
  3. data/Rakefile +17 -2
  4. data/docs/GettingStarted.md +6 -2
  5. data/lib/yard.rb +1 -1
  6. data/lib/yard/cli/yri.rb +1 -1
  7. data/lib/yard/code_objects/macro_object.rb +1 -1
  8. data/lib/yard/handlers/base.rb +1 -1
  9. data/lib/yard/handlers/ruby/attribute_handler.rb +1 -1
  10. data/lib/yard/handlers/ruby/base.rb +2 -2
  11. data/lib/yard/handlers/ruby/exception_handler.rb +9 -7
  12. data/lib/yard/handlers/ruby/legacy/exception_handler.rb +3 -4
  13. data/lib/yard/handlers/ruby/visibility_handler.rb +1 -1
  14. data/lib/yard/parser/c_parser.rb +40 -5
  15. data/lib/yard/parser/ruby/ast_node.rb +2 -1
  16. data/lib/yard/parser/ruby/ruby_parser.rb +47 -7
  17. data/lib/yard/parser/source_parser.rb +13 -2
  18. data/lib/yard/rubygems/specification.rb +2 -2
  19. data/lib/yard/templates/helpers/html_helper.rb +13 -8
  20. data/lib/yard/templates/helpers/markup_helper.rb +1 -1
  21. data/lib/yard/verifier.rb +2 -2
  22. data/spec/cli/server_spec.rb +7 -6
  23. data/spec/cli/yri_spec.rb +1 -1
  24. data/spec/code_objects/extra_file_object_spec.rb +1 -1
  25. data/spec/config_spec.rb +0 -1
  26. data/spec/handlers/base_spec.rb +2 -2
  27. data/spec/handlers/constant_handler_spec.rb +1 -1
  28. data/spec/handlers/examples/exception_handler_001.rb.txt +4 -0
  29. data/spec/handlers/exception_handler_spec.rb +4 -0
  30. data/spec/handlers/ruby/base_spec.rb +3 -3
  31. data/spec/parser/c_parser_spec.rb +100 -11
  32. data/spec/parser/ruby/ast_node_spec.rb +2 -1
  33. data/spec/parser/ruby/ruby_parser_spec.rb +43 -2
  34. data/spec/parser/source_parser_spec.rb +2 -1
  35. data/spec/templates/examples/method001.html +3 -2
  36. data/spec/templates/helpers/html_helper_spec.rb +26 -5
  37. data/templates/default/fulldoc/html/css/full_list.css +2 -0
  38. data/templates/default/fulldoc/html/css/style.css +2 -0
  39. data/templates/default/fulldoc/html/full_list_methods.erb +1 -1
  40. data/templates/default/fulldoc/html/js/full_list.js +23 -6
  41. data/templates/default/tags/html/option.erb +2 -2
  42. data/templates/guide/fulldoc/html/css/style.css +2 -0
  43. metadata +23 -28
data/lib/yard.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module YARD
2
- VERSION = "0.7.2"
2
+ VERSION = "0.7.3"
3
3
 
4
4
  # The root path for YARD source libraries
5
5
  ROOT = File.expand_path(File.dirname(__FILE__))
data/lib/yard/cli/yri.rb CHANGED
@@ -49,7 +49,7 @@ module YARD
49
49
  def run(*args)
50
50
  optparse(*args)
51
51
 
52
- if ::Config::CONFIG['host_os'] =~ /mingw|win32/
52
+ if ::RbConfig::CONFIG['host_os'] =~ /mingw|win32/
53
53
  @serializer ||= YARD::Serializers::StdoutSerializer.new
54
54
  else
55
55
  @serializer ||= YARD::Serializers::ProcessSerializer.new('less')
@@ -81,7 +81,7 @@ module YARD
81
81
  # Interpolation rules:
82
82
  # * $0, $1, $2, ... = the Nth parameter in +call_params+
83
83
  # * $* = the full statement source (excluding block)
84
- # * Also supports $\{N-M} ranges, as well as negative indexes on N or M
84
+ # * Also supports $!{N-M} ranges, as well as negative indexes on N or M
85
85
  # * Use \$ to escape the variable name in a macro.
86
86
  #
87
87
  # @macro [new] macro.expand
@@ -489,7 +489,7 @@ module YARD
489
489
  if object.is_a?(Proxy)
490
490
  if retries <= max_retries
491
491
  log.debug "Missing object #{object} in file `#{parser.file}', moving it to the back of the line."
492
- raise Parser::LoadOrderError, context
492
+ raise Parser::LoadOrderError.new(context)
493
493
  else
494
494
  raise NamespaceMissingError, object
495
495
  end
@@ -7,7 +7,7 @@ class YARD::Handlers::Ruby::AttributeHandler < YARD::Handlers::Ruby::Base
7
7
  namespace_only
8
8
 
9
9
  process do
10
- return if statement.type == :var_ref
10
+ return if statement.type == :var_ref || statement.type == :vcall
11
11
  read, write = true, false
12
12
  params = statement.parameters(false).dup
13
13
 
@@ -38,7 +38,7 @@ module YARD
38
38
  if !node.parent || node.parent.type == :list
39
39
  return true if node[0].type == :ident && (name.nil? || node[0][0] == name)
40
40
  end
41
- when :fcall, :command
41
+ when :fcall, :command, :vcall
42
42
  return true if name.nil? || node[0][0] == name
43
43
  when :call, :command_call
44
44
  return true if name.nil? || node[2][0] == name
@@ -148,7 +148,7 @@ module YARD
148
148
  def caller_method
149
149
  if statement.call?
150
150
  statement.method_name(true).to_s
151
- elsif statement.type == :var_ref
151
+ elsif statement.type == :var_ref || statement.type == :vcall
152
152
  statement[0].jump(:ident).source
153
153
  else
154
154
  nil
@@ -8,15 +8,17 @@ class YARD::Handlers::Ruby::ExceptionHandler < YARD::Handlers::Ruby::Base
8
8
  return if owner.has_tag?(:raise)
9
9
 
10
10
  klass = nil
11
- params = statement.parameters(false)
12
- if params.size == 1
13
- if params.first.ref? && params.first.first.type != :ident
11
+ if statement.call?
12
+ params = statement.parameters(false)
13
+ if params.size == 1
14
+ if params.first.ref? && params.first.first.type != :ident
15
+ klass = params.first.source
16
+ elsif params.first.call? && params.first.method_name(true) == :new
17
+ klass = params.first.namespace.source
18
+ end
19
+ elsif params.size > 1
14
20
  klass = params.first.source
15
- elsif params.first.call? && params.first.method_name(true) == :new
16
- klass = params.first.namespace.source
17
21
  end
18
- elsif params.size > 1
19
- klass = params.first.source
20
22
  end
21
23
 
22
24
  owner.docstring.add_tag YARD::Tags::Tag.new(:raise, '', klass) if klass
@@ -1,13 +1,12 @@
1
1
  # (see Ruby::ExceptionHandler)
2
2
  class YARD::Handlers::Ruby::Legacy::ExceptionHandler < YARD::Handlers::Ruby::Legacy::Base
3
- handles /\Araise(\s|\()/
3
+ handles /\Araise(\s|\(|\Z)/
4
4
 
5
5
  process do
6
6
  return unless owner.is_a?(MethodObject) # Only methods yield
7
7
  return if owner.has_tag?(:raise)
8
8
 
9
- if klass = statement.tokens.to_s[/^raise[\(\s]*(#{NAMESPACEMATCH})\s*(?:\)|,|\s(?:if|unless|until)|;|(?:(?:\.|\:\:)\s*)?new|$)/, 1]
10
- owner.docstring.add_tag YARD::Tags::Tag.new(:raise, '', klass)
11
- end
9
+ klass = statement.tokens.to_s[/^raise[\(\s]*(#{NAMESPACEMATCH})\s*(?:\)|,|\s(?:if|unless|until)|;|(?:(?:\.|\:\:)\s*)?new|$)/, 1]
10
+ owner.docstring.add_tag YARD::Tags::Tag.new(:raise, '', klass) if klass
12
11
  end
13
12
  end
@@ -8,7 +8,7 @@ class YARD::Handlers::Ruby::VisibilityHandler < YARD::Handlers::Ruby::Base
8
8
  process do
9
9
  return if (ident = statement.jump(:ident)) == statement
10
10
  case statement.type
11
- when :var_ref
11
+ when :var_ref, :vcall
12
12
  self.visibility = ident.first
13
13
  when :fcall, :command
14
14
  statement[1].traverse do |node|
@@ -15,6 +15,7 @@ module YARD
15
15
  parse_modules
16
16
  parse_classes
17
17
  parse_methods
18
+ parse_attributes
18
19
  parse_constants
19
20
  parse_includes
20
21
  end
@@ -71,6 +72,7 @@ module YARD
71
72
  @namespaces[var_name] = obj
72
73
  end
73
74
 
75
+ # @return [CodeObjects::Base]
74
76
  def handle_method(scope, var_name, name, func_name, source_file = nil)
75
77
  case scope
76
78
  when "singleton_method", "module_function"; scope = :class
@@ -95,6 +97,18 @@ module YARD
95
97
  content ||= @content
96
98
  end
97
99
  find_method_body(obj, func_name, content)
100
+ obj
101
+ end
102
+
103
+ def handle_attribute(var_name, name, func_name, read, write, source_file = nil)
104
+ values = {:read => read.to_i, :write => write.to_i}
105
+ {:read => name, :write => "#{name}="}.each do |type, meth_name|
106
+ next unless values[type] > 0
107
+ obj = handle_method(:instance, var_name, meth_name, func_name, source_file)
108
+ ensure_loaded!(obj.namespace)
109
+ obj.namespace.attributes[:instance][name] ||= SymbolHash[:read => nil, :write => nil]
110
+ obj.namespace.attributes[:instance][name][type] = obj
111
+ end
98
112
  end
99
113
 
100
114
  def handle_constants(type, var_name, const_name, definition)
@@ -184,6 +198,7 @@ module YARD
184
198
 
185
199
  def find_override_comment(object, content = @content)
186
200
  name = Regexp.escape(object.name.to_s)
201
+ name = "(?:initialize|new)" if name == 'initialize'
187
202
  class_name = object.parent.path
188
203
  if content =~ %r{Document-method:\s+#{class_name}(?:\.|::|#)#{name}\s*?\n((?>.*?\*/))}m then
189
204
  $1
@@ -265,7 +280,7 @@ module YARD
265
280
  when "class"; "Class"
266
281
  when "obj", "object", "anObject"; "Object"
267
282
  when "arr", "array", "anArray", /^\[/; "Array"
268
- when "str", "string", "new_str"; "String"
283
+ when /^char\s*\*/, "char", "str", "string", "new_str"; "String"
269
284
  when "enum", "anEnumerator"; "Enumerator"
270
285
  when "exc", "exception"; "Exception"
271
286
  when "proc", "proc_obj", "prc"; "Proc"
@@ -280,15 +295,16 @@ module YARD
280
295
  when "matchdata"; "MatchData"
281
296
  when "encoding"; "Encoding"
282
297
  when "fixnum", "fix"; "Fixnum"
283
- when "int", "integer", "Integer"; "Integer"
298
+ when /^(?:un)?signed$/, /^(?:(?:un)?signed\s*)?(?:short|int|long|long\s+long)$/, "integer", "Integer"; "Integer"
284
299
  when "num", "numeric", "Numeric", "number"; "Numeric"
285
300
  when "aBignum"; "Bignum"
286
301
  when "nil"; "nil"
287
302
  when "true"; "true"
288
303
  when "false"; "false"
289
- when "boolean", "Boolean"; "Boolean"
304
+ when "bool", "boolean", "Boolean"; "Boolean"
290
305
  when "self"; object.namespace.name.to_s
291
306
  when /^[-+]?\d/; t
307
+ when /[A-Z][_a-z0-9]+/; t
292
308
  end
293
309
  end.compact
294
310
  end
@@ -341,7 +357,7 @@ module YARD
341
357
  \s*"([^"]+)",
342
358
  \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
343
359
  \s*(-?\w+)\s*\)
344
- (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
360
+ (?:;\s*/[*/]\s+in\s+(.+?\.[cy]))?
345
361
  }xm) do |type, var_name, name, func_name, param_count, source_file|
346
362
 
347
363
  # Ignore top-object and weird struct.c dynamic stuff
@@ -357,11 +373,30 @@ module YARD
357
373
  \s*"([^"]+)",
358
374
  \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
359
375
  \s*(-?\w+)\s*\)
360
- (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
376
+ (?:;\s*/[*/]\s+in\s+(.+?\.[cy]))?
361
377
  }xm) do |name, func_name, param_count, source_file|
362
378
  handle_method("method", "rb_mKernel", name, func_name, source_file)
363
379
  end
364
380
  end
381
+
382
+ def parse_attributes
383
+ @content.scan(%r{rb_define_attr
384
+ \s*\(\s*([\w\.]+),
385
+ \s*"([^"]+)",
386
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
387
+ \s*(0|1)\s*,\s*(0|1)\s*\)
388
+ (?:;\s*/[*/]\s+in\s+(.+?\.[cy]))?
389
+ }xm) do |var_name, name, func_name, read, write, source_file|
390
+
391
+ # Ignore top-object and weird struct.c dynamic stuff
392
+ next if var_name == "ruby_top_self"
393
+ next if var_name == "nstr"
394
+ next if var_name == "envtbl"
395
+
396
+ var_name = "rb_cObject" if var_name == "rb_mKernel"
397
+ handle_attribute(var_name, name, func_name, read, write, source_file)
398
+ end
399
+ end
365
400
 
366
401
  def parse_includes
367
402
  @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |klass, mod|
@@ -106,7 +106,7 @@ module YARD
106
106
  case type
107
107
  when :params
108
108
  ParameterNode
109
- when :call, :fcall, :command, :command_call
109
+ when :call, :fcall, :vcall, :command, :command_call
110
110
  MethodCallNode
111
111
  when :if, :elsif, :if_mod, :unless, :unless_mod
112
112
  ConditionalNode
@@ -358,6 +358,7 @@ module YARD
358
358
  end
359
359
 
360
360
  def parameters(include_block_param = true)
361
+ return [] if type == :vcall
361
362
  params = self[1 + index_adjust]
362
363
  return [] unless params
363
364
  params = call_has_paren? ? params.first : params
@@ -34,7 +34,8 @@ module YARD
34
34
  @tokens = []
35
35
  @comments = {}
36
36
  @comments_flags = {}
37
- @heredoc_tokens = []
37
+ @heredoc_tokens = nil
38
+ @heredoc_state = nil
38
39
  @map = {}
39
40
  @ns_charno = 0
40
41
  @list = []
@@ -203,7 +204,7 @@ module YARD
203
204
 
204
205
  def visit_event(node)
205
206
  map = @map[MAPPINGS[node.type]]
206
- lstart, sstart = *(map ? map.pop : [lineno, lineno])
207
+ lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1])
207
208
  node.source_range = Range.new(sstart, @ns_charno - 1)
208
209
  node.line_range = Range.new(lstart, lineno)
209
210
  node
@@ -231,27 +232,37 @@ module YARD
231
232
  def add_token(token, data)
232
233
  if @tokens.last && @tokens.last[0] == :symbeg
233
234
  @tokens[-1] = [:symbol, ":" + data]
234
- elsif token == :heredoc_end
235
- @heredoc_tokens << [@tokens.pop, [token, data]]
235
+ elsif @heredoc_state == :started
236
+ @heredoc_tokens << [token, data]
237
+ @heredoc_state = :ended if token == :heredoc_end
238
+ elsif (token == :nl || token == :comment) && @heredoc_state == :ended
239
+ @heredoc_tokens.unshift([token, data])
240
+ @tokens += @heredoc_tokens
241
+ @heredoc_tokens = nil
242
+ @heredoc_state = nil
236
243
  else
237
244
  @tokens << [token, data]
238
- if token == :nl && @heredoc_tokens.size > 0
239
- @tokens += @heredoc_tokens.pop
245
+ if token == :heredoc_beg
246
+ @heredoc_state = :started
247
+ @heredoc_tokens = []
240
248
  end
241
249
  end
242
250
  end
243
251
 
244
252
  undef on_program
245
253
  undef on_assoc_new
254
+ undef on_array
246
255
  undef on_hash
247
256
  undef on_bare_assoc_hash
248
257
  undef on_assoclist_from_args
249
258
  undef on_aref
259
+ undef on_lbracket
250
260
  undef on_rbracket
251
261
  undef on_qwords_new
252
262
  undef on_qwords_add
253
263
  undef on_string_literal
254
264
  undef on_lambda
265
+ undef on_unary
255
266
  undef on_string_content
256
267
  undef on_rescue
257
268
  undef on_void_stmt
@@ -287,6 +298,15 @@ module YARD
287
298
  def on_assoclist_from_args(*args)
288
299
  args.first
289
300
  end
301
+
302
+ def on_unary(op, val)
303
+ map = @map[op.to_s[0,1]]
304
+ lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1])
305
+ node = AstNode.node_class_for(:unary).new(:unary, [op, val])
306
+ node.source_range = Range.new(sstart, @ns_charno - 1)
307
+ node.line_range = Range.new(lstart, lineno)
308
+ node
309
+ end
290
310
 
291
311
  def on_aref(*args)
292
312
  ll, lc = *@map[:aref].pop
@@ -294,6 +314,25 @@ module YARD
294
314
  lr = args.first.line_range.first..ll
295
315
  AstNode.new(:aref, args, :char => sr, :line => lr)
296
316
  end
317
+
318
+ def on_array(other)
319
+ node = AstNode.node_class_for(:array).new(:array, [other])
320
+ map = @map[MAPPINGS[node.type]]
321
+ if map && !map.empty?
322
+ lstart, sstart = *map.pop
323
+ node.source_range = Range.new(sstart, @ns_charno - 1)
324
+ node.line_range = Range.new(lstart, lineno)
325
+ else
326
+ node.source_range = other.source_range
327
+ node.line_range = other.line_range
328
+ end
329
+ node
330
+ end
331
+
332
+ def on_lbracket(tok)
333
+ (@map[:lbracket] ||= []) << [lineno, charno]
334
+ visit_ns_token(:lbracket, tok, false)
335
+ end
297
336
 
298
337
  def on_rbracket(tok)
299
338
  (@map[:aref] ||= []) << [lineno, charno]
@@ -339,7 +378,8 @@ module YARD
339
378
  end
340
379
 
341
380
  def on_qwords_add(list, item)
342
- list.source_range = (list.source_range.first..@ns_charno-1)
381
+ last = @source[@ns_charno,1] == "\n" ? @ns_charno - 1 : @ns_charno
382
+ list.source_range = (list.source_range.first..last)
343
383
  list.line_range = (list.line_range.first..lineno)
344
384
  list.push(item)
345
385
  list
@@ -18,7 +18,16 @@ module YARD
18
18
  # that has not yet been resolved.
19
19
  #
20
20
  # @see Handers::Base#ensure_loaded!
21
- class LoadOrderError < Exception; end
21
+ class LoadOrderError < Exception
22
+ # @return [Continuation] the context representing the
23
+ # point at which the load order error occurred.
24
+ attr_accessor :context
25
+
26
+ # @param [Continuation] context see {#context}
27
+ def initialize(context)
28
+ @context = context
29
+ end
30
+ end
22
31
 
23
32
  # Responsible for parsing a source file into the namespace. Parsing
24
33
  # also invokes handlers to process the parsed statements and generate
@@ -353,7 +362,7 @@ module YARD
353
362
  end
354
363
  rescue LoadOrderError => e
355
364
  # Out of order file. Push the context to the end and we'll call it
356
- files.push([file, e.message])
365
+ files.push([file, e.context])
357
366
  end
358
367
  end
359
368
 
@@ -436,8 +445,10 @@ module YARD
436
445
  @parser
437
446
  rescue ArgumentError, NotImplementedError => e
438
447
  log.warn("Cannot parse `#{file}': #{e.message}")
448
+ log.backtrace(e) if log.level >= Logger::DEBUG
439
449
  rescue ParserSyntaxError => e
440
450
  log.warn(e.message.capitalize)
451
+ log.backtrace(e) if log.level >= Logger::DEBUG
441
452
  end
442
453
 
443
454
  # Tokenizes but does not parse the block of code using the current {#parser_type}
@@ -25,10 +25,10 @@ class Gem::Specification
25
25
  attr_accessor :has_rdoc
26
26
  end
27
27
 
28
- if defined?(Gem::VERSION) && Gem::VERSION =~ /^1\.7\./
28
+ if defined?(Gem::VERSION) && Gem::VERSION >= '1.7.'
29
29
  def _dump_with_rdoc(limit)
30
30
  dmp = _dump_without_rdoc(limit)
31
- dmp[15] = @has_rdoc
31
+ dmp[15] = @has_rdoc if dmp[15] == true
32
32
  dmp
33
33
  end
34
34
  alias _dump_without_rdoc _dump
@@ -44,10 +44,13 @@ module YARD
44
44
  html = html.encode(:invalid => :replace, :replace => '?')
45
45
  end
46
46
  html = resolve_links(html)
47
- html = html.gsub(/<pre>(?:\s*<code>)?(.+?)(?:<\/code>\s*)?<\/pre>/m) do
48
- str = $1
49
- str = html_syntax_highlight(CGI.unescapeHTML(str)) unless options[:no_highlight]
50
- %Q{<pre class="code">#{str}</pre>}
47
+ html = html.gsub(/<pre\s*(?:lang="(.+?)")?>(?:\s*<code>)?(.+?)(?:<\/code>\s*)?<\/pre>/m) do
48
+ language = $1
49
+ string = $2
50
+
51
+ string = html_syntax_highlight(CGI.unescapeHTML(string), language) unless options[:no_highlight]
52
+ classes = ['code', language].compact.join(' ')
53
+ %Q{<pre class="#{classes}">#{string}</pre>}
51
54
  end unless markup == :text
52
55
  html
53
56
  end
@@ -61,6 +64,8 @@ module YARD
61
64
  provider = markup_class(:markdown)
62
65
  if provider.to_s == 'RDiscount'
63
66
  markup_class(:markdown).new(text, :autolink).to_html
67
+ elsif provider.to_s == 'RedcarpetCompat'
68
+ provider.new(text, :gh_blockcode, :fenced_code).to_html
64
69
  else
65
70
  markup_class(:markdown).new(text).to_html
66
71
  end
@@ -91,7 +96,7 @@ module YARD
91
96
  # @return [String] the output HTML
92
97
  # @since 0.6.0
93
98
  def html_markup_text(text)
94
- "<pre>" + text + "</pre>"
99
+ "<pre>" + h(text) + "</pre>"
95
100
  end
96
101
 
97
102
  # @return [String] the same text with no markup
@@ -116,7 +121,7 @@ module YARD
116
121
  # @return [String] the highlighted HTML
117
122
  # @since 0.7.0
118
123
  def html_markup_ruby(source)
119
- '<pre class="code">' + html_syntax_highlight(source, :ruby) + '</pre>'
124
+ '<pre class="code ruby">' + html_syntax_highlight(source, :ruby) + '</pre>'
120
125
  end
121
126
 
122
127
  # @return [String] HTMLified text as a single line (paragraphs removed)
@@ -169,7 +174,7 @@ module YARD
169
174
  # @return [String] HTML with linkified references
170
175
  def resolve_links(text)
171
176
  code_tags = 0
172
- text.gsub(/<(\/)?(pre|code|tt)|(\\)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W<]|.+<\/|$)/m) do |str|
177
+ text.gsub(/<(\/)?(pre|code|tt)|(\\|!)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W<]|.+<\/|$)/m) do |str|
173
178
  closed, tag, escape, name, title, match = $1, $2, $3, $4, $5, $&
174
179
  if tag
175
180
  code_tags += (closed ? -1 : 1)
@@ -246,7 +251,7 @@ module YARD
246
251
  return title if obj.is_a?(CodeObjects::Proxy)
247
252
 
248
253
  link = url_for(obj, anchor, relative)
249
- link = link ? link_url(link, title, :title => "#{obj.path} (#{obj.type})") : title
254
+ link = link ? link_url(link, title, :title => h("#{obj.path} (#{obj.type})")) : title
250
255
  "<span class='object_link'>" + link + "</span>"
251
256
  end
252
257