Class: Decode::Index

Inherits:
Object
  • Object
show all
Defined in:
lib/decode/index.rb

Overview

Represents a list of definitions organised for quick lookup and lexical enumeration.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(languages = Languages.all) ⇒ Index

Initialize an empty index.



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/decode/index.rb', line 44

def initialize(languages = Languages.all)
	# Initialize with supported languages:
	@languages = languages
	
	# Initialize storage for sources and definitions:
	@sources = {}
	@definitions = {}
	
	# Create a prefix tree for efficient lookups:
	@trie = Trie.new
end

Instance Attribute Details

#A mapping of file paths to source objects.(mappingoffilepathstosourceobjects.) ⇒ Object (readonly)

All source files that have been parsed.



71
# File 'lib/decode/index.rb', line 71

attr :sources

#A mapping of qualified names to definitions.(mappingofqualifiednamestodefinitions.) ⇒ Object (readonly)

All definitions which have been parsed.



75
# File 'lib/decode/index.rb', line 75

attr :definitions

#definitionsObject (readonly)

All definitions which have been parsed.



75
76
77
# File 'lib/decode/index.rb', line 75

def definitions
  @definitions
end

#languagesObject (readonly)

All supported languages for this index.



67
68
69
# File 'lib/decode/index.rb', line 67

def languages
  @languages
end

#sourcesObject (readonly)

All source files that have been parsed.



71
72
73
# File 'lib/decode/index.rb', line 71

def sources
  @sources
end

#The trie structure for efficient lookups.(triestructure) ⇒ Object (readonly)

A (prefix) trie of lexically scoped definitions.



79
# File 'lib/decode/index.rb', line 79

attr :trie

#trieObject (readonly)

A (prefix) trie of lexically scoped definitions.



79
80
81
# File 'lib/decode/index.rb', line 79

def trie
  @trie
end

Class Method Details

.for(*paths, languages: Languages.all) ⇒ Object

Create and populate an index from the given paths.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/decode/index.rb', line 19

def self.for(*paths, languages: Languages.all)
	# Resolve all paths to actual files:
	resolved_paths = paths.flat_map do |path|
		if File.directory?(path)
			Dir.glob(File.join(path, "**/*"))
		elsif File.file?(path)
			[path]
		else
			# Handle glob patterns or non-existent paths:
			Dir.glob(path)
		end
	end
	
	resolved_paths.sort!
	resolved_paths.uniq!
	
	# Create and populate the index:
	index = new(languages)
	index.update(resolved_paths)
	
	return index
end

Instance Method Details

#inspectObject Also known as: to_s

Generate a string representation of this index.



58
59
60
# File 'lib/decode/index.rb', line 58

def inspect
	"#<#{self.class} #{@definitions.size} definition(s)>"
end

#lookup(reference, relative_to: nil) ⇒ Object

Lookup the specified reference and return matching definitions.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/decode/index.rb', line 108

def lookup(reference, relative_to: nil)
	if reference.absolute? || relative_to.nil?
		# Start from root scope:
		lexical_path = [] #: Array[Symbol]
	else
		# Start from the given definition's scope:
		lexical_path = relative_to.full_path.dup
	end
	
	path = reference.path
	
	while true
		# Get the current scope node:
		node = @trie.lookup(lexical_path)
		
		if node.children[path.first]
			if target = node.lookup(path)
				# Return the best matching definition:
				if values = target.values
					return reference.best(values)
				else
					return nil
				end
			else
				return nil
			end
		end
		
		# Move up one scope level:
		break if lexical_path.empty?
		lexical_path.pop
	end
end

#The languages this index can parse.=(languagesthisindexcanparse. = (value)) ⇒ Object

All supported languages for this index.



67
# File 'lib/decode/index.rb', line 67

attr :languages

#update(paths) ⇒ Object

Updates the index by parsing the specified files. All extracted definitions are merged into the existing index.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/decode/index.rb', line 84

def update(paths)
	paths.each do |path|
		if source = @languages.source_for(path)
			# Store the source file:
			@sources[path] = source
			
			# Extract and index all definitions:
			source.definitions do |symbol|
				# $stderr.puts "Adding #{symbol.qualified_name} to #{symbol.lexical_path.join(' -> ')}"
				
				# Add to definitions lookup:
				@definitions[symbol.qualified_name] = symbol
				
				# Add to trie for hierarchical lookup:
				@trie.insert(symbol.full_path, symbol)
			end
		end
	end
end