ruby-lsp 0.26.9 → 0.27.0.beta2
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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +2 -2
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +8 -8
- data/lib/ruby_indexer/ruby_indexer.rb +0 -1
- data/lib/ruby_lsp/addon.rb +19 -19
- data/lib/ruby_lsp/global_state.rb +11 -2
- data/lib/ruby_lsp/internal.rb +6 -1
- data/lib/ruby_lsp/listeners/definition.rb +65 -99
- data/lib/ruby_lsp/listeners/document_link.rb +4 -0
- data/lib/ruby_lsp/listeners/hover.rb +258 -123
- data/lib/ruby_lsp/listeners/spec_style.rb +6 -1
- data/lib/ruby_lsp/listeners/test_discovery.rb +21 -14
- data/lib/ruby_lsp/listeners/test_style.rb +20 -8
- data/lib/ruby_lsp/node_context.rb +32 -9
- data/lib/ruby_lsp/requests/completion_resolve.rb +9 -13
- data/lib/ruby_lsp/requests/discover_tests.rb +5 -41
- data/lib/ruby_lsp/requests/hover.rb +2 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +4 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +66 -22
- data/lib/ruby_lsp/requests/references.rb +170 -70
- data/lib/ruby_lsp/requests/rename.rb +64 -72
- data/lib/ruby_lsp/requests/request.rb +3 -33
- data/lib/ruby_lsp/requests/support/common.rb +53 -0
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +82 -46
- data/lib/ruby_lsp/requests/workspace_symbol.rb +15 -37
- data/lib/ruby_lsp/rubydex/declaration.rb +48 -0
- data/lib/ruby_lsp/rubydex/definition.rb +257 -0
- data/lib/ruby_lsp/rubydex/reference.rb +21 -0
- data/lib/ruby_lsp/server.rb +82 -8
- data/lib/ruby_lsp/store.rb +0 -6
- data/lib/ruby_lsp/test_helper.rb +3 -0
- data/lib/ruby_lsp/type_inferrer.rb +111 -31
- metadata +18 -5
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +0 -335
- data/lib/ruby_lsp/static_docs.rb +0 -20
- data/static_docs/break.md +0 -103
- data/static_docs/yield.md +0 -81
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-lsp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.27.0.beta2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
@@ -63,6 +63,20 @@ dependencies:
|
|
|
63
63
|
- - "<"
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
65
|
version: '5'
|
|
66
|
+
- !ruby/object:Gem::Dependency
|
|
67
|
+
name: rubydex
|
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - "~>"
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: 0.1.0.beta1
|
|
73
|
+
type: :runtime
|
|
74
|
+
prerelease: false
|
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
76
|
+
requirements:
|
|
77
|
+
- - "~>"
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: 0.1.0.beta1
|
|
66
80
|
description: An opinionated language server for Ruby
|
|
67
81
|
email:
|
|
68
82
|
- ruby@shopify.com
|
|
@@ -92,7 +106,6 @@ files:
|
|
|
92
106
|
- lib/ruby_indexer/lib/ruby_indexer/location.rb
|
|
93
107
|
- lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
|
|
94
108
|
- lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb
|
|
95
|
-
- lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb
|
|
96
109
|
- lib/ruby_indexer/lib/ruby_indexer/uri.rb
|
|
97
110
|
- lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb
|
|
98
111
|
- lib/ruby_indexer/ruby_indexer.rb
|
|
@@ -168,12 +181,14 @@ files:
|
|
|
168
181
|
- lib/ruby_lsp/response_builders/signature_help.rb
|
|
169
182
|
- lib/ruby_lsp/response_builders/test_collection.rb
|
|
170
183
|
- lib/ruby_lsp/ruby_document.rb
|
|
184
|
+
- lib/ruby_lsp/rubydex/declaration.rb
|
|
185
|
+
- lib/ruby_lsp/rubydex/definition.rb
|
|
186
|
+
- lib/ruby_lsp/rubydex/reference.rb
|
|
171
187
|
- lib/ruby_lsp/scope.rb
|
|
172
188
|
- lib/ruby_lsp/scripts/compose_bundle.rb
|
|
173
189
|
- lib/ruby_lsp/scripts/compose_bundle_windows.rb
|
|
174
190
|
- lib/ruby_lsp/server.rb
|
|
175
191
|
- lib/ruby_lsp/setup_bundler.rb
|
|
176
|
-
- lib/ruby_lsp/static_docs.rb
|
|
177
192
|
- lib/ruby_lsp/store.rb
|
|
178
193
|
- lib/ruby_lsp/test_helper.rb
|
|
179
194
|
- lib/ruby_lsp/test_reporters/lsp_reporter.rb
|
|
@@ -181,8 +196,6 @@ files:
|
|
|
181
196
|
- lib/ruby_lsp/test_reporters/test_unit_reporter.rb
|
|
182
197
|
- lib/ruby_lsp/type_inferrer.rb
|
|
183
198
|
- lib/ruby_lsp/utils.rb
|
|
184
|
-
- static_docs/break.md
|
|
185
|
-
- static_docs/yield.md
|
|
186
199
|
homepage: https://github.com/Shopify/ruby-lsp
|
|
187
200
|
licenses:
|
|
188
201
|
- MIT
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
# typed: strict
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module RubyIndexer
|
|
5
|
-
class ReferenceFinder
|
|
6
|
-
# @abstract
|
|
7
|
-
class Target; end
|
|
8
|
-
|
|
9
|
-
class ConstTarget < Target
|
|
10
|
-
#: String
|
|
11
|
-
attr_reader :fully_qualified_name
|
|
12
|
-
|
|
13
|
-
#: (String fully_qualified_name) -> void
|
|
14
|
-
def initialize(fully_qualified_name)
|
|
15
|
-
super()
|
|
16
|
-
@fully_qualified_name = fully_qualified_name
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
class MethodTarget < Target
|
|
21
|
-
#: String
|
|
22
|
-
attr_reader :method_name
|
|
23
|
-
|
|
24
|
-
#: (String method_name) -> void
|
|
25
|
-
def initialize(method_name)
|
|
26
|
-
super()
|
|
27
|
-
@method_name = method_name
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
class InstanceVariableTarget < Target
|
|
32
|
-
#: String
|
|
33
|
-
attr_reader :name
|
|
34
|
-
|
|
35
|
-
#: Array[String]
|
|
36
|
-
attr_reader :owner_ancestors
|
|
37
|
-
|
|
38
|
-
#: (String name, Array[String] owner_ancestors) -> void
|
|
39
|
-
def initialize(name, owner_ancestors)
|
|
40
|
-
super()
|
|
41
|
-
@name = name
|
|
42
|
-
@owner_ancestors = owner_ancestors
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
class Reference
|
|
47
|
-
#: String
|
|
48
|
-
attr_reader :name
|
|
49
|
-
|
|
50
|
-
#: Prism::Location
|
|
51
|
-
attr_reader :location
|
|
52
|
-
|
|
53
|
-
#: bool
|
|
54
|
-
attr_reader :declaration
|
|
55
|
-
|
|
56
|
-
#: (String name, Prism::Location location, declaration: bool) -> void
|
|
57
|
-
def initialize(name, location, declaration:)
|
|
58
|
-
@name = name
|
|
59
|
-
@location = location
|
|
60
|
-
@declaration = declaration
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
#: (Target target, RubyIndexer::Index index, Prism::Dispatcher dispatcher, URI::Generic uri, ?include_declarations: bool) -> void
|
|
65
|
-
def initialize(target, index, dispatcher, uri, include_declarations: true)
|
|
66
|
-
@target = target
|
|
67
|
-
@index = index
|
|
68
|
-
@uri = uri
|
|
69
|
-
@include_declarations = include_declarations
|
|
70
|
-
@stack = [] #: Array[String]
|
|
71
|
-
@references = [] #: Array[Reference]
|
|
72
|
-
|
|
73
|
-
dispatcher.register(
|
|
74
|
-
self,
|
|
75
|
-
:on_class_node_enter,
|
|
76
|
-
:on_class_node_leave,
|
|
77
|
-
:on_module_node_enter,
|
|
78
|
-
:on_module_node_leave,
|
|
79
|
-
:on_singleton_class_node_enter,
|
|
80
|
-
:on_singleton_class_node_leave,
|
|
81
|
-
:on_def_node_enter,
|
|
82
|
-
:on_def_node_leave,
|
|
83
|
-
:on_multi_write_node_enter,
|
|
84
|
-
:on_constant_path_write_node_enter,
|
|
85
|
-
:on_constant_path_or_write_node_enter,
|
|
86
|
-
:on_constant_path_operator_write_node_enter,
|
|
87
|
-
:on_constant_path_and_write_node_enter,
|
|
88
|
-
:on_constant_or_write_node_enter,
|
|
89
|
-
:on_constant_path_node_enter,
|
|
90
|
-
:on_constant_read_node_enter,
|
|
91
|
-
:on_constant_write_node_enter,
|
|
92
|
-
:on_constant_or_write_node_enter,
|
|
93
|
-
:on_constant_and_write_node_enter,
|
|
94
|
-
:on_constant_operator_write_node_enter,
|
|
95
|
-
:on_instance_variable_read_node_enter,
|
|
96
|
-
:on_instance_variable_write_node_enter,
|
|
97
|
-
:on_instance_variable_and_write_node_enter,
|
|
98
|
-
:on_instance_variable_operator_write_node_enter,
|
|
99
|
-
:on_instance_variable_or_write_node_enter,
|
|
100
|
-
:on_instance_variable_target_node_enter,
|
|
101
|
-
:on_call_node_enter,
|
|
102
|
-
)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
#: -> Array[Reference]
|
|
106
|
-
def references
|
|
107
|
-
return @references if @include_declarations
|
|
108
|
-
|
|
109
|
-
@references.reject(&:declaration)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
#: (Prism::ClassNode node) -> void
|
|
113
|
-
def on_class_node_enter(node)
|
|
114
|
-
@stack << node.constant_path.slice
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
#: (Prism::ClassNode node) -> void
|
|
118
|
-
def on_class_node_leave(node)
|
|
119
|
-
@stack.pop
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
#: (Prism::ModuleNode node) -> void
|
|
123
|
-
def on_module_node_enter(node)
|
|
124
|
-
@stack << node.constant_path.slice
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
#: (Prism::ModuleNode node) -> void
|
|
128
|
-
def on_module_node_leave(node)
|
|
129
|
-
@stack.pop
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
#: (Prism::SingletonClassNode node) -> void
|
|
133
|
-
def on_singleton_class_node_enter(node)
|
|
134
|
-
expression = node.expression
|
|
135
|
-
return unless expression.is_a?(Prism::SelfNode)
|
|
136
|
-
|
|
137
|
-
@stack << "<Class:#{@stack.last}>"
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
#: (Prism::SingletonClassNode node) -> void
|
|
141
|
-
def on_singleton_class_node_leave(node)
|
|
142
|
-
@stack.pop
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
#: (Prism::ConstantPathNode node) -> void
|
|
146
|
-
def on_constant_path_node_enter(node)
|
|
147
|
-
name = Index.constant_name(node)
|
|
148
|
-
return unless name
|
|
149
|
-
|
|
150
|
-
collect_constant_references(name, node.location)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
#: (Prism::ConstantReadNode node) -> void
|
|
154
|
-
def on_constant_read_node_enter(node)
|
|
155
|
-
name = Index.constant_name(node)
|
|
156
|
-
return unless name
|
|
157
|
-
|
|
158
|
-
collect_constant_references(name, node.location)
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
#: (Prism::MultiWriteNode node) -> void
|
|
162
|
-
def on_multi_write_node_enter(node)
|
|
163
|
-
[*node.lefts, *node.rest, *node.rights].each do |target|
|
|
164
|
-
case target
|
|
165
|
-
when Prism::ConstantTargetNode, Prism::ConstantPathTargetNode
|
|
166
|
-
collect_constant_references(target.name.to_s, target.location)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
#: (Prism::ConstantPathWriteNode node) -> void
|
|
172
|
-
def on_constant_path_write_node_enter(node)
|
|
173
|
-
target = node.target
|
|
174
|
-
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
|
175
|
-
|
|
176
|
-
name = Index.constant_name(target)
|
|
177
|
-
return unless name
|
|
178
|
-
|
|
179
|
-
collect_constant_references(name, target.location)
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
#: (Prism::ConstantPathOrWriteNode node) -> void
|
|
183
|
-
def on_constant_path_or_write_node_enter(node)
|
|
184
|
-
target = node.target
|
|
185
|
-
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
|
186
|
-
|
|
187
|
-
name = Index.constant_name(target)
|
|
188
|
-
return unless name
|
|
189
|
-
|
|
190
|
-
collect_constant_references(name, target.location)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
#: (Prism::ConstantPathOperatorWriteNode node) -> void
|
|
194
|
-
def on_constant_path_operator_write_node_enter(node)
|
|
195
|
-
target = node.target
|
|
196
|
-
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
|
197
|
-
|
|
198
|
-
name = Index.constant_name(target)
|
|
199
|
-
return unless name
|
|
200
|
-
|
|
201
|
-
collect_constant_references(name, target.location)
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
#: (Prism::ConstantPathAndWriteNode node) -> void
|
|
205
|
-
def on_constant_path_and_write_node_enter(node)
|
|
206
|
-
target = node.target
|
|
207
|
-
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
|
208
|
-
|
|
209
|
-
name = Index.constant_name(target)
|
|
210
|
-
return unless name
|
|
211
|
-
|
|
212
|
-
collect_constant_references(name, target.location)
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
#: (Prism::ConstantWriteNode node) -> void
|
|
216
|
-
def on_constant_write_node_enter(node)
|
|
217
|
-
collect_constant_references(node.name.to_s, node.name_loc)
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
#: (Prism::ConstantOrWriteNode node) -> void
|
|
221
|
-
def on_constant_or_write_node_enter(node)
|
|
222
|
-
collect_constant_references(node.name.to_s, node.name_loc)
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
#: (Prism::ConstantAndWriteNode node) -> void
|
|
226
|
-
def on_constant_and_write_node_enter(node)
|
|
227
|
-
collect_constant_references(node.name.to_s, node.name_loc)
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
#: (Prism::ConstantOperatorWriteNode node) -> void
|
|
231
|
-
def on_constant_operator_write_node_enter(node)
|
|
232
|
-
collect_constant_references(node.name.to_s, node.name_loc)
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
#: (Prism::DefNode node) -> void
|
|
236
|
-
def on_def_node_enter(node)
|
|
237
|
-
if @target.is_a?(MethodTarget) && (name = node.name.to_s) == @target.method_name
|
|
238
|
-
@references << Reference.new(name, node.name_loc, declaration: true)
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
if node.receiver.is_a?(Prism::SelfNode)
|
|
242
|
-
@stack << "<Class:#{@stack.last}>"
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
#: (Prism::DefNode node) -> void
|
|
247
|
-
def on_def_node_leave(node)
|
|
248
|
-
if node.receiver.is_a?(Prism::SelfNode)
|
|
249
|
-
@stack.pop
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
#: (Prism::InstanceVariableReadNode node) -> void
|
|
254
|
-
def on_instance_variable_read_node_enter(node)
|
|
255
|
-
collect_instance_variable_references(node.name.to_s, node.location, false)
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
#: (Prism::InstanceVariableWriteNode node) -> void
|
|
259
|
-
def on_instance_variable_write_node_enter(node)
|
|
260
|
-
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
#: (Prism::InstanceVariableAndWriteNode node) -> void
|
|
264
|
-
def on_instance_variable_and_write_node_enter(node)
|
|
265
|
-
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
#: (Prism::InstanceVariableOperatorWriteNode node) -> void
|
|
269
|
-
def on_instance_variable_operator_write_node_enter(node)
|
|
270
|
-
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
#: (Prism::InstanceVariableOrWriteNode node) -> void
|
|
274
|
-
def on_instance_variable_or_write_node_enter(node)
|
|
275
|
-
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
#: (Prism::InstanceVariableTargetNode node) -> void
|
|
279
|
-
def on_instance_variable_target_node_enter(node)
|
|
280
|
-
collect_instance_variable_references(node.name.to_s, node.location, true)
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
#: (Prism::CallNode node) -> void
|
|
284
|
-
def on_call_node_enter(node)
|
|
285
|
-
if @target.is_a?(MethodTarget) && (name = node.name.to_s) == @target.method_name
|
|
286
|
-
@references << Reference.new(
|
|
287
|
-
name,
|
|
288
|
-
node.message_loc, #: as !nil
|
|
289
|
-
declaration: false,
|
|
290
|
-
)
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
private
|
|
295
|
-
|
|
296
|
-
#: (String name, Prism::Location location) -> void
|
|
297
|
-
def collect_constant_references(name, location)
|
|
298
|
-
return unless @target.is_a?(ConstTarget)
|
|
299
|
-
|
|
300
|
-
entries = @index.resolve(name, @stack)
|
|
301
|
-
return unless entries
|
|
302
|
-
|
|
303
|
-
# Filter down to all constant declarations that match the expected name and type
|
|
304
|
-
matching_entries = entries.select do |e|
|
|
305
|
-
[
|
|
306
|
-
Entry::Namespace,
|
|
307
|
-
Entry::Constant,
|
|
308
|
-
Entry::ConstantAlias,
|
|
309
|
-
Entry::UnresolvedConstantAlias,
|
|
310
|
-
].any? { |klass| e.is_a?(klass) } &&
|
|
311
|
-
e.name == @target.fully_qualified_name
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
return if matching_entries.empty?
|
|
315
|
-
|
|
316
|
-
# If any of the matching entries have the same location as the constant and were
|
|
317
|
-
# defined in the same file, then it is that constant's declaration
|
|
318
|
-
declaration = matching_entries.any? do |e|
|
|
319
|
-
e.uri == @uri && e.name_location == location
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
@references << Reference.new(name, location, declaration: declaration)
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
#: (String name, Prism::Location location, bool declaration) -> void
|
|
326
|
-
def collect_instance_variable_references(name, location, declaration)
|
|
327
|
-
return unless @target.is_a?(InstanceVariableTarget) && name == @target.name
|
|
328
|
-
|
|
329
|
-
receiver_type = Index.actual_nesting(@stack, nil).join("::")
|
|
330
|
-
if @target.owner_ancestors.include?(receiver_type)
|
|
331
|
-
@references << Reference.new(name, location, declaration: declaration)
|
|
332
|
-
end
|
|
333
|
-
end
|
|
334
|
-
end
|
|
335
|
-
end
|
data/lib/ruby_lsp/static_docs.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# typed: strict
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module RubyLsp
|
|
5
|
-
# The path to the `static_docs` directory, where we keep long-form static documentation
|
|
6
|
-
STATIC_DOCS_PATH = File.join(
|
|
7
|
-
File.dirname(
|
|
8
|
-
File.dirname(
|
|
9
|
-
__dir__, #: as !nil
|
|
10
|
-
),
|
|
11
|
-
),
|
|
12
|
-
"static_docs",
|
|
13
|
-
) #: String
|
|
14
|
-
|
|
15
|
-
# A map of keyword => short documentation to be displayed on hover or completion
|
|
16
|
-
KEYWORD_DOCS = {
|
|
17
|
-
"break" => "Terminates the execution of a block or loop",
|
|
18
|
-
"yield" => "Invokes the passed block with the given arguments",
|
|
19
|
-
}.freeze #: Hash[String, String]
|
|
20
|
-
end
|
data/static_docs/break.md
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# Break
|
|
2
|
-
|
|
3
|
-
In Ruby, the `break` keyword is used to exit a loop or block prematurely. Unlike `next` which skips to the next iteration, `break` terminates the loop entirely and continues with the code after the loop.
|
|
4
|
-
|
|
5
|
-
```ruby
|
|
6
|
-
# Basic break usage in a loop
|
|
7
|
-
5.times do |i|
|
|
8
|
-
break if i == 3
|
|
9
|
-
|
|
10
|
-
puts i
|
|
11
|
-
end
|
|
12
|
-
# Output:
|
|
13
|
-
# 0
|
|
14
|
-
# 1
|
|
15
|
-
# 2
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
The `break` statement can be used with any of Ruby's iteration methods or loops.
|
|
19
|
-
|
|
20
|
-
```ruby
|
|
21
|
-
array = [1, 2, 3, 4, 5]
|
|
22
|
-
|
|
23
|
-
# Break in each iteration
|
|
24
|
-
array.each do |num|
|
|
25
|
-
break if num > 3
|
|
26
|
-
|
|
27
|
-
puts "Number: #{num}"
|
|
28
|
-
end
|
|
29
|
-
# Output:
|
|
30
|
-
# Number: 1
|
|
31
|
-
# Number: 2
|
|
32
|
-
# Number: 3
|
|
33
|
-
|
|
34
|
-
# Break in an infinite loop
|
|
35
|
-
count = 0
|
|
36
|
-
loop do
|
|
37
|
-
count += 1
|
|
38
|
-
break if count >= 3
|
|
39
|
-
|
|
40
|
-
puts "Count: #{count}"
|
|
41
|
-
end
|
|
42
|
-
# Output:
|
|
43
|
-
# Count: 1
|
|
44
|
-
# Count: 2
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Break with a Value
|
|
48
|
-
|
|
49
|
-
When used inside a block, `break` can return a value that becomes the result of the method call.
|
|
50
|
-
|
|
51
|
-
```ruby
|
|
52
|
-
# Break with a return value in map
|
|
53
|
-
result = [1, 2, 3, 4, 5].map do |num|
|
|
54
|
-
break "Too large!" if num > 3
|
|
55
|
-
|
|
56
|
-
num * 2
|
|
57
|
-
end
|
|
58
|
-
puts result # Output: "Too large!"
|
|
59
|
-
|
|
60
|
-
# Break with a value in find
|
|
61
|
-
number = (1..10).find do |n|
|
|
62
|
-
break n if n > 5 && n.even?
|
|
63
|
-
end
|
|
64
|
-
puts number # Output: 6
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Break in Nested Loops
|
|
68
|
-
|
|
69
|
-
When using `break` in nested loops, it only exits the innermost loop. To break from nested loops, you typically need to use a flag or return.
|
|
70
|
-
|
|
71
|
-
```ruby
|
|
72
|
-
# Break in nested iteration
|
|
73
|
-
(1..3).each do |i|
|
|
74
|
-
puts "Outer: #{i}"
|
|
75
|
-
|
|
76
|
-
(1..3).each do |j|
|
|
77
|
-
break if j == 2
|
|
78
|
-
|
|
79
|
-
puts " Inner: #{j}"
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
# Output:
|
|
83
|
-
# Outer: 1
|
|
84
|
-
# Inner: 1
|
|
85
|
-
# Outer: 2
|
|
86
|
-
# Inner: 1
|
|
87
|
-
# Outer: 3
|
|
88
|
-
# Inner: 1
|
|
89
|
-
|
|
90
|
-
# Breaking from nested loops with a flag
|
|
91
|
-
found = false
|
|
92
|
-
(1..3).each do |i|
|
|
93
|
-
(1..3).each do |j|
|
|
94
|
-
if i * j == 4
|
|
95
|
-
found = true
|
|
96
|
-
break
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
break if found
|
|
100
|
-
end
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
The `break` keyword is essential for controlling loop execution and implementing early exit conditions. It's particularly useful when you've found what you're looking for and don't need to continue iterating.
|
data/static_docs/yield.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# Yield
|
|
2
|
-
|
|
3
|
-
In Ruby, every method implicitly accepts a block, even when not included in the parameters list.
|
|
4
|
-
|
|
5
|
-
```ruby
|
|
6
|
-
def foo
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
foo { 123 } # works!
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
The `yield` keyword is used to invoke the block that was passed with arguments.
|
|
13
|
-
|
|
14
|
-
```ruby
|
|
15
|
-
# Consider this method call. The block being passed to the method `foo` accepts an argument called `a`.
|
|
16
|
-
# It then takes whatever argument was passed and multiplies it by 2
|
|
17
|
-
foo do |a|
|
|
18
|
-
a * 2
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# In the `foo` method declaration, we can use `yield` to invoke the block that was passed and provide the block
|
|
22
|
-
# with the value for the `a` argument
|
|
23
|
-
def foo
|
|
24
|
-
# Invoke the block passed to `foo` with the number 10 as the argument `a`
|
|
25
|
-
result = yield(10)
|
|
26
|
-
puts result # Will print 20
|
|
27
|
-
end
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
If `yield` is used to invoke the block, but no block was passed, that will result in a local jump error.
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
# If we invoke `foo` without a block, trying to `yield` will fail
|
|
34
|
-
foo
|
|
35
|
-
|
|
36
|
-
# `foo': no block given (yield) (LocalJumpError)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
We can decide to use `yield` conditionally by using Ruby's `block_given?` method, which will return `true` if a block
|
|
40
|
-
was passed to the method.
|
|
41
|
-
|
|
42
|
-
```ruby
|
|
43
|
-
def foo
|
|
44
|
-
# If a block is passed when invoking `foo`, call the block with argument 10 and print the result.
|
|
45
|
-
# Otherwise, just print that no block was passed
|
|
46
|
-
if block_given?
|
|
47
|
-
result = yield(10)
|
|
48
|
-
puts result
|
|
49
|
-
else
|
|
50
|
-
puts "No block passed!"
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
foo do |a|
|
|
55
|
-
a * 2
|
|
56
|
-
end
|
|
57
|
-
# => 20
|
|
58
|
-
|
|
59
|
-
foo
|
|
60
|
-
# => No block passed!
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Block parameter
|
|
64
|
-
|
|
65
|
-
In addition to implicit blocks, Ruby also allows developers to use explicit block parameters as part of the method's
|
|
66
|
-
signature. In this scenario, we can use the reference to the block directly instead of relying on the `yield` keyword.
|
|
67
|
-
|
|
68
|
-
```ruby
|
|
69
|
-
# Block parameters are prefixed with & and a name
|
|
70
|
-
def foo(&my_block_param)
|
|
71
|
-
# If a block was passed to `foo`, `my_block_param` will be a `Proc` object. Otherwise, it will be `nil`. We can use
|
|
72
|
-
# that to check for its presence
|
|
73
|
-
if my_block_param
|
|
74
|
-
# Explicit block parameters are invoked using the method `call`, which is present in all `Proc` objects
|
|
75
|
-
result = my_block_param.call(10)
|
|
76
|
-
puts result
|
|
77
|
-
else
|
|
78
|
-
puts "No block passed!"
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
```
|