From 8a22d45d3ed549a445657eacc1c2451240620531 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 16 Aug 2026 22:13:55 +1200 Subject: [PATCH 1/4] Show inherited methods with relationships Assisted-By: devx/08af623d-3e23-42c2-ada9-1ce2bcb7e46f --- lib/utopia/project/inheritance.rb | 39 ++++++++++---------- pages/reference/_relationships.xnode | 35 ++++++++++-------- test/utopia/project/.fixtures/inheritance.rb | 16 +++++++- test/utopia/project/inheritance.rb | 19 ++++++---- test/utopia/project/serve.rb | 5 ++- 5 files changed, 71 insertions(+), 43 deletions(-) diff --git a/lib/utopia/project/inheritance.rb b/lib/utopia/project/inheritance.rb index 915dc3f..0a7895f 100644 --- a/lib/utopia/project/inheritance.rb +++ b/lib/utopia/project/inheritance.rb @@ -13,8 +13,8 @@ class Inheritance # A method inherited from another definition. Method = Struct.new(:name, :definition) - # A group of inherited methods with the same origin. - Group = Struct.new(:definition, :methods) + # Methods inherited through a direct relationship. + Group = Struct.new(:kind, :definition, :methods) # Initialize inheritance resolution for the given definition. # @parameter index [Decode::Index] The index used to resolve relationships. @@ -55,10 +55,10 @@ def relationships end # Enumerate documented public and protected methods inherited by the definition. - # @returns [Array(Group)] Methods grouped by the definition which provides them. + # @returns [Array(Group)] Methods grouped by the direct relationship which provides them. def inherited_methods @groups = [] - @groups_by_definition = {} + @groups_by_relationship = {} collect_instance_methods(@definition, false, {}, {}) collect_class_methods(@definition, false, {}, {}) @@ -113,46 +113,46 @@ def singleton_for(definition) end end - def collect_instance_methods(definition, include_own, seen, visited, display_prefix = "#") + def collect_instance_methods(definition, include_own, seen, visited, display_prefix: "#", kind: nil, provider: nil) key = [definition.qualified_name, display_prefix] return if visited[key] visited[key] = true relationship_definitions(definition, :prepends).reverse_each do |relationship| - collect_instance_methods(relationship, true, seen, visited, display_prefix) + collect_instance_methods(relationship, true, seen, visited, display_prefix: display_prefix, kind: kind || :prepend, provider: provider || relationship) end - collect_methods(definition, "#", display_prefix, include_own, seen) + collect_methods(definition, "#", display_prefix, include_own, seen, kind: kind, provider: provider) relationship_definitions(definition, :includes).reverse_each do |relationship| - collect_instance_methods(relationship, true, seen, visited, display_prefix) + collect_instance_methods(relationship, true, seen, visited, display_prefix: display_prefix, kind: kind || :include, provider: provider || relationship) end if display_prefix == "#" && (super_class = super_class_for(definition)) - collect_instance_methods(super_class, true, seen, visited, display_prefix) + collect_instance_methods(super_class, true, seen, visited, display_prefix: display_prefix, kind: kind || :super_class, provider: provider || super_class) end end - def collect_class_methods(definition, include_own, seen, visited) + def collect_class_methods(definition, include_own, seen, visited, kind: nil, provider: nil) key = definition.qualified_name return if visited[key] visited[key] = true - collect_methods(definition, ".", ".", include_own, seen) + collect_methods(definition, ".", ".", include_own, seen, kind: kind, provider: provider) if singleton = singleton_for(definition) - collect_methods(singleton, "#", ".", include_own, seen, definition) + collect_methods(singleton, "#", ".", include_own, seen, kind: kind, provider: provider) end relationship_definitions(definition, :extends).reverse_each do |relationship| - collect_instance_methods(relationship, true, seen, {}, ".") + collect_instance_methods(relationship, true, seen, {}, display_prefix: ".", kind: kind || :extend, provider: provider || relationship) end if super_class = super_class_for(definition) - collect_class_methods(super_class, true, seen, visited) + collect_class_methods(super_class, true, seen, visited, kind: kind || :super_class, provider: provider || super_class) end end - def collect_methods(definition, source_prefix, display_prefix, include_own, seen, origin = definition) + def collect_methods(definition, source_prefix, display_prefix, include_own, seen, kind:, provider:) methods_for(definition, source_prefix).each do |method| name = "#{display_prefix}#{method.name}" next if seen[name] @@ -168,13 +168,14 @@ def collect_methods(definition, source_prefix, display_prefix, include_own, seen next unless method.documented? next if method.respond_to?(:private?) && method.private? - add_method(origin, name, method) + add_method(kind, provider, name, method) end end - def add_method(definition, name, method) - group = @groups_by_definition[definition.qualified_name] ||= begin - group = Group.new(definition, []) + def add_method(kind, provider, name, method) + key = [kind, provider.qualified_name] + group = @groups_by_relationship[key] ||= begin + group = Group.new(kind, provider, []) @groups << group group end diff --git a/pages/reference/_relationships.xnode b/pages/reference/_relationships.xnode index 685e656..58a5e08 100644 --- a/pages/reference/_relationships.xnode +++ b/pages/reference/_relationships.xnode @@ -5,6 +5,9 @@ inheritance = base.inheritance_for(symbol) relationships = inheritance.relationships inherited_methods = inheritance.inherited_methods +inherited_methods_by_relationship = inherited_methods.to_h do |group| + [[group.kind, group.definition.qualified_name], group.methods] +end relationship_labels = { super_class: "Inherits from", @@ -20,26 +23,28 @@ relationship_labels = {
0 - ?>, ; #{base.linkify(relationship.name, symbol)}: 0 + ?>, #{method.name}
- - -
-

Inherited Methods

From #{group.definition.qualified_name}:

-
- diff --git a/test/utopia/project/.fixtures/inheritance.rb b/test/utopia/project/.fixtures/inheritance.rb index 69ca6b0..f38fc28 100644 --- a/test/utopia/project/.fixtures/inheritance.rb +++ b/test/utopia/project/.fixtures/inheritance.rb @@ -32,7 +32,21 @@ def extended_method end end - class Parent + module ParentIncluded + # A method included by the parent. + def parent_included_method + end + end + + class Grandparent + # An inherited grandparent method. + def grandparent_method + end + end + + class Parent < Grandparent + include ParentIncluded + # Initialize the parent. def initialize end diff --git a/test/utopia/project/inheritance.rb b/test/utopia/project/inheritance.rb index 1f05964..b28a4ea 100644 --- a/test/utopia/project/inheritance.rb +++ b/test/utopia/project/inheritance.rb @@ -26,16 +26,21 @@ } end - it "groups inherited methods by their origin" do - methods = inheritance.inherited_methods.to_h do |group| - [group.definition.qualified_name, group.methods.map(&:name)] + it "groups inherited methods by their direct relationship" do + groups = inheritance.inherited_methods + methods = groups.to_h do |group| + [[group.kind, group.definition.qualified_name], group.methods.map(&:name)] end expect(methods).to be == { - "Example::Prepended" => ["#prepended_method"], - "Example::Included" => ["#included_method"], - "Example::Parent" => ["#parent_method", ".parent_class_method", ".singleton_class_method"], - "Example::Extended" => [".extended_method"], + [:prepend, "Example::Prepended"] => ["#prepended_method"], + [:include, "Example::Included"] => ["#included_method"], + [:super_class, "Example::Parent"] => ["#parent_method", "#parent_included_method", "#grandparent_method", ".parent_class_method", ".singleton_class_method"], + [:extend, "Example::Extended"] => [".extended_method"], } + + parent = groups.find{|group| group.definition.qualified_name == "Example::Parent"} + parent_included_method = parent.methods.find{|method| method.name == "#parent_included_method"} + expect(parent_included_method.definition.qualified_name).to be == "Example::ParentIncluded#parent_included_method" end end diff --git a/test/utopia/project/serve.rb b/test/utopia/project/serve.rb index 0e8419d..b216295 100644 --- a/test/utopia/project/serve.rb +++ b/test/utopia/project/serve.rb @@ -82,7 +82,10 @@ expect(body).to be(:include?, 'class ReleasesDocument < Document') expect(body).to be(:include?, '
') expect(body).to be(:include?, "
Inherits from
") - expect(body).to be(:include?, "/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root") + + relationships = body[/
.*?<\/dl>/m] + expect(relationships).to be(:include?, "/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root") + expect(body).not.to be(:include?, "

Inherited Methods

") end it "summarizes nested definitions" do From 1c783a4909e1d90c76a0b78ee3f7210f44a6c31d Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 16 Aug 2026 22:19:08 +1200 Subject: [PATCH 2/4] Use consistent typography for method lists Assisted-By: devx/08af623d-3e23-42c2-ada9-1ce2bcb7e46f --- pages/reference/_relationships.xnode | 5 +++-- test/utopia/project/serve.rb | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pages/reference/_relationships.xnode b/pages/reference/_relationships.xnode index 58a5e08..fcb86ee 100644 --- a/pages/reference/_relationships.xnode +++ b/pages/reference/_relationships.xnode @@ -34,14 +34,15 @@ relationship_labels = { end if methods&.any? - ?>: : 0 ?>, #{method.name}#{method.name}.*?<\/dl>/m] expect(relationships).to be(:include?, "/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root") + expect(relationships).to be(:include?, ": Inherited Methods") end From 75ff817e219b9954c302277157c7e17d78455d4b Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 16 Aug 2026 22:21:16 +1200 Subject: [PATCH 3/4] Exclude relationship metadata from search Assisted-By: devx/08af623d-3e23-42c2-ada9-1ce2bcb7e46f --- pages/reference/_relationships.xnode | 2 +- test/utopia/project/serve.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/reference/_relationships.xnode b/pages/reference/_relationships.xnode index fcb86ee..82aaece 100644 --- a/pages/reference/_relationships.xnode +++ b/pages/reference/_relationships.xnode @@ -17,7 +17,7 @@ relationship_labels = { } ?> -
#{relationship_labels.fetch(kind)}
Document') - expect(body).to be(:include?, '
') + expect(body).to be(:include?, '
') expect(body).to be(:include?, "
Inherits from
") - relationships = body[/
.*?<\/dl>/m] + relationships = body[/
.*?<\/dl>/m] expect(relationships).to be(:include?, "/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root") expect(relationships).to be(:include?, ": Inherited Methods") From c0d9b910bdc88576cecda89f729e4e4ff884f94f Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 16 Aug 2026 22:23:57 +1200 Subject: [PATCH 4/4] Include method separator in code styling Assisted-By: devx/08af623d-3e23-42c2-ada9-1ce2bcb7e46f --- pages/reference/_relationships.xnode | 2 +- test/utopia/project/serve.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/reference/_relationships.xnode b/pages/reference/_relationships.xnode index 82aaece..9dfe869 100644 --- a/pages/reference/_relationships.xnode +++ b/pages/reference/_relationships.xnode @@ -34,7 +34,7 @@ relationship_labels = { end if methods&.any? - ?>: : 0 ?>, .*?<\/dl>/m] expect(relationships).to be(:include?, "/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root") - expect(relationships).to be(:include?, ": : Inherited Methods") end