mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
6b64447f0e
The document is written by Google Jules.
90 lines
3.3 KiB
Markdown
90 lines
3.3 KiB
Markdown
# mruby-enumerator
|
|
|
|
The `mruby-enumerator` mrbgem provides the `Enumerator` class, which allows for both internal and external iteration in mruby.
|
|
|
|
## Purpose and Functionality
|
|
|
|
Enumerators are useful when you want to work with collections of data in a flexible way. They allow you to:
|
|
|
|
- **Iterate externally:** Fetch elements one by one using methods like `next`.
|
|
- **Chain operations:** Combine multiple iteration steps (e.g., mapping and then selecting) without creating intermediate arrays.
|
|
- **Create custom iterators:** Define your own iteration logic.
|
|
|
|
## Creating an Enumerator
|
|
|
|
You can create an `Enumerator` in several ways:
|
|
|
|
1. **Using `Kernel#to_enum` or `Kernel#enum_for`:** This is the most common way. You can turn any object that has an `each` method (or a similar iteration method) into an Enumerator.
|
|
|
|
```ruby
|
|
e = [1, 2, 3].to_enum # Creates an enumerator for the array
|
|
e = "hello".enum_for(:each_byte) # Creates an enumerator for iterating over bytes
|
|
```
|
|
|
|
2. **Using `Enumerator.new`:** You can create an Enumerator by providing a block that defines how values are yielded.
|
|
|
|
```ruby
|
|
fib = Enumerator.new do |yielder|
|
|
a = b = 1
|
|
loop do
|
|
yielder << a
|
|
a, b = b, a + b
|
|
end
|
|
end
|
|
|
|
fib.take(5) # => [1, 1, 2, 3, 5]
|
|
```
|
|
|
|
## Key Methods
|
|
|
|
The `Enumerator` class includes many helpful methods from the `Enumerable` module, as well as some of its own:
|
|
|
|
- **`next`**: Returns the next value from the enumerator. Raises `StopIteration` if the enumerator is at the end.
|
|
- **`peek`**: Returns the next value without advancing the iterator.
|
|
- **`rewind`**: Resets the enumerator to its beginning.
|
|
- **`with_index(offset = 0)`**: Iterates over elements, providing both the element and its index (with an optional offset). Returns a new Enumerator if no block is given.
|
|
|
|
```ruby
|
|
["a", "b"].each.with_index(1) do |char, index|
|
|
puts "#{index}: #{char}"
|
|
end
|
|
# Output:
|
|
# 1: a
|
|
# 2: b
|
|
```
|
|
|
|
- **`each_with_index`**: Similar to `with_index(0)`.
|
|
- **`with_object(obj)`**: Iterates over elements, passing an arbitrary object along with each element. Returns the given object. Returns a new Enumerator if no block is given.
|
|
|
|
```ruby
|
|
(1..3).each.with_object([]) do |i, arr|
|
|
arr << i * 2
|
|
end # => [2, 4, 6]
|
|
```
|
|
|
|
- **`each(*args)`**: Iterates over the enumerator. If arguments are provided, they are passed to the underlying iteration method.
|
|
- **`feed(value)`**: Sets a value to be returned by the `yield` inside the enumerator on its next call.
|
|
|
|
## Chaining Enumerators
|
|
|
|
One of the powerful features of Enumerators is the ability to chain operations:
|
|
|
|
```ruby
|
|
data = [1, 2, 3, 4, 5]
|
|
|
|
result = data.to_enum
|
|
.with_index # [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]
|
|
.select { |num, idx| num.even? } # [[2, 1], [4, 3]]
|
|
.map { |num, idx| "#{idx}:#{num}" } # ["1:2", "3:4"]
|
|
|
|
p result # => ["1:2", "3:4"]
|
|
```
|
|
|
|
This avoids creating intermediate arrays for each step, making the code more efficient and readable for complex data transformations.
|
|
|
|
## Integration
|
|
|
|
This mrbgem integrates the `Enumerator` class into mruby, making it available for use in your mruby projects. It also extends `Kernel` with `to_enum` and `enum_for`, and `Enumerable` with methods like `zip`, `chunk`, and `chunk_while` that leverage `Enumerator`.
|
|
|
|
Refer to the source code and tests for more detailed examples and advanced usage.
|