Files
Yukihiro "Matz" Matsumoto 6b64447f0e mruby-enumerator: add README.md
The document is written by Google Jules.
2025-06-13 04:40:29 +09:00

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.