Skip to content

Commit

Permalink
Implement RubyVMSpecWalker#on_subject
Browse files Browse the repository at this point in the history
  • Loading branch information
lekemula committed May 16, 2024
1 parent e264bd1 commit 74ba354
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 29 deletions.
37 changes: 28 additions & 9 deletions lib/solargraph/rspec/ruby_vm_spec_walker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ def self.a_context_block?(block_ast)
Solargraph::Rspec::CONTEXT_METHODS.include?(method_name.to_s)
end

# @param ast [RubyVM::AbstractSyntaxTree::Node]
# @return [Boolean]
def self.a_subject_block?(block_ast)
return false unless a_block?(block_ast)

method_call = %i[CALL FCALL].include?(block_ast.children[0].type)
return false unless method_call

method_name = block_ast.children[0].children.select { |child| child.is_a?(Symbol) }.first

Solargraph::Rspec::SUBJECT_METHODS.include?(method_name.to_s)
end

def self.a_constant?(ast)
%i[CONST COLON2].include?(ast.type)
end
Expand All @@ -41,6 +54,12 @@ def self.context_description_node(block_ast)
block_ast.children[0].children[1].children[0]
end
end

# @param block_ast [RubyVM::AbstractSyntaxTree::Node]
# @return [String]
def self.let_method_name(block_ast)
block_ast.children[0].children[1]&.children&.[](0)&.children&.[](0)&.to_s
end
end

class RspecContextNamespace
Expand Down Expand Up @@ -205,17 +224,17 @@ def walk!
# end
# end

# walker.on :SCOPE do |block_ast|
# next if block_ast.children.first.type != :send
walker.on :ITER do |block_ast|
next unless NodeTypes.a_subject_block?(block_ast)

# method_ast = block_ast.children.first
# method_name = method_ast.children[1]
# next unless Rspec::SUBJECT_METHODS.include?(method_name.to_s)
# method_ast = block_ast.children.first
method_name = NodeTypes.let_method_name(block_ast)

# @handlers[:on_subject].each do |handler|
# handler.call(method_ast, block_ast)
# end
# end
@handlers[:on_subject].each do |handler|
method_ast = block_ast # TODO: Only use block_ast and reuse NodeTypes.let_method_name
handler.call(method_ast, block_ast)
end
end

# walker.on :SCOPE do |block_ast|
# next if block_ast.children.first.type != :send
Expand Down
79 changes: 59 additions & 20 deletions spec/solargraph/rspec/ruby_vm_spec_walker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ def parse(code)
end
end

describe '.a_context_block?' do
it 'returns true for subject block with name' do
node = parse('subject(:something) { }')
expect(Solargraph::Rspec::RubyVMSpecWalker::NodeTypes.a_subject_block?(node.children[2])).to be(true)
end

it 'returns true for subject block without name' do
node = parse('subject { }')

expect(Solargraph::Rspec::RubyVMSpecWalker::NodeTypes.a_subject_block?(node.children[2])).to be(true)
end
end

describe '.context_description_node' do
it 'returns correct node of context description' do
node = parse('describe "something" do end')
Expand All @@ -51,6 +64,32 @@ def parse(code)
expect(desc.children.last).to eq(:SomeClass)
end
end

describe '.let_method_name' do
it 'returns correct method name for subject block' do
node = parse('subject(:something) { }')
name = Solargraph::Rspec::RubyVMSpecWalker::NodeTypes.let_method_name(node.children[2])
expect(name).to eq('something')
end

it 'returns nil for subject block without a name' do
node = parse('subject { }')
name = Solargraph::Rspec::RubyVMSpecWalker::NodeTypes.let_method_name(node.children[2])
expect(name).to eq(nil)
end

it 'returns correct method name for let block' do
node = parse('let(:something) { }')
name = Solargraph::Rspec::RubyVMSpecWalker::NodeTypes.let_method_name(node.children[2])
expect(name).to eq('something')
end

it 'returns nil for let block without a name' do
node = parse('let { }')
name = Solargraph::Rspec::RubyVMSpecWalker::NodeTypes.let_method_name(node.children[2])
expect(name).to eq(nil)
end
end
end

# @param code [String]
Expand Down Expand Up @@ -108,29 +147,29 @@ def walk_code(code)
# end
# end

# describe '#on_subject' do
# it 'yields each context block' do
# code = <<~RUBY
# RSpec.describe SomeClass, type: :model do
# subject(:test) { SomeClass.new }
describe '#on_subject' do
it 'yields each context block' do
code = <<~RUBY
RSpec.describe SomeClass, type: :model do
subject(:test) { SomeClass.new }
# context 'when something' do
# subject { test }
# end
# end
# RUBY
context 'when something' do
subject { test }
end
end
RUBY

# called = 0
# # @param walker [Solargraph::Rspec::SpecWalker]
# walk_code(code) do |walker|
# walker.on_subject do |_|
# called += 1
# end
# end
called = 0
# @param walker [Solargraph::Rspec::SpecWalker]
walk_code(code) do |walker|
walker.on_subject do |_|
called += 1
end
end

# expect(called).to eq(2)
# end
# end
expect(called).to eq(2)
end
end

describe '#on_each_context_block' do
it 'yields each context block' do
Expand Down

0 comments on commit 74ba354

Please sign in to comment.