-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor SpecWalker - extract sub-classes into own files
- Loading branch information
Showing
4 changed files
with
168 additions
and
144 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
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,29 @@ | ||
# frozen_string_literal: true | ||
|
||
module Solargraph | ||
module Rspec | ||
class SpecWalker | ||
class FullConstantName | ||
class << self | ||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [String] | ||
def from_ast(ast) | ||
raise 'Node is not a constant' unless NodeTypes.a_constant?(ast) | ||
|
||
if ast.type == :CONST | ||
ast.children[0].to_s | ||
elsif ast.type == :COLON2 | ||
name = ast.children[1].to_s | ||
"#{from_ast(ast.children[0])}::#{name}" | ||
end | ||
end | ||
|
||
def from_context_block_ast(block_ast) | ||
ast = NodeTypes.context_description_node(block_ast) | ||
from_ast(ast) | ||
end | ||
end | ||
end | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# frozen_string_literal: true | ||
|
||
module Solargraph | ||
module Rspec | ||
class SpecWalker | ||
class NodeTypes | ||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [Boolean] | ||
def self.a_block?(ast) | ||
return false unless ast.is_a?(RubyVM::AbstractSyntaxTree::Node) | ||
|
||
%i[ITER LAMBDA].include?(ast.type) | ||
end | ||
|
||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [Boolean] | ||
def self.a_context_block?(block_ast) | ||
Solargraph::Rspec::CONTEXT_METHODS.include?(method_with_block_name(block_ast)) | ||
end | ||
|
||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [Boolean] | ||
def self.a_subject_block?(block_ast) | ||
Solargraph::Rspec::SUBJECT_METHODS.include?(method_with_block_name(block_ast)) | ||
end | ||
|
||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [Boolean] | ||
def self.a_example_block?(block_ast) | ||
Solargraph::Rspec::EXAMPLE_METHODS.include?(method_with_block_name(block_ast)) | ||
end | ||
|
||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @param config [Config] | ||
# @return [Boolean] | ||
def self.a_let_block?(block_ast, config) | ||
config.let_methods.map(&:to_s).include?(method_with_block_name(block_ast)) | ||
end | ||
|
||
# @param ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [Boolean] | ||
def self.a_hook_block?(block_ast) | ||
Solargraph::Rspec::HOOK_METHODS.include?(method_with_block_name(block_ast)) | ||
end | ||
|
||
def self.a_constant?(ast) | ||
%i[CONST COLON2].include?(ast.type) | ||
end | ||
|
||
# @param block_ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [String, nil] | ||
def self.method_with_block_name(block_ast) | ||
return nil unless a_block?(block_ast) | ||
|
||
method_call = %i[CALL FCALL].include?(block_ast.children[0].type) | ||
return nil unless method_call | ||
|
||
block_ast.children[0].children.select { |child| child.is_a?(Symbol) }.first&.to_s | ||
end | ||
|
||
# @param block_ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [RubyVM::AbstractSyntaxTree::Node] | ||
def self.context_description_node(block_ast) | ||
case block_ast.children[0].type | ||
when :CALL # RSpec.describe "something" do end | ||
block_ast.children[0].children[2].children[0] | ||
when :FCALL # describe "something" do end | ||
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 | ||
end | ||
end | ||
end |
56 changes: 56 additions & 0 deletions
56
lib/solargraph/rspec/spec_walker/rspec_context_namespace.rb
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,56 @@ | ||
# frozen_string_literal: true | ||
|
||
module Solargraph | ||
module Rspec | ||
class SpecWalker | ||
class RspecContextNamespace | ||
class << self | ||
# @param block_ast [RubyVM::AbstractSyntaxTree::Node] | ||
# @return [String, nil] | ||
def from_block_ast(block_ast) | ||
return unless block_ast.is_a?(RubyVM::AbstractSyntaxTree::Node) | ||
|
||
ast = NodeTypes.context_description_node(block_ast) | ||
if ast.type == :STR | ||
string_to_const_name(ast) | ||
elsif NodeTypes.a_constant?(ast) | ||
FullConstantName.from_ast(ast).gsub('::', '') | ||
else | ||
Solargraph.logger.warn "[RSpec] Unexpected AST type #{ast.type}" | ||
nil | ||
end | ||
end | ||
|
||
private | ||
|
||
# @see https://github.com/rspec/rspec-core/blob/1eeadce5aa7137ead054783c31ff35cbfe9d07cc/lib/rspec/core/example_group.rb#L862 | ||
# @param ast [Parser::AST::Node] | ||
# @return [String] | ||
def string_to_const_name(string_ast) | ||
return unless string_ast.type == :STR | ||
|
||
name = string_ast.children[0] | ||
return 'Anonymous'.dup if name.empty? | ||
|
||
# Convert to CamelCase. | ||
name = +" #{name}" | ||
name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do | ||
match = ::Regexp.last_match[1] | ||
match.upcase! | ||
match | ||
end | ||
|
||
name.lstrip! # Remove leading whitespace | ||
name.gsub!(/\W/, '') # JRuby, RBX and others don't like non-ascii in const names | ||
|
||
# Ruby requires first const letter to be A-Z. Use `Nested` | ||
# as necessary to enforce that. | ||
name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1') | ||
|
||
name | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |