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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a59fb5f579b3ba52d91480842cba718088aabf7
4
- data.tar.gz: 719132fdcb142763240354613603ade4a7c1422d
3
+ metadata.gz: 7966efdc84cb97c6137cbb70585abb20633f388b
4
+ data.tar.gz: bcdc1e6b09e76868433f0a3165a69fa1972d940b
5
5
  SHA512:
6
- metadata.gz: df1320327489dbe4bb9f61420922a85aa73a2a317d54c7e5311b5c42e43b5f031a775d62816dbfb5e5e5c8b23f680081aac9965fc8a25c1f575b31189674bc34
7
- data.tar.gz: 83e3a17de615b41176dc0aab4ed5bd93e851d84a050f7ea91ce30af17bee4df5f5f8094b151b2bc74a517a4cdc0f60858204cc2d820a175bc0a654b36ee41c70
6
+ metadata.gz: 58df15ecd9f973b793b7578c3b8bc566de595f8cd1c6de7d80d11ef613e8f562fde34d2808361c8471e105d5ae05e4dd80c8a80e58608ce1463d4209d9ab1d94
7
+ data.tar.gz: 81249ca138789654b2027bd81ff9936499da5baaef927a17cafc833d91de661fc1b08164daf0cb8d3ecba2af0f7f4a34755d75f33304e31eccb4dc0531efb1fb
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
data/bin/make_map.rb CHANGED
@@ -1,17 +1,38 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ ##############################################################################
4
+ # Make a {YARD::LinkStdlib::ObjectMap} Data File
5
+ # ============================================================================
6
+ #
7
+ # Running this script is what creates the `//maps/ruby-M.m.p.json.gz` data files
8
+ # index object names to their relative URL path in the generated documentation,
9
+ # which is in turn how the plugin generates document URLs.
10
+ #
11
+ # Coming back now (2019.03.09) I don't remember a ton of how ro why things got
12
+ # this way (comment your code, kids!). From the commit history, I can see that
13
+ # this script came over from initial work somewhere in `nrser/nrser.rb`.
14
+ #
15
+ # I think I remember this needing to run in a separate child process (versus
16
+ # just in the main `yard` one), but I don't recall why.
17
+ #
18
+ # It might have just been to try to emulate `rdoc` as much as possible, and
19
+ # might no longer be needed given present knowledge and understanding, but I
20
+ # think I'm just going to leave it for now, because it does work, and to fuck
21
+ # with it I would probably want some sort of testing set up to check I'm not
22
+ # breaking things, and that's a whole 'nother thing...
23
+ #
24
+ ##############################################################################
25
+
3
26
  require 'pathname'
4
27
  require 'fileutils'
5
28
  require 'zlib'
6
29
 
7
30
  require 'rdoc/rdoc'
8
31
 
9
- # Get paths in order - we want to be in the Ruby repo checkout
10
32
  GEM_ROOT = Pathname.new( __dir__ ).join( '..' ).expand_path
11
- # REPO = GEM_ROOT.join 'tmp', 'ruby'
12
- # REPO = GEM_ROOT.join 'tmp', 'ruby-2_5_1'
13
33
 
14
34
  class RDoc::RDoc
35
+
15
36
  # Pretty much a copy of `RDoc::RDoc#document`, just with the `#generate` step
16
37
  # commented-out.
17
38
  def almost_document options = ARGV
@@ -24,6 +45,10 @@ class RDoc::RDoc
24
45
  @options = load_options
25
46
  @options.parse options
26
47
  end
48
+
49
+ # We want **all** of the names available, so force the highest visibility
50
+ # level.
51
+ @options.visibility = :nodoc
27
52
 
28
53
  if @options.pipe then
29
54
  handle_pipe
@@ -55,18 +80,22 @@ class RDoc::RDoc
55
80
  gen_klass = @options.generator
56
81
 
57
82
  @generator = gen_klass.new @store, @options
58
-
83
+
84
+ # What we *don't* do:
59
85
  # generate
86
+
60
87
  nil
61
- end
62
- end
88
+ end # #almost_document
89
+
90
+ end # class RDoc::RDoc
91
+
63
92
 
64
93
  def main args
65
94
  src = Pathname.new( args.shift ).expand_path
66
95
  dest = Pathname.new( args.shift ).expand_path
67
96
 
68
- puts "src: #{ src.inspect }"
69
- puts "dest: #{ dest.inspect }"
97
+ puts "src: #{ src }"
98
+ puts "dest: #{ dest }"
70
99
 
71
100
  # RDoc needs this output dir arg in `ARGV` or it will bail out with an error
72
101
  # due to `//doc` existing, even though we don't ever actually write to any of
@@ -85,18 +114,26 @@ def main args
85
114
  map = {}
86
115
 
87
116
  rd.store.all_classes_and_modules.each do |mod|
88
- map[mod.full_name] = mod.path
89
-
90
- mod.class_method_list.each do |class_method|
91
- map[class_method.full_name] = class_method.path
92
- end
93
-
94
- mod.instance_method_list.each do |instance_method|
95
- map[instance_method.full_name] = instance_method.path
96
- end
117
+ # if mod.full_name == 'Gem::Specification'
118
+ # require 'pry'
119
+ # Pry.config.should_load_rc = false
120
+ # binding.pry
121
+ # end
122
+
123
+ [
124
+ mod,
125
+ mod.constants,
126
+ mod.class_attributes,
127
+ mod.class_method_list,
128
+ mod.instance_attributes,
129
+ mod.instance_method_list,
130
+ ].flatten.each { |entry|
131
+ map[ entry.full_name ] = entry.path
132
+ }
133
+
97
134
  end
98
135
 
99
- FileUtils.mkdir_p dest.dirname unless dest.dirname.exist?
136
+ FileUtils.mkdir_p( dest.dirname ) unless dest.dirname.exist?
100
137
 
101
138
  Zlib::GzipWriter.open dest do |gz|
102
139
  gz.write JSON.pretty_generate( map )
@@ -4,17 +4,16 @@
4
4
  # Requirements
5
5
  # =======================================================================
6
6
 
7
- # Stdlib
8
- # -----------------------------------------------------------------------
7
+ ### Stdlib ###
9
8
 
10
- # Deps
11
- # -----------------------------------------------------------------------
9
+ require 'optparse'
10
+
11
+ ### Deps ###
12
12
 
13
13
  # We need {YARD::CLI::Command}
14
14
  require 'yard'
15
15
 
16
- # Project / Package
17
- # -----------------------------------------------------------------------
16
+ ### Project / Package ###
18
17
 
19
18
  require 'yard/link_stdlib/ruby_source'
20
19
 
@@ -29,77 +28,314 @@ module CLI
29
28
  # Definitions
30
29
  # =======================================================================
31
30
 
31
+
32
+ class OptionParser < ::OptionParser
33
+ def after_parse_block
34
+ @after_parse_block ||= []
35
+ end
36
+
37
+ def after_parse &block
38
+ after_parse_block << block
39
+ end
40
+
41
+ def parse! *args
42
+ super( *args ).tap { after_parse_block.each &:call }
43
+ end
44
+ end
45
+
46
+
47
+ module CommandHelper
48
+
49
+ def description
50
+ self.class::DESCRIPTION
51
+ end
52
+
53
+
54
+ def usage
55
+ self.class::USAGE
56
+ end
57
+
58
+
59
+ def check_args! args, count
60
+ if args.length < count
61
+ log.error "Too few args! Expected #{ count }, given #{ args.length }"
62
+ exit false
63
+ elsif args.length > count
64
+ log.error "Too many args! Expected #{ count }, given #{ args.length }"
65
+ exit false
66
+ end
67
+
68
+ if args.length == 1 then args[ 0 ] else args end
69
+ end
70
+
71
+
72
+ def opts
73
+ @opts ||= {}
74
+ end
75
+
76
+
77
+ def add_header op, text = nil
78
+ op.banner = description
79
+ op.separator ''
80
+ op.separator 'Usage:'
81
+ op.separator ''
82
+ op.separator " #{ usage }"
83
+ op.separator ''
84
+ unless text.nil?
85
+ text.lines.each { |line| op.separator line }
86
+ end
87
+ op.separator ''
88
+ op.separator 'Options:'
89
+
90
+ op.on_tail( '-q', '--quiet', 'Show no warnings.' ) {
91
+ log.level = Logger::ERROR
92
+ }
93
+
94
+ op.on_tail( '--verbose', 'Show more information.') {
95
+ log.level = Logger::INFO
96
+ }
97
+
98
+ op.on_tail( '--debug', 'Show debugging information.' ) {
99
+ log.level = Logger::DEBUG
100
+ }
101
+
102
+ op.on_tail( '--backtrace', 'Show stack traces' ) {
103
+ log.show_backtraces = true
104
+ }
105
+
106
+ op.on_tail( '-h', '--help', %(You're looking at it!) ) {
107
+ log.puts op
108
+ exit true
109
+ }
110
+ end
111
+
112
+ def add_version_opt op
113
+ # **DON'T** make missing versions by default here!
114
+ YARD::LinkStdlib::RubySource.make_missing = false
115
+
116
+ op.on(
117
+ '-v VERSION',
118
+ '--ruby-version=VERSION',
119
+ %(Set Ruby version)
120
+ ) { |ruby_version|
121
+ YARD::LinkStdlib::RubyVersion.set ruby_version
122
+ # opts[ :ruby_version ] = ruby_version
123
+ }
124
+
125
+ op.on(
126
+ '--make-missing',
127
+ %(Download and make an object map if the Ruby version is not present)
128
+ ) { |make_missing|
129
+ YARD::LinkStdlib::RubySource.make_missing = make_missing
130
+ # opts[ :make_missing ] = make_missing
131
+ }
132
+ end
133
+
134
+ end # CommandHelper
135
+
136
+
32
137
  # @todo document LinkStdlib class.
33
138
  class LinkStdlib < Command
34
139
 
35
- # Subcommands
140
+ # Sub-commands
36
141
  # ============================================================================
37
142
 
38
143
  class List < Command
39
- def description
40
- "List Ruby versions"
41
- end
144
+ include CommandHelper
145
+
146
+ DESCRIPTION = "List Ruby versions"
147
+ USAGE = "yard stdlib list"
42
148
 
43
- def run
149
+ def run *args
150
+
151
+
44
152
  log.puts \
45
153
  YARD::LinkStdlib::ObjectMap.
46
- list.
154
+ all.
47
155
  map { |om| om.version.to_s }.
48
156
  join( "\n" )
49
157
  end
50
- end
158
+ end # class List
51
159
 
52
160
 
53
161
  class Add < Command
54
- def description
55
- "Download version source and build object map"
162
+
163
+ include CommandHelper
164
+
165
+ DESCRIPTION = "Download version source and build object map"
166
+ USAGE = "yard stdlib add [OPTIONS] RUBY_VERSION"
167
+
168
+ def run *args
169
+ # Want to see what's going on by default here...
170
+ log.level = Logger::INFO
171
+
172
+ opts[ :force ] = false
173
+
174
+ OptionParser.new { |op|
175
+ add_header op
176
+
177
+ op.on( '-f', '--force',
178
+ %(Force building of map data when already present)
179
+ ) { |force| opts[ :force ] = force }
180
+
181
+ }.parse! args
182
+
183
+ args.each do |version|
184
+ log.info "Adding object map for Ruby #{ version }..."
185
+ YARD::LinkStdlib::ObjectMap.add version, force: opts[ :force ]
186
+ end
187
+
188
+ exit true
56
189
  end
57
-
58
- def run version
59
- log.puts "Adding object map for Ruby #{ version }..."
60
- YARD::LinkStdlib::ObjectMap.new( version ).make
190
+
191
+ end # class Add
192
+
193
+
194
+ class URL < Command
195
+
196
+ include CommandHelper
197
+
198
+ DESCRIPTION = "Print the online doc URL for a stdlib name"
199
+ USAGE = "yard stdlib url [OPTIONS] NAME"
200
+
201
+ def run *args
202
+ OptionParser.new { |op|
203
+ add_header op
204
+ add_version_opt op
205
+ }.parse! args
206
+
207
+ name = check_args! args, 1
208
+
209
+ url = YARD::LinkStdlib::ObjectMap.current.url_for name
210
+
211
+ if url.nil?
212
+ $stderr.puts "Name not found: #{ name.inspect }"
213
+ exit false
214
+ end
215
+
216
+ puts url
217
+ exit true
61
218
  end
62
219
  end
220
+
221
+
222
+ # Hooks into {YARD::LinkStdlib::ObjectMap#grep} to search for names using
223
+ # regular expressions.
224
+ #
225
+ class Search < Command
226
+
227
+ include CommandHelper
228
+
229
+ DESCRIPTION = "Find stdlib names that match Regexp patterns"
230
+ USAGE = "yard stdlib search [OPTIONS] TERMS..."
231
+
232
+ def run *args
233
+ OptionParser.new { |op|
234
+ add_header op, <<~END
235
+ Examples:
236
+
237
+ 1. {Pathname} instance methods
238
+
239
+ yard stdlib search '^Pathname#'
240
+
241
+ 2. All `#to_s` methods
242
+
243
+ yard stdlib search '#to_s$'
244
+ END
245
+
246
+ add_version_opt op
247
+
248
+ op.on( '-u', '--urls',
249
+ %(Print doc URLs along with names)
250
+ ) { |urls| opts[ :urls ] = urls }
251
+
252
+ }.parse! args
253
+
254
+ if args.empty?
255
+ YARD::LinkStdlib::ObjectMap.
256
+ current.
257
+ names.
258
+ sort_by( &:downcase ).
259
+ each { |key| log.puts key }
260
+ exit true
261
+ end
262
+
263
+ terms = args.map { |arg| Regexp.new arg }
264
+
265
+ log.debug "Terms:\n " + terms.map( &:to_s ).join( "\n " )
266
+
267
+ names = YARD::LinkStdlib.grep *terms
268
+
269
+ names.each { |name|
270
+ line = \
271
+ if opts[ :urls ]
272
+ "#{ name } <#{ YARD::LinkStdlib::ObjectMap.current.url_for name }>"
273
+ else
274
+ name
275
+ end
276
+ log.puts line
277
+ }
278
+
279
+ exit true
280
+ end
281
+ end # class Search
63
282
 
64
283
 
65
284
  class Help < Command
66
- def description
67
- "Show this message"
68
- end
285
+
286
+ include CommandHelper
287
+
288
+ DESCRIPTION = "Show this message"
69
289
 
70
290
  def run
71
291
  commands = LinkStdlib.commands
72
- log.puts "Usage: yard stdlib COMMAND... [OPTIONS] [ARGS]"
73
- log.puts
74
- log.puts "Commands:"
292
+ log.puts <<~END
293
+ yard-link_stdlib provides linking to online Ruby docs for standard
294
+ library code objects.
295
+
296
+ Usage:
297
+
298
+ yard stdlib COMMAND... [OPTIONS] [ARGS]
299
+
300
+ Commands:
301
+
302
+ END
75
303
  commands.keys.sort_by(&:to_s).each do |command_name|
76
304
  command_class = commands[command_name]
77
305
  next unless command_class < Command
78
306
  command = command_class.new
79
307
  log.puts "%-8s %s" % [command_name, command.description]
80
308
  end
309
+ log.puts
81
310
  end
82
311
  end
83
-
84
312
 
85
- # Instance Methods
86
- # ========================================================================
87
-
88
- def description
89
- "Mange Ruby stdlib linking"
90
- end
91
-
92
-
313
+
314
+ # Singleton Methods
315
+ # ==========================================================================
316
+
93
317
  def self.commands
94
318
  {
95
319
  help: Help,
96
320
  list: List,
97
321
  add: Add,
322
+ url: URL,
323
+ search: Search,
98
324
  }
99
325
  end
100
326
 
327
+
328
+ # Instance Methods
329
+ # ========================================================================
330
+
331
+ def description
332
+ "Mange Ruby stdlib linking"
333
+ end
334
+
101
335
 
102
336
  def run *args
337
+ # log.level = Logger::INFO
338
+
103
339
  target = self.class.commands
104
340
 
105
341
  args = [ 'help' ] if args.empty?
@@ -118,25 +354,6 @@ class LinkStdlib < Command
118
354
  end
119
355
 
120
356
 
121
- protected
122
- # ========================================================================
123
-
124
- # @todo Document respond method.
125
- #
126
- # @param [type] arg_name
127
- # @todo Add name param description.
128
- #
129
- # @return [return_type]
130
- # @todo Document return value.
131
- #
132
- def respond response
133
- log.puts response unless response.nil?
134
- exit true
135
- end # #respond
136
-
137
- public # end protected ***************************************************
138
-
139
-
140
357
  end # class LinkStdlib
141
358
 
142
359
 
@@ -17,7 +17,6 @@ require 'yard'
17
17
  # Project / Package
18
18
  # ------------------------------------------------------------------------
19
19
 
20
- require_relative './dump'
21
20
  require_relative './ruby_version'
22
21
  require_relative './object_map'
23
22
 
@@ -89,29 +88,16 @@ module HtmlHelper
89
88
  obj: obj,
90
89
  super_link: super_link
91
90
 
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 ] )
91
+ # if ( path = ObjectMap.current.data[ stdlib_key ] )
92
+ if (url = ObjectMap.current.url_for super_link)
103
93
  LinkStdlib.dump "Matched stdlib link!",
104
- path: path,
105
- key: key,
106
- stdlib_key: stdlib_key
107
-
108
- version = LinkStdlib::RubyVersion.minor
94
+ name: super_link,
95
+ url: url
109
96
 
110
- [
111
- %{<a href="https://docs.ruby-lang.org/en/#{ version }/#{ path }">},
112
- key,
113
- %{</a>},
114
- ].join ''
97
+ # NOTE `url` is **not** escaped because it may contains '#' followed
98
+ # by a fragment, and that needs to be preserved. At this point,
99
+ # I'm just assuming it's ready for use as-is.
100
+ %(<a href="#{ url }">#{ CGI.escapeHTML super_link }</a>)
115
101
 
116
102
  else
117
103
  LinkStdlib.dump "Got nada.",