ruby-lsp-ree 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 350bb1ae1a376f2a8594e3945c396c49d01907b1c840d36311e28761c2fe9d8e
4
- data.tar.gz: dfa9bc947cf5f951d62e2686290a7ac603c5dfa34652cb21be4b1547d2e3b5e1
3
+ metadata.gz: 8eb134e8d6b0ac3bf5321789ed6617ea1347ee096b1e642f953885b398524030
4
+ data.tar.gz: 460f2cc171155affbafe236535604b116d0af15bbcf14c3925470a8ff3616211
5
5
  SHA512:
6
- metadata.gz: eaaa38d222082eb2a55f73a977114a2632d2db2a2b7d10a0d96d2284b87fbd2c02bcab43e45ec617afa63e5c9fd4f9e64339f7cb919ba23365a5deae1aa3df4e
7
- data.tar.gz: 64e7ce28fdb802eadbe27c6f7fd5d5e156c9c3d39627c9a7e191bf808fc9519eb26befa49182cc62bda12941c8e6fd4f478060ec61e33d38035aa10726c087d1
6
+ metadata.gz: cf49632399253b97f3b3df77ae7767008141900552461de8bca6b7395ac0d48fa4dbc5a353d2245f50147d7d119059b3f4d5a3f55aa41ae4fd11521d58b7930d
7
+ data.tar.gz: 0f392c77bbe2bdee9e9f613bc856c1d93b9bb9a2c87a93078017388fb253b27325d244ba289b36c24ff7e71e9f72b4f9c11abb663a7a2f675b5a9661aae29554
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
data/CHANGELOG.md CHANGED
@@ -1,8 +1,20 @@
1
- ## [Unreleased]
1
+ ## [0.1.3] - 2025-02-21
2
2
 
3
- ## [0.1.0] - 2025-01-31
3
+ - improved Go To Definition for ree object methods and imported constants
4
+ - support for :mapper objects
5
+ - support for :aggregate objects
6
+ - improved autocompletion for imported constants
7
+ - basic hover information for ree objects
4
8
 
5
- - Initial release
9
+ ## [0.1.2] - 2025-02-14
10
+
11
+ - support for :bean objects
12
+ - Go To Definition for imported constants
13
+ - use current (not saved) version of the document in autocomplete
14
+ - use current (not saved) version of the document in definition
15
+ - increase autocomplete list limits (affects short functions)
16
+ - improved const autocomplete
17
+ - improved ree errors handling
6
18
 
7
19
  ## [0.1.1] - 2025-02-10
8
20
 
@@ -19,4 +31,10 @@
19
31
  - Add Link for ree actions
20
32
  - sort links in ree actions
21
33
  - autocomplete for ree dao
22
- - autocomplete for dao filters
34
+ - autocomplete for dao filters
35
+
36
+ ## [0.1.0] - 2025-01-31
37
+
38
+ - Initial release
39
+
40
+ ## [Unreleased]
data/Gemfile CHANGED
@@ -6,3 +6,9 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
+
10
+ group :test do
11
+ gem 'rspec'
12
+ gem 'ruby-lsp'
13
+ gem "sorbet-static-and-runtime"
14
+ end
data/Gemfile.lock CHANGED
@@ -1,19 +1,55 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp-ree (0.1.1)
4
+ ruby-lsp-ree (0.1.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ diff-lcs (1.6.0)
10
+ language_server-protocol (3.17.0.4)
11
+ logger (1.6.6)
12
+ prism (1.3.0)
9
13
  rake (13.2.1)
14
+ rbs (3.8.1)
15
+ logger
16
+ rspec (3.13.0)
17
+ rspec-core (~> 3.13.0)
18
+ rspec-expectations (~> 3.13.0)
19
+ rspec-mocks (~> 3.13.0)
20
+ rspec-core (3.13.3)
21
+ rspec-support (~> 3.13.0)
22
+ rspec-expectations (3.13.3)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.13.0)
25
+ rspec-mocks (3.13.2)
26
+ diff-lcs (>= 1.2.0, < 2.0)
27
+ rspec-support (~> 3.13.0)
28
+ rspec-support (3.13.2)
29
+ ruby-lsp (0.23.11)
30
+ language_server-protocol (~> 3.17.0)
31
+ prism (>= 1.2, < 2.0)
32
+ rbs (>= 3, < 4)
33
+ sorbet-runtime (>= 0.5.10782)
34
+ sorbet (0.5.11835)
35
+ sorbet-static (= 0.5.11835)
36
+ sorbet-runtime (0.5.11835)
37
+ sorbet-static (0.5.11835-universal-darwin)
38
+ sorbet-static (0.5.11835-x86_64-linux)
39
+ sorbet-static-and-runtime (0.5.11835)
40
+ sorbet (= 0.5.11835)
41
+ sorbet-runtime (= 0.5.11835)
10
42
 
11
43
  PLATFORMS
44
+ x86_64-darwin-23
12
45
  x86_64-linux
13
46
 
14
47
  DEPENDENCIES
15
48
  rake (~> 13.0)
49
+ rspec
50
+ ruby-lsp
16
51
  ruby-lsp-ree!
52
+ sorbet-static-and-runtime
17
53
 
18
54
  BUNDLED WITH
19
- 2.4.20
55
+ 2.6.3
data/Rakefile CHANGED
@@ -1,4 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: %i[]
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: %i[spec]
@@ -1,8 +1,9 @@
1
1
  require "ruby_lsp/addon"
2
- require_relative "definition"
3
- require_relative "completion"
2
+ require_relative "listeners/definition_listener"
3
+ require_relative "listeners/completion_listener"
4
+ require_relative "listeners/hover_listener"
4
5
  require_relative "ree_indexing_enhancement"
5
- require_relative "ree_lsp_utils"
6
+ require_relative "utils/ree_lsp_utils"
6
7
  require_relative "ree_formatter"
7
8
  require_relative "parsing/parsed_document_builder"
8
9
 
@@ -25,14 +26,17 @@ module RubyLsp
25
26
 
26
27
  def create_definition_listener(response_builder, uri, node_context, dispatcher)
27
28
  index = @global_state.index
28
- RubyLsp::Ree::Definition.new(response_builder, node_context, index, dispatcher, uri)
29
+ RubyLsp::Ree::DefinitionListener.new(response_builder, node_context, index, dispatcher, uri)
29
30
  end
30
31
 
31
32
  def create_completion_listener(response_builder, node_context, dispatcher, uri)
32
- $stderr.puts("create_completion_listener")
33
-
34
33
  index = @global_state.index
35
- RubyLsp::Ree::Completion.new(response_builder, node_context, index, dispatcher, uri)
34
+ RubyLsp::Ree::CompletionListener.new(response_builder, node_context, index, dispatcher, uri)
35
+ end
36
+
37
+ def create_hover_listener(response_builder, node_context, dispatcher)
38
+ index = @global_state.index
39
+ RubyLsp::Ree::HoverListener.new(response_builder, node_context, index, dispatcher)
36
40
  end
37
41
  end
38
42
  end
@@ -1,11 +1,77 @@
1
- require_relative "ree_lsp_utils"
1
+ require_relative "../utils/ree_lsp_utils"
2
+ require_relative "../ree_object_finder"
2
3
 
3
4
  module RubyLsp
4
5
  module Ree
5
- module CompletionUtils
6
+ class CompletionHandler
6
7
  include Requests::Support::Common
7
8
  include RubyLsp::Ree::ReeLspUtils
8
9
 
10
+ RECEIVER_OBJECT_TYPES = [:enum, :dao, :bean]
11
+ CANDIDATES_LIMIT = 100
12
+
13
+ def initialize(index, uri, node_context)
14
+ @index = index
15
+ @uri = uri
16
+ @node_context = node_context
17
+ @finder = ReeObjectFinder.new(@index)
18
+ end
19
+
20
+ def get_ree_receiver(receiver_node)
21
+ return if !receiver_node || !receiver_node.is_a?(Prism::CallNode)
22
+
23
+ @finder.find_objects_by_types(receiver_node.name.to_s, RECEIVER_OBJECT_TYPES).first
24
+ end
25
+
26
+ def get_ree_object_methods_completions_items(ree_receiver, receiver_node, node)
27
+ location = receiver_node.location
28
+
29
+ case @finder.object_type(ree_receiver)
30
+ when :enum
31
+ get_enum_values_completion_items(ree_receiver, location)
32
+ when :bean
33
+ get_bean_methods_completion_items(ree_receiver, location)
34
+ when :dao
35
+ get_dao_filters_completion_items(ree_receiver, location)
36
+ else
37
+ []
38
+ end
39
+ end
40
+
41
+ def get_bean_methods_completion_items(bean_obj, location)
42
+ bean_node = RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(bean_obj.uri, :bean)
43
+
44
+ range = Interface::Range.new(
45
+ start: Interface::Position.new(line: location.start_line - 1, character: location.end_column + 1),
46
+ end: Interface::Position.new(line: location.start_line - 1, character: location.end_column + 1),
47
+ )
48
+
49
+ bean_node.bean_methods.map do |bean_method|
50
+ signature = bean_method.signatures.first
51
+
52
+ label_details = Interface::CompletionItemLabelDetails.new(
53
+ description: "method",
54
+ detail: get_detail_string(signature)
55
+ )
56
+
57
+ Interface::CompletionItem.new(
58
+ label: bean_method.name,
59
+ label_details: label_details,
60
+ filter_text: bean_method.name,
61
+ text_edit: Interface::TextEdit.new(
62
+ range: range,
63
+ new_text: get_method_string(bean_method.name, signature)
64
+ ),
65
+ kind: Constant::CompletionItemKind::METHOD,
66
+ insert_text_format: Constant::InsertTextFormat::SNIPPET,
67
+ data: {
68
+ owner_name: "Object",
69
+ guessed_type: false,
70
+ }
71
+ )
72
+ end
73
+ end
74
+
9
75
  def get_dao_filters_completion_items(dao_obj, location)
10
76
  dao_node = RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(dao_obj.uri, :dao)
11
77
 
@@ -73,33 +139,75 @@ module RubyLsp
73
139
  end
74
140
  end
75
141
 
76
- def get_class_name_completion_items(class_name_objects, parsed_doc, node, index, limit)
77
- class_name_objects.take(limit).map do |full_class_name|
78
- entry = index[full_class_name].first
79
- class_name = full_class_name.split('::').last
142
+ def get_class_name_completion_items(node)
143
+ node_name = node.name.to_s
144
+ class_name_objects = @finder.search_class_objects(node_name)
145
+
146
+ return [] if class_name_objects.size == 0
147
+
148
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
149
+
150
+ imported_consts = []
151
+ not_imported_consts = []
152
+
153
+ class_name_objects.take(CANDIDATES_LIMIT).each do |full_class_name|
154
+ entries = @index[full_class_name]
155
+
156
+ entries.each do |entry|
157
+ class_name = full_class_name.split('::').last
158
+ package_name = package_name_from_uri(entry.uri)
159
+ file_name = File.basename(entry.uri.to_s)
160
+
161
+ matched_import = parsed_doc.find_import_for_package(class_name, package_name)
162
+
163
+ if matched_import
164
+ label_details = Interface::CompletionItemLabelDetails.new(
165
+ description: "imported from: :#{package_name}",
166
+ detail: ""
167
+ )
168
+
169
+ imported_consts << Interface::CompletionItem.new(
170
+ label: class_name,
171
+ label_details: label_details,
172
+ filter_text: class_name,
173
+ text_edit: Interface::TextEdit.new(
174
+ range: range_from_location(node.location),
175
+ new_text: class_name,
176
+ ),
177
+ kind: Constant::CompletionItemKind::CLASS,
178
+ additional_text_edits: []
179
+ )
180
+ else
181
+ label_details = Interface::CompletionItemLabelDetails.new(
182
+ description: "from: :#{package_name}",
183
+ detail: " #{file_name}"
184
+ )
185
+
186
+ not_imported_consts << Interface::CompletionItem.new(
187
+ label: class_name,
188
+ label_details: label_details,
189
+ filter_text: class_name,
190
+ text_edit: Interface::TextEdit.new(
191
+ range: range_from_location(node.location),
192
+ new_text: class_name,
193
+ ),
194
+ kind: Constant::CompletionItemKind::CLASS,
195
+ additional_text_edits: get_additional_text_edits_for_constant(parsed_doc, class_name, package_name, entry)
196
+ )
197
+ end
198
+ end
199
+ end
80
200
 
81
- package_name = package_name_from_uri(entry.uri)
201
+ imported_consts + not_imported_consts
202
+ end
82
203
 
83
- label_details = Interface::CompletionItemLabelDetails.new(
84
- description: "from: :#{package_name}",
85
- detail: ""
86
- )
204
+ def get_ree_objects_completions_items(node)
205
+ ree_objects = @finder.search_objects(node.name.to_s, CANDIDATES_LIMIT)
87
206
 
88
- Interface::CompletionItem.new(
89
- label: class_name,
90
- label_details: label_details,
91
- filter_text: class_name,
92
- text_edit: Interface::TextEdit.new(
93
- range: range_from_location(node.location),
94
- new_text: class_name,
95
- ),
96
- kind: Constant::CompletionItemKind::CLASS,
97
- additional_text_edits: get_additional_text_edits_for_constant(parsed_doc, class_name, package_name, entry)
98
- )
99
- end
100
- end
207
+ return [] if ree_objects.size == 0
208
+
209
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
101
210
 
102
- def get_ree_objects_completions_items(ree_objects, parsed_doc, node)
103
211
  ree_objects.map do |ree_object|
104
212
  ree_object_name = ree_object.name
105
213
  package_name = package_name_from_uri(ree_object.uri)
@@ -163,7 +271,6 @@ module RubyLsp
163
271
 
164
272
  def get_additional_text_edits_for_constant(parsed_doc, class_name, package_name, entry)
165
273
  if parsed_doc.includes_linked_constant?(class_name)
166
- $stderr.puts("links already include #{class_name}")
167
274
  return []
168
275
  end
169
276
 
@@ -173,7 +280,7 @@ module RubyLsp
173
280
  fn_name = File.basename(entry_uri, ".*")
174
281
  "\s\slink :#{fn_name}, import: -> { #{class_name} }"
175
282
  else
176
- path = path_from_package(entry_uri)
283
+ path = path_from_package_folder(entry_uri)
177
284
  "\s\slink \"#{path}\", import: -> { #{class_name} }"
178
285
  end
179
286
 
@@ -200,7 +307,6 @@ module RubyLsp
200
307
 
201
308
  def get_additional_text_edits_for_method(parsed_doc, fn_name, package_name)
202
309
  if parsed_doc.includes_linked_object?(fn_name)
203
- $stderr.puts("links already include #{fn_name}")
204
310
  return []
205
311
  end
206
312
 
@@ -221,6 +327,7 @@ module RubyLsp
221
327
  end
222
328
 
223
329
  range = get_range_for_fn_insert(parsed_doc, link_text)
330
+ return unless range
224
331
 
225
332
  [
226
333
  Interface::TextEdit.new(
@@ -0,0 +1,49 @@
1
+ require_relative "../handlers/completion_handler"
2
+
3
+ module RubyLsp
4
+ module Ree
5
+ class CompletionListener
6
+ include Requests::Support::Common
7
+
8
+ CHARS_COUNT = 1
9
+
10
+ def initialize(response_builder, node_context, index, dispatcher, uri)
11
+ @response_builder = response_builder
12
+ @handler = RubyLsp::Ree::CompletionHandler.new(index, uri, node_context)
13
+
14
+ dispatcher.register(self, :on_call_node_enter)
15
+ dispatcher.register(self, :on_constant_read_node_enter)
16
+ end
17
+
18
+ def on_constant_read_node_enter(node)
19
+ node_name = node.name.to_s
20
+ return if node_name.size < CHARS_COUNT
21
+
22
+ completion_items = @handler.get_class_name_completion_items(node)
23
+ put_items_into_response(completion_items)
24
+ end
25
+
26
+ def on_call_node_enter(node)
27
+ completion_items = []
28
+ ree_receiver = @handler.get_ree_receiver(node.receiver)
29
+
30
+ if ree_receiver
31
+ completion_items = @handler.get_ree_object_methods_completions_items(ree_receiver, node.receiver, node)
32
+ else
33
+ return if node.receiver
34
+ return if node.name.to_s.size < CHARS_COUNT
35
+
36
+ completion_items = @handler.get_ree_objects_completions_items(node)
37
+ end
38
+
39
+ put_items_into_response(completion_items)
40
+ end
41
+
42
+ def put_items_into_response(items)
43
+ items.each do |item|
44
+ @response_builder << item
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,137 @@
1
+ require_relative "../utils/ree_lsp_utils"
2
+ require_relative "../parsing/parsed_link_node"
3
+ require_relative "../parsing/parsed_document_builder"
4
+ require_relative "../ree_object_finder"
5
+
6
+ module RubyLsp
7
+ module Ree
8
+ class DefinitionListener
9
+ include Requests::Support::Common
10
+ include RubyLsp::Ree::ReeLspUtils
11
+
12
+ def initialize(response_builder, node_context, index, dispatcher, uri)
13
+ @response_builder = response_builder
14
+ @node_context = node_context
15
+ @nesting = node_context.nesting
16
+ @index = index
17
+ @uri = uri
18
+
19
+ dispatcher.register(self, :on_call_node_enter, :on_symbol_node_enter, :on_string_node_enter, :on_constant_read_node_enter)
20
+ end
21
+
22
+ def on_constant_read_node_enter(node)
23
+ link_nodes = if @node_context.parent.is_a?(Prism::CallNode) && @node_context.parent.name == :link
24
+ # inside link node
25
+ link_node = RubyLsp::Ree::ParsedLinkNode.new(@node_context.parent)
26
+ link_node.parse_imports
27
+ [link_node]
28
+ else
29
+ parsed_doc = if @node_context.parent.is_a?(Prism::CallNode)
30
+ RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(@uri)
31
+ else
32
+ RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
33
+ end
34
+
35
+ parsed_doc.link_nodes
36
+ end
37
+
38
+ link_nodes.each do |link_node|
39
+ if link_node.imports.include?(node.name.to_s)
40
+ uri = ''
41
+ if link_node.file_path_type?
42
+ path = find_local_file_path(link_node.name)
43
+ next unless path
44
+
45
+ uri = File.join(Dir.pwd, path)
46
+ else
47
+ package_name = link_node.link_package_name || package_name_from_uri(@uri)
48
+
49
+ method_candidates = @index[link_node.name]
50
+ next if !method_candidates || method_candidates.size == 0
51
+
52
+ method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
53
+ next unless method
54
+
55
+ uri = method.uri.to_s
56
+ end
57
+
58
+ @response_builder << Interface::Location.new(
59
+ uri: uri,
60
+ range: Interface::Range.new(
61
+ start: Interface::Position.new(line: 0, character: 0),
62
+ end: Interface::Position.new(line: 0, character: 0),
63
+ ),
64
+ )
65
+ end
66
+ end
67
+ end
68
+
69
+ def on_call_node_enter(node)
70
+ message = node.message
71
+ return unless message
72
+
73
+ definition_uri = nil
74
+
75
+ if node.receiver
76
+ # ruby lsp handles such cases itself
77
+ return
78
+ else
79
+ definition_item = ReeObjectFinder.new(@index).find_object(message)
80
+ definition_uri = definition_item.uri.to_s
81
+ end
82
+
83
+ return unless definition_uri
84
+
85
+ @response_builder << Interface::Location.new(
86
+ uri: definition_uri,
87
+ range: Interface::Range.new(
88
+ start: Interface::Position.new(line: 0, character: 0),
89
+ end: Interface::Position.new(line: 0, character: 0),
90
+ ),
91
+ )
92
+
93
+ nil
94
+ end
95
+
96
+ def on_symbol_node_enter(node)
97
+ parent_node = @node_context.parent
98
+ return unless parent_node.name == :link
99
+
100
+ link_node = RubyLsp::Ree::ParsedLinkNode.new(parent_node, package_name_from_uri(@uri))
101
+ package_name = link_node.link_package_name
102
+
103
+ method_candidates = @index[node.unescaped]
104
+ return if !method_candidates || method_candidates.size == 0
105
+
106
+ method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
107
+ return unless method
108
+
109
+ @response_builder << Interface::Location.new(
110
+ uri: method.uri.to_s,
111
+ range: Interface::Range.new(
112
+ start: Interface::Position.new(line: 0, character: 0),
113
+ end: Interface::Position.new(line: 0, character: 0),
114
+ ),
115
+ )
116
+
117
+ nil
118
+ end
119
+
120
+ def on_string_node_enter(node)
121
+ local_path = find_local_file_path(node.unescaped)
122
+
123
+ if local_path
124
+ @response_builder << Interface::Location.new(
125
+ uri: File.join(Dir.pwd, local_path),
126
+ range: Interface::Range.new(
127
+ start: Interface::Position.new(line: 0, character: 0),
128
+ end: Interface::Position.new(line: 0, character: 0),
129
+ ),
130
+ )
131
+ end
132
+
133
+ nil
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,65 @@
1
+ require_relative "../ree_object_finder"
2
+ require_relative "../parsing/parsed_document_builder"
3
+ require_relative "../parsing/parsed_link_node"
4
+ require_relative "../utils/ree_lsp_utils"
5
+
6
+ module RubyLsp
7
+ module Ree
8
+ class HoverListener
9
+ include RubyLsp::Ree::ReeLspUtils
10
+
11
+ def initialize(response_builder, node_context, index, dispatcher)
12
+ @response_builder = response_builder
13
+ @node_context = node_context
14
+ @finder = ReeObjectFinder.new(index)
15
+
16
+ dispatcher.register(self, :on_call_node_enter)
17
+ dispatcher.register(self, :on_constant_read_node_enter)
18
+ end
19
+
20
+ def on_constant_read_node_enter(node)
21
+ # ree_object = @finder.search_classes(node.name.to_s).first
22
+
23
+ # $stderr.puts("ree_object #{ree_object.inspect}")
24
+
25
+ # return unless ree_object
26
+
27
+ # $stderr.puts("ree_object comm #{ree_object.comments.to_s}")
28
+
29
+ # @response_builder.push(ree_object.comments.to_s, category: :documentation)
30
+ end
31
+
32
+ def on_call_node_enter(node)
33
+ ree_object = @finder.find_object(node.name.to_s)
34
+
35
+ return unless ree_object
36
+
37
+ documentation = <<~DOC
38
+ Ree object, type: :#{@finder.object_type(ree_object)}
39
+
40
+ usage: #{node.name.to_s}#{get_detail_string(ree_object)}
41
+
42
+ package: #{package_name_from_uri(ree_object.uri)}
43
+
44
+ file: #{path_from_package_folder(ree_object.uri)}
45
+ DOC
46
+
47
+ $stderr.puts(documentation)
48
+
49
+ @response_builder.push(documentation, category: :documentation)
50
+ end
51
+
52
+ def get_detail_string(ree_object)
53
+ return '' if ree_object.signatures.size == 0
54
+
55
+ "(#{get_parameters_string(ree_object.signatures.first)})"
56
+ end
57
+
58
+ def get_parameters_string(signature)
59
+ return '' unless signature
60
+
61
+ signature.parameters.map(&:decorated_name).join(', ')
62
+ end
63
+ end
64
+ end
65
+ end