jsduck 4.0.1 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
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