yard-link_stdlib 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bin/make_map.rb +55 -18
- data/lib/yard/cli/link_stdlib.rb +270 -53
- data/lib/yard/link_stdlib/html_helper.rb +8 -22
- data/lib/yard/link_stdlib/object_map.rb +253 -39
- data/lib/yard/link_stdlib/ruby_source.rb +22 -1
- data/lib/yard/link_stdlib/ruby_version.rb +4 -3
- data/lib/yard/link_stdlib/version.rb +3 -3
- data/lib/yard/link_stdlib.rb +439 -167
- data/maps/ruby-2.3.0.json.gz +0 -0
- data/maps/ruby-2.4.0.json.gz +0 -0
- data/maps/ruby-2.5.0.json.gz +0 -0
- metadata +32 -5
- data/lib/yard/link_stdlib/dump.rb +0 -74
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# encoding: UTF-8
|
3
|
+
# doctest: true
|
3
4
|
|
4
5
|
|
5
6
|
# Requirements
|
@@ -56,11 +57,55 @@ class ObjectMap
|
|
56
57
|
}
|
57
58
|
|
58
59
|
@@current = nil
|
60
|
+
|
61
|
+
|
62
|
+
# A map of module names that we know *actually* point to another one.
|
63
|
+
#
|
64
|
+
# This is basically here to support {YAML}, which internally points to
|
65
|
+
# {Psych} in a truly annoying fashion... seems to be a remnant from when
|
66
|
+
# `Syck` was around, but that appears to have been yanked out years ago
|
67
|
+
# around Ruby 2.0, and I can't think of seeing anyone use anything except
|
68
|
+
# {Psych} for about a decade.
|
69
|
+
#
|
70
|
+
# However, it means that there is no entry in the object map for things like
|
71
|
+
# {YAML.load}, which are pretty commonly used. This functionality allows
|
72
|
+
# us to address that, by being aware that {YAML} points to {Psych} for
|
73
|
+
# practical purposes.
|
74
|
+
#
|
75
|
+
# @return [Hash<String, String>]
|
76
|
+
#
|
77
|
+
@@module_aliases = {
|
78
|
+
"YAML" => "Psych",
|
79
|
+
}
|
80
|
+
|
81
|
+
@@name_rewrites = {
|
82
|
+
# The instance methods of the {JSON} module are encapsulated in a
|
83
|
+
# {Module#module_function} context, which adds them as module methods as
|
84
|
+
# well, but RDoc doesn't seem to pick that up, so we just transform them
|
85
|
+
# to make this bullshit work.
|
86
|
+
#
|
87
|
+
# Creates mappings like:
|
88
|
+
#
|
89
|
+
# "JSON::load" => "JSON.html#method-i-load"
|
90
|
+
# "JSON::dump" => "JSON.html#method-i-dump"
|
91
|
+
#
|
92
|
+
/\AJSON#(.*)\z/ => ->( match ) { "JSON::#{ match[ 1 ] }" },
|
93
|
+
}
|
59
94
|
|
60
95
|
|
61
|
-
#
|
96
|
+
# Singleton Methods
|
62
97
|
# ========================================================================
|
63
|
-
|
98
|
+
|
99
|
+
# Set the directory in which to load and store map data. Must exist.
|
100
|
+
#
|
101
|
+
# @param [String | Pathname] path
|
102
|
+
# New data directory. Will be expanded.
|
103
|
+
#
|
104
|
+
# @return [Pathname]
|
105
|
+
#
|
106
|
+
# @raise [ArgumentError]
|
107
|
+
# If `path` is not a directory.
|
108
|
+
#
|
64
109
|
def self.data_dir= path
|
65
110
|
expanded = Pathname.new( path ).expand_path
|
66
111
|
|
@@ -74,12 +119,24 @@ class ObjectMap
|
|
74
119
|
@@data_dir = expanded
|
75
120
|
end
|
76
121
|
|
77
|
-
|
122
|
+
|
123
|
+
# The directory in which to load and store object map data.
|
124
|
+
#
|
125
|
+
# @example
|
126
|
+
# YARD::LinkStdlib::ObjectMap.data_dir
|
127
|
+
# #=> Pathname.new "#{ LinkStdlib::ROOT }/maps"
|
128
|
+
#
|
129
|
+
# @return [Pathname]
|
130
|
+
#
|
78
131
|
def self.data_dir
|
79
132
|
@@data_dir
|
80
133
|
end
|
81
134
|
|
82
|
-
|
135
|
+
|
136
|
+
# Get the {ObjectMap} for {RubyVersion.get}.
|
137
|
+
#
|
138
|
+
# @return [ObjectMap]
|
139
|
+
#
|
83
140
|
def self.current
|
84
141
|
version = RubyVersion.get
|
85
142
|
|
@@ -90,43 +147,40 @@ class ObjectMap
|
|
90
147
|
@@current
|
91
148
|
end
|
92
149
|
|
93
|
-
|
94
150
|
|
95
|
-
#
|
151
|
+
# Get all the object maps present.
|
96
152
|
#
|
97
|
-
# @
|
98
|
-
# @todo Add name param description.
|
153
|
+
# @return [Array<ObjectMap>]
|
99
154
|
#
|
100
|
-
|
101
|
-
# @todo Document return value.
|
102
|
-
#
|
103
|
-
def self.list
|
155
|
+
def self.all
|
104
156
|
data_dir.entries.
|
105
157
|
select { |filename| filename.to_s =~ /\Aruby\-(\d+\.)+json\.gz\z/ }.
|
106
158
|
map { |filename|
|
107
159
|
new File.basename( filename.to_s, '.json.gz' ).sub( /\Aruby\-/, '' )
|
108
160
|
}.
|
109
161
|
sort
|
110
|
-
end # .
|
111
|
-
|
112
|
-
|
113
|
-
#
|
114
|
-
#
|
115
|
-
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
|
120
|
-
#
|
121
|
-
#
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
162
|
+
end # .all
|
163
|
+
|
164
|
+
|
165
|
+
# Add a Ruby version (download and build map data, see {#make}).
|
166
|
+
#
|
167
|
+
# @param [String | Gem::Version] ruby_version
|
168
|
+
# Version to add.
|
169
|
+
#
|
170
|
+
# @param [Boolean] force
|
171
|
+
# Pass `true` to re-build map when already present (see {#make}).
|
172
|
+
#
|
173
|
+
# @return [ObjectMap]
|
174
|
+
# Added map.
|
175
|
+
#
|
176
|
+
def self.add ruby_version, force: false
|
177
|
+
new( ruby_version ).make force: force
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
def self.remove ruby_version, remove_source: true, force: false
|
182
|
+
raise "TODO"
|
183
|
+
end
|
130
184
|
|
131
185
|
|
132
186
|
# Ruby version.
|
@@ -134,18 +188,45 @@ class ObjectMap
|
|
134
188
|
# @return [Gem::Version]
|
135
189
|
#
|
136
190
|
attr_reader :version
|
137
|
-
|
138
|
-
|
191
|
+
|
192
|
+
|
193
|
+
# Construction
|
194
|
+
# ==========================================================================
|
195
|
+
|
196
|
+
# Instantiate an {ObjectMap} for a Ruby version.
|
197
|
+
#
|
198
|
+
# This just initialized the interface - the source may need to be downloaded
|
199
|
+
# and the map generated (see {#make}) to use it for anything.
|
200
|
+
#
|
201
|
+
# @param [String | Gem::Version] version
|
202
|
+
# Ruby version.
|
203
|
+
#
|
139
204
|
def initialize version
|
140
205
|
@version = Gem::Version.new version
|
141
206
|
end
|
207
|
+
|
208
|
+
|
209
|
+
# Instance Methods
|
210
|
+
# ==========================================================================
|
142
211
|
|
143
|
-
|
212
|
+
|
213
|
+
# The name for this {ObjectMap}'s data file.
|
214
|
+
#
|
215
|
+
# @example
|
216
|
+
# YARD::LinkStdlib::ObjectMap.new( '2.3.7' ).filename
|
217
|
+
# #=> "ruby-2.3.7.json.gz"
|
218
|
+
#
|
219
|
+
# @return [String]
|
220
|
+
#
|
144
221
|
def filename
|
145
222
|
@filename ||= "ruby-#{ version }.json.gz"
|
146
223
|
end
|
147
224
|
|
148
|
-
|
225
|
+
|
226
|
+
# Absolute path to this {ObjectMap}'s data file.
|
227
|
+
#
|
228
|
+
# @return [Pathname]
|
229
|
+
#
|
149
230
|
def path
|
150
231
|
@path ||= self.class.data_dir.join filename
|
151
232
|
end
|
@@ -159,12 +240,23 @@ class ObjectMap
|
|
159
240
|
path.exist?
|
160
241
|
end
|
161
242
|
|
162
|
-
|
243
|
+
|
244
|
+
# The {RubySource} interface for this {ObjectMap}.
|
245
|
+
#
|
246
|
+
# @return [RubySource]
|
247
|
+
#
|
163
248
|
def source
|
164
249
|
@source ||= RubySource.new version
|
165
250
|
end
|
166
251
|
|
167
|
-
|
252
|
+
|
253
|
+
# Build the map data file (if needed or forced).
|
254
|
+
#
|
255
|
+
# @param [Boolean] force
|
256
|
+
# Set to true to re-build even if the map data file is present.
|
257
|
+
#
|
258
|
+
# @return [ObjectMap] self
|
259
|
+
#
|
168
260
|
def make force: false
|
169
261
|
# Bail unless forced or the map is not present
|
170
262
|
if force
|
@@ -193,6 +285,7 @@ class ObjectMap
|
|
193
285
|
|
194
286
|
def data reload: false
|
195
287
|
if reload || @data.nil?
|
288
|
+
@name_rewrites = nil
|
196
289
|
@data = Zlib::GzipReader.open path do |gz|
|
197
290
|
JSON.load gz.read
|
198
291
|
end
|
@@ -200,8 +293,129 @@ class ObjectMap
|
|
200
293
|
|
201
294
|
@data
|
202
295
|
end
|
296
|
+
|
297
|
+
|
298
|
+
# Names of the objects in {#data} (equivalent to `self.data.keys`).
|
299
|
+
#
|
300
|
+
# @param [Boolean] reload
|
301
|
+
# When `true`, reload the {#data} from disk first.
|
302
|
+
#
|
303
|
+
# @return [Array<String>]
|
304
|
+
#
|
305
|
+
def names reload: false
|
306
|
+
data( reload: reload ).keys
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
def name_rewrites reload: false
|
311
|
+
data( reload: true ) if reload
|
312
|
+
|
313
|
+
@name_rewrites ||= \
|
314
|
+
data.each_with_object( {} ) do |(name, rel_path), name_rewrites|
|
315
|
+
@@name_rewrites.each do |regexp, transformer|
|
316
|
+
if (match = regexp.match( name ))
|
317
|
+
name_rewrites[ transformer.call match ] = rel_path
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
|
324
|
+
# Get the relative path for the URL of an online stdlib document given the
|
325
|
+
# code object's name.
|
326
|
+
#
|
327
|
+
# @example
|
328
|
+
# YARD::LinkStdlib::ObjectMap.current.resolve 'String'
|
329
|
+
# #=> [ 'String', 'String.html' ]
|
330
|
+
#
|
331
|
+
# @example De-Aliasing
|
332
|
+
# YARD::LinkStdlib::ObjectMap.current.resolve 'YAML.load'
|
333
|
+
# #=> [ 'Psych::load', 'Psych.html#method-c-load' ]
|
334
|
+
#
|
335
|
+
# @param [String] name
|
336
|
+
#
|
337
|
+
# @return [nil]
|
338
|
+
# The (normalized) `name` was not found in the {ObjectMap}.
|
339
|
+
#
|
340
|
+
# @return [Array[(String, String?)>]
|
341
|
+
# The normalized name (which may be totally different than the `name`
|
342
|
+
# argument due to de-aliasing) followed by the relative URL path to it's
|
343
|
+
# doc.
|
344
|
+
#
|
345
|
+
def resolve name
|
346
|
+
name = LinkStdlib.normalize_name name
|
347
|
+
rel_path = data[ name ]
|
348
|
+
|
349
|
+
if rel_path.nil?
|
350
|
+
split = name.split '::'
|
351
|
+
|
352
|
+
if (de_aliased_module_name = @@module_aliases[ split.first ])
|
353
|
+
de_aliased_name = \
|
354
|
+
[ de_aliased_module_name, *split[ 1..-1 ] ].join( '::' )
|
355
|
+
|
356
|
+
if (de_aliased_module_name = data[ de_aliased_name ])
|
357
|
+
return [ de_aliased_name, de_aliased_module_name ]
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
if (rewritten_rel_path = name_rewrites[ name ])
|
362
|
+
log.debug "Found re-written relative path: " +
|
363
|
+
"#{ name } -> #{ rewritten_rel_path.inspect }"
|
364
|
+
|
365
|
+
return [ name, rewritten_rel_path ]
|
366
|
+
end # if rewritten_rel_path
|
367
|
+
end # if rel_path.nil?
|
368
|
+
|
369
|
+
# NOTE `rel_path` may be `nil`, indicating we didn't find shit
|
370
|
+
[ name, rel_path ]
|
371
|
+
end # .resolve
|
372
|
+
|
373
|
+
|
374
|
+
# Get the doc URL for a name.
|
375
|
+
#
|
376
|
+
# @example Using defaults
|
377
|
+
# YARD::LinkStdlib::ObjectMap.current.url_for 'String'
|
378
|
+
# #=> 'https://docs.ruby-lang.org/en/2.3.0/String.html'
|
379
|
+
#
|
380
|
+
# @example Manually override components
|
381
|
+
# YARD::LinkStdlib::ObjectMap.current.url_for 'String',
|
382
|
+
# https: false,
|
383
|
+
# domain: 'example.com',
|
384
|
+
# lang: 'ja'
|
385
|
+
# #=> 'http://example.com/ja/2.3.0/String.html'
|
386
|
+
#
|
387
|
+
# @param [String] name
|
388
|
+
# Name of the code object.
|
389
|
+
#
|
390
|
+
# @param [Hash<Symbol, Object>] url_options
|
391
|
+
# Passed to {LinkStdlib.build_url}.
|
392
|
+
#
|
393
|
+
# @return [nil]
|
394
|
+
# The (normalized) `name` was not found in the {ObjectMap}.
|
395
|
+
#
|
396
|
+
# @return [String]
|
397
|
+
# The fully-formed URL to the online doc.
|
398
|
+
#
|
399
|
+
def url_for name, **url_options
|
400
|
+
name, rel_path = resolve name
|
401
|
+
|
402
|
+
if rel_path
|
403
|
+
LinkStdlib.build_url \
|
404
|
+
rel_path,
|
405
|
+
**url_options,
|
406
|
+
version: RubyVersion.minor( version )
|
407
|
+
end
|
408
|
+
end # .url_for
|
409
|
+
|
410
|
+
|
411
|
+
# Language Integration Instance Methods
|
412
|
+
# --------------------------------------------------------------------------
|
203
413
|
|
204
|
-
|
414
|
+
# Compare {ObjectMap} instances by their {#version} (used to sort them).
|
415
|
+
#
|
416
|
+
# @return [Fixnum]
|
417
|
+
# `0` is equal, negatives and positives denote order.
|
418
|
+
#
|
205
419
|
def <=> other
|
206
420
|
version <=> other.version
|
207
421
|
end
|
@@ -35,7 +35,22 @@ class RubySource
|
|
35
35
|
|
36
36
|
# Class Methods
|
37
37
|
# ============================================================================
|
38
|
-
|
38
|
+
|
39
|
+
|
40
|
+
def self.make_missing?
|
41
|
+
unless instance_variable_defined? :@make_missing
|
42
|
+
@make_missing = true
|
43
|
+
end
|
44
|
+
|
45
|
+
@make_missing
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def self.make_missing= value
|
50
|
+
@make_missing = !!value
|
51
|
+
end
|
52
|
+
|
53
|
+
|
39
54
|
# Ensure the version's source is downloaded and extracted.
|
40
55
|
#
|
41
56
|
# @example
|
@@ -157,6 +172,12 @@ class RubySource
|
|
157
172
|
log.info "Source for Ruby #{ version } is present."
|
158
173
|
return
|
159
174
|
end
|
175
|
+
|
176
|
+
unless self.class.make_missing?
|
177
|
+
raise RuntimeError,
|
178
|
+
"Object map for Ruby version #{ version } missing; " +
|
179
|
+
"not configured to auto-make"
|
180
|
+
end
|
160
181
|
|
161
182
|
# Download unless the tar's already there
|
162
183
|
download
|
@@ -91,8 +91,9 @@ module RubyVersion
|
|
91
91
|
#
|
92
92
|
# @return [Gem::Version]
|
93
93
|
#
|
94
|
-
def self.minor
|
95
|
-
Gem::Version.new
|
94
|
+
def self.minor version = self.get
|
95
|
+
Gem::Version.new \
|
96
|
+
( version.segments[0..1] + [0] ).map( &:to_s ).join( '.' )
|
96
97
|
end
|
97
98
|
|
98
99
|
|
@@ -101,7 +102,7 @@ module RubyVersion
|
|
101
102
|
# we were happy with from the gemspec.
|
102
103
|
#
|
103
104
|
# @param [:minimum_supported, :latest_stable, :current_runtime] value
|
104
|
-
# Just picks which of these versions {
|
105
|
+
# Just picks which of these versions {.fallback} will use:
|
105
106
|
#
|
106
107
|
# 1. {MINIMUM_SUPPORTED}
|
107
108
|
# 2. {LATEST_STABLE}
|
@@ -55,13 +55,13 @@ def self.repo?
|
|
55
55
|
ROOT.join( 'dev' ).directory?
|
56
56
|
end
|
57
57
|
|
58
|
-
# {Singleton} extension of {Gem::Version} that loads {
|
58
|
+
# {Singleton} extension of {Gem::Version} that loads {VERSION} and
|
59
59
|
# provides some convenient methods.
|
60
60
|
#
|
61
61
|
class Version < Gem::Version
|
62
62
|
include ::Singleton
|
63
63
|
|
64
|
-
# Private method to instantiate the {
|
64
|
+
# Private method to instantiate the {.instance} using the {VERSION}
|
65
65
|
# {String}.
|
66
66
|
#
|
67
67
|
# @return [Version]
|
@@ -74,7 +74,7 @@ class Version < Gem::Version
|
|
74
74
|
# instances.
|
75
75
|
private_class_method :new
|
76
76
|
|
77
|
-
# Proxies to the {
|
77
|
+
# Proxies to the {.instance}'s {#dev?}.
|
78
78
|
#
|
79
79
|
# @return (see #dev?)
|
80
80
|
#
|