Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions context/documentation-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Source code documentation is included adjacent to the code it describes, using s
However, in short:

- Documentation is expected to be in markdown format.
- You may embed links to definitions using `{MyClass}` or `{my_method}`.
- You may embed links to definitions using ruby:`MyClass` or ruby:`my_method`.
- You can use tags:
- `@parameters name [Type] Description.`
- `@yields {|argument| ...} If a block is given.`
Expand Down Expand Up @@ -173,7 +173,7 @@ $ bundle add $project

`$project` has several core concepts:

- A {ruby MyProject::MyClass} which represents the main entry point for using the project.
- A ruby:`MyProject::MyClass` which represents the main entry point for using the project.

## Usage

Expand Down Expand Up @@ -284,7 +284,7 @@ Following `utopia-project` guidelines, each guide should:
2. **Provide user context**: Explain why users would need this feature
3. **Include practical examples**: Working code samples that demonstrate real scenarios
4. **Follow consistent structure**: Problem → Use Cases → Implementation → Best Practices
5. **Cross-reference appropriately**: Use `{ruby ClassName}` for internal references
5. **Cross-reference appropriately**: Use ruby:`ClassName` for internal references
6. **Include error handling**: Show how to handle common failure scenarios
7. **Provide troubleshooting**: Common issues and solutions
8. **Maintain currency**: Keep examples updated with latest best practices
Expand Down
6 changes: 3 additions & 3 deletions guides/documentation-guidelines/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Source code documentation is included adjacent to the code it describes, using s
However, in short:

- Documentation is expected to be in markdown format.
- You may embed links to definitions using `{MyClass}` or `{my_method}`.
- You may embed links to definitions using ruby:`MyClass` or ruby:`my_method`.
- You can use tags:
- `@parameters name [Type] Description.`
- `@yields {|argument| ...} If a block is given.`
Expand Down Expand Up @@ -173,7 +173,7 @@ $ bundle add $project

`$project` has several core concepts:

- A {ruby MyProject::MyClass} which represents the main entry point for using the project.
- A ruby:`MyProject::MyClass` which represents the main entry point for using the project.

## Usage

Expand Down Expand Up @@ -284,7 +284,7 @@ Following `utopia-project` guidelines, each guide should:
2. **Provide user context**: Explain why users would need this feature
3. **Include practical examples**: Working code samples that demonstrate real scenarios
4. **Follow consistent structure**: Problem → Use Cases → Implementation → Best Practices
5. **Cross-reference appropriately**: Use `{ruby ClassName}` for internal references
5. **Cross-reference appropriately**: Use ruby:`ClassName` for internal references
6. **Include error handling**: Show how to handle common failure scenarios
7. **Provide troubleshooting**: Common issues and solutions
8. **Maintain currency**: Keep examples updated with latest best practices
Expand Down
2 changes: 1 addition & 1 deletion lib/utopia/project/base.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Provides structured access to a project directory which contains source code and

## Usage

To get an instance for the current project, use {Base#instance}.
To get an instance for the current project, use ruby:`Base#instance`.
6 changes: 3 additions & 3 deletions lib/utopia/project/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,12 @@ def linkify(text, definition, language: definition&.language)
end

# Format the given text in the context of the given definition and language.
# See {document} for details.
# See ruby:`document` for details.
# @returns [XRB::MarkupString]
#
# @example Format text with code links
# base = Utopia::Project::Base.new
# base.format("See {Utopia::Project::Base#guides}.") # => XRB::MarkupString
# base.format("See ruby:`Utopia::Project::Base#guides`.") # => XRB::MarkupString
def format(text, definition = nil, language: definition&.language, **options)
if document = self.document(text, definition, language: language)
return XRB::Markup.raw(
Expand All @@ -152,7 +152,7 @@ def format(text, definition = nil, language: definition&.language, **options)

# Convert the given markdown text into HTML.
#
# Updates source code references (`{language identifier}`) into links.
# Updates language-prefixed inline code (e.g. `ruby:` followed by inline code) into links.
#
# @returns [Document]
#
Expand Down
37 changes: 22 additions & 15 deletions lib/utopia/project/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def initialize(text, base = nil, definition: nil, default_language: nil)
# Parse and resolve the document root.
# @returns [Markly::Node] The root document node.
def root
@root ||= resolve(Markly.parse(@text, extensions: [:table]))
@root ||= resolve(Markly.parse(@text, flags: Markly::INLINE_CODE_INFO, extensions: [:table]))
end

# Extract the leading heading as the document title.
Expand Down Expand Up @@ -99,7 +99,12 @@ def to_markdown(**options)
# @parameter node [Markly::Node] The node to render.
# @returns [XRB::MarkupString] The rendered HTML markup.
def to_html(node = self.root, **options)
renderer = Renderer.new(ids: true, flags: Markly::UNSAFE, **options)
renderer = Renderer.new(
inline_code_resolver: (@index ? method(:reference_node) : nil),
ids: true,
flags: Markly::UNSAFE,
**options
)
XRB::Markup.raw(renderer.render(node))
end

Expand Down Expand Up @@ -160,25 +165,27 @@ def link_node(title, url, child)
# @parameter language [String | Nil] The source language name.
# @returns [Markly::Node] The code node.
def code_node(content, language = nil)
if language
node = inline_html_node(
"<code class=\"language-#{language}\">#{XRB::Strings.to_html(content)}</code>"
)
else
node = Markly::Node.new(:code)
node.string_content = content
return node
end
node = Markly::Node.new(:code)
node.string_content = content
node.code_info = language if language

return node
end

private

# Replace source code references in the given text with HTML anchors.
#
def reference_node(content)
if reference = @index.languages.parse_reference(content, default_language: @default_language)
# @parameter content [String] The source code reference.
# @parameter language [String | Nil] The explicit source language.
# @returns [Markly::Node] The resolved link or code node.
def reference_node(content, language: nil)
reference = if language
@index.languages.reference_for(language, content)
else
@index.languages.parse_reference(content, default_language: @default_language)
end

if reference
definition = @index.lookup(reference, relative_to: @definition)
end

Expand All @@ -189,7 +196,7 @@ def reference_node(content)
elsif reference
code_node(reference.identifier, reference.language.name)
else
code_node(content)
code_node(content, language)
end
end

Expand Down
24 changes: 24 additions & 0 deletions lib/utopia/project/renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ module Utopia
module Project
# Renders project Markdown with support for Mermaid code blocks.
class Renderer < Markly::Renderer::HTML
# Initialize the project renderer.
# @parameter inline_code_resolver [Proc | Nil] Resolves language-prefixed inline code into a replacement node.
def initialize(inline_code_resolver: nil, **options)
@inline_code_resolver = inline_code_resolver
@resolving_inline_code = false

super(**options)
end

# Render a heading and expose its title to Pagefind for sub-results.
# @parameter node [Markly::Node] The heading node.
def header(node)
Expand Down Expand Up @@ -45,6 +54,21 @@ def code_block(node)
super
end
end

# Render inline code, resolving language-prefixed references when possible.
# @parameter node [Markly::Node] The inline code node.
def code(node)
if @inline_code_resolver && !@resolving_inline_code && (language = node.code_language)
begin
@resolving_inline_code = true
out(@inline_code_resolver.call(node.string_content, language: language))
ensure
@resolving_inline_code = false
end
else
super
end
end
end
end
end
4 changes: 4 additions & 0 deletions releases.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changes

## Unreleased

- Add support for language-prefixed inline code references such as ruby:`Object.new`.

## v0.41.0

- Don't render empty signature block when there are only examples.
Expand Down
34 changes: 34 additions & 0 deletions test/utopia/project/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,40 @@
expect(html).to be(:include?, '<section id="installation-&amp;-usage" data-pagefind-title="Installation &amp; Usage">')
end

it "renders language-prefixed inline code" do
root = File.expand_path("../../..", __dir__)
base = Utopia::Project::Base.new(root)
document = subject.new("Use ruby:`Object.new` to create an object.", base)
html = document.to_html.to_s

expect(html).to be(:include?, '<code class="language-ruby">Object.new</code>')
expect(html).not.to be(:include?, "<a ")
expect(document.to_markdown).to be == "Use ruby:`Object.new` to create an object.\n"
end

it "resolves language-prefixed inline code references" do
root = File.expand_path("../../..", __dir__)
base = Utopia::Project::Base.new(root)
base.update([File.join(root, "lib/utopia/project/document.rb")])

document = subject.new("See ruby:`Utopia::Project::Document#root`.", base)
html = document.to_html.to_s

expect(html).to be(:include?, '<a href="/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root"')
expect(html).to be(:include?, '<code class="language-ruby">Utopia::Project::Document#root</code>')
end

it "continues to resolve legacy brace references" do
root = File.expand_path("../../..", __dir__)
base = Utopia::Project::Base.new(root)
base.update([File.join(root, "lib/utopia/project/document.rb")])

document = subject.new("See {ruby Utopia::Project::Document#root}.", base)
html = document.to_html.to_s

expect(html).to be(:include?, '<a href="/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root"')
end

it "can replace usage" do
document.replace_section("Usage") do |header|
header.insert_after(document.html_node("<content:usage/>"))
Expand Down
2 changes: 1 addition & 1 deletion utopia-project.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Gem::Specification.new do |spec|

spec.add_dependency "decode", "~> 0.30"
spec.add_dependency "falcon"
spec.add_dependency "markly", "~> 0.15"
spec.add_dependency "markly", "~> 0.17"
spec.add_dependency "thread-local"
spec.add_dependency "utopia", "~> 3.0.4"
end
Loading