From e78b9b0a394d888674d3f6cc1c3d8fec0d948684 Mon Sep 17 00:00:00 2001 From: kigland Date: Fri, 25 Sep 2026 07:52:43 +0800 Subject: [PATCH] fix(ruby): cover braced factory blocks --- .../class-extractors/configs/ruby.ts | 2 +- .../src/core/ingestion/tree-sitter-queries.ts | 36 +++++++++++++++++++ .../src/core/ingestion/utils/ast-helpers.ts | 2 +- .../ruby-factory-block-owner.test.ts | 9 ++++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/gitnexus/src/core/ingestion/class-extractors/configs/ruby.ts b/gitnexus/src/core/ingestion/class-extractors/configs/ruby.ts index 1c0b36c64..dde6e2fca 100644 --- a/gitnexus/src/core/ingestion/class-extractors/configs/ruby.ts +++ b/gitnexus/src/core/ingestion/class-extractors/configs/ruby.ts @@ -15,7 +15,7 @@ export type RubyFactoryType = ClassLikeNodeLabel | 'Trait'; * type container. */ export const rubyFactoryType = (node: SyntaxNode): RubyFactoryType | undefined => { - if (node.type !== 'do_block') return undefined; + if (node.type !== 'do_block' && node.type !== 'block') return undefined; const call = node.parent; if (call?.type !== 'call' || call.childForFieldName?.('block') !== node) return undefined; diff --git a/gitnexus/src/core/ingestion/tree-sitter-queries.ts b/gitnexus/src/core/ingestion/tree-sitter-queries.ts index e10d2d2dd..efc733844 100644 --- a/gitnexus/src/core/ingestion/tree-sitter-queries.ts +++ b/gitnexus/src/core/ingestion/tree-sitter-queries.ts @@ -2238,6 +2238,15 @@ export const RUBY_QUERIES = ` (#eq? @_factory.receiver "Struct") (#eq? @_factory.method "new")) +((assignment + left: (constant) @name + right: (call + receiver: (constant) @_factory.receiver + method: (identifier) @_factory.method + block: (block) @definition.struct)) + (#eq? @_factory.receiver "Struct") + (#eq? @_factory.method "new")) + ((assignment left: (constant) @name right: (call @@ -2247,6 +2256,15 @@ export const RUBY_QUERIES = ` (#eq? @_factory.receiver "Data") (#eq? @_factory.method "define")) +((assignment + left: (constant) @name + right: (call + receiver: (constant) @_factory.receiver + method: (identifier) @_factory.method + block: (block) @definition.class)) + (#eq? @_factory.receiver "Data") + (#eq? @_factory.method "define")) + ((assignment left: (constant) @name right: (call @@ -2256,6 +2274,15 @@ export const RUBY_QUERIES = ` (#eq? @_factory.receiver "Class") (#eq? @_factory.method "new")) +((assignment + left: (constant) @name + right: (call + receiver: (constant) @_factory.receiver + method: (identifier) @_factory.method + block: (block) @definition.class)) + (#eq? @_factory.receiver "Class") + (#eq? @_factory.method "new")) + ((assignment left: (constant) @name right: (call @@ -2265,6 +2292,15 @@ export const RUBY_QUERIES = ` (#eq? @_factory.receiver "Module") (#eq? @_factory.method "new")) +((assignment + left: (constant) @name + right: (call + receiver: (constant) @_factory.receiver + method: (identifier) @_factory.method + block: (block))) @definition.module + (#eq? @_factory.receiver "Module") + (#eq? @_factory.method "new")) + ; ── Instance methods ───────────────────────────────────────────────────────── (method name: (identifier) @name) @definition.method diff --git a/gitnexus/src/core/ingestion/utils/ast-helpers.ts b/gitnexus/src/core/ingestion/utils/ast-helpers.ts index 24aaecd08..f78ba4f64 100644 --- a/gitnexus/src/core/ingestion/utils/ast-helpers.ts +++ b/gitnexus/src/core/ingestion/utils/ast-helpers.ts @@ -1015,7 +1015,7 @@ export const findEnclosingClassInfo = ( // the global container set. Let the Ruby hooks jointly opt an exact factory // shape in; arbitrary blocks fall through to their lexical owner unchanged. if ( - current.type === 'do_block' && + (current.type === 'do_block' || current.type === 'block') && resolveEnclosingOwner !== undefined && resolveContainerTypeOwner !== undefined && resolveEnclosingOwner(current) === current diff --git a/gitnexus/test/integration/ruby-factory-block-owner.test.ts b/gitnexus/test/integration/ruby-factory-block-owner.test.ts index 0de5275f0..da33ad1b4 100644 --- a/gitnexus/test/integration/ruby-factory-block-owner.test.ts +++ b/gitnexus/test/integration/ruby-factory-block-owner.test.ts @@ -33,6 +33,10 @@ class Outer def module_method = 1 end + BraceType = Class.new { + def brace_method = 1 + } + ArbitraryType = Builder.make do def arbitrary_method = 1 end @@ -57,6 +61,7 @@ end ['DataType', 'Class', 'data_method'], ['ClassType', 'Class', 'class_method'], ['ModuleType', 'Trait', 'module_method'], + ['BraceType', 'Class', 'brace_method'], ])( 'materializes %s as a %s and attributes its factory-block method', (owner, ownerLabel, method) => { @@ -96,6 +101,8 @@ end expect(owners).toHaveLength(2); expect(new Set(owners.map((node) => node.id)).size).toBe(2); - expect(ownership.map((edge) => edge.source)).toEqual(['ClassType']); + const nestedOwner = owners.find((node) => node.id.includes('Outer.Nested.ClassType')); + expect(nestedOwner).toBeDefined(); + expect(ownership.map((edge) => edge.rel.sourceId)).toEqual([nestedOwner?.id]); }); });