Skip to content

Commit 7324157

Browse files
committed
Add 'for' keyword
1 parent ae11a22 commit 7324157

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

lib/ruby_lsp/listeners/hover.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Hover
1818
Prism::DefinedNode,
1919
Prism::ElseNode,
2020
Prism::EnsureNode,
21+
Prism::ForNode,
2122
Prism::GlobalVariableAndWriteNode,
2223
Prism::GlobalVariableOperatorWriteNode,
2324
Prism::GlobalVariableOrWriteNode,
@@ -72,6 +73,7 @@ def initialize(response_builder, global_state, uri, node_context, dispatcher, so
7273
:on_defined_node_enter,
7374
:on_else_node_enter,
7475
:on_ensure_node_enter,
76+
:on_for_node_enter,
7577
:on_global_variable_and_write_node_enter,
7678
:on_global_variable_operator_write_node_enter,
7779
:on_global_variable_or_write_node_enter,
@@ -146,6 +148,11 @@ def on_ensure_node_enter(node)
146148
handle_keyword_documentation(node.ensure_keyword)
147149
end
148150

151+
#: (Prism::ForNode node) -> void
152+
def on_for_node_enter(node)
153+
handle_keyword_documentation(node.for_keyword)
154+
end
155+
149156
#: (Prism::InterpolatedStringNode node) -> void
150157
def on_interpolated_string_node_enter(node)
151158
generate_heredoc_hover(node)

lib/ruby_lsp/static_docs.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module RubyLsp
2121
"defined" => "Checks if a constant, variable or method is defined",
2222
"else" => "Executes the code in the else block if the condition is false",
2323
"ensure" => "Executes the code in the ensure block regardless of whether an exception is raised or not",
24+
"for" => "Iterates over a collection of elements",
2425
"yield" => "Invokes the passed block with the given arguments",
2526
}.freeze #: Hash[String, String]
2627
end

static_docs/for.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# For
2+
3+
In Ruby, the `for` keyword creates a loop that iterates over a collection. While functional, Rubyists typically prefer using iterators like `each` for better readability and block scoping.
4+
5+
```ruby
6+
# Basic for loop with a range
7+
for i in 1..3
8+
puts i
9+
end
10+
# Output:
11+
# 1
12+
# 2
13+
# 3
14+
```
15+
16+
The `for` loop can iterate over any object that responds to `each`, including arrays and hashes.
17+
18+
```ruby
19+
# Iterating over an array
20+
fruits = ["apple", "banana", "orange"]
21+
22+
for fruit in fruits
23+
puts "I like #{fruit}"
24+
end
25+
# Output:
26+
# I like apple
27+
# I like banana
28+
# I like orange
29+
30+
# Iterating over a hash
31+
scores = { alice: 95, bob: 87 }
32+
33+
for name, score in scores
34+
puts "#{name} scored #{score}"
35+
end
36+
# Output:
37+
# alice scored 95
38+
# bob scored 87
39+
```
40+
41+
## Variable Scope
42+
43+
Unlike block-based iterators, variables defined in a `for` loop remain accessible after the loop ends.
44+
45+
```ruby
46+
# Variable remains in scope
47+
for value in [1, 2, 3]
48+
doubled = value * 2
49+
end
50+
51+
puts doubled # Output: 6 (last value)
52+
53+
# Comparison with each (creates new scope)
54+
[1, 2, 3].each do |value|
55+
doubled = value * 2
56+
end
57+
58+
# puts doubled # Would raise NameError
59+
```
60+
61+
## Breaking and Next
62+
63+
The `for` loop supports control flow keywords like `break` and `next`.
64+
65+
```ruby
66+
# Using break to exit early
67+
for number in 1..5
68+
break if number > 3
69+
puts number
70+
end
71+
# Output:
72+
# 1
73+
# 2
74+
# 3
75+
76+
# Using next to skip iterations
77+
for number in 1..5
78+
next if number.even?
79+
puts number
80+
end
81+
# Output:
82+
# 1
83+
# 3
84+
# 5
85+
```
86+
87+
While Ruby provides the `for` loop for compatibility and familiarity, the preferred Ruby way is to use iterators with blocks:
88+
89+
```ruby
90+
# Preferred Ruby style using each
91+
(1..3).each { |i| puts i }
92+
93+
# For more complex iterations
94+
(1..3).each do |i|
95+
puts i
96+
end
97+
```

test/requests/hover_expectations_test.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,13 @@ def my_method
972972
RUBY
973973
position: { line: 2, character: 2 },
974974
},
975+
"for" => {
976+
source: <<~RUBY,
977+
for i in 1..10
978+
end
979+
RUBY
980+
position: { line: 0, character: 2 },
981+
},
975982
}
976983

977984
test_cases.each do |keyword, config|

0 commit comments

Comments
 (0)