Class: Utopia::Project::Base

Inherits:
Object
  • Object
show all
Extended by:
Thread::Local
Defined in:
lib/utopia/project/base.rb

Overview

Provides structured access to a project directory which contains source code and guides.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root = Dir.pwd) ⇒ Base

Initialize the project with the given root path.



44
45
46
47
48
49
50
51
52
# File 'lib/utopia/project/base.rb', line 44

def initialize(root = Dir.pwd)
	@root = root
	
	@reference_path = Utopia::Path["/reference"]
	
	@index = Decode::Index.new
	
	@links = Utopia::Content::Links.new(@root)
end

Instance Attribute Details

#indexObject

The source code index which is used for generating pages.



60
61
62
# File 'lib/utopia/project/base.rb', line 60

def index
  @index
end

#rootObject (readonly)

The file-system path to the root of the project.



56
57
58
# File 'lib/utopia/project/base.rb', line 56

def root
  @root
end

Class Method Details

.localObject

Load the current project and index its Ruby source files.



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/utopia/project/base.rb', line 30

def self.local
	instance = self.new
	
	source_files = Dir.glob(
		File.expand_path("{lib,app}/**/*.rb", instance.root)
	)
	
	instance.update(source_files)
	
	return instance
end

Instance Method Details

#best(definitions) ⇒ Object

Given an array of defintions, return the best definition for the purposes of generating documentation.



84
85
86
87
88
89
90
91
92
# File 'lib/utopia/project/base.rb', line 84

def best(definitions)
	definitions.each do |definition|
		if definition.documentation
			return definition
		end
	end
	
	return definitions.first
end

#document(text, definition = nil, language: definition&.language) ⇒ Object

Convert the given markdown text into HTML.

Updates source code references ({language identifier}) into links.

Examples:

Convert markdown to HTML

base = Utopia::Project::Base.new
doc = base.document("# Title")
doc.to_html # => "<h1>Title</h1>\n"


163
164
165
166
167
168
169
170
171
172
# File 'lib/utopia/project/base.rb', line 163

def document(text, definition = nil, language: definition&.language)
	case text
	when Enumerable
		text = text.to_a.join("\n")
	when nil
		return nil
	end
	
	Document.new(text, self, definition: definition, default_language: language)
end

#document_for(definition) ⇒ Object

Load the supplemental document associated with a definition.



109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/utopia/project/base.rb', line 109

def document_for(definition)
	document_path = File.join("lib", definition.lexical_path.map{|_| _.to_s.downcase}) + ".md"
	
	if File.exist?(document_path)
		document = self.document(File.read(document_path), definition)
		
		if document.first_child.type == :header
			document.first_child.delete
		end
		
		return document
	end
end

#format(text, definition = nil, language: definition&.language, **options) ⇒ Object

Format the given text in the context of the given definition and language. See #document for details.

Examples:

Format text with code links

base = Utopia::Project::Base.new
base.format("See {Utopia::Project::Base#guides}.") # => XRB::MarkupString


145
146
147
148
149
150
151
# File 'lib/utopia/project/base.rb', line 145

def format(text, definition = nil, language: definition&.language, **options)
	if document = self.document(text, definition, language: language)
		return XRB::Markup.raw(
			document.to_html(**options)
		)
	end
end

#gemspecObject

Load and return the gemspec for this project.



264
265
266
267
268
# File 'lib/utopia/project/base.rb', line 264

def gemspec
	if gemspec_path = self.gemspec_path
		@gemspec ||= ::Gem::Specification.load(File.join(@root, gemspec_path))
	end
end

#guidesObject

Get the guides collection for this project.

Examples:

List guide titles

base = Utopia::Project::Base.new
base.guides.each do |guide|
	puts guide.title
end


222
223
224
# File 'lib/utopia/project/base.rb', line 222

def guides
	@guides ||= Guides.new(self, @links)
end

#id_for(definition, suffix = nil) ⇒ Object

Compute a unique string which can be used as id attribute in the HTML output.

Examples:

Compute id for a definition

base = Utopia::Project::Base.local
_, definition = base.lookup(%i[Utopia Project Base])
base.id_for(definition) # => "Utopia::Project::Base"


181
182
183
184
185
186
187
# File 'lib/utopia/project/base.rb', line 181

def id_for(definition, suffix = nil)
	if suffix
		"#{definition.qualified_name}-#{suffix}"
	else
		definition.qualified_name
	end
end

#inheritance_for(definition) ⇒ Object

Resolve inheritance information for the given definition.



210
211
212
# File 'lib/utopia/project/base.rb', line 210

def inheritance_for(definition)
	Inheritance.new(@index, definition)
end

Compute a link href to the given definition for use within the HTML output.

Examples:

Link to a definition

base = Utopia::Project::Base.local
_, definition = base.lookup(%i[Utopia Project Base])
base.link_for(definition).to_s # => "/reference/utopia/project/index#Utopia::Project::Base"


196
197
198
199
200
201
202
203
204
205
# File 'lib/utopia/project/base.rb', line 196

def link_for(definition)
	path = definition.lexical_path.map{|entry| entry.to_s}
	
	if definition.container?
		return XRB::Reference.new(@reference_path + path + "index")
	else
		name = path.pop
		return XRB::Reference.new(@reference_path + path + "index", fragment: id_for(definition))
	end
end

#linkify(text, definition, language: definition&.language) ⇒ Object

Format source text with links to referenced definitions.



128
129
130
131
132
133
134
135
136
# File 'lib/utopia/project/base.rb', line 128

def linkify(text, definition, language: definition&.language)
	rewriter = Linkify.new(self, language, text)
	
	code = language.code_for(text, @index, relative_to: definition)
	
	code.extract(rewriter)
	
	return rewriter.apply
end

#lookup(path) ⇒ Object

Given a lexical path, find the best definition for that path.

Examples:

Lookup a definition

base = Utopia::Project::Base.local
_, definition = base.lookup(%i[Utopia Project Base])


100
101
102
103
104
# File 'lib/utopia/project/base.rb', line 100

def lookup(path)
	if node = @index.trie.lookup(path.map(&:to_sym))
		return node, best(node.values)
	end
end

#path_for(file_name) ⇒ Object

Return the absolute path for the given file name, if it exists in the project.

Examples:

Get README path

base = Utopia::Project::Base.new
base.path_for("readme.md") # => "/path/to/project/readme.md" or nil


69
70
71
72
73
74
# File 'lib/utopia/project/base.rb', line 69

def path_for(file_name)
	full_path = File.expand_path(file_name, @root)
	if File.exist?(full_path)
		return full_path
	end
end

#project_titleObject

Get the project title from its README.



236
237
238
# File 'lib/utopia/project/base.rb', line 236

def project_title
	readme_document&.title || "Project"
end

#readme_documentObject

Load the project README document.



228
229
230
231
232
# File 'lib/utopia/project/base.rb', line 228

def readme_document
	if path = self.path_for("readme.md") || self.path_for("README.md")
		Document.new(File.read(path), self)
	end
end

#releasesObject

Enumerate the project releases.



250
251
252
253
254
# File 'lib/utopia/project/base.rb', line 250

def releases
	if releases_document = self.releases_document
		releases_document.releases
	end
end

#releases_documentObject

Load the project release notes document.



242
243
244
245
246
# File 'lib/utopia/project/base.rb', line 242

def releases_document
	if path = self.path_for("releases.md")
		ReleasesDocument.new(File.read(path), self)
	end
end

#source_code_uriObject

Return the source code URI for this project, if available. Prefers metadata["source_code_uri"] over homepage.



273
274
275
# File 'lib/utopia/project/base.rb', line 273

def source_code_uri
	gemspec&.&.dig("source_code_uri") || gemspec&.homepage
end

#update(paths) ⇒ Object

Update the index with the specified paths.



78
79
80
# File 'lib/utopia/project/base.rb', line 78

def update(paths)
	@index.update(paths)
end