yard-link_stdlib 0.1.0 → 0.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.
- 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
|
#
|