Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112024-01-14T15:10:49ZRuby Issue Tracking System
Redmine Ruby master - Bug #20185 (Closed): String#ascii_only? buggy in ruby 3.3https://bugs.ruby-lang.org/issues/201852024-01-14T15:10:49Zchucke (Tiago Cardoso)
<p>This was the smallest reduction of the bug I could come up with:</p>
<pre><code>require "stringio"
puts StringIO::VERSION
def is_ascii(buffer)
str = buffer.string
puts "\"#{str}\" is ascii: #{str.ascii_only?}"
end
buffer = StringIO.new("".b)
buffer.write("a=b&c=d")
buffer.rewind
is_ascii(buffer)
buffer.write "богус"
is_ascii(buffer)
# in ruby 3.3
#=> 3.1.0
#=> "a=b&c=d" is ascii: true
#=> "богус" is ascii: true
# in ruby 3.2
#=> 3.0.4
#=> "a=b&c=d" is ascii: true
#=> "богус" is ascii: true
# in ruby 3.1
#=> 3.0.1
#=> "a=b&c=d" is ascii: true
#=> "богус" is ascii: false
</code></pre>
<p>I believe that only the 3.1 result is correct, as "богус" first character is not ascii.</p> Ruby master - Feature #20176 (Open): Array#pack: support offset kwarghttps://bugs.ruby-lang.org/issues/201762024-01-10T12:46:19Zchucke (Tiago Cardoso)
<p>I was changing some code to use ruby 3.3's new <code>buffer</code> kwarg (great addition btw!) when using <code>Array#pack</code>. There are a few cases however, where I could perform the change, as not all my usages rely on appending; in some, I'm actually prepending it.</p>
<p>To solve this, I'd like to propose the <code>offset</code> kwarg, which declares where to add the resulting string. picking up on example from the docs:</p>
<pre><code>[65, 66].pack('C*', buffer: 'foo') # => "fooAB"
[65, 66].pack('C*', buffer: 'foo', offset: 0) # => "ABfoo"
[65, 66].pack('C*', buffer: 'foo', offset: 1) # => "fABoo"
</code></pre> Ruby master - Feature #20049 (Feedback): Destructive drop_while for Array and Hashhttps://bugs.ruby-lang.org/issues/200492023-12-07T17:25:46Zchucke (Tiago Cardoso)
<p>I propose a "drop_while!" variant for arrays and hashes, which changes the current instance.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">h</span> <span class="o">=</span> <span class="p">{</span><span class="ss">foo: </span><span class="mi">0</span><span class="p">,</span> <span class="ss">bar: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">baz: </span><span class="mi">2</span><span class="p">}</span>
<span class="n">h</span><span class="p">.</span><span class="nf">drop_while!</span><span class="p">{</span><span class="o">|</span><span class="n">element</span><span class="o">|</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="o">*</span><span class="n">element</span><span class="p">;</span> <span class="n">value</span> <span class="o"><</span> <span class="mi">2</span> <span class="p">}</span>
<span class="n">h</span> <span class="c1">#=> # => { baz: 2 }</span>
</code></pre> Ruby master - Feature #18926 (Open): Ractor should support mutexes and treat the block as critica...https://bugs.ruby-lang.org/issues/189262022-07-19T14:26:08Zchucke (Tiago Cardoso)
<p>This is an improvement suggestion in order to foster adoption of ractors. It may not be technically impossible or unfeasible for some reason, as it may lead to deadlocks, so feel free to discard it if massively hard to undertake.</p>
<p>There's a pattern, common to a lot of popular gems, and stdlib, in the wild, which I call "lazy-load-then-cache". Essentially, smth like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span>
<span class="vi">@map</span> <span class="o">=</span> <span class="p">{}</span>
<span class="vi">@map_mutex</span> <span class="o">=</span> <span class="no">Mutex</span><span class="p">.</span><span class="nf">new</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">set_in_map</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="vi">@map_mutex</span><span class="p">.</span><span class="nf">synchronize</span> <span class="k">do</span>
<span class="vi">@map</span><span class="p">[</span><span class="nb">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">get_from_map</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="vi">@map</span><span class="p">.</span><span class="nf">key?</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">do_smth_heavy_to_figure_out</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="n">set_in_map</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="n">value</span>
<span class="k">else</span>
<span class="vi">@map</span><span class="p">[</span><span class="nb">name</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The main issues here regarding ractor safety are:</p>
<ul>
<li>
<code>@map</code> is not frozen</li>
<li>ractor does not support usage of mutexes</li>
</ul>
<p>Examples:</p>
<ul>
<li>sequel: <a href="https://github.com/jeremyevans/sequel/blob/master/lib/sequel/database/connecting.rb#L76" class="external">https://github.com/jeremyevans/sequel/blob/master/lib/sequel/database/connecting.rb#L76</a>
</li>
<li>resolv:
<ul>
<li>
<a href="https://github.com/ruby/resolv/blob/master/lib/resolv.rb#L187" class="external">https://github.com/ruby/resolv/blob/master/lib/resolv.rb#L187</a> (instance-based variation of the above)</li>
<li>
<a href="https://github.com/ruby/resolv/blob/master/lib/resolv.rb#L1341" class="external">https://github.com/ruby/resolv/blob/master/lib/resolv.rb#L1341</a> (not protected by mutex, but still a usage of a global counter)</li>
</ul>
</li>
</ul>
<p>While I've found <a href="https://github.com/ractor-tools/ractor-cache" class="external">a gem implementing a ractor-aware cache</a>, while looking a bit outdated, it also makes use of <code>ObjectSpace::WeakMap</code>, which is probably a dealbreaker and a "hack" around ractor's limitations. It's also not necessarily a "drop-in" replacement for the pattern exemplified above.</p>
<hr>
<p>Theoretically, ractor could support the pattern above, by allowing the usage of mutexes. It should however run mutex blocks exclusively across ractors, while also disabling "ractor checks". This means that a mutable <code>@map</code> could be mutated within a ractor, as long as protected by a mutex. However, it should be marked as frozen before the block terminates. So the code above should be modified to:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="vi">@map</span> <span class="o">=</span> <span class="p">{}.</span><span class="nf">freeze</span>
<span class="vi">@map_mutex</span> <span class="o">=</span> <span class="no">Mutex</span><span class="p">.</span><span class="nf">new</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">set_in_map</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="vi">@map_mutex</span><span class="p">.</span><span class="nf">synchronize</span> <span class="k">do</span>
<span class="vi">@map</span> <span class="o">=</span> <span class="vi">@map</span><span class="p">.</span><span class="nf">merge</span><span class="p">(</span><span class="nb">name</span> <span class="o">=></span> <span class="n">value</span><span class="p">)</span>
<span class="vi">@map</span><span class="p">.</span><span class="nf">freeze</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<hr>
<p>Again, there may be implementation limitations not enabling usage of such a pattern. But it's a telling sign when ractors can't support simple usages of stdlib. So this proposal aims at enabling yet another case which may diminish the overhead of supporting ractors going forward, thereby making ractors usable in more situations.</p> Ruby master - Feature #18919 (Assigned): Ractor: can't share #Method objectshttps://bugs.ruby-lang.org/issues/189192022-07-15T22:07:09Zchucke (Tiago Cardoso)
<p>The following is not shareable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">></span> <span class="n">meth</span> <span class="o">=</span> <span class="o">::</span><span class="no">Kernel</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:BigDecimal</span><span class="p">)</span>
<span class="o">=></span> <span class="c1">#<Method: Kernel.BigDecimal(*)></span>
<span class="o"><</span><span class="n">internal</span><span class="ss">:ractor</span><span class="o">></span><span class="p">:</span><span class="mi">816</span><span class="ss">:in</span> <span class="sb">`make_shareable': can not make shareable object for #<Method: Kernel.BigDecimal(*)> (Ractor::Error)
</span></code></pre>
<p>I understand that procs have the issue of accessing outer-scope variables, but does the same apply to methods converted to procs?</p> Ruby master - Feature #18894 (Open): Object#make_shareablehttps://bugs.ruby-lang.org/issues/188942022-07-02T23:42:33Zchucke (Tiago Cardoso)
<p>I'm proposing a callback method for when one calls <code>Ractor.make_shareable(obj)</code>, the same way <code>Marshal.dump(obj)</code> calls <code>obj.marshal_dump</code>.</p>
<p>A lot of use cases in the wild involve a quick initialization of an object, only for some more heavy initializattion to be lazily called the first time an operation is called. An example in stdlib is <code>Resolv::Hosts</code>, which calls <code>lazy_initialize</code> on certains calls to resolve a name. Given that <code>Resolv</code> has a default resolver, this is unusable in ractors, due this "lazy" thing. Having a callback would allow to eager-load such an object, thereby making the default resolver usable with ractors.</p> Ruby master - Bug #18246 (Closed): send does not work for unary ! operator when operator isn't a ...https://bugs.ruby-lang.org/issues/182462021-10-07T17:36:19Zchucke (Tiago Cardoso)
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">1</span><span class="p">.</span><span class="nf">send</span><span class="p">(:</span><span class="o">+</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">#=> 2</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:"+"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">#=> 2</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:-@</span><span class="p">)</span> <span class="c1">#=> -1</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:"-@"</span><span class="p">)</span> <span class="c1">#=> -1</span>
<span class="kp">false</span><span class="p">.</span><span class="nf">send</span><span class="p">(:</span><span class="o">!</span><span class="err">@</span><span class="p">)</span> <span class="c1">#=> true</span>
<span class="kp">false</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:"!@"</span><span class="p">)</span> <span class="c1">#> </span>
<span class="c1"># undefined method `!@' for false:FalseClass (NoMethodError)</span>
<span class="c1"># Did you mean? !=</span>
<span class="o">!~</span>
</code></pre> Ruby master - Bug #18149 (Rejected): Can't match against strings with special codes withinhttps://bugs.ruby-lang.org/issues/181492021-09-03T15:35:35Zchucke (Tiago Cardoso)
<p>This can be summed up by the following example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="s2">"</span><span class="se">\xFF</span><span class="s2">"</span><span class="p">.</span><span class="nf">match</span> <span class="sr">/\\x/</span>
<span class="c1">#=> (irb):6:in `match': invalid byte sequence in UTF-8 (ArgumentError)</span>
</code></pre> Ruby master - Bug #17998 (Assigned): ractor: process hanging (with ractors initialized, but not b...https://bugs.ruby-lang.org/issues/179982021-06-17T13:45:50Zchucke (Tiago Cardoso)
<p>I couldn't figure out how to reproduce this in a more contained way, so I'll share what I'm doing <a href="https://github.com/HoneyryderChuck/minitest/tree/issue-872" class="external">in this minitest branch</a>.</p>
<p>I'm trying to make minitest's parallel mode use ractors. If you look at the last commit of the branch, I'm:</p>
<ul>
<li>replacing the parallel executor with a ractor-based one;</li>
<li>I'm defining the ractor executor, where I have a ractor pipe that a pool will consume work from</li>
<li>I'm turning off parallel subset of tests (to reproduce the bug that I'll be describing).</li>
</ul>
<p>When I run <code>rake test</code> in my Mac (BigSur 11.4), the process hangs. I can see that the ractor threads are executing and running, but the test process doesn't respond to the INFO signal interrupt (which should tell me where the process is hanging). This seems like a bug in the VM, as no work is being sent to the parallel executor, i.e. all ractors should be sleeping (I've <code>puts</code>'d also the executor shutdown process, and it never reaches it).</p>
<p>If I replace the ractor-based executor back with the thread based executor, everything works as expected.</p> Ruby master - Feature #17950 (Open): Unable to pattern-match against a String keyhttps://bugs.ruby-lang.org/issues/179502021-06-12T15:36:53Zchucke (Tiago Cardoso)
<p>I'm unable to parse against an internal hash, when the internal hash contains strings as keys:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="p">{</span><span class="ss">status: </span><span class="mi">200</span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{</span><span class="s2">"content-type"</span> <span class="o">=></span> <span class="s2">"application/json"</span><span class="p">},</span> <span class="ss">body: </span><span class="s2">"bla"</span><span class="p">}</span>
<span class="k">in</span> <span class="p">{</span> <span class="ss">status: </span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{</span><span class="s2">"content-type"</span> <span class="o">=></span> <span class="n">type</span><span class="p">},</span> <span class="ss">body: </span><span class="p">}</span>
<span class="c1"># syntax error, unexpected terminator, expecting literal content or tSTRING_DBEG or tSTRING_DVAR or tLABEL_END</span>
<span class="c1"># ...tus: , headers: {"content-type" => type}, body: }</span>
</code></pre>
<p>however, this works:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">h</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"content-type"</span> <span class="o">=></span> <span class="s2">"application/json"</span><span class="p">}</span>
<span class="k">case</span> <span class="p">{</span><span class="ss">status: </span><span class="mi">200</span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{</span><span class="s2">"content-type"</span> <span class="o">=></span> <span class="s2">"application/json"</span><span class="p">},</span> <span class="ss">body: </span><span class="s2">"bla"</span><span class="p">}</span>
<span class="k">in</span> <span class="p">{</span> <span class="ss">status: </span><span class="p">,</span> <span class="ss">headers: </span><span class="o">^</span><span class="n">h</span><span class="p">,</span> <span class="ss">body: </span><span class="p">}</span>
</code></pre> Ruby master - Bug #17722 (Closed): define_method with shareable results in "defined in a differen...https://bugs.ruby-lang.org/issues/177222021-03-14T15:00:41Zchucke (Tiago Cardoso)
<p>Testing against latest master, and expectinng <a href="https://bugs.ruby-lang.org/issues/17159?tab=history" class="external">this</a> to already be handled, I nonetheless found a weird case, for which I managed to build a short reproduction.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span>
<span class="n">define_method</span> <span class="ss">:"a="</span> <span class="k">do</span> <span class="o">|</span><span class="n">val</span><span class="o">|</span>
<span class="nb">instance_variable_set</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="n">v</span><span class="si">}</span><span class="ss">"</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span>
<span class="k">end</span>
<span class="nb">attr_reader</span> <span class="ss">:a</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="o">|</span>
<span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">k</span><span class="si">}</span><span class="s2"> = </span><span class="si">#{</span><span class="n">v</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">__send__</span><span class="p">(</span><span class="ss">:"</span><span class="si">#{</span><span class="n">k</span><span class="si">}</span><span class="ss">="</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">ractors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="no">DEFAULTS</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">a: </span><span class="mi">1</span> <span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="no">DEFAULTS</span><span class="p">)</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
<span class="n">ractors</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">a</span> <span class="o">=</span> <span class="no">A</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">DEFAULTS</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">ractors</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:take</span><span class="p">)</span>
</code></pre>
<p>This script fails with "defined in a different Ractor (RuntimeError)".</p>
<p>The error comes from the execution of "define_method". I was under the expectation that it would work, given that the passed value is shareable, so it shouldn't make a difference if it was defined in a different ractor.</p> Ruby master - Bug #17659 (Closed): Ractor: can't call io/wait methodshttps://bugs.ruby-lang.org/issues/176592021-02-26T18:23:41Zchucke (Tiago Cardoso)
<p>It seems that I can use IO.select inside a ractor, but not call IO.wait_writable, which seems odd.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"io/wait"</span>
<span class="n">ractors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
<span class="n">ractors</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="vg">$stdout</span><span class="p">.</span><span class="nf">wait_writable</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># this fails</span>
<span class="c1"># but this works</span>
<span class="c1"># IO.select(nil, [$stdout], nil, 2)</span>
<span class="vg">$stdout</span><span class="p">.</span><span class="nf">puts</span> <span class="s2">"wow"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">ractors</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:take</span><span class="p">)</span>
</code></pre> Ruby master - Misc #17309 (Open): URI.escape being deprecated, yet there is no replacementhttps://bugs.ruby-lang.org/issues/173092020-11-07T01:26:10Zchucke (Tiago Cardoso)
<p>I'm on ruby 2.7.2 . The moment I do</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">uri</span> <span class="o">=</span> <span class="s2">"http://bücher.ch"</span>
<span class="no">URI</span><span class="p">.</span><span class="nf">escape</span> <span class="n">uri</span>
<span class="p">(</span><span class="n">irb</span><span class="p">):</span><span class="mi">5</span><span class="p">:</span> <span class="ss">warning: </span><span class="no">URI</span><span class="p">.</span><span class="nf">escape</span>
<span class="s2">"http://b%C3%BCcher.ch"</span>
</code></pre>
<p>I get that warning. Rubocop also tells me:</p>
<p>"""<br>
URI.escape method is obsolete and should not be used. Instead, use CGI.escape, URI.encode_www_form or URI.encode_www_form_component depending on your specific use case.<br>
"""</p>
<p>However, none of the suggestions does the same as <code>URI.escape</code>.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">CGI</span><span class="p">.</span><span class="nf">escape</span> <span class="n">uri</span>
<span class="o">=></span> <span class="s2">"http%3A%2F%2Fb%C3%BCcher.ch"</span>
<span class="no">URI</span><span class="p">.</span><span class="nf">encode_www_form_component</span> <span class="n">uri</span>
<span class="o">=></span> <span class="s2">"http%3A%2F%2Fb%C3%BCcher.ch"</span>
<span class="no">URI</span><span class="p">.</span><span class="nf">encode_www_form</span> <span class="n">uri</span>
<span class="no">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="no">NoMethodError</span> <span class="p">(</span><span class="n">undefined</span> <span class="nb">method</span> <span class="sb">`map' for "http://bücher.ch":String)
Did you mean? tap
</span></code></pre>
<p>So my question is: why is this being deprecated? And if there's still reason, what to exactly replace it for, so I can keep the exact same behaviour?</p> Ruby master - Misc #17035 (Closed): is non-symbol key hash spread a bug or a feature?https://bugs.ruby-lang.org/issues/170352020-07-17T15:16:45Zchucke (Tiago Cardoso)
<p>Coming from <a href="https://github.com/jruby/jruby/issues/6327#issuecomment-659577894" class="external">https://github.com/jruby/jruby/issues/6327#issuecomment-659577894</a></p>
<p>I've queried jruby about a bug I found, only to find that the behaviour is correct for the ruby versions jruby emulates.</p>
<p>The following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">{</span><span class="o">**</span><span class="p">{</span><span class="s2">"a"</span> <span class="o">=></span> <span class="s2">"b"</span><span class="p">}}</span>
</code></pre>
<p>breaks in ruby < 2.7, but works in 2.7 .</p>
<p>I've looked at the 2.7 announcements and didn't find any. Is this a feature that ruby wants to keep (I'd very much like so) ? Or was this accidental, and unlikely to be maintained in the long run?</p> Ruby master - Feature #15549 (Open): Enumerable#to_reader (or anything enumerable, Enumerator, la...https://bugs.ruby-lang.org/issues/155492019-01-19T15:38:33Zchucke (Tiago Cardoso)
<p>This is a feature proposal for something I've had to implement before multiple times.</p>
<p>For a lot of IO-related APIs, there is this unspoken (because ruby doesn't have official interfaces) notion of a reader/writer protocol, that is, you pass arguments to certain functions where they either must implement "#read(nsize, buffer)" or "#write(data)". An example would be "IO.copy_stream".</p>
<p>It happened to me multiple times in the past that I started implementing some data-generator using "#each" in a specific format (CSV data, JSON...) to be lazy and memory conservative, but end up rewriting it because I can't read from an enumerable into a socket/file handle directly.</p>
<p>Lately I've been adopting the pattern of "injecting" a "#read" method to these objects, so that I can indeed use these APIs to my benefit. Sadly, I have to reimplement this in every project. This is the gist:</p>
<p><a href="https://gist.github.com/HoneyryderChuck/625c7b873a00a18d12b1a08695551510" class="external">https://gist.github.com/HoneyryderChuck/625c7b873a00a18d12b1a08695551510</a></p>
<p>I think such an API would be very benefitial to the common user. In most projects I've worked in, writing data to a tempfile, S3 bucket, FTP server, is very common, and I've lost the count to the number of implementations which write the whole data in memory <strong>then</strong> write to the handle, which obviously gives the impression that ruby consumes a lot of memory.</p>
<p>Now, I also understand that this is only beneficial to particular case of enums (those which yield strings/"to_s"-ables). But since there's a precedent for "#sum", so maybe I can make a case.</p>
<p>This is an example that works if you load the gist code":</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">enum</span> <span class="o">=</span> <span class="sx">%w(a)</span> <span class="o">*</span> <span class="mi">65536</span>
<span class="nb">puts</span> <span class="s2">"size: </span><span class="si">#{</span><span class="n">enum</span><span class="p">.</span><span class="nf">size</span><span class="si">}</span><span class="s2">"</span>
<span class="n">reader</span> <span class="o">=</span> <span class="n">enum</span><span class="p">.</span><span class="nf">to_reader</span>
<span class="no">IO</span><span class="p">.</span><span class="nf">copy_stream</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="vg">$stderr</span><span class="p">)</span>
</code></pre> Ruby master - Bug #15278 (Closed): Refinements don't work well with Forwardablehttps://bugs.ruby-lang.org/issues/152782018-11-03T00:06:41Zchucke (Tiago Cardoso)
<p>Refined methods become unreachable when called through def_delegator.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"forwardable"</span>
<span class="k">module</span> <span class="nn">URIExtensions</span>
<span class="n">refine</span> <span class="no">URI</span><span class="o">::</span><span class="no">Generic</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">authority</span>
<span class="n">port_string</span> <span class="o">=</span> <span class="n">port</span> <span class="o">==</span> <span class="n">default_port</span> <span class="p">?</span> <span class="kp">nil</span> <span class="p">:</span> <span class="s2">":</span><span class="si">#{</span><span class="n">port</span><span class="si">}</span><span class="s2">"</span>
<span class="s2">"</span><span class="si">#{</span><span class="n">host</span><span class="si">}#{</span><span class="n">port_string</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">origin</span>
<span class="s2">"</span><span class="si">#{</span><span class="n">scheme</span><span class="si">}</span><span class="s2">://</span><span class="si">#{</span><span class="n">authority</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">URIExtensions</span>
<span class="k">class</span> <span class="nc">Container</span>
<span class="kp">extend</span> <span class="no">Forwardable</span>
<span class="n">def_delegator</span> <span class="ss">:@uri</span><span class="p">,</span> <span class="ss">:origin</span>
<span class="n">def_delegator</span> <span class="ss">:@uri</span><span class="p">,</span> <span class="ss">:authority</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
<span class="vi">@uri</span> <span class="o">=</span> <span class="n">uri</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">u</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="s2">"https://google.com"</span><span class="p">)</span>
<span class="n">container</span> <span class="o">=</span> <span class="no">Container</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">u</span><span class="p">)</span>
<span class="nb">puts</span> <span class="n">container</span><span class="p">.</span><span class="nf">origin</span>
<span class="nb">puts</span> <span class="n">container</span><span class="p">.</span><span class="nf">authority</span>
</code></pre> Ruby master - Bug #14612 (Closed): IPv6 address inconsistency (downcase vs. upcase)https://bugs.ruby-lang.org/issues/146122018-03-17T23:52:45Zchucke (Tiago Cardoso)
<p>I've noticed that sometimes ip addresses re shown using a-f characters in downcase, other times upcase. Here is a small script to show results:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"resolv"</span>
<span class="nb">require</span> <span class="s2">"socket"</span>
<span class="nb">puts</span> <span class="no">TCPSocket</span><span class="p">.</span><span class="nf">getaddress</span><span class="p">(</span><span class="s2">"nghttp2.org"</span><span class="p">)</span> <span class="c1">#=> "2400:8902::f03c:91ff:fe69:a454"</span>
<span class="nb">puts</span> <span class="no">Resolv</span><span class="p">.</span><span class="nf">getaddresses</span><span class="p">(</span><span class="s2">"nghttp2.org"</span><span class="p">)</span> <span class="c1">#=> ["139.162.123.134", "2400:8902::F03C:91FF:FE69:A454"]</span>
</code></pre>
<p>Results might be system-dependent (I'm using Mac OS High Sierra).</p>
<p>This makes compare operations a bit harder.</p> Ruby master - Bug #14017 (Rejected): Hash.sort_by inconsistent between 2.2.6 and upper versionshttps://bugs.ruby-lang.org/issues/140172017-10-15T16:25:48Zchucke (Tiago Cardoso)
<p>The bug occurs when sorting by a numeric value and two different keys have similar values: It is very easily demonstrated here:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">enc</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"foo"</span><span class="o">=></span><span class="mf">0.9</span><span class="p">,</span> <span class="s2">"bar"</span><span class="o">=></span><span class="mf">1.0</span><span class="p">,</span> <span class="s2">"identity"</span><span class="o">=></span><span class="mf">1.0</span><span class="p">}</span>
<span class="n">enc</span><span class="p">.</span><span class="nf">sort_by</span> <span class="p">{</span> <span class="o">|</span><span class="n">_</span><span class="p">,</span> <span class="n">q</span><span class="o">|</span> <span class="o">-</span><span class="n">q</span> <span class="p">}</span>
<span class="c1"># in ruby 2.2.6</span>
<span class="c1">#=> [["identity", 1.0], ["bar", 1.0], ["foo", 0.9]]</span>
<span class="c1"># in rubies > 2.2</span>
<span class="c1">#=> [["bar", 1.0], ["identity", 1.0], ["foo", 0.9]]</span>
</code></pre>
<p>For the record, newer rubies present the correct version IMO, as the order of equivalent values shouldn't be changed based on the same value.</p>
<p>I looked at the <a href="https://github.com/ruby/ruby/blob/v2_3_0/NEWS" class="external">ruby 2.3 release notes</a>, but couldn't find the mention to a fix, so I can't say that this is a "behaviour change, upgrade to new" case. What I can say is that this behaviour seems to have changed in ruby 2.3 (tested also with ruby 2.2.2 and ruby 2.1.9 and can reproduce the same result as with 2.2.6).</p>
<p>As an example of production code which is probably returning a wrong result is rack, which <a href="https://github.com/rack/rack/blob/911c4fe15e3e57d44ac891c0cbabbf44bdf71201/lib/rack/utils.rb#L188" class="external">uses as variation of this to select the best content encoding</a> .</p>
<p>Is this something which can be backported into a possible 2.2.7, or is ruby 2.2 in maintenance mode?</p> Ruby master - Bug #14016 (Rejected): URI IPv6 address can't be used to open sockethttps://bugs.ruby-lang.org/issues/140162017-10-14T23:07:41Zchucke (Tiago Cardoso)
<p>The example occurred when trying to use IPv6 to establish communication between HTTP client and server.</p>
<p>I first created an URI, passed it to Net::HTTP.get, and it blew with the following message:</p>
<pre><code>SocketError: Failed to open TCP connection to [::1]:9292 (getaddrinfo: nodename nor servname provided, or not known)
</code></pre>
<p>It seems to me that the URI and the Socket classes don't play well with its expected representation of an IPv6 address:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">URI</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">build</span><span class="p">(</span><span class="ss">host: </span><span class="s2">"[::1]"</span><span class="p">).</span><span class="nf">host</span> <span class="c1">#=> "[::1]"</span>
<span class="no">URI</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">build</span><span class="p">(</span><span class="ss">host: </span><span class="s2">"::1"</span><span class="p">).</span><span class="nf">host</span> <span class="c1">#=> ”[::1]”</span>
<span class="no">TCPSocket</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"::1"</span><span class="p">,</span> <span class="mi">9292</span><span class="p">)</span> <span class="c1">#=> #<TCPSocket fd:15></span>
<span class="no">TCPSocket</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"[::1]"</span><span class="p">,</span> <span class="mi">9292</span><span class="p">)</span> <span class="c1">#=> #<TCPSocket fd:15></span>
</code></pre> Ruby master - Bug #13921 (Closed): buffered read_nonblock doesn't work as expected using SSLSockethttps://bugs.ruby-lang.org/issues/139212017-09-19T18:20:10Zchucke (Tiago Cardoso)
<p>I have something similar to the following code that handles both tcp as well as ssl sockets. The idea is to use the #read_nonblock API which uses a buffer when passed in the argument (instead of creating a string every time).</p>
<pre><code>class A
def initialize
@buffer = String.new("", encoding: Encoding::BINARY)
end
def read(io)
io.read_nonblock(16_384, @buffer, exception: false)
# do stuff...
@buffer.clear
end
</code></pre>
<p>For plain tcp sockets, it works as expected (buffers payload). However, when passed an ssl socket, it buffers the whole SSL payload, which SSLSocket's usually handle transparently. Of course, my logic fails after that.</p>
<p>My current workaround is to resort to the unbuffered API:</p>
<pre><code>buffer = io.read_nonblock(16_384, exception: false)
</code></pre>
<p>however, the call mentioned above should have worked transparently.</p> Ruby master - Bug #13857 (Rejected): frozen string literal: can freeze same string into two uniqu...https://bugs.ruby-lang.org/issues/138572017-09-01T07:16:01Zchucke (Tiago Cardoso)
<p>Running an interpreter with <code>--enable-frozen-string-literal</code> on, I get the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">></span> <span class="s2">"bang"</span><span class="p">.</span><span class="nf">object_id</span> <span class="c1">#=> 70303434940940 GOOD!</span>
<span class="o">></span> <span class="s2">"bang"</span><span class="p">.</span><span class="nf">object_id</span> <span class="c1">#=> 70303434940940 GOOD!</span>
<span class="o">></span> <span class="s2">"bang"</span><span class="p">.</span><span class="nf">object_id</span> <span class="c1">#=> 70303434940940 GOOD!</span>
<span class="o">></span> <span class="n">c</span> <span class="o">=</span> <span class="s2">"bang"</span>
<span class="o">></span> <span class="n">c</span><span class="p">.</span><span class="nf">object_id</span> <span class="c1">#=> 70303434940940 GOOD!</span>
<span class="o">></span> <span class="n">c</span><span class="p">.</span><span class="nf">downcase</span> <span class="c1">#=> "bang"</span>
<span class="o">></span> <span class="n">c</span><span class="p">.</span><span class="nf">downcase</span><span class="p">.</span><span class="nf">object_id</span> <span class="c1">#=> 70303430619560 SO SO!</span>
<span class="o">></span> <span class="n">c</span><span class="p">.</span><span class="nf">downcase</span><span class="p">.</span><span class="nf">freeze</span><span class="p">.</span><span class="nf">object_id</span><span class="err"> </span><span class="c1">#=> 70303430601780 BAD!</span>
</code></pre>
<p>This ticket concerns the last two examples. In the case of performing an operation on the string, it makes sense to return a new string, even if the result is the same. However, I think that the last one could be done differently, in that the frozen result of the downcased value should be the original literal.</p>
<p>I didn't see yet how the frozen string literals are implemented, so this might be dependent on it, but I think that this misses a few optimization use cases. One notable example is keeping a headers hash from an http library. <code>net/http</code> keeps a version of the headers hash with the keys downcased, only to capitalize them on send. Something like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">request</span><span class="p">[</span><span class="s2">"Content-Type"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"text/html"</span> <span class="c1">#=> key stored in request will be "content-type"</span>
</code></pre>
<p>will create more allocations than expected.</p> Ruby master - Bug #13851 (Closed): getting "can't modify string; temporarily locked" on non-froze...https://bugs.ruby-lang.org/issues/138512017-08-30T10:37:36Zchucke (Tiago Cardoso)
<p>I'm doing some nonblocking IO, and using a local string for buffering to avoid allocations. Roughly the following</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span>
<span class="k">def</span> <span class="nf">initialize</span>
<span class="vi">@buffer</span> <span class="o">=</span> <span class="no">String</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">""</span><span class="p">,</span> <span class="ss">encoding: </span><span class="no">Encoding</span><span class="o">::</span><span class="no">BINARY</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="n">io</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="nf">read_nonblock</span><span class="p">(</span><span class="mi">16_384</span><span class="p">,</span> <span class="vi">@buffer</span><span class="p">,</span> <span class="ss">exception: </span><span class="kp">false</span><span class="p">)</span>
<span class="c1"># do stuff...</span>
<span class="vi">@buffer</span><span class="p">.</span><span class="nf">clear</span>
<span class="k">end</span>
</code></pre>
<p>It all goes smoothly, mostly... until I start getting arbitrary error when calling <code>#read_nonblock</code>. Here's an example backtrace:</p>
<pre><code>DEBUG: can't modify string; temporarily locked- - - [30/Aug/2017:13:15:09 +0300] "GET / 1.0" 200 - 0.0000
DEBUG: <internal:prelude>:76:in `__read_nonblock'
DEBUG: <internal:prelude>:76:in `read_nonblock'
DEBUG: /Users/user/Projects/project:NN in `read``
....
</code></pre>
<p>I can't unfortunately reproduce this in a deterministic way. I can only say that the <code>read</code> routine is called in multiple threads (different io's instances of that class). The errors come seldom, however.</p>
<p>I'm running ruby 2.3.4, and the frozen string literal is activated for the file where the class is defined. I first assumed that it was the buffer, but due to its initialization, it should be marken as not-frozen.</p> Ruby master - Bug #13087 (Closed): Regression of instance_exec behaviour in ruby 2.4https://bugs.ruby-lang.org/issues/130872016-12-29T11:05:17Zchucke (Tiago Cardoso)
<p>I've just caught up this running our test suite against the newly released ruby 2.4. Here is the repro gist:</p>
<pre><code class="ruby syntaxhl" data-language="ruby">
<span class="k">class</span> <span class="nc">A</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="vi">@x</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">perform</span>
<span class="nb">puts</span> <span class="s2">"performing </span><span class="si">#{</span><span class="vi">@x</span><span class="si">}</span><span class="s2"> times"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"basic"</span>
<span class="no">A</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">a</span><span class="o">|</span>
<span class="n">a</span><span class="p">.</span><span class="nf">instance_exec</span> <span class="k">do</span>
<span class="n">perform</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1">#puts "advanced" </span>
<span class="no">A</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">a</span><span class="o">|</span>
<span class="n">a</span><span class="p">.</span><span class="nf">instance_exec</span><span class="p">(</span><span class="no">A</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="o">&</span><span class="ss">:perform</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>The last one output "3 times in all ruby 2's except latest 2.4 .</p>
<p>This seems to apply the to_proc symbol to the object itself, and not the argument of instance_exec, which is a regression.</p> Ruby master - Bug #12946 (Closed): net-http is breaking valid http headers like HTTP2-Settingshttps://bugs.ruby-lang.org/issues/129462016-11-15T21:56:55Zchucke (Tiago Cardoso)
<p>The Net::HTTPHeader can't process the <code>HTTP2-Settings</code> header, which is a valid header destined to pass base64-encoded settings to a soon-to-be-upgraded-to-http2 connection.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">req</span><span class="o">=</span><span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Get</span><span class="p">.</span><span class="nf">new</span>
<span class="n">req</span><span class="p">[</span><span class="s2">"Upgrade"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"h2c"</span>
<span class="n">req</span><span class="p">[</span><span class="s2">"HTTP2-Settings] = "</span><span class="n">base64encoded</span><span class="o">==</span><span class="s2">"
req.to_hash #=> "</span><span class="o">...</span> <span class="no">Http2</span><span class="o">-</span><span class="no">Settings</span> <span class="o">=></span> <span class="o">...</span><span class="s2">"
</span></code></pre>
<p>Although one could say that net-http doesn't support to-http2-upgraded connections and even doesn't provide access to the raw socket, it's still a valid HTTP1.1 header, and the headers current MO "force to downcase and store; capitalize on fetch" works against custom Upgrade headers.</p>
<p>As of now, net-http can't upgrade. I'd suggest an API for such things, in that after a successful Upgrade request (101 switch protocols), the http connection "gives up" the socket to something else.</p>
<p>I had to monkey-patch my way out of this to make my code work: <a href="https://github.com/TiagoCardoso1983/jaguar/blob/master/test/test_helper.rb#L16-L25" class="external">https://github.com/TiagoCardoso1983/jaguar/blob/master/test/test_helper.rb#L16-L25</a> .</p> Ruby master - Misc #12935 (Closed): Webrick: Update HTTP Status codes, share themhttps://bugs.ruby-lang.org/issues/129352016-11-14T17:21:03Zchucke (Tiago Cardoso)
<p>I was looking for a common source of http status-to-reason map in ruby, and I've found many sources that address the same, some of them overlapping, most of them clearly copy-pasting from each other. In the process, I also found that the current hashmap used by webrick seems not to be up-to-date. Compare:</p>
<p><a href="https://github.com/nahi/ruby/blob/webrick_trunk/lib/webrick/httpstatus.rb#L56-L97" class="external">https://github.com/nahi/ruby/blob/webrick_trunk/lib/webrick/httpstatus.rb#L56-L97</a><br>
with <a href="https://github.com/puma/puma/blob/3f66b3d7d4413f843e4e541c4d282238318c4cd2/lib/puma/const.rb#L16-L74" class="external">https://github.com/puma/puma/blob/3f66b3d7d4413f843e4e541c4d282238318c4cd2/lib/puma/const.rb#L16-L74</a></p>
<p>I started (this thread in puma)[https://github.com/puma/puma/issues/1133] to see about openness is centralizing this information in ruby (or just use an updated version of webrick hash), and I found out some interesting things, like the fact that rails reloading is not compatible with some of these things.</p>
<p>My main motivation would be to have something similar to nodejs's <code>http.STATUS_CODES</code>:</p>
<pre><code>> require("http").STATUS_CODES
{ '100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'200': 'OK',
....
</code></pre>
<p>As http is something which is internally implemented in ruby's stdlib, question would just remain on how and where to implement it, and public API stability and "up-to-date"ness guarantees. I'd suggest maybe making it part of "net/http", like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"net/http/status"</span>
<span class="nb">puts</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">STATUS_CODES</span>
</code></pre>
<p>but that's just a suggestion.</p> Ruby master - Bug #12674 (Rejected): io/wait: not handling the case when the socket is closed bef...https://bugs.ruby-lang.org/issues/126742016-08-14T14:42:31Zchucke (Tiago Cardoso)
<p>I wrote the following script to show the problem:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'socket'</span>
<span class="nb">require</span> <span class="s1">'io/wait'</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">server</span> <span class="o">=</span> <span class="no">TCPServer</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2000</span> <span class="c1"># Server bind to port 2000</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">client</span> <span class="o">=</span> <span class="n">server</span><span class="p">.</span><span class="nf">accept</span> <span class="c1"># Wait for a client to connect</span>
<span class="n">client</span><span class="p">.</span><span class="nf">puts</span> <span class="s2">"Hello !"</span>
<span class="n">client</span><span class="p">.</span><span class="nf">puts</span> <span class="s2">"Time is </span><span class="si">#{</span><span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">sleep</span> <span class="mi">3</span>
<span class="n">client</span><span class="p">.</span><span class="nf">close</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"server is starting..."</span>
<span class="nb">sleep</span> <span class="mi">2</span>
<span class="nb">puts</span> <span class="s2">"connecting now"</span>
<span class="n">s</span> <span class="o">=</span> <span class="no">TCPSocket</span><span class="p">.</span><span class="nf">new</span> <span class="s1">'localhost'</span><span class="p">,</span> <span class="mi">2000</span>
<span class="nb">puts</span> <span class="s2">"connected"</span>
<span class="mi">10</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
<span class="n">k</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="nf">wait_readable</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"wait: </span><span class="si">#{</span><span class="n">k</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">"</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="nf">read_nonblock</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="ss">exception: </span><span class="kp">false</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"val: </span><span class="si">#{</span><span class="n">v</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">"</span>
<span class="k">break</span> <span class="k">if</span> <span class="n">v</span> <span class="o">==</span> <span class="kp">nil</span>
<span class="k">end</span>
<span class="c1"># server is starting...</span>
<span class="c1"># connecting now</span>
<span class="c1"># connected</span>
<span class="c1"># wait: #<TCPSocket:fd 11></span>
<span class="c1"># val: "Hello !\n"</span>
<span class="c1"># wait: #<TCPSocket:fd 11></span>
<span class="c1"># val: "Time is "</span>
<span class="c1"># wait: #<TCPSocket:fd 11></span>
<span class="c1"># val: "2016-08-"</span>
<span class="c1"># wait: #<TCPSocket:fd 11></span>
<span class="c1"># val: "14 16:30"</span>
<span class="c1"># wait: #<TCPSocket:fd 11></span>
<span class="c1"># val: ":35 +020"</span>
<span class="c1"># wait: #<TCPSocket:fd 11></span>
<span class="c1"># val: "0\n"</span>
<span class="c1"># wait: nil</span>
<span class="c1"># val: :wait_readable</span>
<span class="c1"># ISSUE!</span>
<span class="c1"># wait: nil</span>
<span class="c1"># val: nil</span>
</code></pre>
<p>The problem there is, I'm going to <code>wait_readable(timeout)</code> on the socket, and it's going to return nil. This nil is ambiguous, as it can mean in the spec "timed out on wait" or "server has closed the socket". The only way I have to know exactly what it means is to call read_nonblock again. If nil, it's EOF. If wait_readable, it timed out. So I can't fail early.</p>
<p>The wait methods could benefit from a more explicit return value for #wait. This might have been subject to discussion previously, as "false" was removed as of ruby 2.3 from the possible return values, but I think it's an issue that might prevent correctness in socket programming. Take the example from the standard library: <a href="https://github.com/ruby/ruby/blob/trunk/lib/net/protocol.rb#L154-L159" class="external">https://github.com/ruby/ruby/blob/trunk/lib/net/protocol.rb#L154-L159</a></p>
<p>If the server closes after :wait_readable was returned, wait_readable will return nil, and this will be interpreted as a timeout, instead of EOF. I don't know of any real-world issues with this using net/http, but there was one <a href="https://github.com/httprb/http/issues/298" class="external">here</a>.</p> Ruby master - Bug #12566 (Rejected): IO.copy_stream : tty/command-line events not being passed ar...https://bugs.ruby-lang.org/issues/125662016-07-07T15:12:13Zchucke (Tiago Cardoso)
<p>Coming from here: <a href="http://stackoverflow.com/questions/38248911/ruby-when-copying-streams-how-to-make-it-pass-input-characters" class="external">http://stackoverflow.com/questions/38248911/ruby-when-copying-streams-how-to-make-it-pass-input-characters</a></p>
<p>I don't know if the <code>stdin</code> is not flushing the special characters down the stack, or the leaf process <code>stdout</code> is not flushing upwards, but something is fishy in this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#!/usr/bin/env</span>
<span class="nb">require</span> <span class="s1">'open3'</span>
<span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="s2">"expect -"</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">i</span><span class="p">,</span> <span class="n">o</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">t</span><span class="o">|</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">start</span> <span class="p">{</span> <span class="no">IO</span><span class="p">.</span><span class="nf">copy_stream</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="vg">$stdout</span><span class="p">)</span> <span class="p">}</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">start</span> <span class="p">{</span> <span class="no">IO</span><span class="p">.</span><span class="nf">copy_stream</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="vg">$stderr</span><span class="p">)</span> <span class="p">}</span>
<span class="n">i</span> <span class="o"><<</span> <span class="s2">"spawn bash</span><span class="se">\n</span><span class="s2">interact</span><span class="se">\n</span><span class="s2">wait</span><span class="se">\n</span><span class="s2">exit</span><span class="se">\n</span><span class="s2">"</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">start</span> <span class="p">{</span> <span class="no">IO</span><span class="p">.</span><span class="nf">copy_stream</span><span class="p">(</span><span class="vg">$stdin</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">}</span>
<span class="n">t</span><span class="p">.</span><span class="nf">value</span>
<span class="k">end</span>
<span class="c1">#=> after executing, try "ls" and press tab</span>
</code></pre> Ruby master - Bug #12535 (Rejected): are there 2 sleep methods defined?https://bugs.ruby-lang.org/issues/125352016-06-29T12:47:08Zchucke (Tiago Cardoso)
<p>I'm updating this gem which "patches" the sleep method to use prepend, as I wanted to drop support to ruby < 2.0 . (previous implementation was using alias method chain like solution)</p>
<p>So I came across this funny behaviour:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">AlternativeSleep</span>
<span class="k">def</span> <span class="nf">sleep</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"going to sleep now..."</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="n">prepend</span> <span class="no">AlternativeSleep</span>
<span class="k">end</span>
<span class="k">class</span> <span class="o"><<</span> <span class="no">Kernel</span>
<span class="n">prepend</span> <span class="no">AlternativeSleep</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"these are the locations..."</span>
<span class="nb">puts</span> <span class="no">Kernel</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:sleep</span><span class="p">)</span>
<span class="nb">puts</span> <span class="nb">method</span><span class="p">(</span><span class="ss">:sleep</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"now to work. if you see the going to sleep message only once, there's your bug"</span>
<span class="no">Kernel</span><span class="p">.</span><span class="nf">sleep</span> <span class="mi">1</span>
<span class="nb">sleep</span> <span class="mi">1</span>
</code></pre>
<p>In order to make sleep work in both cases, I have to do those 2 prepends. Try to comment one of them, and you'll see that one of them will always work.</p>
<p>I'm led to believe that sleep method has two implementations, although that doesn't seem to make sense. Could you provide with some insight?</p>
<p>When I was using the alias-method-chain example, I was including in the main object, as <code>main#sleep</code> somehow seemed to land in <code>Kernel.sleep</code> (?) .</p> Ruby master - Feature #12534 (Closed): Refinements: refine modules as wellhttps://bugs.ruby-lang.org/issues/125342016-06-29T12:19:58Zchucke (Tiago Cardoso)
<p>Refinements were added as a feature to scope monkey-patches on ruby core elements. This works for elements such as String, Array (all classes), but not for modules (Enumerable, Timeout...).</p>
<p>This might be related to refinements not working for singleton classes (for example, I can't define a class method inside a refine block).</p>
<p>This code is evaluated, but the method is undefined:</p>
<p>module Extension<br>
refine Array do<br>
def self.foo ; puts "bar" ; end<br>
end<br>
end</p>
<p>This code breaks:</p>
<p>module Extension<br>
refine Kernel do<br>
def foo ; puts "bar" ; end<br>
end<br>
end</p> Ruby master - Feature #12533 (Closed): Refinements: allow modules inclusion, in which the module ...https://bugs.ruby-lang.org/issues/125332016-06-29T12:11:43Zchucke (Tiago Cardoso)
<p>Right now this isn't possible:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Extensions</span>
<span class="k">def</span> <span class="nf">vegetables</span> <span class="p">;</span> <span class="n">potatoe</span> <span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">potatoe</span> <span class="p">;</span> <span class="s2">"potatoe"</span> <span class="p">;</span> <span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">Refinary</span>
<span class="n">refine</span> <span class="no">String</span> <span class="k">do</span>
<span class="c1"># this doesn't work</span>
<span class="kp">include</span> <span class="no">Extensions</span>
<span class="c1"># this would work...</span>
<span class="c1"># def vegetables ; potatoe ; end</span>
<span class="c1"># def potatoe ; "potatoe" ; end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">Refinary</span>
<span class="nb">puts</span> <span class="s2">"tomatoe"</span><span class="p">.</span><span class="nf">vegetables</span>
<span class="c1">#=> in <main>': undefined method 'vegetables' for "tomatoe":String</span>
</code></pre>
<p>Wrongly reported as a bug <a href="https://bugs.ruby-lang.org/issues/12514" class="external">here</a>.</p>
<p>According to Shugo Maeda, this was expected behaviour. I argued that this is the way most monkey-patches work, and if Refinements can't cover the use case of inserting a custom DSL which references itself in the classes it refines, it can't fully replace monkey-patches, which I read was the main reason Refinements have been added to the language.</p> Ruby master - Bug #12514 (Rejected): Refinements: when including Module as refinement, can't call...https://bugs.ruby-lang.org/issues/125142016-06-22T15:09:51Zchucke (Tiago Cardoso)
<p>Very simple script which reproduces the problem:</p>
<pre>
module Extensions
def vegetables ; potatoe ; end
def potatoe ; "potatoe" ; end
end
module Refinary
refine String do
# this doesn't work
include Extensions
# this would work...
# def vegetables ; potatoe ; end
# def potatoe ; "potatoe" ; end
end
end
using Refinary
puts "tomatoe".vegetables
#=> in `': undefined method `vegetables' for "tomatoe":String
</pre>
<p>failing from ruby 2.0 to 2.3</p> Ruby master - Bug #12257 (Rejected): io/wait: wait_readable/writable working different than IO.se...https://bugs.ruby-lang.org/issues/122572016-04-07T12:49:59Zchucke (Tiago Cardoso)
<p>Coming from this pending issue:</p>
<p><a href="https://github.com/net-ssh/net-ssh/pull/303" class="external">https://github.com/net-ssh/net-ssh/pull/303</a></p>
<p>Gist of it:</p>
<pre>
f = IO.popen("/bin/sh","r+")
f.close_write
f.wait_writable #=> IOError: not opened for writing
IO.select(nil,[f],nil,10) #=> no error
</pre>
<p>The way I see it, it should have the same behaviour, i.e. either IO.select should complain, or wait_writable should just return nil.</p> Ruby master - Misc #12013 (Closed): io/wait: allow to wait on readable and writablehttps://bugs.ruby-lang.org/issues/120132016-01-21T16:53:09Zchucke (Tiago Cardoso)
<p>If I have a socket and I want to wait for both read and write events, IO.select is my only co-pilot:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">IO</span><span class="p">.</span><span class="nf">select</span><span class="p">([</span><span class="n">mysock</span><span class="p">],[</span><span class="n">mysock</span><span class="p">])</span>
</code></pre>
<p>the beautiful thing about the <code>#wait_readable</code> and <code>#wait_writable</code> methods is that I can have a friendlier way to compose sockets for other event loops which monkey-patching <code>IO.select</code>. One example is celluloid-io, which has its own wrappers around the network sockets classes.</p>
<p>But I think there is a limitation when I want to listen for both reads and writes. See both examples below:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">IO</span><span class="p">.</span><span class="nf">select</span><span class="p">([</span><span class="n">mysock</span><span class="p">],[</span><span class="n">mysock</span><span class="p">],</span> <span class="kp">nil</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
<span class="c1"># as opposed to</span>
<span class="nb">require</span> <span class="s1">'io/wait'</span>
<span class="n">mysock</span><span class="p">.</span><span class="nf">wait_readable</span><span class="p">(</span><span class="mi">30</span><span class="p">)</span> <span class="o">&&</span> <span class="n">mysock</span><span class="p">.</span><span class="nf">wait_writable</span><span class="p">(</span><span class="mi">30</span><span class="p">)</span>
</code></pre>
<p>in the second example, I can wait potentially 60 seconds, instead of the 30 from the first example.</p>
<p>I'm not sure which API it should be, my main reference is the celluloid io reactor api in this case:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">mysock</span><span class="p">.</span><span class="nf">wait</span><span class="p">(</span><span class="ss">:r</span><span class="p">)</span>
<span class="n">mysock</span><span class="p">.</span><span class="nf">wait</span><span class="p">(</span><span class="ss">:w</span><span class="p">)</span>
<span class="n">mysock</span><span class="p">.</span><span class="nf">wait</span><span class="p">(</span><span class="ss">:rw</span><span class="p">)</span>
</code></pre>
<p>drawback: there is already a wait method, so backwards compatibility would be gone. or would it? Current arity is 0, which means, one could still alias it to <code>#wait_readable</code> if no argument is passed.</p> Ruby master - Bug #12002 (Rejected): **param notation seems to be creating a new hash in ruby 2.2.0https://bugs.ruby-lang.org/issues/120022016-01-18T14:51:09Zchucke (Tiago Cardoso)
<p>I found the regression regarding the handling of the <code>**</code> notation for options hash in a method. In ruby 2.1 and lower, it seems to always be handled in the same way, i.e. it is always the same object:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">hashie1</span><span class="p">(</span><span class="n">o</span><span class="o">=</span><span class="p">{})</span>
<span class="nb">puts</span> <span class="n">o</span><span class="p">.</span><span class="nf">object_id</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">hashie2</span><span class="p">(</span><span class="o">**</span><span class="n">o</span><span class="p">)</span>
<span class="nb">puts</span> <span class="n">o</span><span class="p">.</span><span class="nf">object_id</span>
<span class="k">end</span>
<span class="n">v</span><span class="o">=</span><span class="p">{}</span>
<span class="nb">puts</span> <span class="n">v</span><span class="p">.</span><span class="nf">object_id</span>
<span class="n">hashie1</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="n">hashie2</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="c1"># 2.0.0</span>
<span class="mi">69830362391800</span>
<span class="mi">69830362391800</span>
<span class="mi">69830362391800</span>
<span class="c1"># 2.1.6 </span>
<span class="mi">69884363736320</span>
<span class="mi">69884363736320</span>
<span class="mi">69884363736320</span>
<span class="c1"># 2.2.4</span>
<span class="mi">69922787909840</span>
<span class="mi">69922787909840</span>
<span class="mi">69922787909700</span>
<span class="c1"># 2.3.0</span>
<span class="mi">69915134419200</span>
<span class="mi">69915134419200</span>
<span class="mi">69915134419000</span>
</code></pre>
<p>I didn't find any documentation regarding this change. Is it supposed to work the way it works in 2.2 and 2.3? Because my understanding was that <code>**</code> was supposed to be the new notation and should just work as the previous notation.</p>