rucoa 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +12 -2
  5. data/README.md +37 -6
  6. data/data/definitions_ruby_3_1 +0 -0
  7. data/images/diagnostics.gif +0 -0
  8. data/images/document-formatting.gif +0 -0
  9. data/images/document-symbol.gif +0 -0
  10. data/images/selection-ranges.gif +0 -0
  11. data/lib/rucoa/configuration.rb +62 -28
  12. data/lib/rucoa/definition_archiver.rb +29 -0
  13. data/lib/rucoa/definition_builders/rbs_constant_definition_builder.rb +44 -0
  14. data/lib/rucoa/definition_builders/rbs_method_definition_builder.rb +106 -0
  15. data/lib/rucoa/definition_builders/yard_method_definition_builder.rb +218 -0
  16. data/lib/rucoa/definition_builders.rb +9 -0
  17. data/lib/rucoa/definition_store.rb +63 -0
  18. data/lib/rucoa/definitions/base.rb +12 -0
  19. data/lib/rucoa/definitions/constant_definition.rb +51 -0
  20. data/lib/rucoa/definitions/method_definition.rb +126 -0
  21. data/lib/rucoa/definitions/method_parameter_definition.rb +30 -0
  22. data/lib/rucoa/definitions.rb +9 -0
  23. data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +140 -0
  24. data/lib/rucoa/handlers/base.rb +8 -0
  25. data/lib/rucoa/handlers/exit_handler.rb +11 -0
  26. data/lib/rucoa/handlers/initialize_handler.rb +7 -0
  27. data/lib/rucoa/handlers/initialized_handler.rb +10 -0
  28. data/lib/rucoa/handlers/shutdown_handler.rb +12 -0
  29. data/lib/rucoa/handlers/text_document_code_action_handler.rb +78 -3
  30. data/lib/rucoa/handlers/text_document_did_change_handler.rb +1 -20
  31. data/lib/rucoa/handlers/text_document_did_open_handler.rb +11 -4
  32. data/lib/rucoa/handlers/text_document_document_symbol_handler.rb +242 -0
  33. data/lib/rucoa/handlers/text_document_formatting_handler.rb +36 -5
  34. data/lib/rucoa/handlers/text_document_range_formatting_handler.rb +65 -13
  35. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +124 -8
  36. data/lib/rucoa/handlers/text_document_signature_help_handler.rb +68 -0
  37. data/lib/rucoa/handlers.rb +4 -0
  38. data/lib/rucoa/node_concerns/name_full_qualifiable.rb +20 -0
  39. data/lib/rucoa/node_concerns.rb +7 -0
  40. data/lib/rucoa/node_inspector.rb +111 -0
  41. data/lib/rucoa/nodes/base.rb +43 -0
  42. data/lib/rucoa/nodes/casgn_node.rb +14 -0
  43. data/lib/rucoa/nodes/class_node.rb +8 -0
  44. data/lib/rucoa/nodes/const_node.rb +12 -0
  45. data/lib/rucoa/nodes/def_node.rb +71 -0
  46. data/lib/rucoa/nodes/defs_node.rb +12 -0
  47. data/lib/rucoa/nodes/lvar_node.rb +25 -0
  48. data/lib/rucoa/nodes/module_node.rb +21 -0
  49. data/lib/rucoa/nodes/sclass_node.rb +8 -0
  50. data/lib/rucoa/nodes/send_node.rb +60 -0
  51. data/lib/rucoa/nodes/str_node.rb +4 -0
  52. data/lib/rucoa/nodes/sym_node.rb +12 -0
  53. data/lib/rucoa/nodes.rb +10 -0
  54. data/lib/rucoa/parser_builder.rb +20 -10
  55. data/lib/rucoa/position.rb +2 -2
  56. data/lib/rucoa/range.rb +64 -14
  57. data/lib/rucoa/rbs_document_loader.rb +43 -0
  58. data/lib/rucoa/rubocop_autocorrector.rb +1 -1
  59. data/lib/rucoa/rubocop_investigator.rb +1 -1
  60. data/lib/rucoa/server.rb +20 -1
  61. data/lib/rucoa/source.rb +56 -6
  62. data/lib/rucoa/source_store.rb +6 -10
  63. data/lib/rucoa/types/method_type.rb +23 -0
  64. data/lib/rucoa/types.rb +7 -0
  65. data/lib/rucoa/version.rb +1 -1
  66. data/lib/rucoa/yard_glob_document_loader.rb +47 -0
  67. data/lib/rucoa/yard_string_document_loader.rb +70 -0
  68. data/lib/rucoa.rb +10 -5
  69. data/rucoa.gemspec +2 -0
  70. metadata +68 -7
  71. data/lib/rucoa/code_action_provider.rb +0 -102
  72. data/lib/rucoa/diagnostic_provider.rb +0 -143
  73. data/lib/rucoa/formatting_provider.rb +0 -54
  74. data/lib/rucoa/range_formatting_provider.rb +0 -67
  75. data/lib/rucoa/selection_range_provider.rb +0 -99
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Rucoa
6
+ class NodeInspector
7
+ # @param definition_store [Rucoa::DefinitionStore]
8
+ # @param node [Rucoa::Node]
9
+ def initialize(definition_store:, node:)
10
+ @definition_store = definition_store
11
+ @node = node
12
+ end
13
+
14
+ # @return [Array<String>]
15
+ def method_definitions
16
+ method_full_qualified_names.flat_map do |full_qualified_name|
17
+ @definition_store.select_by_full_qualified_name(full_qualified_name)
18
+ end
19
+ end
20
+
21
+ # @return [Array<String>]
22
+ def method_receiver_types
23
+ return [] unless @node.is_a?(Nodes::SendNode)
24
+
25
+ if @node.receiver
26
+ self.class.new(
27
+ definition_store: @definition_store,
28
+ node: @node.receiver
29
+ ).return_types
30
+ else
31
+ [@node.namespace]
32
+ end
33
+ end
34
+
35
+ # @return [Array<String>]
36
+ def return_types
37
+ case @node.type
38
+ when :const
39
+ [@node.name]
40
+ when :lvar
41
+ return_types_for_lvar
42
+ when :send
43
+ return_types_for_send
44
+ when :array
45
+ %w[Array]
46
+ when :class, :module, :nil
47
+ %w[NilClass]
48
+ when :complex
49
+ %w[Complex]
50
+ when :def, :sym
51
+ %w[Symbol]
52
+ when :dstr, :str, :xstr
53
+ %w[String]
54
+ when :erange, :irange
55
+ %w[Range]
56
+ when false
57
+ %w[FalseClass]
58
+ when :float
59
+ %w[Float]
60
+ when :hash, :pair
61
+ %w[Hash]
62
+ when :int
63
+ %w[Integer]
64
+ when :rational
65
+ %w[Rational]
66
+ when :regexp, :regopt
67
+ %w[Regexp]
68
+ when true
69
+ %w[TrueClass]
70
+ else
71
+ []
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ # @return [Array<String>]
78
+ def method_full_qualified_names
79
+ method_receiver_types.map do |type|
80
+ [
81
+ type,
82
+ @node.name
83
+ ].join('#')
84
+ end
85
+ end
86
+
87
+ # @return [String, nil]
88
+ def nearest_def_full_qualified_name
89
+ @node.each_ancestor(:def).first&.full_qualified_name
90
+ end
91
+
92
+ # @return [Array<String>]
93
+ def return_types_for_lvar
94
+ full_qualified_name = nearest_def_full_qualified_name
95
+ return [] unless full_qualified_name
96
+
97
+ @definition_store.select_by_full_qualified_name(full_qualified_name).flat_map do |definition|
98
+ definition.parameters.select do |parameter|
99
+ parameter.name == @node.name
100
+ end.flat_map(&:types)
101
+ end
102
+ end
103
+
104
+ # @return [Array<String>]
105
+ def return_types_for_send
106
+ method_full_qualified_names.flat_map do |full_qualified_name|
107
+ @definition_store.select_by_full_qualified_name(full_qualified_name).flat_map(&:return_types)
108
+ end.uniq
109
+ end
110
+ end
111
+ end
@@ -64,6 +64,19 @@ module Rucoa
64
64
  self
65
65
  end
66
66
 
67
+ # @note Override.
68
+ # Some nodes change their type depending on the context.
69
+ # For example, `const` node can be `casgn` node.
70
+ # @return [Rucoa::Nodes::Base]
71
+ def updated(type = nil, children = nil, properties = {})
72
+ properties[:location] ||= @location
73
+ ParserBuilder.node_class_for(type || @type).new(
74
+ type || @type,
75
+ children || @children,
76
+ properties
77
+ )
78
+ end
79
+
67
80
  # @param position [Rucoa::Position]
68
81
  # @return [Boolean]
69
82
  def include_position?(position)
@@ -72,6 +85,36 @@ module Rucoa
72
85
  Range.from_parser_range(location.expression).include?(position)
73
86
  end
74
87
 
88
+ # @note namespace is a String representation of `Module.nesting`.
89
+ # @return [String]
90
+ # @example returns namespace
91
+ # node = Rucoa::Source.new(
92
+ # content: <<~RUBY
93
+ # module Foo
94
+ # class Bar
95
+ # def baz
96
+ # end
97
+ # end
98
+ # end
99
+ # RUBY
100
+ # ).node_at(
101
+ # Rucoa::Position.new(
102
+ # column: 4,
103
+ # line: 3
104
+ # )
105
+ # )
106
+ # expect(node.namespace).to eq('Foo::Bar')
107
+ # @example returns "Object" when the node is not in a namespace
108
+ # node = Rucoa::Parser.call(
109
+ # <<~RUBY
110
+ # foo
111
+ # RUBY
112
+ # )
113
+ # expect(node.namespace).to eq('Object')
114
+ def namespace
115
+ each_ancestor(:module, :class).first&.full_qualified_name || 'Object'
116
+ end
117
+
75
118
  protected
76
119
 
77
120
  # Visit all descendants.
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class CasgnNode < Base
6
+ include NodeConcerns::NameFullQualifiable
7
+
8
+ # @return [String]
9
+ def name
10
+ children[1].to_s
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class ClassNode < ModuleNode
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class ConstNode < Base
6
+ # @return [String]
7
+ def name
8
+ children[1].to_s
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class DefNode < Base
6
+ # @return [String]
7
+ # @example returns method name
8
+ # node = Rucoa::Source.new(
9
+ # content: <<~RUBY
10
+ # module Foo
11
+ # class Bar
12
+ # def baz
13
+ # end
14
+ # end
15
+ # end
16
+ # RUBY
17
+ # ).node_at(
18
+ # Rucoa::Position.new(
19
+ # column: 4,
20
+ # line: 3
21
+ # )
22
+ # )
23
+ # expect(node.name).to eq('baz')
24
+ def name
25
+ children[0].to_s
26
+ end
27
+
28
+ # @return [String]
29
+ # @example returns full qualified name
30
+ # node = Rucoa::Source.new(
31
+ # content: <<~RUBY
32
+ # module Foo
33
+ # class Bar
34
+ # def baz
35
+ # end
36
+ # end
37
+ # end
38
+ # RUBY
39
+ # ).node_at(
40
+ # Rucoa::Position.new(
41
+ # column: 4,
42
+ # line: 3
43
+ # )
44
+ # )
45
+ # expect(node.full_qualified_name).to eq('Foo::Bar#baz')
46
+ def full_qualified_name
47
+ [
48
+ namespace,
49
+ method_marker,
50
+ name
51
+ ].join
52
+ end
53
+
54
+ private
55
+
56
+ # @return [String]
57
+ def method_marker
58
+ if singleton?
59
+ '.'
60
+ else
61
+ '#'
62
+ end
63
+ end
64
+
65
+ # @return [Boolean]
66
+ def singleton?
67
+ each_ancestor(:sclass).any?
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class DefsNode < Base
6
+ # @return [String]
7
+ def name
8
+ children[1].to_s
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class LvarNode < Base
6
+ # @return [String]
7
+ # @example returns local variable name
8
+ # node = Rucoa::Source.new(
9
+ # content: <<~RUBY
10
+ # foo = 1
11
+ # foo
12
+ # RUBY
13
+ # ).node_at(
14
+ # Rucoa::Position.new(
15
+ # column: 2,
16
+ # line: 2
17
+ # )
18
+ # )
19
+ # expect(node.name).to eq('foo')
20
+ def name
21
+ children[0].to_s
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class ModuleNode < Base
6
+ include NodeConcerns::NameFullQualifiable
7
+
8
+ # @return [String]
9
+ def name
10
+ const_node.name
11
+ end
12
+
13
+ private
14
+
15
+ # @return [Rucoa::Nodes::ConstNode]
16
+ def const_node
17
+ children[0]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class SclassNode < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class SendNode < Base
6
+ # @return [Array<Rucoa::Nodes::Base>]
7
+ # @example returns arguments
8
+ # node = Rucoa::Parser.call(
9
+ # <<~RUBY
10
+ # foo(bar, baz)
11
+ # RUBY
12
+ # )
13
+ # expect(node.arguments.map(&:name)).to eq(
14
+ # %w[
15
+ # bar
16
+ # baz
17
+ # ]
18
+ # )
19
+ def arguments
20
+ children[2..]
21
+ end
22
+
23
+ # @return [String]
24
+ # @example returns method name
25
+ # node = Rucoa::Parser.call(
26
+ # <<~RUBY
27
+ # foo(bar, baz)
28
+ # RUBY
29
+ # )
30
+ # expect(node.name).to eq('foo')
31
+ def name
32
+ children[1].to_s
33
+ end
34
+
35
+ # @return [Rucoa::Nodes::Base, nil]
36
+ # @example returns nil for receiver-less method call
37
+ # node = Rucoa::Parser.call(
38
+ # <<~RUBY
39
+ # foo(bar, baz)
40
+ # RUBY
41
+ # )
42
+ # expect(node.receiver).to be_nil
43
+ # @example returns receiver
44
+ # node = Rucoa::Source.new(
45
+ # content: <<~RUBY
46
+ # foo.bar
47
+ # RUBY
48
+ # ).node_at(
49
+ # Rucoa::Position.new(
50
+ # column: 4,
51
+ # line: 1
52
+ # )
53
+ # )
54
+ # expect(node.receiver).to be_a(Rucoa::Nodes::SendNode)
55
+ def receiver
56
+ children[0]
57
+ end
58
+ end
59
+ end
60
+ end
@@ -3,6 +3,10 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class StrNode < Base
6
+ # @return [String]
7
+ def value
8
+ children[0]
9
+ end
6
10
  end
7
11
  end
8
12
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class SymNode < Base
6
+ # @return [String]
7
+ def value
8
+ children[0]
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/rucoa/nodes.rb CHANGED
@@ -3,6 +3,16 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  autoload :Base, 'rucoa/nodes/base'
6
+ autoload :ClassNode, 'rucoa/nodes/class_node'
7
+ autoload :CasgnNode, 'rucoa/nodes/casgn_node'
8
+ autoload :ConstNode, 'rucoa/nodes/const_node'
9
+ autoload :DefNode, 'rucoa/nodes/def_node'
10
+ autoload :DefsNode, 'rucoa/nodes/defs_node'
11
+ autoload :LvarNode, 'rucoa/nodes/lvar_node'
12
+ autoload :ModuleNode, 'rucoa/nodes/module_node'
13
+ autoload :SclassNode, 'rucoa/nodes/sclass_node'
14
+ autoload :SendNode, 'rucoa/nodes/send_node'
6
15
  autoload :StrNode, 'rucoa/nodes/str_node'
16
+ autoload :SymNode, 'rucoa/nodes/sym_node'
7
17
  end
8
18
  end
@@ -5,24 +5,34 @@ require 'parser/current'
5
5
  module Rucoa
6
6
  class ParserBuilder < ::Parser::Builders::Default
7
7
  NODE_CLASS_BY_TYPE = {
8
- str: Nodes::StrNode
8
+ casgn: Nodes::CasgnNode,
9
+ class: Nodes::ClassNode,
10
+ const: Nodes::ConstNode,
11
+ def: Nodes::DefNode,
12
+ defs: Nodes::DefsNode,
13
+ lvar: Nodes::LvarNode,
14
+ module: Nodes::ModuleNode,
15
+ sclass: Nodes::SclassNode,
16
+ send: Nodes::SendNode,
17
+ str: Nodes::StrNode,
18
+ sym: Nodes::SymNode
9
19
  }.freeze
10
20
 
21
+ class << self
22
+ # @param type [Symbol]
23
+ # @return [Class]
24
+ def node_class_for(type)
25
+ NODE_CLASS_BY_TYPE.fetch(type, Nodes::Base)
26
+ end
27
+ end
28
+
11
29
  # @note Override.
12
30
  def n(type, children, source_map)
13
- node_class_for(type).new(
31
+ self.class.node_class_for(type).new(
14
32
  type,
15
33
  children,
16
34
  location: source_map
17
35
  )
18
36
  end
19
-
20
- private
21
-
22
- # @param type [Symbol]
23
- # @return [Class]
24
- def node_class_for(type)
25
- NODE_CLASS_BY_TYPE.fetch(type, Nodes::Base)
26
- end
27
37
  end
28
38
  end
@@ -47,8 +47,8 @@ module Rucoa
47
47
  # @return [Hash]
48
48
  def to_vscode_position
49
49
  {
50
- character: @column,
51
- line: @line - 1
50
+ 'character' => @column,
51
+ 'line' => @line - 1
52
52
  }
53
53
  end
54
54
  end
data/lib/rucoa/range.rb CHANGED
@@ -30,28 +30,85 @@ module Rucoa
30
30
 
31
31
  # @param beginning [Rucoa::Position]
32
32
  # @param ending [Ruoca::Position]
33
- # @param exclude_end [Boolean]
34
- def initialize(beginning, ending, exclude_end: true)
33
+ # @param including_ending [Boolean]
34
+ def initialize(beginning, ending, including_ending: true)
35
35
  @beginning = beginning
36
36
  @ending = ending
37
- @exclude_end = exclude_end
37
+ @including_ending = including_ending
38
38
  end
39
39
 
40
40
  # @param range [Rucoa::Range]
41
41
  # @return [Boolean]
42
- def contains?(range)
43
- copy = with_including_end
44
- copy.include?(range.beginning) && copy.include?(range.ending)
42
+ # @example returns true when the range is contained in self
43
+ # range = Rucoa::Range.new(
44
+ # Rucoa::Position.new(
45
+ # column: 0,
46
+ # line: 0
47
+ # ),
48
+ # Rucoa::Position.new(
49
+ # column: 0,
50
+ # line: 2
51
+ # )
52
+ # )
53
+ # expect(range).to contain(
54
+ # Rucoa::Range.new(
55
+ # Rucoa::Position.new(
56
+ # column: 0,
57
+ # line: 0
58
+ # ),
59
+ # Rucoa::Position.new(
60
+ # column: 0,
61
+ # line: 0
62
+ # )
63
+ # )
64
+ # )
65
+ def contain?(range)
66
+ include?(range.beginning) && include?(range.ending)
45
67
  end
46
68
 
47
69
  # @param position [Rucoa::Position]
48
70
  # @return [Boolean]
71
+ # @example returns true when the position is included in self
72
+ # range = Rucoa::Range.new(
73
+ # Rucoa::Position.new(
74
+ # column: 0,
75
+ # line: 0
76
+ # ),
77
+ # Rucoa::Position.new(
78
+ # column: 0,
79
+ # line: 2
80
+ # )
81
+ # )
82
+ # expect(range).to include(
83
+ # Rucoa::Position.new(
84
+ # column: 0,
85
+ # line: 0
86
+ # )
87
+ # )
88
+ # expect(range).to include(
89
+ # Rucoa::Position.new(
90
+ # column: 0,
91
+ # line: 1
92
+ # )
93
+ # )
94
+ # expect(range).to include(
95
+ # Rucoa::Position.new(
96
+ # column: 0,
97
+ # line: 2
98
+ # )
99
+ # )
100
+ # expect(range).not_to include(
101
+ # Rucoa::Position.new(
102
+ # column: 0,
103
+ # line: 3
104
+ # )
105
+ # )
49
106
  def include?(position)
50
107
  return false if position.line > @ending.line
51
108
  return false if position.line < @beginning.line
52
109
  return false if position.column < @beginning.column
53
110
  return false if position.column > @ending.column
54
- return false if position.column == @ending.column && @exclude_end
111
+ return false if position.column == @ending.column && !@including_ending
55
112
 
56
113
  true
57
114
  end
@@ -63,12 +120,5 @@ module Rucoa
63
120
  start: @beginning.to_vscode_position
64
121
  }
65
122
  end
66
-
67
- private
68
-
69
- # @return [Rucoa::Range]
70
- def with_including_end
71
- self.class.new(@beginning, @ending, exclude_end: false)
72
- end
73
123
  end
74
124
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+
5
+ module Rucoa
6
+ class RbsDocumentLoader
7
+ class << self
8
+ def call
9
+ new.call
10
+ end
11
+ end
12
+
13
+ # @return [Array<Rucoa::Definitions::Base>]
14
+ def call
15
+ declarations.flat_map do |declaration|
16
+ case declaration
17
+ when ::RBS::AST::Declarations::Constant
18
+ [
19
+ DefinitionBuilders::RbsConstantDefinitionBuilder.call(declaration: declaration)
20
+ ]
21
+ when ::RBS::AST::Declarations::Class, ::RBS::AST::Declarations::Module
22
+ declaration.members.grep(::RBS::AST::Members::MethodDefinition).map do |method_definition|
23
+ DefinitionBuilders::RbsMethodDefinitionBuilder.call(
24
+ declaration: declaration,
25
+ method_definition: method_definition
26
+ )
27
+ end
28
+ else
29
+ []
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # @return [Array<RBS::AST::Declarations::Base>]
37
+ def declarations
38
+ ::RBS::Environment.from_loader(
39
+ ::RBS::EnvironmentLoader.new
40
+ ).resolve_type_names.declarations
41
+ end
42
+ end
43
+ end
@@ -31,7 +31,7 @@ module Rucoa
31
31
  # @return [String]
32
32
  def call
33
33
  @options[:stdin] = @source.content
34
- run([@source.path])
34
+ run([@source.path || 'untitled'])
35
35
  @options[:stdin]
36
36
  end
37
37
  end
@@ -31,7 +31,7 @@ module Rucoa
31
31
  # @return [Array<RuboCop::Cop::Offense>]
32
32
  def call
33
33
  @options[:stdin] = @source.content
34
- run([@source.path])
34
+ run([@source.path || 'untitled'])
35
35
  @offenses
36
36
  end
37
37