From: rohitpaulk@... Date: 2017-10-23T13:13:20+00:00 Subject: [ruby-core:83529] [Ruby trunk Feature#14042] IO#puts: use writev if available Issue #14042 has been updated by rohitpaulk (Paul Kuruvilla). > Would it make sense to add a deprecation warning in this case? i.e. If the receiver doesn't accept multiple arguments, we emit a deprecation warning and make 2 calls instead of one. If the receiver accepts multiple arguments, we make a single call. Something along the lines of... ~~~diff rb_io_writev(VALUE io, int argc, VALUE *argv) { - return rb_funcallv(io, id_write, argc, argv); + if (rb_obj_method_arity(io, id_write) == -1) { + rb_funcallv(io, id_write, argc, argv); + } + else { + /** + * Previously, IO#write only accepted one argument. This was changed + * to use multiple arguments in revision #60343. + * + * To play well with programs that might've mocked an IO object and are + * only expecting a single argument - let's make multiple calls with + * a single argument each. + */ + rb_warn("IO#write has been changed to accept multiple arguments. \ +You are seeing this warning because an object expected to implement the IO \ +interface has a #write method that doesn't accept multiple arguments. Please \ +change the implementation to accept multiple arguments."); + for (int i = 0; i < argc; i++) { + rb_io_write(io, argv[i]); + } + } } ~~~ ~~~diff + def test_puts_works_with_io_objects_that_only_accept_single_arg + klass = Class.new do + attr_reader :captured + + def write(str) + (@captured ||= "") << str + end + end + + mocked_io_obj = klass.new + old_stdout, $stdout = $stdout, mocked_io_obj + puts "hey" # Should write to the mocked class + assert_equal("hey\n", mocked_io_obj.captured) + ensure + $stdout = old_stdout + end + ~~~ ---------------------------------------- Feature #14042: IO#puts: use writev if available https://bugs.ruby-lang.org/issues/14042#change-67555 * Author: rohitpaulk (Paul Kuruvilla) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- Hi, I've attached a patch to make IO#puts use writev if available. Currently, IO#puts calls `write` twice: Once to write the string, and the second to write a newline (if the string doesn't end with one already). With this patch, those two calls are replaced with a single `writev` call. A test has been added that demonstrates the problem. For a bit of background: * A related issue: https://bugs.ruby-lang.org/issues/9420. (I couldn't figure out a way to 'attach' my patch to that issue, so I'm creating a new one) * A blog post I wrote a while back about this: https://hackernoon.com/rubys-puts-is-not-atomic-889c57fc9a28 Command I used to run the test I added: `make test-all TESTS='ruby/test_io.rb -n test_puts_parallel'` I'm a first time contributor, a bit confused as to where a changelog entry should be added. Is the `NEWS` file the right place? Regards, Paul ---Files-------------------------------- ruby-changes.patch (2.83 KB) -- https://bugs.ruby-lang.org/ Unsubscribe: