Conversation
IO.foreach reads a file line by line without holding the whole thing as an array, and is the form most Ruby code reaches for. Neither it nor the class-level IO.readlines existed on Node.js, so both raised NoMethodError. Both delegate to File.open's block form, which closes the handle, and to the existing IO#each_line and IO#readlines, so the separator handling and the enumerator behaviour come from code that is already tested rather than from a second implementation. Matching MRI, foreach returns an Enumerator when called without a block, returns nil when given one, honours a custom separator, and keeps a last line that has no trailing separator. File.foreach inherits both, since MRI defines them on IO's singleton and File subclasses it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1845.
What changed
IO.foreachreads a file line by line without materialising the whole thing as an array, and is the form most Ruby code reaches for. It did not exist on Node.js, so it raisedNoMethodError: undefined method 'foreach' for IO. The class-levelIO.readlineswas missing for the same reason, so both are added here.Both delegate to
File.open's block form, which closes the handle, and to the existingIO#each_lineandIO#readlines. The separator handling and the enumerator behaviour come from code that is already tested rather than from a second implementation, which is why the diff is 16 lines.IO#each_linelanded in #2309, which is what made this a thin delegation rather than real work.Behaviour checked against MRI:
"a\n" "b\n" "c\n"nilwhen given a blocknilEnumeratorwithout a blockEnumeratorIO.foreach(f, 'b')"a\nb","\nc\n"["no-newline"]Errno::ENOENTIO.readlines["a\n", "b\n", "c\n"]File.foreachinherits both, since MRI defines them onIO's singleton andFilesubclasses it. Verified rather than assumed.How to test
Verification I ran locally:
bundle exec rake minitest_node_nodejs— 87 runs, 160 assertions, 0 failuresbundle exec rake mspec_nodejs— 14626 examples, 0 failuresbundle exec rubocop— 226 files, no offensesSeven tests added to
test/nodejs/test_io.rb, covering each row of the table above. Reverting juststdlib/nodejs/io.rband rerunning turns them red withNoMethodError: undefined method 'foreach' for IO, so they pin the feature rather than the implementation.Note for anyone rerunning these:
test/nodejs/is driven byminitest_node_nodejs. The similarly namedminitest_cruby_nodejsruns the CRuby suite instead and passes whether or not this change is present.🤖 Generated with Claude Code