Skip to content

Commit e189737

Browse files
committed
Add 'rescue' keyword
1 parent f84f4a6 commit e189737

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

lib/ruby_lsp/listeners/hover.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class Hover
3333
Prism::InstanceVariableWriteNode,
3434
Prism::ModuleNode,
3535
Prism::NextNode,
36+
Prism::RescueNode,
3637
Prism::SymbolNode,
3738
Prism::StringNode,
3839
Prism::InterpolatedStringNode,
@@ -90,6 +91,7 @@ def initialize(response_builder, global_state, uri, node_context, dispatcher, so
9091
:on_instance_variable_target_node_enter,
9192
:on_module_node_enter,
9293
:on_next_node_enter,
94+
:on_rescue_node_enter,
9395
:on_super_node_enter,
9496
:on_forwarding_super_node_enter,
9597
:on_string_node_enter,
@@ -167,6 +169,11 @@ def on_next_node_enter(node)
167169
handle_keyword_documentation(node.keyword)
168170
end
169171

172+
#: (Prism::RescueNode node) -> void
173+
def on_rescue_node_enter(node)
174+
handle_keyword_documentation(node.keyword)
175+
end
176+
170177
#: (Prism::InterpolatedStringNode node) -> void
171178
def on_interpolated_string_node_enter(node)
172179
generate_heredoc_hover(node)

lib/ruby_lsp/static_docs.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module RubyLsp
2424
"for" => "Iterates over a collection of elements",
2525
"module" => "Defines a module",
2626
"next" => "Skips the rest of the current iteration and moves to the next iteration of a loop or block",
27+
"rescue" => "Handles exceptions that occur in the code block",
2728
"yield" => "Invokes the passed block with the given arguments",
2829
}.freeze #: Hash[String, String]
2930
end

static_docs/rescue.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Rescue
2+
3+
In Ruby, `rescue` is used to handle exceptions that occur during program execution. It allows you to catch and handle errors gracefully, preventing your program from crashing.
4+
5+
```ruby
6+
# Basic rescue usage
7+
begin
8+
# Code that might raise an exception
9+
result = 10 / 0
10+
rescue
11+
puts "An error occurred!"
12+
end
13+
```
14+
15+
You can specify which type of exception to rescue, and capture the exception object for inspection:
16+
17+
```ruby
18+
begin
19+
# Attempting to divide by zero raises a ZeroDivisionError
20+
result = 10 / 0
21+
rescue ZeroDivisionError => e
22+
puts "Cannot divide by zero: #{e.message}"
23+
end
24+
```
25+
26+
Multiple rescue clauses can be used to handle different types of exceptions:
27+
28+
```ruby
29+
begin
30+
# Code that might raise different types of exceptions
31+
JSON.parse(invalid_json)
32+
rescue JSON::ParserError => e
33+
puts "Invalid JSON format: #{e.message}"
34+
rescue StandardError => e
35+
puts "Some other error occurred: #{e.message}"
36+
end
37+
```
38+
39+
## Inline rescue
40+
41+
Ruby also supports inline rescue clauses for simple error handling:
42+
43+
```ruby
44+
# If the division fails, return nil instead
45+
result = 10 / params[:divisor].to_i rescue nil
46+
47+
# This is equivalent to:
48+
result = begin
49+
10 / params[:divisor].to_i
50+
rescue
51+
nil
52+
end
53+
```
54+
55+
## Ensure and else clauses
56+
57+
The `rescue` keyword can be used with `ensure` and `else` clauses:
58+
59+
```ruby
60+
begin
61+
# Attempt some operation
62+
file = File.open("example.txt")
63+
content = file.read
64+
rescue Errno::ENOENT => e
65+
puts "Could not find the file: #{e.message}"
66+
else
67+
# This block only executes if no exception was raised
68+
puts "Successfully read #{content.length} bytes"
69+
ensure
70+
# This block always executes, whether an exception occurred or not
71+
file&.close
72+
end
73+
```
74+
75+
## Method-level rescue
76+
77+
You can also use `rescue` at the method level without an explicit `begin` block:
78+
79+
```ruby
80+
def process_file(path)
81+
File.read(path)
82+
rescue Errno::ENOENT
83+
puts "File not found"
84+
rescue Errno::EACCES
85+
puts "Permission denied"
86+
end
87+
```
88+
89+
When rescuing exceptions, it's important to:
90+
- Only rescue specific exceptions you can handle
91+
- Avoid rescuing `Exception` as it captures all exceptions, including system ones
92+
- Use `ensure` for cleanup code that must always run
93+
- Keep the rescue block focused on error handling logic

test/requests/hover_expectations_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,16 @@ module MyModule
994994
RUBY
995995
position: { line: 1, character: 2 },
996996
},
997+
"rescue" => {
998+
source: <<~RUBY,
999+
begin
1000+
true
1001+
rescue
1002+
false
1003+
end
1004+
RUBY
1005+
position: { line: 2, character: 2 },
1006+
},
9971007
}
9981008

9991009
test_cases.each do |keyword, config|

0 commit comments

Comments
 (0)