solargraph-rspec 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,13 +10,53 @@ module Solargraph
10
10
  # @param source_map [Solargraph::SourceMap]
11
11
  # @return [void]
12
12
  def correct(_source_map)
13
- rspec_walker.on_subject do |ast|
14
- namespace_pin = closest_namespace_pin(namespace_pins, ast.loc.line)
13
+ rspec_walker.on_subject do |subject_name, location_range, fake_method_ast|
14
+ namespace_pin = closest_namespace_pin(namespace_pins, location_range.start.line)
15
15
  next unless namespace_pin
16
16
 
17
- subject_pin = rspec_let_method(namespace_pin, ast)
18
- yield [subject_pin].compact if block_given?
17
+ subject_pin = rspec_subject_method(namespace_pin, subject_name, location_range, fake_method_ast)
18
+ add_pin(subject_pin)
19
19
  end
20
+
21
+ rspec_walker.after_walk do
22
+ next unless described_class_pin
23
+
24
+ namespace_pin = closest_namespace_pin(namespace_pins, described_class_pin.location.range.start.line)
25
+
26
+ add_pin(implicit_subject_pin(described_class_pin, namespace_pin)) if namespace_pin
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ # @return [Pin::Method, nil]
33
+ def described_class_pin
34
+ @described_class_pin ||= added_pins.find { |pin| pin.is_a?(Pin::Method) && pin.name == 'described_class' }
35
+ end
36
+
37
+ # @param namespace_pin [Pin::Namespace]
38
+ # @param subject_name [String, nil]
39
+ # @param location_range [Solargraph::Range]
40
+ # @param fake_method_ast [Parser::AST::Node]
41
+ # @return [Pin::Method]
42
+ def rspec_subject_method(namespace_pin, subject_name, location_range, fake_method_ast)
43
+ method_name = subject_name || 'subject'
44
+ rspec_let_method(namespace_pin, method_name, location_range, fake_method_ast)
45
+ end
46
+
47
+ # @param described_class_pin [Pin::Method]
48
+ # @param namespace_pin [Pin::Namespace]
49
+ # @return [Pin::Method]
50
+ def implicit_subject_pin(described_class_pin, namespace_pin)
51
+ described_class = described_class_pin.return_type.first.subtypes.first.name
52
+
53
+ PinFactory.build_public_method(
54
+ namespace_pin,
55
+ 'subject',
56
+ types: ["::#{described_class}"],
57
+ location: described_class_pin.location,
58
+ scope: :instance
59
+ )
20
60
  end
21
61
  end
22
62
  end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Credits: This file is a copy of the file from the solargraph-rspec gem
4
+
5
+ module Solargraph
6
+ module Rspec
7
+ # Factory class for building pins and references.
8
+ module PinFactory
9
+ # @param namespace [Solargraph::Pin::Namespace]
10
+ # @param name [String]
11
+ # @param types [Array<String>]
12
+ # @param location [Solargraph::Location]
13
+ # @param comments [Array<String>]
14
+ # @param attribute [Boolean]
15
+ # @param scope [:instance, :class]
16
+ # @return [Solargraph::Pin::Method]
17
+ def self.build_public_method(
18
+ namespace,
19
+ name,
20
+ types: nil,
21
+ location: nil,
22
+ comments: [],
23
+ attribute: false,
24
+ scope: :instance,
25
+ node: nil
26
+ )
27
+ opts = {
28
+ name: name,
29
+ location: location,
30
+ closure: namespace,
31
+ scope: scope,
32
+ attribute: attribute,
33
+ comments: [],
34
+ node: node
35
+ }
36
+
37
+ comments << "@return [#{types.join(",")}]" if types
38
+
39
+ opts[:comments] = comments.join("\n")
40
+
41
+ Solargraph::Pin::Method.new(**opts)
42
+ end
43
+
44
+ # @param namespace [Solargraph::Pin::Namespace]
45
+ # @param name [String]
46
+ # @param location [Solargraph::Location]
47
+ # @return [Solargraph::Pin::Reference::Include]
48
+ def self.build_module_include(namespace, module_name, location)
49
+ Solargraph::Pin::Reference::Include.new(
50
+ closure: namespace,
51
+ name: module_name,
52
+ location: location
53
+ )
54
+ end
55
+
56
+ # @param namespace [Solargraph::Pin::Namespace]
57
+ # @param module_name [String]
58
+ # @param location [Solargraph::Location]
59
+ # @return [Solargraph::Pin::Reference::Extend]
60
+ def self.build_module_extend(namespace, module_name, location)
61
+ Solargraph::Pin::Reference::Extend.new(
62
+ closure: namespace,
63
+ name: module_name,
64
+ location: location
65
+ )
66
+ end
67
+
68
+ # @param path [String]
69
+ # @return [Solargraph::Location]
70
+ def self.dummy_location(path)
71
+ Solargraph::Location.new(
72
+ File.expand_path(path),
73
+ Solargraph::Range.from_to(0, 0, 0, 0)
74
+ )
75
+ end
76
+
77
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
78
+ # @see [RubyVM::AbstractSyntaxTree::NodeWrapper] - for why we need -1 for lineno
79
+ # @return [Solargraph::Range]
80
+ def self.build_location_range(ast)
81
+ Solargraph::Range.from_to(
82
+ ast.first_lineno - 1,
83
+ ast.first_column,
84
+ ast.last_lineno - 1,
85
+ ast.last_column
86
+ )
87
+ end
88
+
89
+ # @param location_range [Solargraph::Range]
90
+ # @param path [String]
91
+ # @return [Solargraph::Location]
92
+ def self.build_location(location_range, path)
93
+ Solargraph::Location.new(
94
+ File.expand_path(path),
95
+ location_range
96
+ )
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rspec
5
+ class SpecWalker
6
+ class FakeLetMethod
7
+ MATCH_BODY = Regexp.union(
8
+ /do(.*)end/m,
9
+ /{(.*)}/m
10
+ )
11
+
12
+ # @param block_ast [RubyVM::AbstractSyntaxTree::Node]
13
+ # @return [RubyVM::AbstractSyntaxTree::Node]
14
+ def self.transform_block(block_ast, code, method_name = nil)
15
+ method_name ||= NodeTypes.let_method_name(block_ast)
16
+ block_body = block_ast.children[1]
17
+ matches = code.lines[block_body.first_lineno - 1..block_body.last_lineno - 1].join.match(MATCH_BODY)
18
+ method_body = (matches[1] || matches[2]).strip
19
+
20
+ ast = RubyVM::AbstractSyntaxTree.parse <<~RUBY
21
+ def #{method_name}
22
+ #{method_body}
23
+ end
24
+ RUBY
25
+
26
+ ast.children[2]
27
+ rescue SyntaxError
28
+ raise "Failed to build fake let method: #{block_ast.inspect}, message: #{e.message}"
29
+ ensure
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rspec
5
+ class SpecWalker
6
+ class FullConstantName
7
+ class << self
8
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
9
+ # @return [String]
10
+ def from_ast(ast)
11
+ raise 'Node is not a constant' unless NodeTypes.a_constant?(ast)
12
+
13
+ if ast.type == :CONST
14
+ ast.children[0].to_s
15
+ elsif ast.type == :COLON2
16
+ name = ast.children[1].to_s
17
+ "#{from_ast(ast.children[0])}::#{name}"
18
+ end
19
+ end
20
+
21
+ def from_context_block_ast(block_ast)
22
+ ast = NodeTypes.context_description_node(block_ast)
23
+ from_ast(ast)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rspec
5
+ class SpecWalker
6
+ class NodeTypes
7
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
8
+ # @return [Boolean]
9
+ def self.a_block?(ast)
10
+ return false unless ast.is_a?(RubyVM::AbstractSyntaxTree::Node)
11
+
12
+ %i[ITER LAMBDA].include?(ast.type)
13
+ end
14
+
15
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
16
+ # @return [Boolean]
17
+ def self.a_context_block?(block_ast)
18
+ Solargraph::Rspec::CONTEXT_METHODS.include?(method_with_block_name(block_ast))
19
+ end
20
+
21
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
22
+ # @return [Boolean]
23
+ def self.a_subject_block?(block_ast)
24
+ Solargraph::Rspec::SUBJECT_METHODS.include?(method_with_block_name(block_ast))
25
+ end
26
+
27
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
28
+ # @return [Boolean]
29
+ def self.a_example_block?(block_ast)
30
+ Solargraph::Rspec::EXAMPLE_METHODS.include?(method_with_block_name(block_ast))
31
+ end
32
+
33
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
34
+ # @param config [Config]
35
+ # @return [Boolean]
36
+ def self.a_let_block?(block_ast, config)
37
+ config.let_methods.map(&:to_s).include?(method_with_block_name(block_ast))
38
+ end
39
+
40
+ # @param ast [RubyVM::AbstractSyntaxTree::Node]
41
+ # @return [Boolean]
42
+ def self.a_hook_block?(block_ast)
43
+ Solargraph::Rspec::HOOK_METHODS.include?(method_with_block_name(block_ast))
44
+ end
45
+
46
+ def self.a_constant?(ast)
47
+ %i[CONST COLON2].include?(ast.type)
48
+ end
49
+
50
+ # @param block_ast [RubyVM::AbstractSyntaxTree::Node]
51
+ # @return [String, nil]
52
+ def self.method_with_block_name(block_ast)
53
+ return nil unless a_block?(block_ast)
54
+
55
+ method_call = %i[CALL FCALL].include?(block_ast.children[0].type)
56
+ return nil unless method_call
57
+
58
+ block_ast.children[0].children.select { |child| child.is_a?(Symbol) }.first&.to_s
59
+ end
60
+
61
+ # @param block_ast [RubyVM::AbstractSyntaxTree::Node]
62
+ # @return [RubyVM::AbstractSyntaxTree::Node]
63
+ def self.context_description_node(block_ast)
64
+ return nil unless a_context_block?(block_ast)
65
+
66
+ case block_ast.children[0].type
67
+ when :CALL # RSpec.describe "something" do end
68
+ block_ast.children[0].children[2].children[0]
69
+ when :FCALL # describe "something" do end
70
+ block_ast.children[0].children[1].children[0]
71
+ end
72
+ end
73
+
74
+ # @param block_ast [RubyVM::AbstractSyntaxTree::Node]
75
+ # @return [String]
76
+ def self.let_method_name(block_ast)
77
+ block_ast.children[0].children[1]&.children&.[](0)&.children&.[](0)&.to_s
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rspec
5
+ class SpecWalker
6
+ class RspecContextNamespace
7
+ class << self
8
+ # @param block_ast [RubyVM::AbstractSyntaxTree::Node]
9
+ # @return [String, nil]
10
+ def from_block_ast(block_ast)
11
+ return unless block_ast.is_a?(RubyVM::AbstractSyntaxTree::Node)
12
+
13
+ ast = NodeTypes.context_description_node(block_ast)
14
+ if ast.type == :STR
15
+ string_to_const_name(ast)
16
+ elsif NodeTypes.a_constant?(ast)
17
+ FullConstantName.from_ast(ast).gsub('::', '')
18
+ else
19
+ Solargraph.logger.warn "[RSpec] Unexpected AST type #{ast.type}"
20
+ nil
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ # @see https://github.com/rspec/rspec-core/blob/1eeadce5aa7137ead054783c31ff35cbfe9d07cc/lib/rspec/core/example_group.rb#L862
27
+ # @param ast [Parser::AST::Node]
28
+ # @return [String]
29
+ def string_to_const_name(string_ast)
30
+ return unless string_ast.type == :STR
31
+
32
+ name = string_ast.children[0]
33
+ return 'Anonymous'.dup if name.empty?
34
+
35
+ # Convert to CamelCase.
36
+ name = +" #{name}"
37
+ name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do
38
+ match = ::Regexp.last_match[1]
39
+ match.upcase!
40
+ match
41
+ end
42
+
43
+ name.lstrip! # Remove leading whitespace
44
+ name.gsub!(/\W/, '') # JRuby, RBX and others don't like non-ascii in const names
45
+
46
+ # Ruby requires first const letter to be A-Z. Use `Nested`
47
+ # as necessary to enforce that.
48
+ name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1')
49
+
50
+ name
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'walker'
4
+ require_relative 'spec_walker/node_types'
5
+ require_relative 'spec_walker/full_constant_name'
6
+ require_relative 'spec_walker/rspec_context_namespace'
7
+ require_relative 'spec_walker/fake_let_method'
4
8
 
5
9
  module Solargraph
6
10
  module Rspec
@@ -10,7 +14,7 @@ module Solargraph
10
14
  def initialize(source_map:, config:)
11
15
  @source_map = source_map
12
16
  @config = config
13
- @walker = Rspec::Walker.from_source(source_map.source)
17
+ @walker = Rspec::Walker.new(source_map.source.node)
14
18
  @handlers = {
15
19
  on_described_class: [],
16
20
  on_let_method: [],
@@ -30,24 +34,34 @@ module Solargraph
30
34
  attr_reader :config
31
35
 
32
36
  # @param block [Proc]
37
+ # @yieldparam class_name [String]
38
+ # @yieldparam location_range [Solargraph::Range]
33
39
  # @return [void]
34
40
  def on_described_class(&block)
35
41
  @handlers[:on_described_class] << block
36
42
  end
37
43
 
38
44
  # @param block [Proc]
45
+ # @yieldparam method_name [String]
46
+ # @yieldparam location_range [Solargraph::Range]
47
+ # @yieldparam fake_method_ast [RubyVM::AbstractSyntaxTree::Node]
39
48
  # @return [void]
40
49
  def on_let_method(&block)
41
50
  @handlers[:on_let_method] << block
42
51
  end
43
52
 
44
53
  # @param block [Proc]
54
+ # @yieldparam method_name [String]
55
+ # @yieldparam location_range [Solargraph::Range]
56
+ # @yieldparam fake_method_ast [RubyVM::AbstractSyntaxTree::Node]
45
57
  # @return [void]
46
58
  def on_subject(&block)
47
59
  @handlers[:on_subject] << block
48
60
  end
49
61
 
50
62
  # @param block [Proc]
63
+ # @yieldparam namespace_name [String]
64
+ # @yieldparam location_range [Solargraph::Range]
51
65
  # @return [void]
52
66
  def on_each_context_block(&block)
53
67
  @handlers[:on_each_context_block] << block
@@ -55,18 +69,21 @@ module Solargraph
55
69
 
56
70
  #
57
71
  # @param block [Proc]
72
+ # @yieldparam location_range [Solargraph::Range]
58
73
  # @return [void]
59
74
  def on_example_block(&block)
60
75
  @handlers[:on_example_block] << block
61
76
  end
62
77
 
63
78
  # @param block [Proc]
79
+ # @yieldparam location_range [Solargraph::Range]
64
80
  # @return [void]
65
81
  def on_hook_block(&block)
66
82
  @handlers[:on_hook_block] << block
67
83
  end
68
84
 
69
85
  # @param block [Proc]
86
+ # @yieldparam location_range [Solargraph::Range]
70
87
  # @return [void]
71
88
  def on_blocks_in_examples(&block)
72
89
  @handlers[:on_blocks_in_examples] << block
@@ -80,77 +97,72 @@ module Solargraph
80
97
 
81
98
  # @return [void]
82
99
  def walk!
83
- each_context_block(@walker.ast, Rspec::ROOT_NAMESPACE) do |namespace_name, ast|
100
+ each_context_block(@walker.ast, Rspec::ROOT_NAMESPACE) do |namespace_name, block_ast|
101
+ desc_node = NodeTypes.context_description_node(block_ast)
102
+
84
103
  @handlers[:on_each_context_block].each do |handler|
85
- handler.call(namespace_name, ast)
104
+ handler.call(namespace_name, PinFactory.build_location_range(block_ast))
86
105
  end
87
- end
88
106
 
89
- rspec_const = ::Parser::AST::Node.new(:const, [nil, :RSpec])
90
- walker.on :send, [rspec_const, :describe, :any] do |ast|
91
- @handlers[:on_described_class].each do |handler|
92
- class_ast = ast.children[2]
93
- next unless class_ast
94
-
95
- class_name = full_constant_name(class_ast)
96
- handler.call(class_ast, class_name)
107
+ if NodeTypes.a_constant?(desc_node) # rubocop:disable Style/Next
108
+ @handlers[:on_described_class].each do |handler|
109
+ class_name_ast = NodeTypes.context_description_node(block_ast)
110
+ class_name = FullConstantName.from_ast(class_name_ast)
111
+ handler.call(class_name, PinFactory.build_location_range(class_name_ast))
112
+ end
97
113
  end
98
114
  end
99
115
 
100
- config.let_methods.each do |let_method|
101
- walker.on :send, [nil, let_method] do |ast|
102
- @handlers[:on_let_method].each do |handler|
103
- handler.call(ast)
104
- end
116
+ walker.on :ITER do |block_ast|
117
+ next unless NodeTypes.a_let_block?(block_ast, config)
118
+
119
+ method_name = NodeTypes.let_method_name(block_ast)
120
+ next unless method_name
121
+
122
+ fake_method_ast = FakeLetMethod.transform_block(block_ast, @source_map.source.code)
123
+
124
+ @handlers[:on_let_method].each do |handler|
125
+ handler.call(method_name, PinFactory.build_location_range(block_ast.children[0]), fake_method_ast)
105
126
  end
106
127
  end
107
128
 
108
- walker.on :block do |block_ast|
109
- next if block_ast.children.first.type != :send
129
+ walker.on :ITER do |block_ast|
130
+ next unless NodeTypes.a_subject_block?(block_ast)
110
131
 
111
- method_ast = block_ast.children.first
112
- method_name = method_ast.children[1]
113
- next unless Rspec::SUBJECT_METHODS.include?(method_name.to_s)
132
+ method_name = NodeTypes.let_method_name(block_ast)
133
+ fake_method_ast = FakeLetMethod.transform_block(block_ast, @source_map.source.code, method_name || 'subject')
114
134
 
115
135
  @handlers[:on_subject].each do |handler|
116
- handler.call(method_ast)
136
+ handler.call(method_name, PinFactory.build_location_range(block_ast.children[0]), fake_method_ast)
117
137
  end
118
138
  end
119
139
 
120
- walker.on :block do |block_ast|
121
- next if block_ast.children.first.type != :send
122
-
123
- method_ast = block_ast.children.first
124
- method_name = method_ast.children[1]
125
- next unless Rspec::EXAMPLE_METHODS.include?(method_name.to_s)
140
+ walker.on :ITER do |block_ast|
141
+ next unless NodeTypes.a_example_block?(block_ast)
126
142
 
127
143
  @handlers[:on_example_block].each do |handler|
128
- handler.call(block_ast)
144
+ handler.call(PinFactory.build_location_range(block_ast))
129
145
  end
130
146
 
131
- # @param blocks_in_examples [Parser::AST::Node]
132
- each_block(block_ast.children[2]) do |blocks_in_examples|
147
+ # @param blocks_in_examples [RubyVM::AbstractSyntaxTree::Node]
148
+ each_block(block_ast.children[1]) do |blocks_in_examples|
133
149
  @handlers[:on_blocks_in_examples].each do |handler|
134
- handler.call(blocks_in_examples)
150
+ handler.call(PinFactory.build_location_range(blocks_in_examples))
135
151
  end
136
152
  end
137
153
  end
138
154
 
139
- walker.on :block do |block_ast|
140
- next if block_ast.children.first.type != :send
141
-
142
- method_ast = block_ast.children.first
143
- method_name = method_ast.children[1]
144
- next unless Rspec::HOOK_METHODS.include?(method_name.to_s)
155
+ walker.on :ITER do |block_ast|
156
+ next unless NodeTypes.a_hook_block?(block_ast)
145
157
 
146
158
  @handlers[:on_hook_block].each do |handler|
147
- handler.call(block_ast)
159
+ handler.call(PinFactory.build_location_range(block_ast))
148
160
  end
149
161
 
150
- # @param blocks_in_examples [Parser::AST::Node]
151
- each_block(block_ast.children[2]) do |blocks_in_examples|
162
+ # @param blocks_in_examples [RubyVM::AbstractSyntaxTree::Node]
163
+ each_block(block_ast.children[1]) do |blocks_in_examples|
152
164
  @handlers[:on_blocks_in_examples].each do |handler|
153
- handler.call(blocks_in_examples)
165
+ handler.call(PinFactory.build_location_range(blocks_in_examples))
154
166
  end
155
167
  end
156
168
  end
@@ -165,9 +177,9 @@ module Solargraph
165
177
  # @param ast [Parser::AST::Node]
166
178
  # @param parent_result [Object]
167
179
  def each_block(ast, parent_result = nil, &block)
168
- return unless ast.is_a?(::Parser::AST::Node)
180
+ return unless ast.is_a?(RubyVM::AbstractSyntaxTree::Node)
169
181
 
170
- is_a_block = ast.type == :block && ast.children[0].type == :send
182
+ is_a_block = NodeTypes.a_block?(ast)
171
183
 
172
184
  if is_a_block
173
185
  result = block&.call(ast, parent_result)
@@ -182,72 +194,22 @@ module Solargraph
182
194
  # @yield [String, Parser::AST::Node]
183
195
  def each_context_block(ast, root_namespace = Rspec::ROOT_NAMESPACE, &block)
184
196
  each_block(ast, root_namespace) do |block_ast, parent_namespace|
185
- is_a_context = %i[describe context].include?(block_ast.children[0].children[1])
197
+ is_a_context = NodeTypes.a_context_block?(block_ast)
186
198
 
187
199
  next unless is_a_context
188
200
 
189
- description_node = block_ast.children[0].children[2]
190
- block_name = rspec_describe_class_name(description_node)
201
+ block_name = RspecContextNamespace.from_block_ast(block_ast)
191
202
  next unless block_name
192
203
 
204
+ # @HACK: When we describe `SomeClass` without a namespace, Solargraph confuses described_class with the
205
+ # `RSpec::ExampleGroups::SomeClass` constant. To avoid this, we append the root namespace with "Test"
206
+ block_name = "Test#{block_name}" if parent_namespace == Rspec::ROOT_NAMESPACE
207
+
193
208
  parent_namespace = namespace_name = "#{parent_namespace}::#{block_name}"
194
209
  block&.call(namespace_name, block_ast)
195
210
  next parent_namespace
196
211
  end
197
212
  end
198
-
199
- # @param ast [Parser::AST::Node]
200
- # @return [String, nil]
201
- def rspec_describe_class_name(ast)
202
- if ast.type == :str
203
- string_to_const_name(ast)
204
- elsif ast.type == :const
205
- full_constant_name(ast).gsub('::', '')
206
- else
207
- Solargraph.logger.warn "[RSpec] Unexpected AST type #{ast.type}"
208
- nil
209
- end
210
- end
211
-
212
- # @param ast [Parser::AST::Node]
213
- # @return [String]
214
- def full_constant_name(ast)
215
- raise 'Node is not a constant' unless ast.type == :const
216
-
217
- name = ast.children[1].to_s
218
- if ast.children[0].nil?
219
- name
220
- else
221
- "#{full_constant_name(ast.children[0])}::#{name}"
222
- end
223
- end
224
-
225
- # @see https://github.com/rspec/rspec-core/blob/1eeadce5aa7137ead054783c31ff35cbfe9d07cc/lib/rspec/core/example_group.rb#L862
226
- # @param ast [Parser::AST::Node]
227
- # @return [String]
228
- def string_to_const_name(string_ast)
229
- return unless string_ast.type == :str
230
-
231
- name = string_ast.children[0]
232
- return 'Anonymous'.dup if name.empty?
233
-
234
- # Convert to CamelCase.
235
- name = +" #{name}"
236
- name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do
237
- match = ::Regexp.last_match[1]
238
- match.upcase!
239
- match
240
- end
241
-
242
- name.lstrip! # Remove leading whitespace
243
- name.gsub!(/\W/, '') # JRuby, RBX and others don't like non-ascii in const names
244
-
245
- # Ruby requires first const letter to be A-Z. Use `Nested`
246
- # as necessary to enforce that.
247
- name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1')
248
-
249
- name
250
- end
251
213
  end
252
214
  end
253
215
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Solargraph
4
4
  module Rspec
5
- VERSION = '0.1.1'
5
+ VERSION = '0.2.1'
6
6
  end
7
7
  end