Module: YARD::LinkStdlib

Defined in:
lib/yard/link_stdlib.rb,
lib/yard/link_stdlib/version.rb,
lib/yard/link_stdlib/object_map.rb,
lib/yard/link_stdlib/html_helper.rb,
lib/yard/link_stdlib/ruby_source.rb,
lib/yard/link_stdlib/ruby_version.rb

Overview

Definitions

Defined Under Namespace

Modules: HtmlHelper, RubyVersion Classes: ObjectMap, RubySource, Version

Constant Summary collapse

DEFAULT_DOMAIN =

Constants

"docs.ruby-lang.org"
DEFAULT_LANG =
'en'
DEFAULT_HTTP_URLS =
true
HELPERS_BY_FORMAT =

Available helper modules by their format (as found in ‘options.format`).

We only cover ‘:html` for the moment, but may add more in the future.

Returns:

  • (Hash<Symbol, Module>)
{
  html: HtmlHelper,
}.freeze
HELPER_FOR_OPTIONS =

The Proc that we add to Templates::Template.extra_includes on install!. The proc accepts template options and responds with the helper module corresponding to the format (if any - right now we only handle ‘:html`).

We want this to be a constant so we can tell if it’s there and avoid ever double-adding it.

Returns:

  • (Proc<YARD::Templates::TemplateOptions -> Module?)

    ]

proc { |options|
  HELPERS_BY_FORMAT[ options.format ]
}.freeze
OPERATOR_METHOD_NAMES =

Names of valid Ruby operator methods. Used to form OPERATOR_METHOD_NAME_REGEXP_FRAGMENT.

Returns:

  • (::Array<::String>)
(
  %w([] []= ** ~ ~ @+ @- * / % + - >> << & ^ |) +
  %w(<= < > >= <=> == === != =~ !~)
).map( &:freeze )
OPERATOR_METHOD_NAME_REGEXP_FRAGMENT =

Regexp source fragment that matches a Ruby operator method name.

Used in normalize_name to swap out ‘.’ separators for ‘::’ in operator methods.

Returns:

  • (::String)
OPERATOR_METHOD_NAMES.
map { |op_name| "(?:#{ Regexp.escape op_name })" }
.join '|'
ROOT =

Absolute, expanded path to the gem’s root directory.

Returns:

  • (Pathname)
Pathname.new( __dir__ ).join( '..', '..', '..' ).expand_path
VERSION =

String version read from ‘//VERSION` and used in the gemspec.

Returns:

  • (String)
(ROOT + 'VERSION').read.chomp
NAME =

The gem name, read from the ‘//NAME` file, and used in the gemspec.

Returns:

  • (String)
(ROOT + 'NAME').read.chomp

Configuration Singleton Methods collapse

Resolving Names Singleton Methods collapse

Querying Singleton Methods collapse

Installation Singleton Methods collapse

Class Method Summary collapse

Class Method Details

.build_url(rel_path, https: self.https_urls?, domain: self.domain, lang: self.lang, version: RubyVersion.minor) ⇒ String

Note:

Will NOT generate working URLs for <ruby-doc.org> because they divide language docs into “core” and “stdlib” using an unknown methodology (it’s probably that C code is in “core” and Ruby in “stdlib”, but I’m not sure, and not sure who would be).

Build a URL given a relative path to the document (see rel_path_for).

Components may all be individually overridden via keyword arguments; otherwise the current configuration values are used.

Format targets <docs.ruby-lang.org>, but may work for local or alternative versions as well.

Examples:

Using defaults

YARD::LinkStdlib.build_url 'String.html'
#=> 'https://docs.ruby-lang.org/en/2.3.0/String.html'

Manually override components

YARD::LinkStdlib.build_url 'String.html',
  https: false,
  domain: 'example.com',
  lang: 'ja',
  version: '2.6.0'
#=> 'http://example.com/ja/2.6.0/String.html'

Parameters:

  • rel_path (String)

    Relative path to the document, as returned from rel_path_for.

  • https (Boolean) (defaults to: self.https_urls?)

    Build ‘https://` URLs (versus `http://`)? Defaults to https_urls?.

  • domain (String) (defaults to: self.domain)

    Domain docs are hosted at. Defaults to domain.

  • lang (String) (defaults to: self.lang)

    Language to link to, defaults to lang.

    Note that at the time of writing (2019.03.08) only English (“en”) and Japanese (“ja”) are available on <docs.ruby-lang.org>.

  • version (#to_s) (defaults to: RubyVersion.minor)

    Ruby version for the URL. Anything that supports ‘#to_s` will work, but meant for use with String or Gem::Version (the later of which being what YARD::LinkStdlib::RubyVersion.minor returns).

    Note that <docs.ruby-lang.org> uses only minor version-level resolution: you can link to ‘2.3.0` or `2.4.0`, but not `2.3.7`, `2.4.4`, etc.

Returns:

  • (String)

    Fully-formed URL, ready for clicks!



195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/yard/link_stdlib.rb', line 195

def self.build_url  rel_path,
                    https: self.https_urls?,
                    domain: self.domain,
                    lang: self.lang,
                    version: RubyVersion.minor
  File.join \
    "http#{ https ? 's' : '' }://",
    domain,
    lang,
    version.to_s,
    rel_path
end

.domainString

Configured domain used as the default to build_url.

Examples:

Default configuration responds with DEFAULT_DOMAIN

YARD::LinkStdlib.domain
#=> 'docs.ruby-lang.org'

Returns:

  • (String)


119
120
121
# File 'lib/yard/link_stdlib.rb', line 119

def self.domain
  DEFAULT_DOMAIN
end

.dump(*message, **values) ⇒ Object

Dump a hash of values as a ‘debug`-level log message (`log` is a global function when you’re hangin’ in the YARD).

Examples:

Dump values with a message

obj = [ 1, 2, 3 ]

dump "There was a problem with the ", obj, "object!",
  value_a: 'aye!',
  value_b: 'bzzz'

Dump values without a message

dump value_a: 'aye!', value_b: 'bzzz'

Parameters:

  • message (Array<String | Object>)

    Optional log message. Entries will be space-joined to form the message string: strings will be left as-is, and other objects will be stringified by calling their ‘#inspect` method. See examples.

  • values (Hash<Symbol, Object>)

    Map of names to values to dump.

Returns:

  • Whatever ‘log.debug` returns.



476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/yard/link_stdlib.rb', line 476

def self.dump *message, **values

  max_name_length = values.
    keys.
    map { |name| name.to_s.length }.
    max

  values_str = values.
    map { |name, value|
      name_str = "%-#{ max_name_length + 2 }s" % "#{ name }:"

      "  #{ name_str } #{ value.inspect } (#{ value.class })"
    }.
    join( "\n" )
  
  message_str = message.
    map { |part|
      case part
      when String
        part
      else
        part.inspect
      end
    }.
    join( " " )
  
  log_str = "Values:\n\n#{ values_str }\n"
  log_str = "#{ message_str }\n\n#{ log_str }" unless message_str.empty?

  log.debug "yard-link_stdlib: #{ log_str }"
end

.grep(*terms, mode: :any) ⇒ Array<String>

Find names in the YARD::LinkStdlib::ObjectMap.current that match terms.

Terms are tested with ‘#===`, allowing use of String, Regexp, and potentially others.

‘mode` controls if names must match any or all terms.

Parameters:

  • terms (Array<Object>)

    Objects that will be tested with ‘#===` against names in the map to select results.

Returns:

  • (Array<String>)

    Matching names.



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/yard/link_stdlib.rb', line 228

def self.grep *terms, mode: :any
  ObjectMap.
    current.
    names.
    select { |key|
      case mode
      when :any
        terms.any? { |term| term === key }
      when :all
        terms.all? { |term| term === key }
      else
        raise ArgumentError,
          "Bad mode, expected `:any` or `:all`, found #{ mode.inspect }"
      end
    }.
    sort_by( &:downcase )
end

.http_get(url, redirect_limit = 5) ⇒ Net::HTTPResponse

Make a ‘GET` request. Follows redirects. Handles SSL.

Parameters:

  • url (String)

    What ya want.

  • redirect_limit (Integer) (defaults to: 5)

    Max number of redirects to follow before it gives up.

Returns:

  • (Net::HTTPResponse)

    The first successful response that’s not a redirect.

Raises:

  • (Net::HTTPError)

    If there was an HTTP error.



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/yard/link_stdlib.rb', line 430

def self.http_get url, redirect_limit = 5
  raise "Too many HTTP redirects" if redirect_limit < 0

  uri = URI url
  request = Net::HTTP::Get.new uri.path
  response = Net::HTTP.start(
    uri.host,
    uri.port,
    use_ssl: uri.scheme == 'https',
  ) { |http| http.request request }
  
  case response
  when Net::HTTPSuccess
    response
  when Net::HTTPRedirection
    http_get response['location'], redirect_limit - 1
  else
    response.error!
  end 
end

.https_urls?Boolean

Configured to build ‘https://` URLs by default?

Examples:

Default configuration responds with DEFAULT_HTTP_URLS

YARD::LinkStdlib.https_urls?
#=> true

Returns:

  • (Boolean)


106
107
108
# File 'lib/yard/link_stdlib.rb', line 106

def self.https_urls?
  DEFAULT_HTTP_URLS
end

.install!nil

Add the HELPER_FOR_OPTIONS Proc to Templates::Template.extra_includes (if it’s not there already).



259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/yard/link_stdlib.rb', line 259

def self.install!
  # NOTE  Due to YARD start-up order, this happens *before* log level is set,
  #       so the `--debug` CLI switch won't help see it... don't know a way to
  #       at the moment.
  log.debug "Installing `yard-link_stdlib` plugin..."

  unless YARD::Templates::Template.extra_includes.include? HELPER_FOR_OPTIONS
    YARD::Templates::Template.extra_includes << HELPER_FOR_OPTIONS
  end

  YARD::CLI::CommandParser.commands[:stdlib] ||= YARD::CLI::LinkStdlib

  nil
end

.langString

Documentation language to build_url for (when not overridden in method call).

Examples:

Default configuration responds with DEFAULT_LANG

YARD::LinkStdlib.lang
#=> 'en'

Returns:

  • (String)


133
134
135
# File 'lib/yard/link_stdlib.rb', line 133

def self.lang
  DEFAULT_LANG
end

.normalize_name(name) ⇒ ::String

Normalize a stdlib name: remove “::” prefix if present, and convert “.” to “::”.

Examples:

Just passing through

YARD::LinkStdlib.normalize_name 'String#length'
#=> 'String#length'

Strip “::” prefix

YARD::LinkStdlib.normalize_name '::String#length'
#=> 'String#length'

Puke if it’s not a String

YARD::LinkStdlib.normalize_name 123
#=> raise TypeError, %(`name` must be a String, given Integer: 123)

Handle operator singleton methods separated by ‘.’

YARD::LinkStdlib.normalize_name 'Dir.[]'
#=> 'Dir::[]'

Parameters:

  • name (::String)

    Code object name, as it may appear in YARD.

Returns:

  • (::String)


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/yard/link_stdlib.rb', line 304

def self.normalize_name name
  unless name.is_a? ::String
    raise TypeError,
      "`name` must be a String, given #{ name.class }: #{ name.inspect }"
  end
  
  # Stdlib rdoc uses `ClassOrModule::class_method` format for class methods,
  # so we want to convert to that, and strip off any leading '::'
  name.
    # Strip off any leading '::'
    sub( /\A::/, '' ).
    # Convert most singleton methods using '.' to '::' (except operators)
    sub( /\.(\w+[\?\!]?)\z/, '::\1' ).
    # Convert operator singleton methods using '.' to '::'
    sub( /\.(#{ OPERATOR_METHOD_NAME_REGEXP_FRAGMENT })\z/, '::\1' )
end

.repo?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/yard/link_stdlib/version.rb', line 54

def self.repo?
  ROOT.join( 'dev' ).directory?
end

.system!(*args) ⇒ true

Run a Kernel#system, raising if it fails.

Parameters:

  • args (Array)

    See Kernel#system.

Returns:

  • (true)

Raises:

  • (SystemCallError)

    If the command fails.



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/yard/link_stdlib.rb', line 393

def self.system! *args
  opts  = args[-1].is_a?( Hash )  ? args.pop : {}
  env   = args[0].is_a?( Hash )   ? args.shift : {}

  log.info [
    "Making system call:",
    "\t#{ Shellwords.join args }",
    ( opts.empty? ? nil : "\toptions: #{ opts.inspect }" ),
    ( env.empty? ? nil : "\tenv: #{ env.inspect }" ),
  ].compact.join( "\n" )

  Kernel.system( *args ).tap { |success|
    unless success
      raise SystemCallError.new \
        %{ Code #{ $?.exitstatus } error executing #{ args.inspect } },
        $?.exitstatus
    end
  }
end

.tmp_dir(&block) ⇒ Pathname

Get where to put temporary shit, most Ruby source code that’s been downloaded to generate the link maps from.

Returns:

  • (Pathname)


370
371
372
373
374
375
376
377
378
379
380
# File 'lib/yard/link_stdlib.rb', line 370

def self.tmp_dir &block
  if @tmp_dir.nil?
    self.tmp_dir = repo? ? :gem : :user
  end

  if block
    Dir.chdir @tmp_dir, &block
  else
    @tmp_dir
  end
end

.tmp_dir=(value) ⇒ Pathname

Set the tmp_dir where we put temporary files (like Ruby source downloads).

Parameters:

  • value (Symbol | #to_s)

    Either an object whose string representation expands to a path to an existing directory, or one of the following symbols:

    1. ‘:system`, `:global` → `/tmp/yard-link_stdlib`.

    2. ‘:user` → `~/tmp/yard-link_stdlib`.

    3. ‘:gem`, `:install` → `tmp` relative to `yard-link_stdlib`’s root directory (ROOT).

Returns:

  • (Pathname)

    The assigned path.



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/yard/link_stdlib.rb', line 339

def self.tmp_dir= value
  @tmp_dir = case value
  when :system, :global
    Pathname.new '/tmp/yard-link_stdlib'
  when :user
    Pathname.new( '~/tmp/yard-link_stdlib' ).expand_path
  when :gem, :install
    ROOT.join 'tmp'
  when :project
    Pathname.getwd.join 'tmp', 'yard-link_stdlib'
  else
    dir = Pathname.new( value.to_s ).expand_path

    unless dir.directory?
      raise ArgumentError,
        "When assigning a custom tmp_dir path it must be an existing " +
        "directory, received #{ value.to_s.inspect }"
    end
  end

  FileUtils.mkdir_p @tmp_dir unless @tmp_dir.exist?

  @tmp_dir
end