yard-link_stdlib 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +28 -0
- data/NAME +1 -0
- data/README.md +39 -0
- data/VERSION +1 -0
- data/bin/make_map.rb +107 -0
- data/lib/yard-link_stdlib.rb +21 -0
- data/lib/yard/cli/link_stdlib.rb +147 -0
- data/lib/yard/link_stdlib.rb +212 -0
- data/lib/yard/link_stdlib/dump.rb +74 -0
- data/lib/yard/link_stdlib/html_helper.rb +133 -0
- data/lib/yard/link_stdlib/object_map.rb +217 -0
- data/lib/yard/link_stdlib/ruby_source.rb +189 -0
- data/lib/yard/link_stdlib/ruby_version.rb +233 -0
- data/lib/yard/link_stdlib/version.rb +101 -0
- 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 +176 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
|
5
|
+
# Namespace
|
6
|
+
# ========================================================================
|
7
|
+
|
8
|
+
module YARD
|
9
|
+
module LinkStdlib
|
10
|
+
|
11
|
+
|
12
|
+
# Definitions
|
13
|
+
# ========================================================================
|
14
|
+
|
15
|
+
# Dump a hash of values as a `debug`-level log message (`log` is a global
|
16
|
+
# function when you're hangin' in the YARD).
|
17
|
+
#
|
18
|
+
# @example Dump values with a message
|
19
|
+
# dump "There was a problem with the ", obj, "object!",
|
20
|
+
# value_a: value_a,
|
21
|
+
# value_b: value_b
|
22
|
+
#
|
23
|
+
# @example Dump values without a message
|
24
|
+
# dump value_a: value_a, value_b: value_b
|
25
|
+
#
|
26
|
+
# @param [Array<String | Object>] message
|
27
|
+
# Optional log message. Entries will be space-joined to form the message
|
28
|
+
# string: strings will be left as-is, and other objects will be
|
29
|
+
# stringified by calling their `#inspect` method. See examples.
|
30
|
+
#
|
31
|
+
# @param [Hash<Symbol, Object>] values
|
32
|
+
# Map of names to values to dump.
|
33
|
+
#
|
34
|
+
# @return
|
35
|
+
# Whatever `log.debug` returns.
|
36
|
+
#
|
37
|
+
def self.dump *message, **values
|
38
|
+
|
39
|
+
max_name_length = values.
|
40
|
+
keys.
|
41
|
+
map { |name| name.to_s.length }.
|
42
|
+
max
|
43
|
+
|
44
|
+
values_str = values.
|
45
|
+
map { |name, value|
|
46
|
+
name_str = "%-#{ max_name_length + 2 }s" % "#{ name }:"
|
47
|
+
|
48
|
+
" #{ name_str } #{ value.inspect } (#{ value.class })"
|
49
|
+
}.
|
50
|
+
join( "\n" )
|
51
|
+
|
52
|
+
message_str = message.
|
53
|
+
map { |part|
|
54
|
+
case part
|
55
|
+
when String
|
56
|
+
part
|
57
|
+
else
|
58
|
+
part.inspect
|
59
|
+
end
|
60
|
+
}.
|
61
|
+
join( " " )
|
62
|
+
|
63
|
+
log_str = "Values:\n\n#{ values_str }\n"
|
64
|
+
log_str = "#{ message_str }\n\n#{ log_str }" unless message_str.empty?
|
65
|
+
|
66
|
+
log.debug "yard-link_stdlib: #{ log_str }"
|
67
|
+
end # .dump
|
68
|
+
|
69
|
+
|
70
|
+
# /Namespace
|
71
|
+
# ========================================================================
|
72
|
+
|
73
|
+
end # module LinkStdlib
|
74
|
+
end # module YARD
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# ========================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# ------------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'zlib'
|
11
|
+
|
12
|
+
# Deps
|
13
|
+
# ------------------------------------------------------------------------
|
14
|
+
|
15
|
+
require 'yard'
|
16
|
+
|
17
|
+
# Project / Package
|
18
|
+
# ------------------------------------------------------------------------
|
19
|
+
|
20
|
+
require_relative './dump'
|
21
|
+
require_relative './ruby_version'
|
22
|
+
require_relative './object_map'
|
23
|
+
|
24
|
+
|
25
|
+
# Namespace
|
26
|
+
# ========================================================================
|
27
|
+
|
28
|
+
module YARD
|
29
|
+
module LinkStdlib
|
30
|
+
|
31
|
+
|
32
|
+
# Definitions
|
33
|
+
# ========================================================================
|
34
|
+
|
35
|
+
# A helper module to add to {YARD::Templates::Template.extra_includes} to
|
36
|
+
# handle linking stdlib references.
|
37
|
+
#
|
38
|
+
# @see https://www.rubydoc.info/gems/yard/YARD%2FTemplates%2FTemplate.extra_includes
|
39
|
+
#
|
40
|
+
module HtmlHelper
|
41
|
+
|
42
|
+
# The {Proc} we pass to
|
43
|
+
#
|
44
|
+
# @return [Proc]
|
45
|
+
#
|
46
|
+
INCLUDE_FILTER = proc do |options|
|
47
|
+
HtmlHelper if options.format == :html
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# The only real meat of this whole gem - hook into object linking.
|
52
|
+
#
|
53
|
+
# We link to the stdlib if:
|
54
|
+
#
|
55
|
+
# 1. We didn't link to anything else (local stuff take precedence).
|
56
|
+
# 2. We can find a match for the reference.
|
57
|
+
#
|
58
|
+
# @see https://www.rubydoc.info/gems/yard/YARD/Templates/Helpers/HtmlHelper#link_object-instance_method
|
59
|
+
#
|
60
|
+
# @param [YARD::CodeObjects::Base] obj
|
61
|
+
# The object to link to.
|
62
|
+
#
|
63
|
+
# @param [String?] title
|
64
|
+
# Optional title to display the link as.
|
65
|
+
#
|
66
|
+
# @param [nil | ?] anchor
|
67
|
+
# Not sure... not doc'd in YARD.
|
68
|
+
#
|
69
|
+
# @param [Boolean] relative
|
70
|
+
# Again, not sure... not doc'd in YARD, but seems like a boolean.
|
71
|
+
#
|
72
|
+
# @return [String]
|
73
|
+
# The HTML source for the link.
|
74
|
+
#
|
75
|
+
def link_object obj, title = nil, anchor = nil, relative = true
|
76
|
+
# See what the super method can do...
|
77
|
+
super_link = super
|
78
|
+
|
79
|
+
# Bail out unless `super` returned a {String}, which I'm guessing would be
|
80
|
+
# `nil`, but not sure.
|
81
|
+
unless super_link.is_a?( String )
|
82
|
+
LinkStdlib.dump "Object not linkable",
|
83
|
+
obj: obj,
|
84
|
+
super_link: super_link
|
85
|
+
return super_link
|
86
|
+
end
|
87
|
+
|
88
|
+
LinkStdlib.dump "Object *may* be linkable!",
|
89
|
+
obj: obj,
|
90
|
+
super_link: super_link
|
91
|
+
|
92
|
+
# `key` is what we gonna look up in the stdlib...
|
93
|
+
key = super_link
|
94
|
+
|
95
|
+
# Strip off any leading `::`
|
96
|
+
key = key[2..-1] if key.start_with?( '::' )
|
97
|
+
|
98
|
+
# Stdlib rdoc uses `ClassOrModule::class_method` format for class methods,
|
99
|
+
# so we want to convert to that
|
100
|
+
stdlib_key = key.sub /\.(\w+[\?\!]?)\z/, '::\1'
|
101
|
+
|
102
|
+
if ( path = ObjectMap.current.data[ stdlib_key ] )
|
103
|
+
LinkStdlib.dump "Matched stdlib link!",
|
104
|
+
path: path,
|
105
|
+
key: key,
|
106
|
+
stdlib_key: stdlib_key
|
107
|
+
|
108
|
+
version = LinkStdlib::RubyVersion.minor
|
109
|
+
|
110
|
+
[
|
111
|
+
%{<a href="https://docs.ruby-lang.org/en/#{ version }/#{ path }">},
|
112
|
+
key,
|
113
|
+
%{</a>},
|
114
|
+
].join ''
|
115
|
+
|
116
|
+
else
|
117
|
+
LinkStdlib.dump "Got nada.",
|
118
|
+
super_link: super_link
|
119
|
+
|
120
|
+
super_link
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end # #link_object
|
125
|
+
|
126
|
+
end # module HtmlHelper
|
127
|
+
|
128
|
+
|
129
|
+
# /Namespace
|
130
|
+
# ========================================================================
|
131
|
+
|
132
|
+
end # module LinkStdlib
|
133
|
+
end # module YARD
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
|
5
|
+
# Requirements
|
6
|
+
# ========================================================================
|
7
|
+
|
8
|
+
# Stdlib
|
9
|
+
# ----------------------------------------------------------------------------
|
10
|
+
|
11
|
+
# Encode object maps in JSON... it's just super easy for everything, and
|
12
|
+
# gzip should take care of any size concerns.
|
13
|
+
require 'json'
|
14
|
+
|
15
|
+
# Good ol' mkdir_p...
|
16
|
+
require 'fileutils'
|
17
|
+
|
18
|
+
# Store the JSON-encoded maps compressed
|
19
|
+
require 'zlib'
|
20
|
+
|
21
|
+
|
22
|
+
# Project / Package
|
23
|
+
# ------------------------------------------------------------------------
|
24
|
+
|
25
|
+
# We need {YARD::LinkStdlib::ROOT} to find `//tmp`
|
26
|
+
require_relative './version'
|
27
|
+
|
28
|
+
# Need to be able to {RubySource.ensure} we have source code we need
|
29
|
+
require_relative './ruby_source'
|
30
|
+
|
31
|
+
|
32
|
+
# Namespace
|
33
|
+
# ========================================================================
|
34
|
+
|
35
|
+
module YARD
|
36
|
+
module LinkStdlib
|
37
|
+
|
38
|
+
|
39
|
+
# Definitions
|
40
|
+
# ========================================================================
|
41
|
+
|
42
|
+
|
43
|
+
class ObjectMap
|
44
|
+
|
45
|
+
# Mixins
|
46
|
+
# ==========================================================================
|
47
|
+
|
48
|
+
include Comparable
|
49
|
+
|
50
|
+
|
51
|
+
# Class Variables
|
52
|
+
# ==========================================================================
|
53
|
+
|
54
|
+
@@data_dir = LinkStdlib::ROOT.join( 'maps' ).tap { |path|
|
55
|
+
FileUtils.mkdir_p( path ) unless path.exist?
|
56
|
+
}
|
57
|
+
|
58
|
+
@@current = nil
|
59
|
+
|
60
|
+
|
61
|
+
# Class Methods
|
62
|
+
# ========================================================================
|
63
|
+
|
64
|
+
def self.data_dir= path
|
65
|
+
expanded = Pathname.new( path ).expand_path
|
66
|
+
|
67
|
+
unless expanded.directory?
|
68
|
+
raise ArgumentError,
|
69
|
+
"Custom ObjectMap.data_dir must expand to an existing directory," +
|
70
|
+
"try creating it first? Received #{ path.inspect }, expanded to " +
|
71
|
+
expanded.to_s.inspect
|
72
|
+
end
|
73
|
+
|
74
|
+
@@data_dir = expanded
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def self.data_dir
|
79
|
+
@@data_dir
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def self.current
|
84
|
+
version = RubyVersion.get
|
85
|
+
|
86
|
+
if @@current.nil? || @@current.version != version
|
87
|
+
@@current = new( version ).make
|
88
|
+
end
|
89
|
+
|
90
|
+
@@current
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
# @todo Document list method.
|
96
|
+
#
|
97
|
+
# @param [type] arg_name
|
98
|
+
# @todo Add name param description.
|
99
|
+
#
|
100
|
+
# @return [return_type]
|
101
|
+
# @todo Document return value.
|
102
|
+
#
|
103
|
+
def self.list
|
104
|
+
data_dir.entries.
|
105
|
+
select { |filename| filename.to_s =~ /\Aruby\-(\d+\.)+json\.gz\z/ }.
|
106
|
+
map { |filename|
|
107
|
+
new File.basename( filename.to_s, '.json.gz' ).sub( /\Aruby\-/, '' )
|
108
|
+
}.
|
109
|
+
sort
|
110
|
+
end # .list
|
111
|
+
|
112
|
+
|
113
|
+
# def self.cache key, &load
|
114
|
+
# @cache ||= {}
|
115
|
+
|
116
|
+
# unless @cache.key? key
|
117
|
+
# @cache[key] = load.call
|
118
|
+
# end
|
119
|
+
|
120
|
+
# @cache[key]
|
121
|
+
# end
|
122
|
+
|
123
|
+
|
124
|
+
# def self.get version = LinkStdlib::RubyVersion.get, make: true
|
125
|
+
# cache version do
|
126
|
+
# make( version ) if make
|
127
|
+
# load version
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
|
131
|
+
|
132
|
+
# Ruby version.
|
133
|
+
#
|
134
|
+
# @return [Gem::Version]
|
135
|
+
#
|
136
|
+
attr_reader :version
|
137
|
+
|
138
|
+
|
139
|
+
def initialize version
|
140
|
+
@version = Gem::Version.new version
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def filename
|
145
|
+
@filename ||= "ruby-#{ version }.json.gz"
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def path
|
150
|
+
@path ||= self.class.data_dir.join filename
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Is the object map present for this {#version}?
|
155
|
+
#
|
156
|
+
# @return [Boolean]
|
157
|
+
#
|
158
|
+
def present?
|
159
|
+
path.exist?
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def source
|
164
|
+
@source ||= RubySource.new version
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def make force: false
|
169
|
+
# Bail unless forced or the map is not present
|
170
|
+
if force
|
171
|
+
log.info "FORCE making object map for Ruby #{ version }..."
|
172
|
+
elsif !present?
|
173
|
+
log.info "Making object map for Ruby #{ version }..."
|
174
|
+
else
|
175
|
+
log.info "Object map for Ruby #{ version } is present."
|
176
|
+
return self
|
177
|
+
end
|
178
|
+
|
179
|
+
# Make sure we have the source files in place
|
180
|
+
source.ensure
|
181
|
+
|
182
|
+
# Invoke the build script
|
183
|
+
LinkStdlib.system! \
|
184
|
+
LinkStdlib::ROOT.join( 'bin', 'make_map.rb' ).to_s,
|
185
|
+
source.src_path.to_s,
|
186
|
+
path.to_s
|
187
|
+
|
188
|
+
log.info "Made object map for Ruby #{ version }."
|
189
|
+
|
190
|
+
self
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
def data reload: false
|
195
|
+
if reload || @data.nil?
|
196
|
+
@data = Zlib::GzipReader.open path do |gz|
|
197
|
+
JSON.load gz.read
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
@data
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
def <=> other
|
206
|
+
version <=> other.version
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
end # class ObjectMap
|
211
|
+
|
212
|
+
|
213
|
+
# /Namespace
|
214
|
+
# ========================================================================
|
215
|
+
|
216
|
+
end # module LinkStdlib
|
217
|
+
end # module YARD
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
|
5
|
+
# Requirements
|
6
|
+
# ========================================================================
|
7
|
+
|
8
|
+
# Stdlib
|
9
|
+
# ----------------------------------------------------------------------------
|
10
|
+
|
11
|
+
require 'net/http'
|
12
|
+
require 'uri'
|
13
|
+
|
14
|
+
|
15
|
+
# Namespace
|
16
|
+
# ========================================================================
|
17
|
+
|
18
|
+
module YARD
|
19
|
+
module LinkStdlib
|
20
|
+
|
21
|
+
|
22
|
+
# Definitions
|
23
|
+
# ========================================================================
|
24
|
+
|
25
|
+
# Light utility object around a Ruby {Gem::Version} used to download and
|
26
|
+
# extract it's source code to the {LinkStdlib.tmp_dir}.
|
27
|
+
#
|
28
|
+
class RubySource
|
29
|
+
|
30
|
+
# Mixins
|
31
|
+
# ========================================================================
|
32
|
+
|
33
|
+
include Comparable
|
34
|
+
|
35
|
+
|
36
|
+
# Class Methods
|
37
|
+
# ============================================================================
|
38
|
+
|
39
|
+
# Ensure the version's source is downloaded and extracted.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# YARD::LinkStdlib::RubySource.ensure '2.5.1'
|
43
|
+
#
|
44
|
+
# @param [Gem::Version || #to_s] version
|
45
|
+
# The Ruby version you need present.
|
46
|
+
#
|
47
|
+
# @return [RubySource]
|
48
|
+
# The utility object instance.
|
49
|
+
#
|
50
|
+
def self.ensure version
|
51
|
+
new( version ).ensure
|
52
|
+
end # .ensure
|
53
|
+
|
54
|
+
|
55
|
+
def self.list
|
56
|
+
LinkStdlib.tmp_dir.entries.
|
57
|
+
select { |filename|
|
58
|
+
filename.to_s =~ /\Aruby\-\d+\_\d+\_\d+\z/
|
59
|
+
}.
|
60
|
+
map { |filename|
|
61
|
+
new filename.to_s.sub( /\Aruby\-/, '' ).gsub( '_', '.' )
|
62
|
+
}.
|
63
|
+
sort
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Ruby version.
|
68
|
+
#
|
69
|
+
# @return [Gem::Version]
|
70
|
+
#
|
71
|
+
attr_reader :version
|
72
|
+
|
73
|
+
|
74
|
+
# Construction
|
75
|
+
# ========================================================================
|
76
|
+
|
77
|
+
# Make a new instance for a version.
|
78
|
+
#
|
79
|
+
# @param [Gem::Version || #to_s] version
|
80
|
+
# The Ruby version to work with.
|
81
|
+
#
|
82
|
+
def initialize version
|
83
|
+
@version = Gem::Version.new version
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Instance Methods
|
88
|
+
# ========================================================================
|
89
|
+
|
90
|
+
def ruby_style_version
|
91
|
+
@ruby_style_version ||= version.to_s.gsub '.', '_'
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def url
|
96
|
+
@url ||=
|
97
|
+
"https://github.com/ruby/ruby/archive/v#{ ruby_style_version }.tar.gz"
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def tar_filename
|
102
|
+
@tar_filename ||= "ruby-#{ ruby_style_version }.tar.gz"
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def tar_path
|
107
|
+
@tar_path ||= LinkStdlib.tmp_dir.join tar_filename
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
def src_path
|
112
|
+
@src_path ||= LinkStdlib.tmp_dir.join "ruby-#{ ruby_style_version }"
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def download force: false
|
117
|
+
if force
|
118
|
+
log.info "FORCING download of Ruby #{ version } tarball..."
|
119
|
+
elsif tar_path.exist?
|
120
|
+
log.info "Ruby #{ version } tarball present."
|
121
|
+
return self
|
122
|
+
else
|
123
|
+
log.info "Downloading Ruby #{ version } tarball..."
|
124
|
+
end
|
125
|
+
|
126
|
+
response = LinkStdlib.http_get url
|
127
|
+
tar_path.open( "wb" ) { |file| file.write response.body }
|
128
|
+
|
129
|
+
self # For chaining
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def extract force: false
|
134
|
+
if force
|
135
|
+
log.info "FORCING extraction of Ruby #{ version } source tarball..."
|
136
|
+
elsif src_path.exist?
|
137
|
+
log.info "Ruby #{ version } source present."
|
138
|
+
return self
|
139
|
+
else
|
140
|
+
log.info "Extracting #{ tar_path } -> #{ src_path }..."
|
141
|
+
end
|
142
|
+
|
143
|
+
LinkStdlib.system! \
|
144
|
+
'tar', '-x', # extract
|
145
|
+
'-f', tar_path.to_s, # file
|
146
|
+
'-C', LinkStdlib.tmp_dir.to_s # directory (chdir)
|
147
|
+
|
148
|
+
log.info "Source for Ruby #{ version } extracted to #{ src_path }."
|
149
|
+
|
150
|
+
self # For chaining
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
def ensure
|
155
|
+
if src_path.exist?
|
156
|
+
# Nothing to do, source is already in place
|
157
|
+
log.info "Source for Ruby #{ version } is present."
|
158
|
+
return
|
159
|
+
end
|
160
|
+
|
161
|
+
# Download unless the tar's already there
|
162
|
+
download
|
163
|
+
|
164
|
+
# And we must need to extract it since the src path wasn't there
|
165
|
+
extract
|
166
|
+
|
167
|
+
self # For chaining
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
def to_s
|
172
|
+
%{#<YARD::LinkStdlib::RubySource "#{ version }">}
|
173
|
+
end
|
174
|
+
|
175
|
+
def inspect; to_s; end
|
176
|
+
|
177
|
+
|
178
|
+
def <=> other
|
179
|
+
version <=> other.version
|
180
|
+
end
|
181
|
+
|
182
|
+
end # class RubySource
|
183
|
+
|
184
|
+
|
185
|
+
# /Namespace
|
186
|
+
# ========================================================================
|
187
|
+
|
188
|
+
end # module LinkStdlib
|
189
|
+
end # module YARD
|