From e4ef2dacd1ac1a63499e96778da2cc8fb72ac66c Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Fri, 11 Nov 2022 16:47:13 -0700 Subject: [PATCH] Improve handling of constants that are just aliases * In the constant summary, link to its target object * When linking from other locations, link directly to the target. --- lib/yard/code_objects/constant_object.rb | 18 +++++++ lib/yard/templates/helpers/html_helper.rb | 11 ++++ spec/code_objects/constant_object_spec.rb | 48 +++++++++++++++++ spec/templates/examples/module006.html | 54 +++++++++++++++++++ spec/templates/module_spec.rb | 12 +++++ .../default/module/html/constant_summary.erb | 2 +- 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 spec/code_objects/constant_object_spec.rb create mode 100644 spec/templates/examples/module006.html diff --git a/lib/yard/code_objects/constant_object.rb b/lib/yard/code_objects/constant_object.rb index b7904648b..b09e00f88 100644 --- a/lib/yard/code_objects/constant_object.rb +++ b/lib/yard/code_objects/constant_object.rb @@ -12,5 +12,23 @@ class ConstantObject < Base def value=(value) @value = format_source(value) end + + # @return [Base, nil] the target object the constant points to + def target + return @target if instance_variable_defined?(:@target) + + if !value.empty? && + (target = P(namespace, value)) && + !target.is_a?(YARD::CodeObjects::Proxy) && + target != self + @target = target + else + @target = nil + end + @target + rescue YARD::Parser::UndocumentableError + # means the value isn't an alias to another object + @target = nil + end end end diff --git a/lib/yard/templates/helpers/html_helper.rb b/lib/yard/templates/helpers/html_helper.rb index 9f7dae9b4..61a785bf1 100644 --- a/lib/yard/templates/helpers/html_helper.rb +++ b/lib/yard/templates/helpers/html_helper.rb @@ -301,6 +301,17 @@ def insert_include(text, markup = options.markup) def link_object(obj, title = nil, anchor = nil, relative = true) return title if obj.nil? obj = Registry.resolve(object, obj, true, true) if obj.is_a?(String) + + was_const = false + # Re-link references to constants that are aliases to their target. But keep + # their current title. + while obj.is_a?(CodeObjects::ConstantObject) && obj.target + title ||= h(object.relative_path(obj)).to_s + was_const = true + obj = obj.target + end + return link_object(obj, title, anchor, relative) if was_const + if title title = title.to_s elsif object.is_a?(CodeObjects::Base) diff --git a/spec/code_objects/constant_object_spec.rb b/spec/code_objects/constant_object_spec.rb new file mode 100644 index 000000000..50b68aee6 --- /dev/null +++ b/spec/code_objects/constant_object_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +require File.dirname(__FILE__) + '/spec_helper' + +RSpec.describe YARD::CodeObjects::ConstantObject do + before do + Registry.clear + end + + describe "#target" do + it "resolves" do + const1 = ConstantObject.new(:root, :A) + const2 = ConstantObject.new(:root, :B) + const2.value = "A" + expect(const2.target).to eq const1 + end + + it "returns nil for an integer value" do + const = ConstantObject.new(:root, :A) + const.value = "1" + expect(const.target).to be_nil + end + + it "returns nil for a string value" do + const = ConstantObject.new(:root, :A) + const.value = '"String"' + expect(const.target).to be_nil + end + + it "returns nil for an empty value" do + const = ConstantObject.new(:root, :A) + const.value = "" + expect(const.target).to be_nil + end + + it "returns nil for an explicit self-referential constant" do + const = ConstantObject.new(:root, :A) + const.value = "A" + expect(const.target).to be_nil + end + + it "returns nil for an explicit self-referential constant" do + mod = ModuleObject.new(:root, :M) + const = ConstantObject.new(mod, :A) + const.value = "self" + expect(const.target).to be_nil + end + end +end diff --git a/spec/templates/examples/module006.html b/spec/templates/examples/module006.html new file mode 100644 index 000000000..499513e5c --- /dev/null +++ b/spec/templates/examples/module006.html @@ -0,0 +1,54 @@ +

Module: A + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
(stdin)
+
+ +
+ +

Overview

+
+ Checkout BAR + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
FOO = + +
+
1
+ +
BAR = + +
+
FOO
+ +
+ diff --git a/spec/templates/module_spec.rb b/spec/templates/module_spec.rb index 416008249..d02d3f5cc 100644 --- a/spec/templates/module_spec.rb +++ b/spec/templates/module_spec.rb @@ -200,4 +200,16 @@ module A eof html_equals(Registry.at('A').format(html_options), :module005) end + + it "renders constants that are aliases as links in html" do + Registry.clear + YARD.parse_string <<~RUBY + # Checkout {BAR} + module A + FOO = 1 + BAR = FOO + end + RUBY + html_equals(Registry.at('A').format(html_options), :module006) + end end diff --git a/templates/default/module/html/constant_summary.erb b/templates/default/module/html/constant_summary.erb index 46f7ef861..a39ab57f4 100644 --- a/templates/default/module/html/constant_summary.erb +++ b/templates/default/module/html/constant_summary.erb @@ -10,7 +10,7 @@
<%= cnst.name %> = <%= yieldall :object => cnst %>
-
<%= format_constant cnst.value %>
+
<% if cnst.is_a?(YARD::CodeObjects::ConstantObject) && cnst.target %><%= linkify(cnst.target, cnst.value) %><% else %>
<%= format_constant cnst.value %>
<% end %>
<% end %> <% end %>