jsduck 4.0.1 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/Rakefile +14 -0
  2. data/esprima/esprima.js +210 -85
  3. data/jsduck.gemspec +3 -3
  4. data/lib/jsduck/accessors.rb +10 -8
  5. data/lib/jsduck/aggregator.rb +7 -7
  6. data/lib/jsduck/app.rb +24 -164
  7. data/lib/jsduck/app_data.rb +2 -4
  8. data/lib/jsduck/assets.rb +5 -2
  9. data/lib/jsduck/ast.rb +9 -4
  10. data/lib/jsduck/batch_formatter.rb +54 -0
  11. data/lib/jsduck/batch_parser.rb +106 -0
  12. data/lib/jsduck/categories.rb +5 -6
  13. data/lib/jsduck/class.rb +77 -239
  14. data/lib/jsduck/class_doc_expander.rb +0 -5
  15. data/lib/jsduck/class_formatter.rb +14 -10
  16. data/lib/jsduck/class_name.rb +23 -0
  17. data/lib/jsduck/class_writer.rb +9 -8
  18. data/lib/jsduck/doc_ast.rb +5 -6
  19. data/lib/jsduck/doc_formatter.rb +61 -272
  20. data/lib/jsduck/enum.rb +4 -4
  21. data/lib/jsduck/esprima.rb +10 -4
  22. data/lib/jsduck/examples.rb +5 -5
  23. data/lib/jsduck/export_writer.rb +62 -0
  24. data/lib/jsduck/exporter/app.rb +62 -0
  25. data/lib/jsduck/exporter/examples.rb +58 -0
  26. data/lib/jsduck/exporter/full.rb +60 -0
  27. data/lib/jsduck/file_categories.rb +7 -4
  28. data/lib/jsduck/function_ast.rb +99 -0
  29. data/lib/jsduck/grouped_asset.rb +27 -16
  30. data/lib/jsduck/guide_writer.rb +8 -7
  31. data/lib/jsduck/guides.rb +31 -29
  32. data/lib/jsduck/icons.rb +12 -1
  33. data/lib/jsduck/images.rb +3 -3
  34. data/lib/jsduck/importer.rb +7 -7
  35. data/lib/jsduck/index_html.rb +20 -6
  36. data/lib/jsduck/inherit_doc.rb +9 -12
  37. data/lib/jsduck/inline/example.rb +42 -0
  38. data/lib/jsduck/inline/img.rb +55 -0
  39. data/lib/jsduck/inline/link.rb +227 -0
  40. data/lib/jsduck/inline/video.rb +67 -0
  41. data/lib/jsduck/inline_examples.rb +7 -7
  42. data/lib/jsduck/js_parser.rb +5 -4
  43. data/lib/jsduck/lint.rb +14 -2
  44. data/lib/jsduck/logger.rb +5 -6
  45. data/lib/jsduck/members_index.rb +132 -0
  46. data/lib/jsduck/merger.rb +3 -9
  47. data/lib/jsduck/options.rb +39 -41
  48. data/lib/jsduck/override.rb +3 -7
  49. data/lib/jsduck/relations.rb +9 -9
  50. data/lib/jsduck/renderer.rb +3 -3
  51. data/lib/jsduck/return_values.rb +72 -0
  52. data/lib/jsduck/search_data.rb +16 -20
  53. data/lib/jsduck/shortener.rb +58 -0
  54. data/lib/jsduck/signature_renderer.rb +1 -2
  55. data/lib/jsduck/source/file.rb +98 -0
  56. data/lib/jsduck/source/file_parser.rb +72 -0
  57. data/lib/jsduck/source/writer.rb +89 -0
  58. data/lib/jsduck/tag/aside.rb +1 -1
  59. data/lib/jsduck/tag/since.rb +1 -1
  60. data/lib/jsduck/template_dir.rb +2 -2
  61. data/lib/jsduck/util/html.rb +27 -0
  62. data/lib/jsduck/util/io.rb +32 -0
  63. data/lib/jsduck/util/json.rb +60 -0
  64. data/lib/jsduck/util/null_object.rb +23 -0
  65. data/lib/jsduck/util/os.rb +14 -0
  66. data/lib/jsduck/util/parallel.rb +34 -0
  67. data/lib/jsduck/util/singleton.rb +35 -0
  68. data/lib/jsduck/util/stdout.rb +33 -0
  69. data/lib/jsduck/videos.rb +5 -5
  70. data/lib/jsduck/web_writer.rb +79 -0
  71. data/lib/jsduck/welcome.rb +6 -6
  72. data/spec/class_factory.rb +20 -0
  73. metadata +32 -20
  74. data/lib/jsduck/api_exporter.rb +0 -48
  75. data/lib/jsduck/app_exporter.rb +0 -60
  76. data/lib/jsduck/examples_exporter.rb +0 -56
  77. data/lib/jsduck/full_exporter.rb +0 -35
  78. data/lib/jsduck/html.rb +0 -25
  79. data/lib/jsduck/inline_img.rb +0 -53
  80. data/lib/jsduck/inline_video.rb +0 -58
  81. data/lib/jsduck/io.rb +0 -30
  82. data/lib/jsduck/json_duck.rb +0 -52
  83. data/lib/jsduck/lexer.rb +0 -251
  84. data/lib/jsduck/null_object.rb +0 -19
  85. data/lib/jsduck/os.rb +0 -11
  86. data/lib/jsduck/parallel_wrap.rb +0 -32
  87. data/lib/jsduck/source_file.rb +0 -97
  88. data/lib/jsduck/source_file_parser.rb +0 -70
  89. data/lib/jsduck/source_writer.rb +0 -87
  90. data/lib/jsduck/stats.rb +0 -103
  91. data/lib/jsduck/stdout.rb +0 -31
@@ -107,14 +107,9 @@ module JsDuck
107
107
  results = []
108
108
 
109
109
  if docset[:code]
110
-
111
110
  (docset[:code][:members] || []).each do |m|
112
111
  results << code_to_docset(m) unless @constructor_found && m[:name] == "constructor"
113
112
  end
114
-
115
- (docset[:code][:statics] || []).each do |m|
116
- results << code_to_docset(m)
117
- end
118
113
  end
119
114
 
120
115
  results
@@ -1,6 +1,7 @@
1
1
  require 'jsduck/type_parser'
2
2
  require 'jsduck/logger'
3
3
  require 'jsduck/meta_tag_registry'
4
+ require 'jsduck/shortener'
4
5
 
5
6
  module JsDuck
6
7
 
@@ -25,21 +26,24 @@ module JsDuck
25
26
  @formatter.class_context = cls[:name]
26
27
  @formatter.doc_context = cls[:files][0]
27
28
  cls[:doc] = @formatter.format(cls[:doc]) if cls[:doc]
28
- [:members, :statics].each do |group|
29
- cls[group].each_pair do |type, members|
30
- # format all members (except hidden ones)
31
- cls[group][type] = members.map {|m| m[:meta][:hide] ? m : format_member(m) }
32
- end
33
- end
29
+ # format all members (except hidden ones)
30
+ cls[:members] = cls[:members].map {|m| m[:meta][:hide] ? m : format_member(m) }
34
31
  cls[:html_meta] = format_meta_data(cls)
35
32
  cls
36
33
  end
37
34
 
35
+ # Returns the images detected by doc-formatter
36
+ def images
37
+ @formatter.images
38
+ end
39
+
40
+ private
41
+
38
42
  def format_member(m)
39
43
  @formatter.doc_context = m[:files][0]
40
44
  m[:doc] = @formatter.format(m[:doc]) if m[:doc]
41
- if expandable?(m) || @formatter.too_long?(m[:doc])
42
- m[:shortDoc] = @formatter.shorten(m[:doc])
45
+ if expandable?(m) || Shortener.too_long?(m[:doc])
46
+ m[:shortDoc] = Shortener.shorten(m[:doc])
43
47
  end
44
48
 
45
49
  # We don't validate and format CSS var and mixin type definitions
@@ -72,9 +76,9 @@ module JsDuck
72
76
  else
73
77
  context = @formatter.doc_context
74
78
  if tp.error == :syntax
75
- Logger.instance.warn(:type_syntax, "Incorrect type syntax #{type}", context[:filename], context[:linenr])
79
+ Logger.warn(:type_syntax, "Incorrect type syntax #{type}", context[:filename], context[:linenr])
76
80
  else
77
- Logger.instance.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
81
+ Logger.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
78
82
  end
79
83
  type
80
84
  end
@@ -0,0 +1,23 @@
1
+ module JsDuck
2
+
3
+ # Common routines for manipulating class names.
4
+ class ClassName
5
+
6
+ # Given a full class name extracts the "class"-part of the name.
7
+ #
8
+ # ClassName.short("My.package.Foo") --> "Foo"
9
+ #
10
+ # Because we try to emulate ext-doc, it's not as simple as just
11
+ # taking the last part. See class_spec.rb for details.
12
+ def self.short(name)
13
+ parts = name.split(/\./)
14
+ short = parts.pop
15
+ while parts.length > 1 && parts.last =~ /^[A-Z]/
16
+ short = parts.pop + "." + short
17
+ end
18
+ short
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -1,6 +1,7 @@
1
- require 'jsduck/parallel_wrap'
1
+ require 'jsduck/util/parallel'
2
2
  require 'jsduck/logger'
3
- require 'jsduck/stdout'
3
+ require 'jsduck/util/json'
4
+ require 'jsduck/util/stdout'
4
5
  require 'fileutils'
5
6
 
6
7
  module JsDuck
@@ -23,22 +24,22 @@ module JsDuck
23
24
  private
24
25
 
25
26
  def write_stdout
26
- json = ParallelWrap.map(@relations.classes) {|cls| @exporter.export(cls) }.compact
27
- Stdout.instance.add(json)
27
+ json = Util::Parallel.map(@relations.classes) {|cls| @exporter.export(cls) }.compact
28
+ Util::Stdout.add(json)
28
29
  end
29
30
 
30
31
  def write_dir(dir, extension)
31
32
  FileUtils.mkdir(dir)
32
- ParallelWrap.each(@relations.classes) do |cls|
33
+ Util::Parallel.each(@relations.classes) do |cls|
33
34
  filename = dir + "/" + cls[:name] + extension
34
- Logger.instance.log("Writing docs", filename)
35
+ Logger.log("Writing docs", filename)
35
36
  json = @exporter.export(cls)
36
37
  # skip file if exporter returned nil
37
38
  if json
38
39
  if extension == ".json"
39
- JsonDuck.write_json(filename, json)
40
+ Util::Json.write_json(filename, json)
40
41
  elsif extension == ".js"
41
- JsonDuck.write_jsonp(filename, cls[:name].gsub(/\./, "_"), json)
42
+ Util::Json.write_jsonp(filename, cls[:name].gsub(/\./, "_"), json)
42
43
  else
43
44
  throw "Unexpected file extension: #{extension}"
44
45
  end
@@ -58,14 +58,13 @@ module JsDuck
58
58
 
59
59
  def create_method(docs)
60
60
  doc_map = build_doc_map(docs)
61
- name = detect_name(:method, doc_map)
62
61
  return add_shared({
63
62
  :tagname => :method,
64
- :name => name,
63
+ :name => detect_name(:method, doc_map),
65
64
  :owner => detect_owner(doc_map),
66
65
  :doc => detect_doc(docs),
67
66
  :params => detect_params(doc_map),
68
- :return => detect_return(doc_map, name == "constructor" ? "Object" : "undefined"),
67
+ :return => detect_return(doc_map),
69
68
  :throws => detect_throws(doc_map),
70
69
  }, doc_map)
71
70
  end
@@ -248,7 +247,7 @@ module JsDuck
248
247
  parent[:properties] = [] unless parent[:properties]
249
248
  parent[:properties] << it
250
249
  else
251
- Logger.instance.warn(:subproperty, "Ignoring subproperty #{$1}.#{$2}, no parent found with name '#{$1}'.", @filename, @linenr)
250
+ Logger.warn(:subproperty, "Ignoring subproperty #{$1}.#{$2}, no parent found with name '#{$1}'.", @filename, @linenr)
252
251
  end
253
252
  else
254
253
  items << it
@@ -257,10 +256,10 @@ module JsDuck
257
256
  items
258
257
  end
259
258
 
260
- def detect_return(doc_map, default_type="undefined")
259
+ def detect_return(doc_map)
261
260
  ret = extract(doc_map, :return) || {}
262
261
  return {
263
- :type => ret[:type] || default_type,
262
+ :type => ret[:type] || "undefined",
264
263
  :name => ret[:name] || "return",
265
264
  :doc => ret[:doc] || "",
266
265
  :properties => doc_map[:return] ? detect_subproperties(:return, doc_map[:return]) : []
@@ -1,71 +1,80 @@
1
- # -*- coding: utf-8 -*-
2
1
  require 'rubygems'
3
2
  require 'strscan'
4
3
  require 'rdiscount'
5
- require 'jsduck/logger'
6
- require 'jsduck/inline_img'
7
- require 'jsduck/inline_video'
8
- require 'jsduck/html'
4
+ require 'jsduck/inline/link'
5
+ require 'jsduck/inline/img'
6
+ require 'jsduck/inline/video'
7
+ require 'jsduck/inline/example'
9
8
 
10
9
  module JsDuck
11
10
 
12
11
  # Formats doc-comments
13
12
  class DocFormatter
14
- # Template HTML that replaces {@link Class#member anchor text}.
15
- # Can contain placeholders:
16
- #
17
- # %c - full class name (e.g. "Ext.Panel")
18
- # %m - class member name prefixed with member type (e.g. "method-urlEncode")
19
- # %# - inserts "#" if member name present
20
- # %- - inserts "-" if member name present
21
- # %a - anchor text for link
22
- #
23
- # Default value: '<a href="%c%M">%a</a>'
24
- attr_accessor :link_tpl
13
+
14
+ # Creates a formatter configured with options originating from
15
+ # command line. For the actual effect of the options see
16
+ # Inline::* classes.
17
+ def initialize(opts={})
18
+ @inline_link = Inline::Link.new(opts)
19
+ @inline_img = Inline::Img.new(opts)
20
+ @inline_video = Inline::Video.new(opts)
21
+ @inline_example = Inline::Example.new(opts)
22
+ end
23
+
24
+ # Sets base path to prefix images from {@img} tags.
25
+ def img_path=(path)
26
+ @inline_img.base_path = path
27
+ end
28
+
29
+ # Returns list of all image paths gathered from {@img} tags.
30
+ def images
31
+ @inline_img.images
32
+ end
25
33
 
26
34
  # Sets up instance to work in context of particular class, so
27
35
  # that when {@link #blah} is encountered it knows that
28
36
  # Context#blah is meant.
29
- attr_accessor :class_context
37
+ def class_context=(cls)
38
+ @inline_link.class_context = cls
39
+ end
30
40
 
31
41
  # Sets up instance to work in context of particular doc object.
32
42
  # Used for error reporting.
33
- attr_accessor :doc_context
43
+ def doc_context=(doc)
44
+ @inline_video.doc_context = doc
45
+ @inline_link.doc_context = doc
46
+ end
34
47
 
35
- # Maximum length for text that doesn't get shortened, defaults to 120
36
- attr_accessor :max_length
48
+ # Returns the current documentation context
49
+ def doc_context
50
+ @inline_link.doc_context
51
+ end
37
52
 
38
53
  # JsDuck::Relations for looking up class names.
39
54
  #
40
55
  # When auto-creating class links from CamelCased names found from
41
56
  # text, we check the relations object to see if a class with that
42
57
  # name actually exists.
43
- attr_accessor :relations
44
-
45
- def initialize(relations={}, opts={})
46
- @class_context = ""
47
- @doc_context = {}
48
- @max_length = 120
49
- @relations = relations
50
- @images = []
51
-
52
- @inline_img = InlineImg.new(opts)
53
- @inline_video = InlineVideo.new(opts)
54
-
55
- @link_tpl = opts[:link_tpl] || '<a href="%c%#%m">%a</a>'
56
- @link_re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m
57
-
58
- @example_annotation_re = /<pre><code>\s*@example( +[^\n]*)?\s+/m
58
+ def relations=(relations)
59
+ @inline_link.relations = relations
59
60
  end
60
61
 
61
- # Sets base path to prefix images from {@img} tags.
62
- def img_path=(path)
63
- @inline_img.base_path = path
64
- end
62
+ # Formats doc-comment for placement into HTML.
63
+ # Renders it with Markdown-formatter and replaces @link-s.
64
+ def format(input)
65
+ # In ExtJS source "<pre>" is often at the end of paragraph, not
66
+ # on its own line. But in that case RDiscount doesn't recognize
67
+ # it as the beginning of <pre>-block and goes on parsing it as
68
+ # normal Markdown, which often causes nested <pre>-blocks.
69
+ #
70
+ # To prevent this, we always add extra newline before <pre>.
71
+ input.gsub!(/([^\n])<pre>/, "\\1\n<pre>")
65
72
 
66
- # Returns list of all image paths gathered from {@img} tags.
67
- def images
68
- @inline_img.images
73
+ # But we remove trailing newline after <pre> to prevent
74
+ # code-blocks beginning with empty line.
75
+ input.gsub!(/<pre>(<code>)?\n?/, "<pre>\\1")
76
+
77
+ replace(RDiscount.new(input).to_html)
69
78
  end
70
79
 
71
80
  # Replaces {@link} and {@img} tags, auto-generates links for
@@ -91,21 +100,17 @@ module JsDuck
91
100
  open_a_tags = 0
92
101
 
93
102
  while !s.eos? do
94
- if s.check(@link_re)
95
- out += replace_link_tag(s.scan(@link_re))
103
+ if substitute = @inline_link.replace(s)
104
+ out += substitute
96
105
  elsif substitute = @inline_img.replace(s)
97
106
  out += substitute
98
- elsif substitute = @inline_video.replace(s, @doc_context)
107
+ elsif substitute = @inline_video.replace(s)
99
108
  out += substitute
100
109
  elsif s.check(/[{]/)
101
110
  # There might still be "{" that doesn't begin {@link} or {@img} - ignore it
102
111
  out += s.scan(/[{]/)
103
- elsif s.check(@example_annotation_re)
104
- # Match possible classnames following @example and add them
105
- # as CSS classes inside <pre> element.
106
- s.scan(@example_annotation_re) =~ @example_annotation_re
107
- css_classes = ($1 || "").strip
108
- out += "<pre class='inline-example #{css_classes}'><code>"
112
+ elsif substitute = @inline_example.replace(s)
113
+ out += substitute
109
114
  elsif s.check(/<a\b/)
110
115
  # Increment number of open <a> tags.
111
116
  open_a_tags += 1
@@ -121,232 +126,16 @@ module JsDuck
121
126
  # Replace class names in the following text up to next "<" or "{"
122
127
  # but only when we're not inside <a>...</a>
123
128
  text = s.scan(/[^{<]+/)
124
- out += open_a_tags > 0 ? text : create_magic_links(text)
125
- end
126
- end
127
- out
128
- end
129
-
130
- def replace_link_tag(input)
131
- input.sub(@link_re) do
132
- target = $1
133
- text = $2
134
- if target =~ /^(.*)#(static-)?(?:(cfg|property|method|event|css_var|css_mixin)-)?(.*)$/
135
- cls = $1.empty? ? @class_context : $1
136
- static = $2 ? true : nil
137
- type = $3 ? $3.intern : nil
138
- member = $4
139
- else
140
- cls = target
141
- static = nil
142
- type = false
143
- member = false
144
- end
145
-
146
- # Construct link text
147
- if text
148
- text = text
149
- elsif member
150
- text = (cls == @class_context) ? member : (cls + "." + member)
151
- else
152
- text = cls
153
- end
154
-
155
- file = @doc_context[:filename]
156
- line = @doc_context[:linenr]
157
- if !@relations[cls]
158
- Logger.instance.warn(:link, "#{input} links to non-existing class", file, line)
159
- return text
160
- elsif member
161
- ms = get_members(cls, member, type, static)
162
- if ms.length == 0
163
- Logger.instance.warn(:link, "#{input} links to non-existing member", file, line)
164
- return text
165
- end
166
-
167
- if ms.length > 1
168
- # When multiple public members, see if there remains just
169
- # one when we ignore the static members. If there's more,
170
- # report ambiguity. If there's only static members, also
171
- # report ambiguity.
172
- instance_ms = ms.find_all {|m| !m[:meta][:static] }
173
- if instance_ms.length > 1
174
- alternatives = instance_ms.map {|m| m[:tagname].to_s }.join(", ")
175
- Logger.instance.warn(:link_ambiguous, "#{input} is ambiguous: "+alternatives, file, line)
176
- elsif instance_ms.length == 0
177
- static_ms = ms.find_all {|m| m[:meta][:static] }
178
- alternatives = static_ms.map {|m| "static " + m[:tagname].to_s }.join(", ")
179
- Logger.instance.warn(:link_ambiguous, "#{input} is ambiguous: "+alternatives, file, line)
180
- end
181
- end
182
-
183
- return link(cls, member, text, type, static)
184
- else
185
- return link(cls, false, text)
186
- end
187
- end
188
- end
189
-
190
- # Looks input text for patterns like:
191
- #
192
- # My.ClassName
193
- # MyClass#method
194
- # #someProperty
195
- #
196
- # and converts them to links, as if they were surrounded with
197
- # {@link} tag. One notable exception is that Foo is not created to
198
- # link, even when Foo class exists, but Foo.Bar is. This is to
199
- # avoid turning normal words into links. For example:
200
- #
201
- # Math involves a lot of numbers. Ext JS is a JavaScript framework.
202
- #
203
- # In these sentences we don't want to link "Math" and "Ext" to the
204
- # corresponding JS classes. And that's why we auto-link only
205
- # class names containing a dot "."
206
- #
207
- def create_magic_links(input)
208
- cls_re = "([A-Z][A-Za-z0-9.]*[A-Za-z0-9])"
209
- member_re = "(?:#([A-Za-z0-9]+))"
210
-
211
- input.gsub(/\b#{cls_re}#{member_re}?\b|#{member_re}\b/m) do
212
- replace_magic_link($1, $2 || $3)
213
- end
214
- end
215
-
216
- def replace_magic_link(cls, member)
217
- if cls && member
218
- if @relations[cls] && get_matching_member(cls, member)
219
- return link(cls, member, cls+"."+member)
220
- else
221
- warn_magic_link("#{cls}##{member} links to non-existing " + (@relations[cls] ? "member" : "class"))
222
- end
223
- elsif cls && cls =~ /\./
224
- if @relations[cls]
225
- return link(cls, nil, cls)
226
- else
227
- cls2, member2 = split_to_cls_and_member(cls)
228
- if @relations[cls2] && get_matching_member(cls2, member2)
229
- return link(cls2, member2, cls2+"."+member2)
230
- elsif cls =~ /\.(js|css|html|php)\Z/
231
- # Ignore common filenames
232
- else
233
- warn_magic_link("#{cls} links to non-existing class")
234
- end
235
- end
236
- elsif !cls && member
237
- if get_matching_member(@class_context, member)
238
- return link(@class_context, member, member)
239
- elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\Z/i || member =~ /\A[0-9]/
240
- # Ignore HEX color codes and
241
- # member names beginning with number
242
- else
243
- warn_magic_link("##{member} links to non-existing member")
129
+ out += open_a_tags > 0 ? text : @inline_link.create_magic_links(text)
244
130
  end
245
131
  end
246
132
 
247
- return "#{cls}#{member ? '#' : ''}#{member}"
248
- end
249
-
250
- def split_to_cls_and_member(str)
251
- parts = str.split(/\./)
252
- return [parts.slice(0, parts.length-1).join("."), parts.last]
253
- end
254
-
255
- def warn_magic_link(msg)
256
- Logger.instance.warn(:link_auto, msg, @doc_context[:filename], @doc_context[:linenr])
133
+ out
257
134
  end
258
135
 
259
- # applies the link template
136
+ # Creates a link based on the link template.
260
137
  def link(cls, member, anchor_text, type=nil, static=nil)
261
- # Use the canonical class name for link (not some alternateClassName)
262
- cls = @relations[cls].full_name
263
- # prepend type name to member name
264
- member = member && get_matching_member(cls, member, type, static)
265
-
266
- @link_tpl.gsub(/(%[\w#-])/) do
267
- case $1
268
- when '%c'
269
- cls
270
- when '%m'
271
- member ? member[:id] : ""
272
- when '%#'
273
- member ? "#" : ""
274
- when '%-'
275
- member ? "-" : ""
276
- when '%a'
277
- HTML.escape(anchor_text||"")
278
- else
279
- $1
280
- end
281
- end
282
- end
283
-
284
- def get_matching_member(cls, member, type=nil, static=nil)
285
- ms = get_members(cls, member, type, static).find_all {|m| !m[:private] }
286
- if ms.length > 1
287
- instance_ms = ms.find_all {|m| !m[:meta][:static] }
288
- instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:meta][:static] }[0]
289
- else
290
- ms[0]
291
- end
292
- end
293
-
294
- def get_members(cls, member, type=nil, static=nil)
295
- @relations[cls] ? @relations[cls].get_members(member, type, static) : []
296
- end
297
-
298
- # Formats doc-comment for placement into HTML.
299
- # Renders it with Markdown-formatter and replaces @link-s.
300
- def format(input)
301
- # In ExtJS source "<pre>" is often at the end of paragraph, not
302
- # on its own line. But in that case RDiscount doesn't recognize
303
- # it as the beginning of <pre>-block and goes on parsing it as
304
- # normal Markdown, which often causes nested <pre>-blocks.
305
- #
306
- # To prevent this, we always add extra newline before <pre>.
307
- input.gsub!(/([^\n])<pre>/, "\\1\n<pre>")
308
-
309
- # But we remove trailing newline after <pre> to prevent
310
- # code-blocks beginning with empty line.
311
- input.gsub!(/<pre>(<code>)?\n?/, "<pre>\\1")
312
-
313
- replace(RDiscount.new(input).to_html)
314
- end
315
-
316
- # Shortens text
317
- #
318
- # 116 chars is also where ext-doc makes its cut, but unlike
319
- # ext-doc we only make the cut when there's more than 120 chars.
320
- #
321
- # This way we don't get stupid expansions like:
322
- #
323
- # Blah blah blah some text...
324
- #
325
- # expanding to:
326
- #
327
- # Blah blah blah some text.
328
- #
329
- def shorten(input)
330
- sent = first_sentence(HTML.strip_tags(input).strip)
331
- # Use u-modifier to correctly count multi-byte characters
332
- chars = sent.scan(/./mu)
333
- if chars.length > @max_length
334
- chars[0..(@max_length-4)].join + "..."
335
- else
336
- sent + " ..."
337
- end
338
- end
339
-
340
- def first_sentence(str)
341
- str.sub(/\A(.+?(\.|。))\s.*\Z/mu, "\\1")
342
- end
343
-
344
- # Returns true when input should get shortened.
345
- def too_long?(input)
346
- stripped = HTML.strip_tags(input).strip
347
- # for sentence v/s full - compare byte length
348
- # for full v/s max - compare char length
349
- first_sentence(stripped).length < stripped.length || stripped.scan(/./mu).length > @max_length
138
+ @inline_link.link(cls, member, anchor_text, type, static)
350
139
  end
351
140
 
352
141
  end