From 6b64447f0e17928e92950dd8cfe35ceae4b4091a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 13 Jun 2025 04:40:29 +0900 Subject: [PATCH] mruby-enumerator: add README.md The document is written by Google Jules. --- mrbgems/mruby-enumerator/README.md | 89 ++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 mrbgems/mruby-enumerator/README.md diff --git a/mrbgems/mruby-enumerator/README.md b/mrbgems/mruby-enumerator/README.md new file mode 100644 index 000000000..55164a9c6 --- /dev/null +++ b/mrbgems/mruby-enumerator/README.md @@ -0,0 +1,89 @@ +# 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.