-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow for indexing augmentations and included hooks
- Loading branch information
Showing
5 changed files
with
255 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# typed: strict | ||
# frozen_string_literal: true | ||
|
||
module RubyIndexer | ||
module Augmentation | ||
extend T::Sig | ||
extend T::Helpers | ||
|
||
interface! | ||
|
||
# The `on_extend` indexing augmentation is invoked whenever an extend is encountered in the code. It can be used to | ||
# register for an included callback, similar to what `ActiveSupport::Concern` does in order to auto-extend the | ||
# `ClassMethods` modules | ||
sig do | ||
abstract.params( | ||
index: Index, | ||
owner: T.nilable(Entry::Namespace), | ||
node: Prism::CallNode, | ||
file_path: String, | ||
).void | ||
end | ||
def on_call_node(index, owner, node, file_path); end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# typed: true | ||
# frozen_string_literal: true | ||
|
||
require_relative "test_case" | ||
|
||
module RubyIndexer | ||
class AugmentationsTest < TestCase | ||
def test_augmenting_indexing_included_hook | ||
aug_class = Class.new do | ||
include Augmentation | ||
|
||
def on_call_node(index, owner, node, file_path) | ||
return unless owner | ||
return unless node.name == :extend | ||
|
||
arguments = node.arguments&.arguments | ||
return unless arguments | ||
|
||
location = node.location | ||
|
||
arguments.each do |node| | ||
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode) | ||
|
||
module_name = node.full_name | ||
next unless module_name == "ActiveSupport::Concern" | ||
|
||
index.register_included_hook(owner.name) do |index, base| | ||
class_methods_name = "#{owner.name}::ClassMethods" | ||
|
||
if index.indexed?(class_methods_name) | ||
singleton = index.existing_or_new_singleton_class(base.name) | ||
singleton.mixin_operations << Entry::Include.new(class_methods_name) | ||
end | ||
end | ||
|
||
index.add(Entry::Method.new( | ||
"new_method", | ||
file_path, | ||
location, | ||
location, | ||
[], | ||
[Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])], | ||
Entry::Visibility::PUBLIC, | ||
owner, | ||
)) | ||
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError, | ||
Prism::ConstantPathNode::MissingNodesInConstantPathError | ||
# Do nothing | ||
end | ||
end | ||
end | ||
|
||
@index.register_augmentation(aug_class.new) | ||
index(<<~RUBY) | ||
module ActiveSupport | ||
module Concern | ||
def self.extended(base) | ||
base.class_eval("def new_method(a); end") | ||
end | ||
end | ||
end | ||
module ActiveRecord | ||
module Associations | ||
extend ActiveSupport::Concern | ||
module ClassMethods | ||
def belongs_to(something); end | ||
end | ||
end | ||
class Base | ||
include Associations | ||
end | ||
end | ||
class User < ActiveRecord::Base | ||
end | ||
RUBY | ||
|
||
assert_equal( | ||
[ | ||
"User::<Class:User>", | ||
"ActiveRecord::Base::<Class:Base>", | ||
"ActiveRecord::Associations::ClassMethods", | ||
"Object::<Class:Object>", | ||
"BasicObject::<Class:BasicObject>", | ||
"Class", | ||
"Module", | ||
"Object", | ||
"Kernel", | ||
"BasicObject", | ||
], | ||
@index.linearized_ancestors_of("User::<Class:User>"), | ||
) | ||
|
||
assert_entry("new_method", Entry::Method, "/fake/path/foo.rb:10-4:10-33") | ||
end | ||
|
||
def test_augmenting_indexing_configuration_dsl | ||
aug_class = Class.new do | ||
include Augmentation | ||
|
||
def on_call_node(index, owner, node, file_path) | ||
return unless owner | ||
|
||
name = node.name | ||
return unless name == :has_many | ||
|
||
arguments = node.arguments&.arguments | ||
return unless arguments | ||
|
||
association_name = arguments.first | ||
return unless association_name.is_a?(Prism::SymbolNode) | ||
|
||
location = association_name.location | ||
|
||
index.add(Entry::Method.new( | ||
T.must(association_name.value), | ||
file_path, | ||
location, | ||
location, | ||
[], | ||
[], | ||
Entry::Visibility::PUBLIC, | ||
owner, | ||
)) | ||
end | ||
end | ||
|
||
@index.register_augmentation(aug_class.new) | ||
index(<<~RUBY) | ||
module ActiveSupport | ||
module Concern | ||
def self.extended(base) | ||
base.class_eval("def new_method(a); end") | ||
end | ||
end | ||
end | ||
module ActiveRecord | ||
module Associations | ||
extend ActiveSupport::Concern | ||
module ClassMethods | ||
def belongs_to(something); end | ||
end | ||
end | ||
class Base | ||
include Associations | ||
end | ||
end | ||
class User < ActiveRecord::Base | ||
has_many :posts | ||
end | ||
RUBY | ||
|
||
assert_entry("posts", Entry::Method, "/fake/path/foo.rb:23-11:23-17") | ||
end | ||
end | ||
end |