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 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.",