Class: BitClust::SearchIndexGenerator

Inherits:
Object
  • Object
show all
Includes:
NameUtils
Defined in:
lib/bitclust/search_index_generator.rb

Constant Summary collapse

TYPENAME_TO_SEARCH_TYPE =

Maps BitClust method typenames onto the type vocabulary understood by Aliki's searcher (class/module/constant/class_method/instance_method). Module functions are callable as singleton methods, so they are indexed as class methods; special variables have no Aliki equivalent and keep their own label (the searcher only uses the type for ranking).

{
  singleton_method: 'class_method',
  module_function:  'class_method',
  instance_method:  'instance_method',
  constant:         'constant',
  special_variable: 'variable',
}.freeze
ANCHORED_HEADING_RE =

Doc pages (manual/doc/**/*.md) are prose, so language keywords such as "defined?", "undef" or "alias" (see rurema/doctree#2352) are never indexed as a class/method/library. They do, however, live at their own #id-anchored heading within a doc page (e.g. spec/def.md's "defined?" section). Rather than hardcoding a keyword list, scan every doc page for ATX headings carrying an explicit #id anchor -- the same anchors [ref:d:...] cross references already rely on -- and index each one individually so a keyword search can jump straight to its section. Headings without an explicit anchor aren't linkable, so they are skipped; a "# comment" that happens to open a line inside a fenced code block is not a heading at all, so fenced regions are skipped wholesale.

/\A(\#{1,6})[ \t]+(.*?)(?:[ \t]+\{#([\w-]+)\})?[ \t]*\z/.freeze
FENCE_START_RE =
/\A`{3,}/.freeze

Constants included from NameUtils

NameUtils::CHAR_TO_MARK, NameUtils::CHAR_TO_NAME, NameUtils::CLASS_NAME_RE, NameUtils::CLASS_PATH_RE, NameUtils::CONST_PATH_RE, NameUtils::CONST_RE, NameUtils::GVAR_RE, NameUtils::LIBNAME_RE, NameUtils::MARK_TO_CHAR, NameUtils::MARK_TO_NAME, NameUtils::METHOD_NAME_RE, NameUtils::METHOD_SPEC_RE, NameUtils::MID, NameUtils::NAME_TO_CHAR, NameUtils::NAME_TO_MARK, NameUtils::TYPEMARK_RE

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NameUtils

build_method_id, classid2name, classname2id, classname?, decodeid, decodename_fs, decodename_url, display_typemark, encodeid, encodename_fs, encodename_rdocurl, encodename_url, functionname?, gvarname?, html_filename, libid2name, libname2id, libname?, method_spec?, methodid2classid, methodid2libid, methodid2mname, methodid2specparts, methodid2specstring, methodid2typechar, methodid2typemark, methodid2typename, methodname?, split_method_id, split_method_spec, typechar2mark, typechar2name, typechar?, typemark2char, typemark2name, typemark?, typename2char, typename2mark, typename?

Constructor Details

#initialize(suffix: '.html', fs_casesensitive: false) ⇒ SearchIndexGenerator

Returns a new instance of SearchIndexGenerator.



65
66
67
68
# File 'lib/bitclust/search_index_generator.rb', line 65

def initialize(suffix: '.html', fs_casesensitive: false)
  @suffix = suffix
  @fs_casesensitive = fs_casesensitive
end

Class Method Details

.merge(version_indexes) ⇒ Object

Merges per-version indexes (an array of [version, index] pairs) into a single index whose entries carry a versions array, for the standalone cross-version search page. Entries are considered the same when all of name/full_name/type/path match. Versions are sorted numerically ("3.10" sorts after "3.4"), and entry order is the first appearance while scanning versions in ascending order — independent of the caller's argument order, so the generated file diffs stay stable.

A module function's full_name is spelled ".#" by pre-4.0 databases and "?." by 4.0+ ones (bitclust#250), which would split it into two rows — confusing on a page that lists every version side by side. Fold the display to the current "?." spelling here, so both spellings collapse into one row with a unified versions list (name/type/path/match_name are spelling-independent already). Only entries carrying a match_name (dot-qualified methods) are folded: a prose heading whose text happens to contain ".#" must keep matching its page verbatim. The single-version in-page search keeps each version's own spelling — build_index is not affected. See the report in bitclust#279.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/bitclust/search_index_generator.rb', line 106

def self.merge(version_indexes)
  merged = {} #: Hash[Array[String?], merged_entry]
  sorted = version_indexes.sort_by { |version, _| Gem::Version.new(version) }
  sorted.each do |version, index|
    index.each do |e|
      if e[:match_name] && e[:full_name].include?('.#')
        e = e.merge(full_name: e[:full_name].gsub('.#', '?.'))
      end
      key = e.values_at(:name, :full_name, :type, :path)
      entry = (merged[key] ||= e.merge(versions: []))
      entry[:versions] << version
    end
  end
  merged.values
end

.merged_js(version_indexes) ⇒ Object

Serializes a merged multi-version index as a search_data.js body.



123
124
125
# File 'lib/bitclust/search_index_generator.rb', line 123

def self.merged_js(version_indexes)
  "var search_data = #{JSON.generate(index: merge(version_indexes))};"
end

Instance Method Details

#build_index(db, fdb = nil) ⇒ Object

Builds the search index as an array of entry hashes. db is a MethodDatabase; fdb is an optional FunctionDatabase (C API).



72
73
74
75
76
77
78
79
80
81
# File 'lib/bitclust/search_index_generator.rb', line 72

def build_index(db, fdb = nil)
  index = [] #: Array[entry]
  index.concat(class_entries(db))
  index.concat(method_entries(db))
  index.concat(library_entries(db))
  index.concat(document_entries(db))
  index.concat(document_heading_entries(db))
  index.concat(function_entries(fdb)) if fdb
  index
end

#to_js(db, fdb = nil) ⇒ Object

Serializes the index as an Aliki-compatible search_data.js body.



84
85
86
# File 'lib/bitclust/search_index_generator.rb', line 84

def to_js(db, fdb = nil)
  "var search_data = #{JSON.generate(index: build_index(db, fdb))};"
end