jsduck 4.0.beta → 4.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -0
- data/Rakefile +6 -0
- data/bin/compare +199 -37
- data/bin/graph +52 -0
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/aggregator.rb +6 -0
- data/lib/jsduck/app.rb +7 -4
- data/lib/jsduck/ast.rb +44 -14
- data/lib/jsduck/class.rb +8 -2
- data/lib/jsduck/class_writer.rb +2 -3
- data/lib/jsduck/doc_ast.rb +10 -0
- data/lib/jsduck/doc_formatter.rb +7 -7
- data/lib/jsduck/doc_parser.rb +12 -0
- data/lib/jsduck/enum.rb +73 -0
- data/lib/jsduck/guide_writer.rb +2 -3
- data/lib/jsduck/guides.rb +11 -12
- data/lib/jsduck/importer.rb +102 -0
- data/lib/jsduck/inherit_doc.rb +26 -15
- data/lib/jsduck/lint.rb +10 -0
- data/lib/jsduck/logger.rb +3 -0
- data/lib/jsduck/markdown.rb +46 -0
- data/lib/jsduck/merger.rb +3 -1
- data/lib/jsduck/options.rb +17 -4
- data/lib/jsduck/parallel_wrap.rb +10 -9
- data/lib/jsduck/renderer.rb +21 -0
- data/lib/jsduck/source_file.rb +1 -1
- data/lib/jsduck/source_file_parser.rb +0 -2
- data/lib/jsduck/source_writer.rb +3 -3
- data/lib/jsduck/tag/new.rb +20 -0
- data/lib/jsduck/tag/since.rb +26 -0
- data/lib/jsduck/type_parser.rb +25 -1
- metadata +9 -3
data/lib/jsduck/ast.rb
CHANGED
@@ -73,7 +73,7 @@ module JsDuck
|
|
73
73
|
|
74
74
|
# Foo = ...
|
75
75
|
elsif exp && assignment?(exp) && class_name?(to_s(exp["left"]))
|
76
|
-
make_class(to_s(exp["left"]))
|
76
|
+
make_class(to_s(exp["left"]), exp["right"])
|
77
77
|
|
78
78
|
# var foo = Ext.extend("Parent", {})
|
79
79
|
elsif var && var["init"] && ext_extend?(var["init"])
|
@@ -81,7 +81,7 @@ module JsDuck
|
|
81
81
|
|
82
82
|
# var Foo = ...
|
83
83
|
elsif var && class_name?(to_s(var["id"]))
|
84
|
-
make_class(to_s(var["id"]))
|
84
|
+
make_class(to_s(var["id"]), var["right"])
|
85
85
|
|
86
86
|
# function Foo() {}
|
87
87
|
elsif function?(ast) && class_name?(to_s(ast["id"]))
|
@@ -193,12 +193,20 @@ module JsDuck
|
|
193
193
|
:name => name,
|
194
194
|
}
|
195
195
|
|
196
|
-
# apply information from Ext.extend
|
196
|
+
# apply information from Ext.extend, Ext.define, or {}
|
197
197
|
if ast
|
198
198
|
if ext_extend?(ast)
|
199
|
-
|
199
|
+
args = ast["arguments"]
|
200
|
+
cls[:extends] = to_s(args[0])
|
201
|
+
if args.length == 2 && args[1]["type"] == "ObjectExpression"
|
202
|
+
detect_class_members_from_object(cls, args[1])
|
203
|
+
end
|
200
204
|
elsif ext_define?(ast)
|
201
205
|
detect_ext_define(cls, ast)
|
206
|
+
elsif ast["type"] == "ObjectExpression"
|
207
|
+
detect_class_members_from_object(cls, ast)
|
208
|
+
elsif ast["type"] == "ArrayExpression"
|
209
|
+
detect_class_members_from_array(cls, ast)
|
202
210
|
end
|
203
211
|
end
|
204
212
|
|
@@ -217,6 +225,7 @@ module JsDuck
|
|
217
225
|
cls[:aliases] = []
|
218
226
|
cls[:members] = []
|
219
227
|
cls[:statics] = []
|
228
|
+
cls[:code_type] = :ext_define
|
220
229
|
|
221
230
|
each_pair_in_object_expression(ast["arguments"][1]) do |key, value, pair|
|
222
231
|
case key
|
@@ -247,17 +256,38 @@ module JsDuck
|
|
247
256
|
when "inheritableStatics"
|
248
257
|
cls[:statics] += make_statics(value, {:inheritable => true})
|
249
258
|
else
|
250
|
-
|
251
|
-
m = make_method(key, value)
|
252
|
-
cls[:members] << m if apply_autodetected(m, pair)
|
253
|
-
else
|
254
|
-
p = make_property(key, value)
|
255
|
-
cls[:members] << p if apply_autodetected(p, pair)
|
256
|
-
end
|
259
|
+
detect_method_or_property(cls, key, value, pair)
|
257
260
|
end
|
258
261
|
end
|
259
262
|
end
|
260
263
|
|
264
|
+
# Detects class members from object literal
|
265
|
+
def detect_class_members_from_object(cls, ast)
|
266
|
+
cls[:members] = []
|
267
|
+
each_pair_in_object_expression(ast) do |key, value, pair|
|
268
|
+
detect_method_or_property(cls, key, value, pair)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# Detects class members from array literal
|
273
|
+
def detect_class_members_from_array(cls, ast)
|
274
|
+
cls[:members] = []
|
275
|
+
ast["elements"].each do |el|
|
276
|
+
detect_method_or_property(cls, key_value(el), el, el)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# Detects item in object literal either as method or property
|
281
|
+
def detect_method_or_property(cls, key, value, pair)
|
282
|
+
if function?(value)
|
283
|
+
m = make_method(key, value)
|
284
|
+
cls[:members] << m if apply_autodetected(m, pair)
|
285
|
+
else
|
286
|
+
p = make_property(key, value)
|
287
|
+
cls[:members] << p if apply_autodetected(p, pair)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
261
291
|
def make_extends(cfg_value)
|
262
292
|
return nil unless cfg_value
|
263
293
|
|
@@ -325,8 +355,8 @@ module JsDuck
|
|
325
355
|
# returns false.
|
326
356
|
#
|
327
357
|
# Otherwise detects the line number of member and returns true.
|
328
|
-
def apply_autodetected(m,
|
329
|
-
docset = find_docset(
|
358
|
+
def apply_autodetected(m, ast, inheritable=true)
|
359
|
+
docset = find_docset(ast)
|
330
360
|
|
331
361
|
if !docset || docset[:type] != :doc_comment
|
332
362
|
if inheritable
|
@@ -344,7 +374,7 @@ module JsDuck
|
|
344
374
|
# Get line number from third place at range array.
|
345
375
|
# This third item exists in forked EsprimaJS at
|
346
376
|
# https://github.com/nene/esprima/tree/linenr-in-range
|
347
|
-
m[:linenr] =
|
377
|
+
m[:linenr] = ast["range"][2]
|
348
378
|
return true
|
349
379
|
end
|
350
380
|
end
|
data/lib/jsduck/class.rb
CHANGED
@@ -239,7 +239,11 @@ module JsDuck
|
|
239
239
|
#
|
240
240
|
# Optionally one can also specify type name to differenciate
|
241
241
|
# between different types of members.
|
242
|
-
|
242
|
+
#
|
243
|
+
# Finally static flag can be specified. True to look only at
|
244
|
+
# static members, false to look at instance members, and nil to
|
245
|
+
# look at both.
|
246
|
+
def get_members(name, type_name=nil, static=nil)
|
243
247
|
# build hash of all members
|
244
248
|
unless @members_map
|
245
249
|
@members_map = {}
|
@@ -254,7 +258,9 @@ module JsDuck
|
|
254
258
|
|
255
259
|
ms = @members_map[name] || []
|
256
260
|
ms = ms.find_all {|m| m[:tagname] == type_name } if type_name
|
257
|
-
|
261
|
+
# static = true | false | nil
|
262
|
+
ms = ms.find_all {|m| m[:meta][:static] } if static == true
|
263
|
+
ms = ms.find_all {|m| !m[:meta][:static] } if static == false
|
258
264
|
return ms
|
259
265
|
end
|
260
266
|
|
data/lib/jsduck/class_writer.rb
CHANGED
@@ -10,7 +10,6 @@ module JsDuck
|
|
10
10
|
def initialize(exporter_class, relations, opts)
|
11
11
|
@relations = relations
|
12
12
|
@exporter = exporter_class.new(relations, opts)
|
13
|
-
@parallel = ParallelWrap.new(:in_processes => opts.processes)
|
14
13
|
end
|
15
14
|
|
16
15
|
# Writes class data into given directory or STDOUT when dir == :stdout.
|
@@ -24,13 +23,13 @@ module JsDuck
|
|
24
23
|
private
|
25
24
|
|
26
25
|
def write_stdout
|
27
|
-
json =
|
26
|
+
json = ParallelWrap.map(@relations.classes) {|cls| @exporter.export(cls) }.compact
|
28
27
|
Stdout.instance.add(json)
|
29
28
|
end
|
30
29
|
|
31
30
|
def write_dir(dir, extension)
|
32
31
|
FileUtils.mkdir(dir)
|
33
|
-
|
32
|
+
ParallelWrap.each(@relations.classes) do |cls|
|
34
33
|
filename = dir + "/" + cls[:name] + extension
|
35
34
|
Logger.instance.log("Writing docs", filename)
|
36
35
|
json = @exporter.export(cls)
|
data/lib/jsduck/doc_ast.rb
CHANGED
@@ -51,6 +51,7 @@ module JsDuck
|
|
51
51
|
:singleton => !!doc_map[:singleton],
|
52
52
|
:requires => detect_list(:requires, doc_map),
|
53
53
|
:uses => detect_list(:uses, doc_map),
|
54
|
+
:enum => detect_enum(doc_map),
|
54
55
|
}, doc_map)
|
55
56
|
end
|
56
57
|
|
@@ -276,6 +277,15 @@ module JsDuck
|
|
276
277
|
end
|
277
278
|
end
|
278
279
|
|
280
|
+
def detect_enum(doc_map)
|
281
|
+
return nil unless extract(doc_map, :class, :enum)
|
282
|
+
|
283
|
+
return {
|
284
|
+
:type => extract(doc_map, :class, :type),
|
285
|
+
:default => extract(doc_map, :class, :default),
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
279
289
|
# Combines :doc-s of most tags
|
280
290
|
# Ignores tags that have doc comment themselves and subproperty tags
|
281
291
|
def detect_doc(docs)
|
data/lib/jsduck/doc_formatter.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'rubygems'
|
3
|
-
require 'rdiscount'
|
4
3
|
require 'strscan'
|
4
|
+
require 'jsduck/markdown'
|
5
5
|
require 'jsduck/logger'
|
6
6
|
require 'jsduck/inline_img'
|
7
7
|
require 'jsduck/inline_video'
|
@@ -133,12 +133,12 @@ module JsDuck
|
|
133
133
|
text = $2
|
134
134
|
if target =~ /^(.*)#(static-)?(?:(cfg|property|method|event|css_var|css_mixin)-)?(.*)$/
|
135
135
|
cls = $1.empty? ? @class_context : $1
|
136
|
-
static =
|
136
|
+
static = $2 ? true : nil
|
137
137
|
type = $3 ? $3.intern : nil
|
138
138
|
member = $4
|
139
139
|
else
|
140
140
|
cls = target
|
141
|
-
static =
|
141
|
+
static = nil
|
142
142
|
type = false
|
143
143
|
member = false
|
144
144
|
end
|
@@ -257,7 +257,7 @@ module JsDuck
|
|
257
257
|
end
|
258
258
|
|
259
259
|
# applies the link template
|
260
|
-
def link(cls, member, anchor_text, type=nil, static=
|
260
|
+
def link(cls, member, anchor_text, type=nil, static=nil)
|
261
261
|
# Use the canonical class name for link (not some alternateClassName)
|
262
262
|
cls = @relations[cls].full_name
|
263
263
|
# prepend type name to member name
|
@@ -281,7 +281,7 @@ module JsDuck
|
|
281
281
|
end
|
282
282
|
end
|
283
283
|
|
284
|
-
def get_matching_member(cls, member, type=nil, static=
|
284
|
+
def get_matching_member(cls, member, type=nil, static=nil)
|
285
285
|
ms = get_members(cls, member, type, static).find_all {|m| !m[:private] }
|
286
286
|
if ms.length > 1
|
287
287
|
instance_ms = ms.find_all {|m| !m[:meta][:static] }
|
@@ -291,7 +291,7 @@ module JsDuck
|
|
291
291
|
end
|
292
292
|
end
|
293
293
|
|
294
|
-
def get_members(cls, member, type=nil, static=
|
294
|
+
def get_members(cls, member, type=nil, static=nil)
|
295
295
|
@relations[cls] ? @relations[cls].get_members(member, type, static) : []
|
296
296
|
end
|
297
297
|
|
@@ -310,7 +310,7 @@ module JsDuck
|
|
310
310
|
# code-blocks beginning with empty line.
|
311
311
|
input.gsub!(/<pre>(<code>)?\n?/, "<pre>\\1")
|
312
312
|
|
313
|
-
replace(
|
313
|
+
replace(JsDuck::Markdown.to_html(input))
|
314
314
|
end
|
315
315
|
|
316
316
|
# Shortens text
|
data/lib/jsduck/doc_parser.rb
CHANGED
@@ -130,6 +130,8 @@ module JsDuck
|
|
130
130
|
at_var
|
131
131
|
elsif look(/@throws\b/)
|
132
132
|
at_throws
|
133
|
+
elsif look(/@enum\b/)
|
134
|
+
at_enum
|
133
135
|
elsif look(/@inheritable\b/)
|
134
136
|
boolean_at_tag(/@inheritable/, :inheritable)
|
135
137
|
elsif look(/@accessor\b/)
|
@@ -282,6 +284,16 @@ module JsDuck
|
|
282
284
|
skip_white
|
283
285
|
end
|
284
286
|
|
287
|
+
# matches @enum {type} name ...
|
288
|
+
def at_enum
|
289
|
+
match(/@enum/)
|
290
|
+
add_tag(:class)
|
291
|
+
@current_tag[:enum] = true
|
292
|
+
maybe_type
|
293
|
+
maybe_name_with_default
|
294
|
+
skip_white
|
295
|
+
end
|
296
|
+
|
285
297
|
# matches @type {type} or @type type
|
286
298
|
#
|
287
299
|
# The presence of @type implies that we are dealing with property.
|
data/lib/jsduck/enum.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module JsDuck
|
2
|
+
|
3
|
+
class Enum
|
4
|
+
def initialize(classes)
|
5
|
+
@classes = classes
|
6
|
+
end
|
7
|
+
|
8
|
+
# Applies additional processing to all enum-classes.
|
9
|
+
def process_all!
|
10
|
+
@classes.each_value do |cls|
|
11
|
+
if cls[:enum]
|
12
|
+
process(cls)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# processes single class
|
20
|
+
def process(cls)
|
21
|
+
expand_default(cls)
|
22
|
+
strip_inheritdoc(cls)
|
23
|
+
cls[:enum][:type] = infer_type(cls) unless cls[:enum][:type]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Given an enum class, returns the type infered from its values.
|
27
|
+
def infer_type(cls)
|
28
|
+
if cls[:members][:property].length > 0
|
29
|
+
types = cls[:members][:property].map {|p| p[:type] }
|
30
|
+
types.sort.uniq.join("/")
|
31
|
+
else
|
32
|
+
"Object"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Expands default value like widget.* into list of properties
|
37
|
+
def expand_default(cls)
|
38
|
+
if cls[:enum][:default] =~ /\A(.*)\.\*\Z/
|
39
|
+
each_alias($1) do |name, owner|
|
40
|
+
cls[:members][:property] << {
|
41
|
+
:tagname => :property,
|
42
|
+
:id => 'property-' + name,
|
43
|
+
:name => name,
|
44
|
+
:default => "'" + name + "'",
|
45
|
+
:type => "String",
|
46
|
+
:meta => {:private => owner[:private]},
|
47
|
+
:private => owner[:private],
|
48
|
+
:files => cls[:files],
|
49
|
+
:owner => cls[:name],
|
50
|
+
:doc => "Alias for {@link #{owner[:name]}}.",
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def each_alias(prefix)
|
57
|
+
@classes.each_value do |cls|
|
58
|
+
if cls[:aliases] && cls[:aliases][prefix]
|
59
|
+
cls[:aliases][prefix].each {|name| yield(name, cls) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Remove the auto-inserted inheritdoc tag so the auto-detected enum
|
65
|
+
# values default to being public.
|
66
|
+
def strip_inheritdoc(cls)
|
67
|
+
cls[:members][:property].each do |p|
|
68
|
+
p[:inheritdoc] = nil if p[:autodetected]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/lib/jsduck/guide_writer.rb
CHANGED
@@ -10,7 +10,6 @@ module JsDuck
|
|
10
10
|
def initialize(exporter_class, guides, opts)
|
11
11
|
@guides = guides
|
12
12
|
@exporter = exporter_class.new(guides, opts)
|
13
|
-
@parallel = ParallelWrap.new(:in_processes => opts.processes)
|
14
13
|
end
|
15
14
|
|
16
15
|
# Writes guide data into given directory or STDOUT when dir == :stdout.
|
@@ -24,13 +23,13 @@ module JsDuck
|
|
24
23
|
private
|
25
24
|
|
26
25
|
def write_stdout
|
27
|
-
json =
|
26
|
+
json = ParallelWrap.map(all_guides) {|guide| @exporter.export_guide(guide) }.compact
|
28
27
|
Stdout.instance.add(json)
|
29
28
|
end
|
30
29
|
|
31
30
|
def write_dir(dir, extension)
|
32
31
|
FileUtils.mkdir(dir) unless File.exists?(dir)
|
33
|
-
|
32
|
+
ParallelWrap.each(all_guides) do |guide|
|
34
33
|
filename = dir + "/" + guide["name"] + extension
|
35
34
|
Logger.instance.log("Writing guide", filename)
|
36
35
|
json = @exporter.export_guide(guide)
|
data/lib/jsduck/guides.rb
CHANGED
@@ -36,15 +36,13 @@ module JsDuck
|
|
36
36
|
end
|
37
37
|
|
38
38
|
# Modified each_item that also loads HTML for each guide
|
39
|
-
def each_item
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
def each_item
|
40
|
+
super do |guide|
|
41
|
+
# Load the guide if not loaded
|
42
|
+
guide[:html] = load_guide(guide) if guide[:html] == nil
|
43
|
+
# Pass guide to block if it was successfully loaded.
|
44
|
+
yield guide if guide[:html]
|
45
45
|
end
|
46
|
-
|
47
|
-
super(&block)
|
48
46
|
end
|
49
47
|
|
50
48
|
# Modified to_array that excludes the :html from guide nodes
|
@@ -60,12 +58,13 @@ module JsDuck
|
|
60
58
|
def load_guide(guide)
|
61
59
|
in_dir = @path + "/guides/" + guide["name"]
|
62
60
|
|
63
|
-
|
64
|
-
return Logger.instance.warn(:guide, "Guide #{in_dir} not found") unless File.exists?(in_dir)
|
61
|
+
return Logger.instance.warn(:guide, "Guide #{in_dir} not found") unless File.exists?(in_dir)
|
65
62
|
|
66
|
-
|
67
|
-
return Logger.instance.warn(:guide, "README.md not found in #{in_dir}") unless File.exists?(guide_file)
|
63
|
+
guide_file = in_dir + "/README.md"
|
68
64
|
|
65
|
+
return Logger.instance.warn(:guide, "README.md not found in #{in_dir}") unless File.exists?(guide_file)
|
66
|
+
|
67
|
+
begin
|
69
68
|
@formatter.doc_context = {:filename => guide_file, :linenr => 0}
|
70
69
|
name = File.basename(in_dir)
|
71
70
|
@formatter.img_path = "guides/#{name}"
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'jsduck/json_duck'
|
2
|
+
require 'jsduck/null_object'
|
3
|
+
require 'jsduck/logger'
|
4
|
+
require 'jsduck/parallel_wrap'
|
5
|
+
|
6
|
+
module JsDuck
|
7
|
+
|
8
|
+
# Reads in JSDuck exports of different versions of docs.
|
9
|
+
module Importer
|
10
|
+
module_function
|
11
|
+
|
12
|
+
# Loads in exported docs and generates @since and @new tags based on that data.
|
13
|
+
def import(imports, relations)
|
14
|
+
if imports.length > 0
|
15
|
+
generate_since_tags(read_all(imports), relations)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Reads in data for all versions, returning array of
|
20
|
+
# version/class-data pairs. We don't use a hash to preserve the
|
21
|
+
# order of versions (from oldest to newest).
|
22
|
+
def read_all(imports)
|
23
|
+
imports.map do |ver|
|
24
|
+
{
|
25
|
+
:version => ver[:version],
|
26
|
+
:classes => ver[:path] ? read(ver) : current_version,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_version
|
32
|
+
NullObject.new(:[] => NullObject.new(:[] => true))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Reads in data from all .json files in directory
|
36
|
+
def read(ver)
|
37
|
+
# Map list of files into pairs of (classname, members-hash)
|
38
|
+
pairs = ParallelWrap.map(Dir[ver[:path] + "/*.json"]) do |filename|
|
39
|
+
JsDuck::Logger.instance.log("Importing #{ver[:version]}", filename)
|
40
|
+
json = JsonDuck.read(filename)
|
41
|
+
[json["name"], members_id_index(json)]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Turn key-value pairs array into hash
|
45
|
+
return Hash[ pairs ]
|
46
|
+
end
|
47
|
+
|
48
|
+
# creates index of all class members
|
49
|
+
def members_id_index(json)
|
50
|
+
index = {}
|
51
|
+
["members", "statics"].each do |group_name|
|
52
|
+
json[group_name].each_pair do |tagname, members|
|
53
|
+
members.each do |m|
|
54
|
+
index[m["id"]] = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
index
|
59
|
+
end
|
60
|
+
|
61
|
+
# Using the imported versions data, adds @since tags to all
|
62
|
+
# classes/members.
|
63
|
+
def generate_since_tags(versions, relations)
|
64
|
+
last_version = versions.last[:version]
|
65
|
+
|
66
|
+
relations.each do |cls|
|
67
|
+
v = cls[:meta][:since] || class_since(versions, cls)
|
68
|
+
cls[:meta][:since] = v
|
69
|
+
cls[:meta][:new] = true if v == last_version
|
70
|
+
|
71
|
+
cls.all_local_members.each do |m|
|
72
|
+
v = m[:meta][:since] || member_since(versions, cls, m)
|
73
|
+
m[:meta][:since] = v
|
74
|
+
m[:meta][:new] = true if v == last_version
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def member_since(versions, cls, m)
|
80
|
+
versions.each do |ver|
|
81
|
+
c = ver[:classes][cls[:name]]
|
82
|
+
return ver[:version] if c && c[m[:id]]
|
83
|
+
cls[:alternateClassNames].each do |name|
|
84
|
+
c = ver[:classes][name]
|
85
|
+
return ver[:version] if c && c[m[:id]]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns name of the version since which the class is available
|
91
|
+
def class_since(versions, cls)
|
92
|
+
versions.each do |ver|
|
93
|
+
return ver[:version] if ver[:classes][cls[:name]]
|
94
|
+
cls[:alternateClassNames].each do |name|
|
95
|
+
return ver[:version] if ver[:classes][name]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|