Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112024-03-05T15:21:08ZRuby Issue Tracking System
Redmine Ruby master - Bug #20325 (Open): Enumerator.product.size bug with zero * infinite enumeratorshttps://bugs.ruby-lang.org/issues/203252024-03-05T15:21:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([],</span> <span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">to_a</span> <span class="c1"># => [] (OK)</span>
<span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([],</span> <span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">size</span> <span class="c1"># => Infinity (Should be 0)</span>
</code></pre> Ruby master - Bug #18018 (Closed): Float#floor / truncate sometimes result that is too small.https://bugs.ruby-lang.org/issues/180182021-07-01T22:53:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => 291.39 (not ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># => 291.39999 (not ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
</code></pre>
<p><code>g = f.floor(n)</code>, for <code>n > 0</code> must return the highest float that has the correct properties:</p>
<ul>
<li>
<code>g</code> <= <code>f</code>
</li>
<li>
<code>g</code>'s decimal string representation has at most <code>n</code> digits</li>
</ul>
<p>I'll note that <code>floor</code> should be stable, i.e. <code>f.floor(n).floor(n) == f.floor(n)</code> for all <code>f</code> and <code>n</code>.</p>
<p>Same idea for <code>truncate</code>, except for negative numbers (where <code>(-f).truncate(n) == -(f.floor(n))</code> for positive <code>f</code>).</p>
<p>Noticed by Eustáquio Rangel but posted on the mailing list.</p>
<p>Please do not reply that I need to learn how floats work. Note that example given in doc <code>(0.3/0.1).floor == 2</code> is not this issue, since <code>0.3/0.1 #=> 2.9999999999999996</code></p> Ruby master - Bug #17506 (Open): Ractor isolation broken by ThreadGrouphttps://bugs.ruby-lang.org/issues/175062021-01-03T20:05:43Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Ractors currently share the ThreadGroup.</p>
<p>This doesn't seem very useful as there is no possible communication between the Threads of different Ractors.</p>
<p>It is also an isolation error:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">ThreadGroup</span><span class="p">.</span><span class="nf">attr_accessor</span> <span class="ss">:foo</span>
<span class="n">var</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">foo</span> <span class="o">=</span> <span class="p">[</span><span class="ss">:example</span><span class="p">]</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">foo</span> <span class="o"><<</span> <span class="p">[</span><span class="ss">:oops</span><span class="p">]</span> <span class="p">}.</span><span class="nf">take</span>
<span class="n">var</span> <span class="c1"># => [:example, [:oops]]</span>
</code></pre>
<p>Should <code>Ractor.new</code> create a new <code>ThreadGroup</code>? Should <code>ThreadGroup</code> not have (non-shareable) instance variables? Or should <code>Ractor.new { Thread.current.group }.take</code> be <code>nil</code>? See also <a href="https://bugs.ruby-lang.org/issues/17505" class="external">https://bugs.ruby-lang.org/issues/17505</a> about <code>nil</code>.</p>
<p>Note that <code>Ractor</code> respects the <code>ThreadGroup</code>'s state:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">enclose</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">)</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => can't move to the enclosed thread group</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{}</span> <span class="c1"># => ThreadError (can't start a new thread (frozen ThreadGroup))</span>
</code></pre>
<p>I am not sure what is the best behavior as I don't have enough experience with how ThreadGroups are used, especially enclosed ThreadGroups.</p> Ruby master - Bug #17505 (Closed): Can `Thread#group` actually be `nil`?https://bugs.ruby-lang.org/issues/175052021-01-03T19:41:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Is there a circumstance where <code>Thread#group</code> could actually be <code>nil</code>?</p>
<p>The documentation says so, there seems to be source code for this, but I can find no test or RubySpec for this and I don't see anywhere in the <code>ThreadGroup</code> API that could allow this.</p> Ruby master - Feature #17406 (Open): Add `NoMatchingPatternError#depth`https://bugs.ruby-lang.org/issues/174062020-12-18T21:45:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Could we have <code>NoMatchingPatternError#depth</code>, returning the number of <code>case...in...end</code> an exception has traversed?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">show_depth</span>
<span class="k">yield</span>
<span class="k">rescue</span> <span class="no">NoMatchingPatternError</span> <span class="o">=></span> <span class="n">e</span>
<span class="nb">puts</span> <span class="s2">"Depth: </span><span class="si">#{</span><span class="n">e</span><span class="p">.</span><span class="nf">depth</span><span class="si">}</span><span class="s2">"</span>
<span class="k">raise</span>
<span class="k">end</span>
<span class="n">show_depth</span> <span class="k">do</span>
<span class="k">case</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span>
<span class="k">in</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">]</span> <span class="k">then</span>
<span class="n">show_depth</span> <span class="k">do</span>
<span class="n">x</span> <span class="o">=></span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]</span> <span class="c1"># => raises NoMatchingPatternError</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Prints "Depth: 0" then "Depth: 1"</span>
</code></pre>
<p>This could help bring pattern match closer to a language construct people can play with.</p>
<p>Example usecase: implement <code>Ractor#receive_if</code> as in <a href="https://bugs.ruby-lang.org/issues/17378#note-6" class="external">https://bugs.ruby-lang.org/issues/17378#note-6</a></p> Ruby master - Bug #17374 (Rejected): Refined methods aren't visible from a refinement's modulehttps://bugs.ruby-lang.org/issues/173742020-12-07T05:25:04Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.caRuby master - Feature #17365 (Closed): Can not respond (well) to a Ractor https://bugs.ruby-lang.org/issues/173652020-12-04T05:05:31Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Summary: currently there is no good way to return a response to a Ractor message.</p>
<p>Sorry, this is long.<br>
Points 1 to 3 look at possible current solutions and why they aren't great.<br>
Point 4 discusses how Elixir/Erlang's builtin filtering allows responses.<br>
Last point proposes one of the many APIs that would allow responses.</p>
<p>Details:</p>
<p>If I want to program a "server" using Ractor, there has to be some way to receive the data from it.<br>
To simplify, say I want a global <code>Config</code> that can be used to set/retrieve some global config parameters.<br>
To set a parameter, I can use <code>server.send [:set, :key, 'value']</code>.<br>
But what about retrieving? There is no good way to achieve that with the current API.</p>
<ol>
<li>"pull" API</li>
</ol>
<p>It is not safe, as two clients could send a <code>:set</code> before the server answers, and the clients could resolve their <code>server.take</code> in the reverse order.</p>
<p>Another issue is that <code>Ractor.yield</code> is blocking, so the unexpected death of the client could mean the server hangs, and subsequent requests/responses are desynchronized and thus wrong.</p>
<p>My impression is that the "pull" API is best only used for monitoring of Ractors, rescuing exceptions, etc., or otherwise reserved for Ractors that are not shared, is this correct?</p>
<ol start="2">
<li>"push" API</li>
</ol>
<p>It seems much more appropriate to design a server such that one sends the client ractor with the push API. E.g. the client calls <code>server.send [:retrieve, :key, Ractor.current]</code>; the server can use the last element <code>cient_ractor</code> to respond with <code>client_ractor.send 'value'</code> that is non-blocking.</p>
<p>The client can then call <code>Ractor.receive</code>, immediately or later, to get the answer.</p>
<p>This is perfect, <em>except</em> that the client can not use <code>Ractor.receive</code> for any other purpose. It can not act itself a server, or if it calls multiple servers then it must do so synchroneously. Otherwise it might <code>receive</code> a request for something other than the response it was waiting for.</p>
<ol start="3">
<li>create Ractor + "push" + "pull"</li>
</ol>
<p>The only way I can think of currently is to create a temporary private Ractor (both to be able to use the "pull" and the "push" API):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># on the client:</span>
<span class="n">response</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">server</span><span class="p">,</span> <span class="o">*</span><span class="n">etc</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">server</span><span class="p">,</span> <span class="o">*</span><span class="n">etc</span><span class="o">|</span>
<span class="n">server</span><span class="p">.</span><span class="nf">send</span> <span class="p">[</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="ss">:key</span><span class="p">,</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">].</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span><span class="p">(</span><span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="p">}.</span><span class="nf">take</span>
<span class="c1"># on the server</span>
<span class="k">case</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span>
<span class="k">in</span> <span class="p">[</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">client_ractor</span><span class="p">]</span>
<span class="n">client_ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="s1">'response'</span><span class="p">)</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre>
<p>I fear this would be quite inefficient (one Ractor per request, extra <code>move</code> of data) and seems very verbose.</p>
<ol start="4">
<li>Filtered <code>receive</code>
</li>
</ol>
<p>If I look at Elixir/Erlang, this is not an issue because the equivalent of <code>Ractor.receive</code> has builtin pattern matching.</p>
<p>The key is that unmatched messages are <a href="https://www.erlang-solutions.com/blog/receiving-messages-in-elixir-or-a-few-things-you-need-to-know-in-order-to-avoid-performance-issues.html#receiving-messages-with-%E2%80%9Ca-priority%E2%80%9D" class="external">queued for later retrieval</a>. This way there can be different <code>Ractor.receive</code> used in different ways in the same Ractor and they will not interact (assuming they use different patterns).</p>
<p>For a general server ("gen_server"), a unique tag is created for each request, that is <a href="https://stackoverflow.com/questions/56741322/gen-serverreply-2-format-of-message-sent-to-client" class="external">sent with the request and with the response</a></p>
<p>The same pattern is possible to implement with Ruby but this can only work if as long as all the <code>Ractor.receive</code> use this implementation in a given Ractor, it has to be thread-safe, etc.</p>
<p>Issue is that it may not be possible to have the same protocol and access to the same <code>receive</code> method, in particular if some of the functionality is provided in a gem.</p>
<ol start="5">
<li>In conclusion...</li>
</ol>
<p>The API of <code>Ractor</code> is currently lacking a good way to handle responses.</p>
<p>It needs to allow filtering/subdivision of the inbox in some way.</p>
<p>One API could be to add a <code>tag: nil</code> parameter to <code>Ractor#send</code> and <code>Ractor.receive</code> that would use that value to match.</p>
<p>A server could decide to use the default <code>nil</code> tag for it's main API, and ask its clients to specify a tag for a response:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">my_tag</span> <span class="o">=</span> <span class="ss">:some_return_tag</span>
<span class="n">server</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="ss">:key</span><span class="p">,</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">,</span> <span class="n">my_tag</span><span class="p">)</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span> <span class="ss">tag: </span><span class="n">my_tag</span>
<span class="c1"># on the server</span>
<span class="k">case</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span>
<span class="k">in</span> <span class="p">[</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">client_ractor</span><span class="p">,</span> <span class="n">client_tag</span><span class="p">]</span>
<span class="n">client_ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="s1">'response'</span><span class="p">,</span> <span class="ss">tag: </span><span class="n">client_tag</span><span class="p">)</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre>
<p>Tags would have to be Ractor-shareable objects and they could be compared by identity.</p>
<p>Note that messages sent with a non-nil tag (e.g. <code>send 'value' tag: 42</code>) would not be matched by <code>Ractor.receive</code>.<br>
Maybe we should allow for a special <code>tag: :*</code> to match any tag?</p>
<p>There are other solutions possible; a request ID could be returned by <code>Ractor#send</code>, or there could be an API to create object for returns (like a "Self-addressed stamped envelope"), etc.</p>
<p>The basic filtering API I'm proposing has the advantage of being reasonable easy to implement efficiently and still allowing other patterns (for example handling messages by priority, assuming there can be a 0 timeout, see <a class="issue tracker-2 status-2 priority-4 priority-default" title="Feature: Timeouts (Assigned)" href="https://bugs.ruby-lang.org/issues/17363">#17363</a>), but I'll be happy as long as we can offer efficient and reliable builtin ways to respond to Ractor messages.</p> Ruby master - Feature #17357 (Open): `Queue#pop` should have a block form for closed queueshttps://bugs.ruby-lang.org/issues/173572020-12-01T01:42:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It is currently difficult to reliably distinguish a <code>nil</code> value in a queue from the <code>nil</code> that is returned when a Queue is closed:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">n</span> <span class="o">=</span> <span class="mi">100_000</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">t2</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">times</span> <span class="p">{</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">pass</span> <span class="p">}}</span> <span class="c1"># to make things less predictable</span>
<span class="n">n</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">count</span> <span class="k">do</span>
<span class="n">q</span> <span class="o">=</span> <span class="no">Queue</span><span class="p">.</span><span class="nf">new</span>
<span class="n">t</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="n">q</span><span class="p">.</span><span class="nf">pop</span><span class="p">;</span> <span class="n">result</span> <span class="o"><<</span> <span class="n">q</span><span class="p">.</span><span class="nf">closed?</span> <span class="p">}</span>
<span class="n">q</span> <span class="o"><<</span> <span class="kp">nil</span>
<span class="n">q</span><span class="p">.</span><span class="nf">close</span>
<span class="n">t</span><span class="p">.</span><span class="nf">join</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="n">result</span><span class="p">.</span><span class="nf">count</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="c1"># => some number usually > 9990 and < 10000</span>
</code></pre>
<p>To be completely sure, one needs a Mutex or wrap/unwrap <code>nil</code> values.</p>
<p><code>Queue#pop</code> should offer a surefire way to handle closed queues. I propose that an optional block be called in this case:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">q</span> <span class="o">=</span> <span class="no">Queue</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">close</span>
<span class="n">q</span><span class="p">.</span><span class="nf">pop</span> <span class="c1"># => nil</span>
<span class="n">q</span><span class="p">.</span><span class="nf">pop</span> <span class="p">{</span> <span class="ss">:closed</span> <span class="p">}</span> <span class="c1"># => :closed</span>
</code></pre>
<p>Proposed PR: <a href="https://github.com/ruby/ruby/pull/3830" class="external">https://github.com/ruby/ruby/pull/3830</a></p> Ruby master - Misc #17329 (Closed): Doc for pattern match?https://bugs.ruby-lang.org/issues/173292020-11-17T01:59:34Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Is there an official doc for pattern matching?</p>
<p>I note that <code>case</code> in <a href="https://ruby-doc.org/core-2.7.2/doc/syntax/control_expressions_rdoc.html" class="external">https://ruby-doc.org/core-2.7.2/doc/syntax/control_expressions_rdoc.html</a> does not mention it, and <code>in</code> does not appear.</p> Ruby master - Feature #17286 (Open): `Ractor.new` should accept `move: true`https://bugs.ruby-lang.org/issues/172862020-10-26T05:10:00Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Another surprise when writing my backport is that <code>Ractor.new</code> does not accept <code>move:</code> keyword argument.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">data</span><span class="o">|</span> <span class="o">...</span> <span class="p">}</span>
<span class="c1"># equivalent to</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="n">data</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span><span class="p">;</span> <span class="o">...</span> <span class="p">}.</span><span class="nf">tap</span> <span class="p">{</span> <span class="o">|</span><span class="n">r</span><span class="o">|</span> <span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span> <span class="p">}</span>
</code></pre> Ruby master - Feature #17285 (Open): Less strict `Ractor.select`https://bugs.ruby-lang.org/issues/172852020-10-26T02:49:44Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Summary: could we have a way for <code>Ractor.select</code> to skip ractors with closed queues and raise only if no ractor with an open queue remains?</p>
<p>Detail:</p>
<p>I <a href="https://github.com/marcandre/backports/pull/153" class="external">backported <code>Ractor</code> for earlier Ruby versions</a>, as I'd like to use it in some gems that would work great in 3.0 and work ok in older Rubies without rewriting. That was a lot of fun :-)</p>
<p>One surprise for me was that <code>Ractor.select</code> enforces that no given ractor is terminated(*).</p>
<p>This means that one must remove terminated ractors from a pool of ractors before calling <code>select</code> again:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">pool</span> <span class="o">=</span> <span class="mi">20</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="n">do_processing</span> <span class="p">}</span> <span class="p">}</span>
<span class="mi">20</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
<span class="n">ractor</span><span class="p">,</span> <span class="n">result</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">pool</span><span class="p">)</span>
<span class="n">handle</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="n">pool</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="n">ractor</span><span class="p">)</span> <span class="c1"># necessary!</span>
<span class="k">end</span>
</code></pre>
<ol start="0">
<li>
<p>This can be tedious, but I know I'm very lazy</p>
</li>
<li>
<p>It is not convenient to share a pool between different ractors. Try writing code that starts 5 ractors that would consume the results from <code>pool</code> above.</p>
</li>
<li>
<p>It might require special synchronization if the ractors may yield a variable number of values:</p>
</li>
</ol>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">do_processing</span>
<span class="nb">rand</span><span class="p">(</span><span class="mi">10</span><span class="p">).</span><span class="nf">times</span> <span class="k">do</span> <span class="p">{</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:a_result</span>
<span class="p">}</span>
<span class="ss">:finish</span>
<span class="k">end</span>
<span class="n">pool</span> <span class="o">=</span> <span class="mi">20</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="n">do_processing</span> <span class="p">}</span> <span class="p">}</span>
<span class="k">until</span> <span class="n">pool</span><span class="p">.</span><span class="nf">empty?</span> <span class="k">do</span>
<span class="n">ractor</span><span class="p">,</span> <span class="n">result</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">pool</span><span class="p">)</span>
<span class="k">if</span> <span class="n">result</span> <span class="o">==</span> <span class="ss">:finish</span>
<span class="n">pool</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="n">ractor</span><span class="p">)</span>
<span class="k">else</span>
<span class="n">do_something_with</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I would like to propose that it would be allowed (by default or at least via keyword parameter) to call <code>select</code> on terminated ractors, as long as there is at least one remaining open one.</p>
<p>This would make it very to resolve 1 and 2 above. Here's an example combine them both together:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">do_processing</span>
<span class="nb">rand</span><span class="p">(</span><span class="mi">10</span><span class="p">).</span><span class="nf">times</span> <span class="k">do</span> <span class="p">{</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:a_result</span>
<span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">close</span> <span class="c1"># avoid yielding a value at the end</span>
<span class="k">end</span>
<span class="n">pool</span> <span class="o">=</span> <span class="mi">20</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="n">do_processing</span> <span class="p">}</span> <span class="p">}.</span><span class="nf">freeze</span>
<span class="mi">5</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span> <span class="c1"># divide processing into 5 ractors</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">pool</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">pool</span><span class="o">|</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">_ractor</span><span class="p">,</span> <span class="n">result</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">pool</span><span class="p">)</span> <span class="c1"># with my proposed lax select</span>
<span class="n">do_something_with</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The <code>loop</code> above terminates when <code>Ractor.select</code> raises an error once the whole <code>pool</code> is terminated.</p>
<p>I'm new to actors but my intuition currently is that I will never want to take care of a pool of Ractors myself and would always prefer if <code>Ractor.select</code> did it for me. Are there use-cases where <code>Ractor.select</code> raising an error if it encounters a closed queue is helpful?</p>
<p>Notes:</p>
<ul>
<li>(*) <code>Ractor.select</code> doesn't really enforce ractors to be opened of course, it will work if the ractors are consumed in the right order, like in this example by chance:</li>
</ul>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">10</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span> <span class="k">do</span>
<span class="n">r</span> <span class="o">=</span> <span class="mi">2</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="nb">sleep</span><span class="p">(</span><span class="mf">0.05</span><span class="p">);</span> <span class="ss">:ok</span> <span class="p">}</span> <span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">r</span><span class="p">)</span> <span class="c1"># Get first available result</span>
<span class="c1"># Don't remove the ractor from `r`</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">r</span><span class="p">).</span><span class="nf">last</span> <span class="k">rescue</span> <span class="ss">:error</span> <span class="c1"># Get second result</span>
<span class="k">end</span>
<span class="c1"># => [:ok, :error, :error, :error, :error, :error, :error, :ok, :ok, :ok]</span>
</code></pre>
<ul>
<li>I think <code>Ractor.select(*pool, yield_value: 42)</code> would raise only if the current outgoing queue is closed, even if the whole pool was terminated</li>
<li>Similarly <code>Ractor.select(*pool, Ractor.current)</code> would raise only if the current incomming queue is also closed.</li>
</ul> Ruby master - Bug #17197 (Rejected): Some Hash methods still have arity 2 instead of 1https://bugs.ruby-lang.org/issues/171972020-09-28T02:13:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p><code>Hash#each</code> was changed recently to have arity of 1.<br>
All other methods of <code>Hash</code> should behave the same.<br>
Much has been fixed since <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Enumerable & Hash yielding arity (Closed)" href="https://bugs.ruby-lang.org/issues/14015">#14015</a>, but some remains:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Some methods consistently have arity 2:</span>
<span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">}.</span><span class="nf">select</span><span class="p">(</span> <span class="o">&-></span><span class="p">(</span><span class="n">_kvp</span><span class="p">)</span> <span class="p">{}</span> <span class="p">)</span> <span class="c1"># => ArgumentError (wrong number of arguments (given 2, expected 1))</span>
</code></pre>
<p>All in all: <code>%i[select keep_if delete_if reject to_h]</code> have their arity still set at 2.</p> Ruby master - Feature #17171 (Rejected): Why is the visibility of constants not affected by `priv...https://bugs.ruby-lang.org/issues/171712020-09-15T20:34:44Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">call_me</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="no">SOME_DATA</span> <span class="o">=</span> <span class="sx">%i[...]</span><span class="p">.</span><span class="nf">freeze</span> <span class="c1"># is public, why not private?</span>
<span class="k">def</span> <span class="nf">calc_stuff</span> <span class="c1"># is private, ok.</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>It's probably a naive question, but why shouldn't <code>SOME_DATA</code>'s visibility be private?</p>
<p>When writing gems, more often than not the constants that I write are not meant for public consumption. I find it redundant (and tiresome) to explicitly write <code>private_constant :SOME_DATA</code>.</p> Ruby master - Feature #17145 (Rejected): Ractor-aware `Object#deep_freeze`https://bugs.ruby-lang.org/issues/171452020-09-03T18:42:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to propose <code>Object#deep_freeze</code>:</p>
<p>Freezes recursively the contents of the receiver (by calling <code>deep_freeze</code>) and<br>
then the receiver itself (by calling <code>freeze</code>).<br>
Values that are shareable via <code>Ractor</code> (e.g. classes) are never frozen this way.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># freezes recursively:</span>
<span class="n">ast</span> <span class="o">=</span> <span class="p">[</span><span class="ss">:hash</span><span class="p">,</span> <span class="p">[</span><span class="ss">:pair</span><span class="p">,</span> <span class="p">[</span><span class="ss">:str</span><span class="p">,</span> <span class="s1">'hello'</span><span class="p">],</span> <span class="p">[</span><span class="ss">:sym</span><span class="p">,</span> <span class="ss">:world</span><span class="p">]]].</span><span class="nf">deep_freeze</span>
<span class="n">ast</span><span class="p">.</span><span class="nf">dig</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1"># => [:str, 'hello']</span>
<span class="n">ast</span><span class="p">.</span><span class="nf">dig</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span><span class="nf">compact!</span> <span class="c1"># => FrozenError</span>
<span class="c1"># does not freeze classes:</span>
<span class="p">[[</span><span class="no">String</span><span class="p">]].</span><span class="nf">deep_freeze</span>
<span class="no">String</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># => false</span>
<span class="c1"># calls `freeze`:</span>
<span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">freeze</span>
<span class="n">build_cache!</span>
<span class="nb">puts</span> <span class="s2">"Ready for freeze"</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="p">[[[</span><span class="no">Foo</span><span class="p">.</span><span class="nf">new</span><span class="p">]]].</span><span class="nf">deep_freeze</span> <span class="c1"># => Outputs "Ready for freeze"</span>
</code></pre>
<p>I think a variant <code>deep_freeze!</code> that raises an exception if the result isn't Ractor-shareable would be useful too:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Fire</span>
<span class="k">def</span> <span class="nf">freeze</span>
<span class="c1"># do not call super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="no">Fire</span><span class="p">.</span><span class="nf">new</span><span class="p">]</span>
<span class="n">x</span><span class="p">.</span><span class="nf">deep_freeze!</span> <span class="c1"># => "Could not be deeply-frozen: #<Fire:0x00007ff151994748>"</span>
</code></pre> Ruby master - Bug #17124 (Closed): Wrong "ambiguous first argument" warninghttps://bugs.ruby-lang.org/issues/171242020-08-18T20:02:54Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="sh syntaxhl" data-language="sh"><span class="nv">$ </span>ruby <span class="nt">-v</span> <span class="nt">-e</span> <span class="s2">"x='a'; x.match? /[a-z]/"</span>
ruby 2.8.0dev <span class="o">(</span>2020-07-30T14:07:06Z master 352895b751<span class="o">)</span> <span class="o">[</span>x86_64-darwin18]
<span class="nt">-e</span>:1: warning: ambiguous first argument<span class="p">;</span> put parentheses or a space even after <span class="sb">`</span>/<span class="s1">' operator
</span></code></pre>
<p>There is no <code>/</code> operator in there and there is also no ambiguity as adding a space after the first <code>/</code> is a syntax error.</p>
<p>Is it possible to remove the warning altogether when the argument is lexed as a regexp?</p>
<p>The message could use a rewording too, maybe "ambiguous first argument; put parentheses around argument or add a space after `/' operator"</p> Ruby master - Bug #17092 (Closed): Array#flatten with finite depth should flatten recursive arrayshttps://bugs.ruby-lang.org/issues/170922020-07-30T12:29:24Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Recursive arrays can not be flattened currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="p">[];</span> <span class="n">a</span> <span class="o"><<</span> <span class="n">a</span>
<span class="n">a</span><span class="p">.</span><span class="nf">flatten</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => tried to flatten recursive array</span>
</code></pre>
<p>The only valid reason to raise an error for recursive arrays is for flatten with no argument (or negative argument); the case for finite-depth flatten is not problematic.</p>
<p>This fix has the bonus of speeding up the finite-depth case in general.</p>
<p>I will merge <a href="https://github.com/ruby/ruby/pull/3374" class="external">https://github.com/ruby/ruby/pull/3374</a>, <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/4">@nobu (Nobuyoshi Nakada)</a> asked for backports.</p> Ruby master - Bug #17031 (Closed): `Kernel#caller_locations(m, n)` should be optimizedhttps://bugs.ruby-lang.org/issues/170312020-07-14T19:07:29Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p><code>Kernel#caller_locations(1, 1)</code> currently appears to needlessly allocate memory for the whole backtrace.</p>
<p>It allocates ~20kB for a 800-deep stacktrace, vs 1.6 kB for a shallow backtrace.<br>
It is also much slower for long stacktraces: about 7x slower for a 800-deep backtrace than for a shallow one.</p>
<p>Test used:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">do_something</span>
<span class="n">location</span> <span class="o">=</span> <span class="n">caller_locations</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span><span class="nf">first</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">depth</span><span class="p">,</span> <span class="n">trigger</span><span class="p">)</span>
<span class="n">do_something</span> <span class="k">if</span> <span class="n">depth</span> <span class="o">==</span> <span class="n">trigger</span>
<span class="nb">test</span><span class="p">(</span><span class="n">depth</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">trigger</span><span class="p">)</span> <span class="k">unless</span> <span class="n">depth</span> <span class="o">==</span> <span class="mi">0</span>
<span class="k">end</span>
<span class="nb">require</span> <span class="s1">'benchmark/ips'</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">(</span><span class="ss">:short_backtrace</span> <span class="p">)</span> <span class="p">{</span><span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="mi">800</span><span class="p">)}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">(</span><span class="ss">:long_backtrace</span> <span class="p">)</span> <span class="p">{</span><span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span> <span class="mi">0</span><span class="p">)}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">(</span><span class="ss">:no_caller_locations</span><span class="p">)</span> <span class="p">{</span><span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)}</span>
<span class="k">end</span>
<span class="nb">require</span> <span class="s1">'memory_profiler'</span>
<span class="no">MemoryProfiler</span><span class="p">.</span><span class="nf">report</span> <span class="p">{</span> <span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="mi">800</span><span class="p">)</span> <span class="p">}.</span><span class="nf">pretty_print</span><span class="p">(</span><span class="ss">scale_bytes: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">detailed_report: </span><span class="kp">false</span><span class="p">)</span>
<span class="no">MemoryProfiler</span><span class="p">.</span><span class="nf">report</span> <span class="p">{</span> <span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">}.</span><span class="nf">pretty_print</span><span class="p">(</span><span class="ss">scale_bytes: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">detailed_report: </span><span class="kp">false</span><span class="p">)</span>
</code></pre>
<p>Found when checking memory usage on RuboCop.</p> Ruby master - Bug #17030 (Closed): Enumerable#grep{_v} should be optimized for Regexphttps://bugs.ruby-lang.org/issues/170302020-07-13T20:26:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">array</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span> <span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="n">e</span><span class="p">.</span><span class="nf">match?</span><span class="p">(</span><span class="no">REGEXP</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>is about three times faster and six times more memory efficient than</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">array</span><span class="p">.</span><span class="nf">grep</span><span class="p">(</span><span class="no">REGEXP</span><span class="p">)</span>
</code></pre>
<p>This is because <code>grep</code> calls <code>Regexp#===</code>, which creates useless <code>MatchData</code>.</p> Ruby master - Bug #16996 (Closed): Hash should avoid doing unnecessary rehashhttps://bugs.ruby-lang.org/issues/169962020-06-27T08:20:32Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Pop quiz: Which is the fastest way to get a copy of a Hash <code>h</code>?</p>
<p>If, like me, you thought <code>h.dup</code> (of course, right?), you are actually wrong.</p>
<p>The fastest way is to call <code>h.merge</code>. Try it:</p>
<pre><code>require 'benchmark/ips'
lengths = 1..50
h = lengths.to_h { |i| ['x' * i, nil] }
Benchmark.ips do |x|
x.report("dup") { h.dup }
x.report("merge") { h.merge }
end
</code></pre>
<p>I get</p>
<pre><code>Calculating -------------------------------------
dup 259.233k (± 9.2%) i/s - 1.285M in 5.013445s
merge 944.095k (± 8.2%) i/s - 4.693M in 5.005315s
</code></pre>
<p>Yup, it's <em>3.5x faster</em> with this example!!</p>
<p>Why? Because <code>Hash#dup</code> does a rehash, and <code>merge</code> does not.</p>
<p>Pop quiz 2: which methods of <code>Hash</code> that produce a new hash do a rehash?</p>
<p>Answer: it depends on the method and on the Ruby version</p>
<pre><code>
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| Does this rehash? | head | 2.7 | 2.6 | 2.5 | 2.4 | 2.3 | 2.2 | 2.1 | 2.0 |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.dup / clone | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.select{true} / reject{false} | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.select!{true} / reject!{false}| Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| sub_h.to_h | Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.merge({}) | Ø | Ø | Ø | Ø | Yes | Yes | Yes | Yes | Yes |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.merge | Ø | Ø | Ø | n/a |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.transform_values(&:itself) | Ø | Ø | Yes | Yes | Yes | n/a |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
(where `sub_h = Class.new(Hash).replace(h)`, Ø = no rehash)
</code></pre>
<p>So in Ruby head, doing <code>h.merge({})</code> or even <code>h.transform_values(&:itself)</code> will be much faster than <code>h.dup</code> (but slower in Ruby 2.4) (*)</p>
<p>Notice that <code>select</code> rehashes, but <code>select!</code> doesn't, so the fastest way to do a <code>select</code> in Ruby is... not to call select and instead to actually do a <code>merge.select!</code>! (*)</p>
<p>*: on hashes with non-negligible hash functions</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Hash</span>
<span class="k">def</span> <span class="nf">fast_select</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="n">merge</span><span class="p">.</span><span class="nf">select!</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="c1"># don't call dup because it's slow</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"select"</span><span class="p">)</span> <span class="p">{</span> <span class="n">h</span><span class="p">.</span><span class="nf">select</span><span class="p">{</span><span class="kp">true</span><span class="p">}</span> <span class="p">}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"fast_select"</span><span class="p">)</span> <span class="p">{</span> <span class="n">h</span><span class="p">.</span><span class="nf">fast_select</span><span class="p">{</span><span class="kp">true</span><span class="p">}</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre>
<p>On my test case above, <code>fast_select</code> is <em>2.5x faster</em> than <code>select</code>. <code>fast_select</code> will always return exactly the same result (unless the receiver needed a rehash).</p>
<p>Pop quiz 3: Is this a bug or a feature?</p>
<p>It should be clear that no feature of Ruby should be re-implementable in Ruby with a 3.5x / 2.5x speed gain, so many would think "of course it's a bug".</p>
<p>Well, <a href="https://bugs.ruby-lang.org/issues/16121" class="external">https://bugs.ruby-lang.org/issues/16121</a> seems to think that <code>Hash#dup</code>'s rehash is a feature...<br>
Why?<br>
Because there is actually a test that <code>dup</code> does a rehash<br>
Why?<br>
Because a test of <code>Set</code> was failing otherwise!<br>
Commit: <a href="https://github.com/ruby/ruby/commit/a34a3c2caae4c1fbd" class="external">https://github.com/ruby/ruby/commit/a34a3c2caae4c1fbd</a><br>
Short discussion: <a href="http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/48040?47945-48527" class="external">http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/48040?47945-48527</a><br>
Actual test: <a href="https://github.com/ruby/ruby/blob/master/test/test_set.rb#L621-L625" class="external">https://github.com/ruby/ruby/blob/master/test/test_set.rb#L621-L625</a><br>
Why?<br>
This test construct a <code>Set</code> that needs to be rehashed (by mutating an element of the set after it is added), and then checks that <code>rehash_me == rehash_me.clone</code>.<br>
That test is bogus. It passes for obscure and undocumented reasons, and <code>rehash_me.clone == rehash_me</code> doesn't pass.<br>
Today, it is official that sets with elements that are later mutated must be <code>Set#reset</code>, so it is official that this should not be relied upon.</p>
<p>Probably more clear is the case of <code>select/reject</code> (but I didn't check for failing test), and even more clear that <code>merge</code> changed in Ruby 2.5 and <code>transform_values</code> in 2.7, but not a single <code>NEWS</code> file mentions the word "rehash".</p>
<p>My conclusion is that Hash should avoid doing an unnecessary rehash: <code>dup</code>/<code>clone</code>/<code>select</code>/<code>reject</code>. We probably should add a reminder in the <code>NEWS</code> that if anyone mutates a key of a Hash, or an element of a Set and does not call <code>rehash</code>/<code>reset</code>, improper behavior should be expected.</p>
<p>Let's make <code>Hash#dup/clone/select/reject</code> fast please.</p>
<p>Any objection?</p> Ruby master - Feature #16995 (Closed): Sets: <=> should be specializedhttps://bugs.ruby-lang.org/issues/169952020-06-26T20:43:58Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>This is quite minor, but <code>Set#<=></code> should be refined.</p>
<p>Reminder: <code>Set</code> defines <code><</code>, <code>></code>, etc. as inclusion, but does not have a corresponding <code><=></code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o"><</span> <span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="c1"># => true</span>
<span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o"><=></span> <span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="c1"># => nil, should be -1</span>
<span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o"><=></span> <span class="no">Set</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="c1"># => nil, ok, not orderable</span>
</code></pre>
<p>The official stated reason for <code>Set</code> to <em>not</em> implement is that some sets are not comparable. That is exactly what <code>nil</code> result type is for IMO. Sets are partically ordered and <code><=></code> should reflect that. <a href="https://en.wikipedia.org/wiki/Partially_ordered_set" class="external">https://en.wikipedia.org/wiki/Partially_ordered_set</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o"><</span> <span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="c1"># => true</span>
<span class="p">[</span><span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]].</span><span class="nf">sort</span> <span class="c1"># => ArgumentError, should be [Set[1], Set[1, 2]]</span>
<span class="p">[</span><span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="no">Set</span><span class="p">[</span><span class="mi">2</span><span class="p">]].</span><span class="nf">sort</span> <span class="c1"># => ArgumentError, ok, can't be ordered</span>
</code></pre>
<p>This is <em>exactly the same</em> idea as <code>Class</code>, which correctly refines <code><=></code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Array</span> <span class="o"><</span> <span class="no">Enumerable</span> <span class="c1"># => true</span>
<span class="no">Array</span> <span class="o"><=></span> <span class="no">Enumerable</span> <span class="c1"># => -1, ok</span>
<span class="p">[</span><span class="no">Array</span><span class="p">,</span> <span class="no">Enumerable</span><span class="p">].</span><span class="nf">sort</span> <span class="c1"># => [Array, Enumerable]</span>
<span class="p">[</span><span class="no">Array</span><span class="p">,</span> <span class="no">String</span><span class="p">].</span><span class="nf">sort</span> <span class="c1"># => ArgumentError (comparison of Class with Class failed), ok</span>
</code></pre> Ruby master - Feature #16994 (Feedback): Sets: shorthand for frozen sets of symbols / stringshttps://bugs.ruby-lang.org/issues/169942020-06-26T20:32:22Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I would like a shorthand syntax for <em>frozen Sets of symbols or of strings</em>.</p>
<p>I am thinking of:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">%</span><span class="n">ws</span><span class="p">{</span><span class="n">hello</span> <span class="n">world</span><span class="p">}</span> <span class="c1"># => Set['hello', 'world'].freeze</span>
<span class="o">%</span><span class="n">is</span><span class="p">{</span><span class="n">hello</span> <span class="n">world</span><span class="p">}</span> <span class="c1"># => Set[:hello, :world].freeze</span>
</code></pre>
<p>The individual strings would be frozen. These literals would be created once at parse time (like Regex are):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span>
<span class="nb">p</span> <span class="o">%</span><span class="n">ws</span><span class="p">{</span><span class="n">hello</span> <span class="n">world</span><span class="p">}.</span><span class="nf">object_id</span>
<span class="k">end</span>
<span class="n">foo</span>
<span class="n">foo</span> <span class="c1"># => prints the same id twice</span>
</code></pre>
<p>We should consider these sets to return a unique frozen <code>to_a</code>.</p>
<p>Reminder: Ruby has literal notations for <code>Rational</code> and <code>Complex</code>. I've sadly never had to use either.<br>
I would venture to say that <code>Complex</code> is much less used than <code>Sets</code>, and that sets are underused.</p>
<p>Reminder: previous discussion for builtin syntax was not for frozen literal, strings or symbols specifically: <a href="https://bugs.ruby-lang.org/issues/5478" class="external">https://bugs.ruby-lang.org/issues/5478</a></p>
<p>For builtin notations for generic sets (i.e. <em>unfrozen</em> or containing <em>other than string/symbol</em>), please discuss in another issue.</p> Ruby master - Feature #16993 (Open): Sets: from hash keys using Hash#key_sethttps://bugs.ruby-lang.org/issues/169932020-06-26T20:31:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>To create a set from hash keys currently implies a temporary array for all keys, rehashing all those keys and rebuilding a hash. Instead, the hash could be copied and its values set to <code>true</code>.</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">a: </span><span class="mi">1</span><span class="p">}</span>
<span class="c1"># Now:</span>
<span class="no">Set</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">h</span><span class="p">.</span><span class="nf">keys</span><span class="p">)</span> <span class="c1"># => Set[:a]</span>
<span class="c1"># After</span>
<span class="n">h</span><span class="p">.</span><span class="nf">key_set</span> <span class="c1"># => Set[:a], efficiently.</span>
</code></pre> Ruby master - Feature #16991 (Closed): Sets: add Set#joinhttps://bugs.ruby-lang.org/issues/169912020-06-26T20:29:01Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to add <code>#join</code> to <code>Set</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Now:</span>
<span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">join</span><span class="p">(</span><span class="s1">'x'</span><span class="p">)</span> <span class="c1"># => NoMethodError</span>
<span class="c1"># After</span>
<span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">join</span><span class="p">(</span><span class="s1">'x'</span><span class="p">)</span> <span class="c1"># => "1x2x3"</span>
</code></pre>
<p>I'd make this join never recursive. (I've never wanted to use the recursivity of <code>Array#join</code>, but it may very well just be my particular experience)</p>
<p>Reminder: Why there is no <code>Enumerable#join</code>: <a href="https://bugs.ruby-lang.org/issues/1893" class="external">https://bugs.ruby-lang.org/issues/1893</a></p> Ruby master - Feature #16990 (Open): Sets: operators compatibility with Arrayhttps://bugs.ruby-lang.org/issues/169902020-06-26T20:27:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We currently have <code>set <operator> array</code> work fine:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Set</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="c1"># => Set[1, 2]</span>
</code></pre>
<p>Nothing works in the reverse order:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="no">Set</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="c1"># => no implicit conversion of Set into Array</span>
<span class="c1"># should be:</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="no">Set</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="c1"># => [1, 2]</span>
</code></pre>
<a name="set-like-operators"></a>
<h4 >set-like operators<a href="#set-like-operators" class="wiki-anchor">¶</a></h4>
<p>Note that the situation is particularly frustrating for <code>&</code>, <code>|</code> and <code>-</code>.<br>
If someone wants to do <code>ary - set</code>, one <strong>has</strong> to do <code>ary - set.to_a</code> which will, internally, do a <code>to_set</code>, so what is happening is <code>set.to_a.to_set</code>!! (assuming <code>ary</code> is over <code>SMALL_ARRAY_LEN == 16</code> size, otherwise it's still doing in <code>O(ary * set)</code> instead of <code>O(ary)</code>).</p>
<p>The same holds with <code>&</code> and <code>|</code>; see order issue as to why this can <em>not</em> (officially) be done any other way.</p>
<p>Reminder:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">ary</span> <span class="o">&</span> <span class="n">ary</span><span class="p">.</span><span class="nf">reverse</span> <span class="c1"># => ary</span>
<span class="no">Set</span><span class="p">[</span><span class="o">*</span><span class="n">ary</span><span class="p">]</span> <span class="o">&</span> <span class="no">Set</span><span class="p">[</span><span class="o">*</span><span class="n">ary</span><span class="p">.</span><span class="nf">reverse</span><span class="p">]</span> <span class="c1"># => Set[*ary.reverse], officially order is indeterminate</span>
</code></pre> Ruby master - Bug #15731 (Closed): Wrong evaluation of many keyword default arguments in 2.3 - 2.5https://bugs.ruby-lang.org/issues/157312019-03-27T17:53:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I don't know if it's worth fixing at this point, but we found a strange bug with evaluation of default keyword arguments when there are many of them (more than 32).</p>
<pre><code>def foo(
k0: puts(0), k1: puts(1), k2: puts(2), k3: puts(3), k4: puts(4),
k5: puts(5), k6: puts(6), k7: puts(7), k8: puts(8), k9: puts(9),
k10: puts(10), k11: puts(11), k12: puts(12), k13: puts(13), k14: puts(14),
k15: puts(15), k16: puts(16), k17: puts(17), k18: puts(18), k19: puts(19),
k20: puts(20), k21: puts(21), k22: puts(22), k23: puts(23), k24: puts(24),
k25: puts(25), k26: puts(26), k27: puts(27), k28: puts(28), k29: puts(29),
k30: puts(30), k31: puts(31), k32: puts(32), k33: puts(33)
)
k33
end
puts "No params:"
foo # Should print 1 to 33
puts "Only k33 param:"
foo(k33: 1) # Should print 1 to 32
puts "Only k32 and k33 params:"
r = foo(k32: 1, k33: 1) # Should print 1 to 31 and return 1
puts "Result: #{r.inspect}"
</code></pre>
<p>Ruby 2.4:<br>
last case is wrong. It prints 1 to 33 instead of 1 to 31 and returns <code>nil</code> instead of 1.</p>
<p>Ruby 2.5:<br>
same result for last case<br>
first two cases evaluates the default exactly the wrong parameters: those that are given and not for those not given. So it prints nothing and 33 respectively, instead of 1 to 33 and 1 to 32!</p>
<p>Ruby 2.6:<br>
results are ok</p>
<p>This strange behavior disappears with fewer keyword arguments.</p> Ruby master - Bug #15718 (Closed): YAML raises error when dumping strings with UTF32 encodinghttps://bugs.ruby-lang.org/issues/157182019-03-20T20:21:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="shell syntaxhl" data-language="shell">ruby <span class="nt">-r</span> yaml <span class="nt">-e</span> <span class="s2">"p YAML.dump( ''.force_encoding('UTF-32LE') )"</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
4: from <span class="nt">-e</span>:1:in <span class="sb">`</span><main><span class="s1">'
3: from /Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych.rb:513:in `dump'</span>
2: from /Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych/visitors/yaml_tree.rb:118:in <span class="sb">`</span>push<span class="s1">'
1: from /Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych/visitors/yaml_tree.rb:136:in `accept'</span>
/Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych/visitors/yaml_tree.rb:298:in <span class="sb">`</span>visit_String<span class="s1">': incompatible encoding regexp match (US-ASCII regexp with UTF-32LE string) (Encoding::CompatibilityError)
</span></code></pre>
<p>Surprisingly, this works in Ruby 2.4.x, but not in 2.2, 2.3, 2.5 nor 2.6!</p> Ruby master - Bug #15613 (Closed): Enumerator::Chain#each doesn't relay block signaturehttps://bugs.ruby-lang.org/issues/156132019-02-20T04:29:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, the block given when iterating on the components of a <code>Enumerator::Chain</code> always have arity of -1 and <code>lambda?</code> is always <code>false</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">def</span> <span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">return</span> <span class="n">to_enum</span> <span class="k">unless</span> <span class="n">block</span>
<span class="nb">p</span> <span class="n">block</span><span class="p">.</span><span class="nf">arity</span><span class="p">,</span> <span class="n">block</span><span class="p">.</span><span class="nf">lambda?</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">foo</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span>
<span class="n">foo</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&-></span><span class="p">{})</span> <span class="c1"># => 0, true</span>
<span class="n">foo</span><span class="p">.</span><span class="nf">each</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&-></span><span class="p">{})</span> <span class="c1"># => 0, true</span>
<span class="n">foo</span><span class="p">.</span><span class="nf">chain</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&-></span><span class="p">{})</span> <span class="c1"># => -1, false. Would ideally be 0, true</span>
</code></pre>
<p>It would be preferable if the block information wasn't lost.</p> Ruby master - Bug #15332 (Closed): coverage and InstructionSequence regressionhttps://bugs.ruby-lang.org/issues/153322018-11-22T23:31:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>With the current head:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="nb">require</span> <span class="s1">'coverage'</span>
<span class="no">Coverage</span><span class="p">.</span><span class="nf">start</span>
<span class="no">RubyVM</span><span class="o">::</span><span class="no">InstructionSequence</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="s2">"puts 'hi'"</span><span class="p">,</span> <span class="s1">'hello_world.rb'</span><span class="p">).</span><span class="nf">eval</span>
<span class="no">Coverage</span><span class="p">.</span><span class="nf">result</span> <span class="c1"># => {}, should be {'hello_world.rb' => [1]}</span>
</code></pre>
<p>This is not intended, right?</p> Ruby master - Bug #15206 (Closed): require_relative in std_libhttps://bugs.ruby-lang.org/issues/152062018-10-06T03:17:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I noticed that there are some <code>require</code> for internal files in <code>lib/</code>. Ideally, they would be using <code>require_relative</code> instead. This is faster and more explicit.</p>
<p>Note: <code>require_relative</code> had a potential issue with symlinks that was fixed in 2.5, so libraries that might be loaded from earlier Ruby, like <code>rubygems</code>, can not yet be updated.</p>
<p>I've <a href="https://github.com/ruby/ruby/pull/1976" class="external">created a PR</a> and would like to know if there are comments / objections / things I'm missing.</p> Ruby master - Bug #14674 (Closed): New mismatched indentations warnings?https://bugs.ruby-lang.org/issues/146742018-04-10T17:43:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I recently got a failure in my test suite because ruby head warns of indentation it considers mismatched:</p>
<pre><code>$ ruby -w -e "
case
when :foo
end
"
-e:3: warning: mismatched indentations at 'when' with 'case' at 2
</code></pre>
<p>I hope this is not intentional and will be fixed.</p> Ruby master - Bug #14201 (Closed): Regression due to over optimization of hash splathttps://bugs.ruby-lang.org/issues/142012017-12-18T20:27:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The following doesn't print anything nor raise anything in 2.5.0-rc1 or trunk:</p>
<pre><code>$ ruby -e "{**puts('hello')}; 42"
</code></pre>
<p>It should be the same as in Ruby 2.0-2.4:</p>
<pre><code>hello
-e:1:in `<main>': no implicit conversion of nil into Hash (TypeError)
</code></pre>
<p>Note: If you try to use the hash (e.g. passing as argument, storing in variable), then the correct behavior takes place. Found this bug through DeepCover's test suite.</p> Ruby master - Bug #14031 (Closed): WeakRef example misleading and wronghttps://bugs.ruby-lang.org/issues/140312017-10-19T02:43:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I just noticed that the second part of the doc of <code>WeakRef</code> is misleading and later plainly wrong.</p>
<p>I'm talking about the example with <code>WeakHash</code> in<br>
<a href="https://ruby-doc.org/stdlib-2.4.0/libdoc/weakref/rdoc/WeakRef.html" class="external">https://ruby-doc.org/stdlib-2.4.0/libdoc/weakref/rdoc/WeakRef.html</a></p>
<p>The example shows</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">GC</span><span class="p">.</span><span class="nf">start</span>
<span class="n">c</span><span class="p">[</span><span class="s1">'foo'</span><span class="p">]</span> <span class="c1">#=> nil</span>
<span class="n">c</span><span class="p">[</span><span class="s1">'baz'</span><span class="p">]</span> <span class="c1">#=> nil</span>
<span class="n">c</span><span class="p">[</span><span class="s1">'qux'</span><span class="p">]</span> <span class="c1">#=> nil</span>
</code></pre>
<p>This is very <em>misleading</em>, since even before the GC that would be also the case, because <code>WeakHash</code> didn't redefine the lookup, and that <code>WeakHash.new('foo').eql?('foo')</code> is always <code>false</code>.</p>
<p>The doc goes on with:<br>
"You can see the local variable <code>omg</code> stayed, although its reference in our hash object was garbage collected, along with the rest of the keys and values."</p>
<p>That is <em>wrong</em>. The reference in our hash object was not garbage collected, since <code>omg</code> held on to it. This can be proven with <code>c.values.last # => 'lol'</code>.</p>
<p>My opinion is that fixing this example isn't worth it, and that even fixed it wouldn't add anything to the first simple example on WeakRef. In it's current form, it is worse dans not having it. Unless there are objections, I'll simply remove it.</p> Ruby master - Bug #14014 (Closed): NaN.finite?https://bugs.ruby-lang.org/issues/140142017-10-13T21:23:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Ruby gives contradictory answers for NaN:</p>
<pre><code>> (0/0.0).finite?
=> false
> Complex(0/0.0, 0).finite?
=> true
</code></pre>
<p>Note that <code>(0/0.0).infinite?</code> returns <code>nil</code>, so the float answer of <code>false</code> looks even more wrong.</p>
<p>The two solutions I see are either changing <code>Float#finite?</code> to return <code>true</code> for NaN, or to raise in both cases.</p>
<p>I'd lean towards raising in both cases, as NaN can not be said to be finite or infinite</p> Ruby master - Bug #13973 (Closed): super_method fails on some UnboundMethodshttps://bugs.ruby-lang.org/issues/139732017-10-05T02:01:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p><code>super_method</code> fails to go up the ancestry chain for methods that are only defined in included modules:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">A</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">B</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">C</span>
<span class="kp">include</span> <span class="no">A</span>
<span class="kp">include</span> <span class="no">B</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">D</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="kp">include</span> <span class="no">A</span>
<span class="kp">include</span> <span class="no">B</span>
<span class="k">end</span>
<span class="no">C</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">)</span> <span class="c1"># => #<UnboundMethod: C(B)#foo> (ok)</span>
<span class="no">C</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span> <span class="c1"># => nil (wrong, should be <UnboundMethod: <something>(A)#foo>)</span>
<span class="no">C</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span> <span class="c1"># => #<Method: Object(A)#foo> (ok)</span>
<span class="no">D</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span> <span class="c1"># => #<UnboundMethod: Object(B)#foo> (ok)</span>
<span class="no">D</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span><span class="p">.</span><span class="nf">super_method</span> <span class="c1"># => #<UnboundMethod: Object(A)#foo> (ok)</span>
</code></pre>
<p>Note that the results for C and D's super_method differ slightly, with one outputing "C(B)" and the other "Object(B)". I don't understand why "Object" shows anywhere in my example. I would have expected the output to be "D(B)" in the later case. Should I open a different issue for this?</p> Ruby master - Bug #10831 (Closed): Variable keyword arguments shouldn't create immortal symbolshttps://bugs.ruby-lang.org/issues/108312015-02-05T19:58:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Calling a method with keyword arguments will, sometimes, create immortal symbols.</p>
<p>The following tests should not fail:</p>
<pre><code>def test_kwarg_symbol_leak_no_rest
foo = -> (arg: 42) {}
assert_no_immortal_symbol_created("kwarg no rest") do |name|
assert_raise(ArgumentError) { foo.call(name.to_sym => 42) }
end
end
def test_kwarg_symbol_leak_with_rest
foo = -> (arg: 2, **options) {}
assert_no_immortal_symbol_created("kwarg with rest") do |name|
foo.call(name.to_sym => 42)
end
end
def test_kwarg_symbol_leak_just_rest
foo = -> (**options) {}
assert_no_immortal_symbol_created("kwarg just rest") do |name|
foo.call(name.to_sym => 42)
end
end
</code></pre>
<p>Note: the last one succeeds (because the hash is simply cloned internally), and is there for completeness.</p> Ruby master - Bug #10828 (Closed): send should not create immortal symbolshttps://bugs.ruby-lang.org/issues/108282015-02-04T19:01:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>While <code>public_send</code> is ok, <code>send</code> and <code>__send__</code> create immortal symbols when they shouldn't.</p> Ruby master - Feature #10354 (Closed): Optimize Integer#prime?https://bugs.ruby-lang.org/issues/103542014-10-10T03:22:13Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Nick Slocum shows in <a href="https://github.com/ruby/ruby/pull/736" class="external">https://github.com/ruby/ruby/pull/736</a> that Integer#prime? can be optimized quite a bit.</p>
<p>First, that's because there are some basic things to avoid in the current lib, like needlessly capturing blocks and there's a useless <code>loop do</code> too.</p>
<p>I'm attaching a patch that fixes many of these things.</p>
<p>Even after these fixes applied, Nick's version is still faster and I don't see why we would not use it for Fixnum#prime?</p>
<p>For Bignum#prime?, since division costs more, we can go slightly faster with the following implementation:</p>
<pre><code>class Integer
# Returns true if +self+ is a prime number, else returns false.
def prime?
return true if self == 2
return false if self % 2 == 0 || self % 3 == 0 || self < 2
skip_division = true
(5..(self**0.5).floor).step(2) do |i|
return false if skip_division && self % i == 0
skip_division = !skip_division
end
true
end
end
</code></pre> Ruby master - Bug #9660 (Closed): test/unit, minitest & bundlerhttps://bugs.ruby-lang.org/issues/96602014-03-21T19:15:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>test/unit now calls <code>gem 'minitest'</code>, but this will create regressions for anyone using <code>bundler</code>.</p>
<p>For example, create an empty <code>Gemfile</code> and try <code>bundle exec ruby -e "require 'test/unit'"</code></p>
<p>You get an error:</p>
<pre><code>.rvm/gems/ruby-head@global/gems/bundler-1.5.3/lib/bundler/rubygems_integration.rb:240:in `block in replace_gem': minitest is not part of the bundle. Add it to Gemfile. (Gem::LoadError)
</code></pre>
<p>See: <a href="https://github.com/ruby/ruby/commit/da61291a25faae95f33de6756b2eaa4804d5ef2b#commitcomment-5761129" class="external">https://github.com/ruby/ruby/commit/da61291a25faae95f33de6756b2eaa4804d5ef2b#commitcomment-5761129</a></p> Backport21 - Backport #9575 (Closed): Step with 0 step is buggyhttps://bugs.ruby-lang.org/issues/95752014-02-27T17:25:15Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I didn't realize that we now allow stepping with a '0' step. It should probably have been mentioned in the NEWS of 2.1.0?</p>
<p>Anyways, couple of bugs with that new feature:</p>
<pre><code>bn = 1 << 100
bn.step(by: 0, to: bn).first(2) # => [bn, bn] ok
bn.step(by: 0).first(2) # => [bn.to_f, bn.to_f] not ok
bn.step(by: 0, to: 0).first(2) # => [] not ok
</code></pre>
<p>The corresponding <code>size</code> don't all work either:</p>
<pre><code>bn.step(by: 0) # => Float::INFINITY, ok
bn.step(by: 0, to: bn).size # => ZeroDivisionError: divided by 0, should be infinity
bn.step(by: 0, to: 0).size # => same
1.step(by:0, to: 42).size # => same
</code></pre>
<p>My patch is almost finished.</p> Backport21 - Backport #9270 (Closed): Array#to_h should not ignore badly formed elementshttps://bugs.ruby-lang.org/issues/92702013-12-21T02:59:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The upcoming Array#to_h feature currently ignores elements that are not 2-elements arrays. Array#to_h could instead raise an error on those elements. I argued otherwise before, but maybe that would be safer.</p>
<p>One reason I think I was wrong is that current form could encourage code like:</p>
<p>enum.map{|x| [x.foo, x.bar] if x.baz? }.to_h</p>
<p>using the fact that any <code>nil</code> will be ignored. I'm not sure that it's a good idea.</p>
<p>It would probably be safer to raise an Exception for elements that are not a key-value pair. It also satisfies fail-early principle.</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/2963">@sawa (Tsuyoshi Sawada)</a> agrees with this.<br>
<a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> agrees with the change.</p>
<p>Since this feature has not already been released in an official version, changing this behavior now would not cause any incompatibility and there should be no risk of regression. Changing this feature after the official 2.1 release would be more problematic as it could cause incompatibilities.</p>
<p>Yui, could you please confirm that there is no problem on your end for me to commit the following patch: <a href="https://github.com/marcandre/ruby/compare/to_h_raise" class="external">https://github.com/marcandre/ruby/compare/to_h_raise</a></p> Ruby master - Bug #8894 (Closed): Fixnum#quo returns wrong result when given a floathttps://bugs.ruby-lang.org/issues/88942013-09-11T13:07:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Fixnum#quo is buggy.</p>
<p>2.quo(2.0) # => Rational(2, 2)</p>
<ol>
<li>Should return a float, not a rational</li>
<li>Moreover, that rational is invalid as it is not reduced.</li>
</ol>
<p>Noticed by David MacMahon <a href="/issues/8883">[ruby-core:57121]</a></p> Ruby master - Bug #8162 (Closed): Documentation for trust/taint lackinghttps://bugs.ruby-lang.org/issues/81622013-03-25T11:04:42Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>If would be good to make the documentation for {un}{trust|taint}{ed?} clearer. c.f. <a href="https://blade.ruby-lang.org/ruby-core/53679">[ruby-core:53679]</a></p> Ruby master - Bug #8161 (Closed): String#+ should inherit untrustednesshttps://bugs.ruby-lang.org/issues/81612013-03-25T11:02:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>As noted by Nikolai Weibull <a href="https://blade.ruby-lang.org/ruby-core/53679">[ruby-core:53679]</a>, String#+ doesn't maintain untrustedness.</p>
<pre><code>s = "foo".untrust
(s * 2).untrusted? # => true
(s + s).untrusted? # => false, should be true
(s + '').untrusted? # => false, should also be true
</code></pre> Ruby master - Bug #8045 (Closed): Object#singleton_methods incompatible with prependhttps://bugs.ruby-lang.org/issues/80452013-03-08T09:57:00Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Similar to <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Object#methods incompatible with prepend (Closed)" href="https://bugs.ruby-lang.org/issues/8044">#8044</a>, although implementation is independent:</p>
<pre><code>o=Object.new
def o.foo; end
o.singleton_methods(false) # => [:foo], ok
o.singleton_class.send :prepend, Enumerable
o.singleton_methods(false) # => [], should be [:foo]
</code></pre> Ruby master - Bug #8044 (Closed): Object#methods incompatible with prependhttps://bugs.ruby-lang.org/issues/80442013-03-08T09:49:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Object#methods incompatible with prepend:</p>
<pre><code>o = Object.new
def o.foo; end
o.methods(false) # => [:foo], ok
o.singleton_class.send :prepend, Enumerable
o.methods(false) # => [], should be [:foo]
</code></pre> Ruby master - Bug #8041 (Closed): Marshal incompatibility with prependhttps://bugs.ruby-lang.org/issues/80412013-03-08T08:13:21Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Marshal doesn't work for objects with prepended modules:</p>
<pre><code>o = Object.new
o.singleton_class.send :include, Enumerable
Marshal.load(Marshal.dump(o)) # => ok
o = Object.new
o.singleton_class.send :prepend, Enumerable
Marshal.load(Marshal.dump(o)) # => ArgumentError: Object does not refer to module
</code></pre>
<p>=end</p> Backport200 - Backport #7925 (Closed): refine bug with putshttps://bugs.ruby-lang.org/issues/79252013-02-24T07:16:29Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>As reported by Dave Thomas in <a href="https://blade.ruby-lang.org/ruby-core/52515">[ruby-core:52515]</a></p>
<pre><code>module VanityPuts
refine Object do
private
def puts(*args)
args.each do |arg|
super("Dave says: #{arg}")
end
end
end
end
using VanityPuts
puts "Hello" # => SystemStackError, expected "Dave says: Hello"
</code></pre> Backport200 - Backport #7922 (Closed): Keyword arguments bug with unnamed resthttps://bugs.ruby-lang.org/issues/79222013-02-24T00:44:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We have:</p>
<pre><code>def foo(**ignore_all_options)
end
foo(bar: 42) # => nil, OK
method(:foo).parameters # => [[:keyrest, :ignore_all_options]], OK
</code></pre>
<p>But:</p>
<pre><code>def foo(**)
end
foo(bar: 42) # => ArgumentError: unknown keyword: bar, expected nil
method(:foo).parameters # => [], expected [[:keyrest]]
</code></pre> Ruby master - Bug #7916 (Closed): Callback Module.used is not used...https://bugs.ruby-lang.org/issues/79162013-02-23T08:08:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Module.used was meant to be called when it is called with <code>using</code>, see r36596.</p>
<p>It's not called right now.</p> Ruby master - Bug #7757 (Closed): String#start_with? and end_with? should accept Regexphttps://bugs.ruby-lang.org/issues/77572013-01-31T01:22:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>As suggested by Ilya in <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: String#start_with? and end_with? ignore arguments convertible to a String [PATCH] (Closed)" href="https://bugs.ruby-lang.org/issues/5536">#5536</a>, the following should work:</p>
<pre><code>"hello".start_with? /h/ # => true, not a TypeError
</code></pre> Ruby master - Bug #7755 (Closed): JSON::Generate#configure's argument conversionhttps://bugs.ruby-lang.org/issues/77552013-01-30T04:33:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I notice a tiny bug in ext/json/generator/generator.c:514</p>
<pre><code>tmp = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
if (NIL_P(tmp)) {
rb_raise(rb_eArgError, "opts has to be hash like or convertable into a hash");
}
opts = tmp;
</code></pre>
<p>Bug is that rb_convert_type never returns nil.</p>
<p>Either both rb_convert_type are changed to rb_check_convert_type, or these lines are simply replaced by:</p>
<pre><code>opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
</code></pre>
<p>I'd recommend this last option, for consistency with the rest of MRI.</p> Ruby master - Bug #7691 (Closed): 3 bugs with Lazy enumerators with statehttps://bugs.ruby-lang.org/issues/76912013-01-14T14:53:31Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I found the following 3 bugs with Lazy#drop, drop_while and zip:</p>
<pre><code>drop = (1..4).lazy.drop(2)
drop.to_a # => [3, 4]
drop.to_a # => [1, 2, 3, 4], should be same as above
drop_while = (1..4).lazy.drop_while(&:odd?)
drop_while.to_a # => [2, 3, 4]
drop_while.to_a # => [1, 2, 3, 4], should be same as above
zip = (1..2).lazy.zip([3, 4]) # or (3..4)
zip.to_a # => [[1, 3], [2, 4]]
zip.to_a # => [[1, nil], [2, nil]] should be same as above
</code></pre>
<p>I found them when writing a Ruby implementation of Enumerator::Lazy.</p>
<p>My implementation created the same bug with #take as described in <a href="https://bugs.ruby-lang.org/issues/6428" class="external">https://bugs.ruby-lang.org/issues/6428</a>.</p>
<p>This made me realize that the api of Lazy.new makes it near impossible to write most lazy enumerators requiring a state, as there is no general way to reset that state.</p>
<p>When looking at my code, I used a state for drop, drop_while and zip. A quick verification showed me that the MRI implementation also has the same bugs!gene</p>
<p>So the meta question is: should there not be a general way to initialize the state of the lazy enum?</p> Ruby master - Bug #7690 (Closed): Enumerable::Lazy#flat_map should not call eachhttps://bugs.ruby-lang.org/issues/76902013-01-13T11:30:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I would expect that</p>
<pre><code>array.flat_map{...} == array.lazy.flat_map{...}.force
</code></pre>
<p>This is not always the case:</p>
<pre><code>[1].flat_map{|i| {i => i} } # => [{1 => 1}], ok
[1].lazy.flat_map{|i| {i => i} }.force # => [[1, 1]], expected [{1 => 1}]
</code></pre>
<p>Note that Matz confirmed that it is acceptable to return straight objects instead of arrays for flat_map <a href="/issues/6155">[ruby-core:43365]</a></p>
<p>It looks like this was intended for nested lazy enumerators:</p>
<pre><code>[1].lazy.flat_map{|i| [i].lazy }.force # => [1]
</code></pre>
<p>I don't think that's the correct result, and it is different from a straight flat_map:</p>
<pre><code>[1].flat_map{|i| [i].lazy } # => [#<Enumerator::Lazy: [1]>]
</code></pre>
<p>This is caused by Lazy#flat_map calls each (while Enumerable#flat_map only looks for Arrays/object responding to to_ary).</p> Ruby master - Feature #7299 (Rejected): Ruby should not completely ignore blocks.https://bugs.ruby-lang.org/issues/72992012-11-07T13:06:31Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Ruby should not completely ignore blocks.</p>
<p>const_set :Example, Class.new do<br>
p "Hello, world"<br>
end</p>
<a name="Doesnt-print-anything-generate-any-warning-nor-error"></a>
<h1 >Doesn't print anything, generate any warning nor error.<a href="#Doesnt-print-anything-generate-any-warning-nor-error" class="wiki-anchor">¶</a></h1>
<p>To minimize any impact, Ruby should issue a warning, and in future version could even raise an error.</p>
<p>Even unused variables provide warnings in verbose mode, and they have their use.</p>
<p>I can't think of a case where passing a block to a builtin method that doesn't accept a block is not a programming error though.</p>
<p>If this is approved, I volunteer to implement this.</p> Ruby master - Bug #6658 (Closed): Module#ancestors & prependhttps://bugs.ruby-lang.org/issues/66582012-06-28T03:16:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Wouldn't it be best if <code>Module#ancestors</code> returned the modules & classes in the order they will be looked at?</p>
<p>Currently:</p>
<pre><code>module M; end
class C; prepend M; end
C.ancestors # => [C, M, Class, Object, Kernel, BasicObject]
# even though actual lookup order is [M, C, Class, Object, Kernel, BasicObject]
</code></pre> Ruby master - Feature #6539 (Closed): public and private for core methodshttps://bugs.ruby-lang.org/issues/65392012-06-03T07:55:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I feel there are inconsistencies in which methods are public and which are private.</p>
<p>For example:</p>
<pre><code> obj = []
prev = obj.instance_variable_get(:@foo) # allowed
obj.instance_variable_set(:@foo, nil) # allowed
# But these are almost equivalent to:
prev = obj.remove_instance_variable(:@foo)
# => NoMethodError: private method `remove_instance_variable' called for []:Array
</code></pre>
<p>Another example:</p>
<pre><code> module M
def foo
42
end
end
M.module_function :foo # private method `module_function' called for M:Module
M.extend M # allowed
M.foo # => 42
</code></pre>
<p>Reverse example:</p>
<pre><code> {}.method_missing :foo # => private method `method_missing' called
{}.respond_to_missing? :foo, false # => allowed, why?
</code></pre>
<p>Which methods should be private is a different question for Ruby than for apps and libraries; the "real" private methods of Ruby are in C!<br>
For Ruby, I feel that a method should be private if it is <em>not meant to be called</em> except by Ruby itself (callbacks, etc...), or if it's a "global" methods of Kernel that is meant to be called directly (i.e. <code>puts</code> instead of <code>42.puts</code>)</p>
<p>Otherwise, it should be public. This includes methods like <code>Module#include</code>.</p>
<p>I don't know what the rationale was to make <code>include</code> and the like private.</p>
<p>I feel it is now quite common to use metaprogramming, e.g. to <code>include</code> modules from outside a class. It's part of a Class' API that it can be extended and modified, so these methods should be public.</p>
<p>Concrete proposal:</p>
<p>Should be made private:</p>
<pre><code> Object and descendants
#initialize_clone
#initialize_dup
#respond_to_missing?
Rational & Complex
#marshal_dump
#marshal_load
Time
#_dump
._load
</code></pre>
<p>Note that Delegate#initialize_{clone|dup} are already private</p>
<p>Should be made public:</p>
<pre><code> Object
#remove_instance_variable
Module
#attr
#attr_reader
#attr_writer
#attr_accessor
#remove_const
#include
#remove_method
#undef_method
#alias_method
#public
#protected
#private
#module_function
#define_method
</code></pre> Ruby master - Bug #6538 (Rejected): Mutability of Rational and Complexhttps://bugs.ruby-lang.org/issues/65382012-06-03T07:20:46Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I hesitated to report this, but there is a "hole" in the immutability of Rational & Complex:</p>
<pre><code>r = Rational(0) # Rationals are immutable
r.freeze # but let's be certain and freeze it!
magic_trick(r) # r is now changed:
r # => (1/42)
</code></pre>
<p>The same thing occurs with Complex. I've left out the definition of <code>magic_trick</code> for anyone who wants to try and figure it out, but it's here: <a href="http://pastie.org/4016117" class="external">http://pastie.org/4016117</a></p>
<p>Is this worth fixing?</p> Backport193 - Backport #6044 (Closed): Float#% bug in cornercaseshttps://bugs.ruby-lang.org/issues/60442012-02-18T09:26:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>On my platform, current behavior is:</p>
<p>4.0 % Float::INFINITY # => NaN<br>
4.0.send :%, Float::INFINITY # => 4.0</p>
<p>-0.0 % 42 # => 0.0<br>
-0.0.send(:%, 42) # => -0.0</p>
<p>On some platforms, these might return NaN and 0.0 in all cases.</p>
<p>My proposed behavior is to return 4.0 and -0.0 on all cases and on all platforms.</p>
<p>I'm tempted to assume it is clear that this is bug and that my proposed behavior is the right solution, but let me use my guidelines:</p>
<p>Proposed behavior passes my "strict superiority test" as it is clearly more consistent:</p>
<ul>
<li>consistent for different calling methods</li>
<li>consistent accross platforms</li>
<li>consistent with 4 % Float::INFINITY</li>
<li>consistent with the IEEE definition of fmod (see <a href="http://pubs.opengroup.org/onlinepubs/007904975/functions/fmod.html" class="external">http://pubs.opengroup.org/onlinepubs/007904975/functions/fmod.html</a> )</li>
</ul>
<p>It is also more intuitive and useful, since:</p>
<p>any_small_number % any_big_number == any_small_number</p>
<p>Current behavior passes the "clear defect test" as it is platform dependent (when it can reasonable be platfom independent). I'll add to the list of "clear defect" criteria the fact that calling an operator directly doesn't yield the same result as using <code>#send</code>.</p>
<p>The proposed solution fails my "straightforward" test as the proposed behavior contradicts part of the documentation which states "x.modulo(y) means x-y*(x/y).floor".</p>
<p>Any objection for me to commit this?</p>
<a name="Thanks"></a>
<h2 >Thanks<a href="#Thanks" class="wiki-anchor">¶</a></h2>
<p>Marc-André</p> Ruby master - Bug #5782 (Closed): File.binwrite doc and hash argumenthttps://bugs.ruby-lang.org/issues/57822011-12-20T16:14:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The doc for <code>File.binwrite</code> doesn't mention the possibility of a fourth argument (option hash), unlike <code>File.write</code>. Judging from the code, this looks like an oversight.</p>
<p>Can we get confirmation that it does accept a fourth parameter and that the doc should be updated?</p>
<p>I would personally simplify the rdoc to state that it <code>File.binwrite</code> does exactly the same as <code>File.write</code> except that it opens the file in binary mode.</p>
<p>Noticed by Konstantin Haase.</p>
<a name="Thanks"></a>
<h2 >Thanks,<a href="#Thanks" class="wiki-anchor">¶</a></h2>
<p>Marc-Andre</p> Ruby master - Bug #5694 (Closed): Proc#arity doesn't take optional arguments into account. https://bugs.ruby-lang.org/issues/56942011-12-01T20:16:05Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently:</p>
<pre><code>->(foo = 42){}.arity # => 0, should be -1
</code></pre>
<p>This is contrary to the documentation and to what we should expect from the equivalent method definition.</p>
<p>Fixed in trunk, requesting backport for the 1.9 line.</p> Backport193 - Backport #5272 (Closed): Float#round doesn't round big valueshttps://bugs.ruby-lang.org/issues/52722011-09-05T05:08:21Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>For large enough values (outside of Fixnum range), Float#round does not round at all but simply truncates:</p>
<p>2.999999999999999e20.round(-20) # => 200000000000000000000</p>
<p>Fixed in trunk, but would be nice to backport for Ruby 1.9.3.</p> Backport193 - Backport #5271 (Closed): Integer#round should never return a Floathttps://bugs.ruby-lang.org/issues/52712011-09-05T04:24:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Integer#round sometimes returns... a float!</p>
<pre><code>42.round(-1e9) # => 0.0
</code></pre>
<p>There's a check for out of range arguments, but it's not really needed and is machine dependent.</p>
<p>The following patch fixes the issue by optimizing for most cases and double checking for the rare extremely unlikely case where 10**ndigits does not fit in a bignum but <code>num</code> does and has almost <code>ndigits</code> digits.</p>
<p>Committed to trunk but would be nice to backport for Ruby 1.9.3.</p>
<p>diff --git a/numeric.c b/numeric.c<br>
index 201dfab..a767fa5 100644<br>
--- a/numeric.c<br>
+++ b/numeric.c<br>
@@ -3320,6 +3320,7 @@ int_round(int argc, VALUE* argv, VALUE num)<br>
{<br>
VALUE n, f, h, r;<br>
int ndigits;</p>
<ul>
<li>
<p>long bytes;<br>
ID op;</p>
<p>if (argc == 0) return num;<br>
@@ -3331,11 +3332,15 @@ int_round(int argc, VALUE* argv, VALUE num)<br>
if (ndigits == 0) {<br>
return num;<br>
}</p>
</li>
</ul>
<ul>
<li>ndigits = -ndigits;</li>
<li>if (ndigits < 0) {</li>
<li>
<pre><code> rb_raise(rb_eArgError, "ndigits out of range");
</code></pre>
</li>
</ul>
<ul>
<li>
<li>/* If 10**N / 2 > num, then return 0 */</li>
<li>/* We have log_256(10) > 0.415241 and log_256(1/2) = -0.125, so */</li>
<li>bytes = FIXNUM_P(num) ? sizeof(long) : rb_funcall(num, rb_intern("size"), 0);</li>
<li>if (-0.415241 * ndigits - 0.125 > bytes ) {</li>
<li>
<pre><code> return INT2FIX(0);
</code></pre>
}</li>
</ul>
<ul>
<li>f = int_pow(10, ndigits);</li>
</ul>
<ul>
<li>
<li>f = int_pow(10, -ndigits);<br>
if (FIXNUM_P(num) && FIXNUM_P(f)) {<br>
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);<br>
int neg = x < 0;<br>
@@ -3344,6 +3349,10 @@ int_round(int argc, VALUE* argv, VALUE num)<br>
if (neg) x = -x;<br>
return LONG2NUM(x);<br>
}</li>
<li>if (TYPE(f) == T_FLOAT) {</li>
<li>
<pre><code> /* then int_pow overflow */
</code></pre>
</li>
<li>
<pre><code> return INT2FIX(0);
</code></pre>
</li>
<li>}<br>
h = rb_funcall(f, '/', 1, INT2FIX(2));<br>
r = rb_funcall(num, '%', 1, f);<br>
n = rb_funcall(num, '-', 1, r);</li>
</ul> Ruby master - Bug #5178 (Closed): Complex#rationalize should rationalizehttps://bugs.ruby-lang.org/issues/51782011-08-10T10:39:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Complex#rationalize currently calls <code>to_r</code> on the real part instead of <code>rationalize</code>:</p>
<p>f = 1/3.0<br>
c = Complex(f)<br>
c.to_r == f.to_r # => true<br>
c.rationalize == f.rationalize # => false</p>
<p>Should I not commit this to 1.9.3 too?</p>
<p>diff --git a/complex.c b/complex.c<br>
index 78f0902..1b76074 100644<br>
--- a/complex.c<br>
+++ b/complex.c<br>
@@ -1335,7 +1335,8 @@ nucomp_to_f(VALUE self)</p>
<ul>
<li>call-seq:</li>
<li>cmp.to_r -> rational</li>
<li>
</ul>
<ul>
<li>
<ul>
<li>Returns the value as a rational if possible.</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>If the imaginary part is exactly 0, returns the real part as a Rational,</li>
</ul>
</li>
<li>
<ul>
<li>otherwise a RangeError is raised.<br>
*/<br>
static VALUE<br>
nucomp_to_r(VALUE self)<br>
@@ -1354,14 +1355,22 @@ nucomp_to_r(VALUE self)</li>
<li>call-seq:</li>
<li>cmp.rationalize([eps]) -> rational</li>
<li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>Returns the value as a rational if possible. An optional argument</li>
</ul>
</li>
<li>
<ul>
<li>eps is always ignored.</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>If the imaginary part is exactly 0, returns the real part as a Rational,</li>
</ul>
</li>
<li>
<ul>
<li>otherwise a RangeError is raised.<br>
*/<br>
static VALUE<br>
nucomp_rationalize(int argc, VALUE *argv, VALUE self)<br>
{</li>
</ul>
</li>
<li>get_dat1(self);</li>
<li>rb_scan_args(argc, argv, "01", NULL);</li>
</ul>
<ul>
<li>return nucomp_to_r(self);</li>
</ul>
<ul>
<li>
<li>if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {</li>
<li>
<pre><code> VALUE s = f_to_s(self);
</code></pre>
</li>
<li>
<pre><code> rb_raise(rb_eRangeError, "can't convert %s into Rational",
</code></pre>
</li>
<li>
<pre><code> StringValuePtr(s));
</code></pre>
</li>
<li>}</li>
<li>return rb_funcall(dat->real, rb_intern("rationalize"), argc, argv);<br>
}</li>
</ul> Ruby master - Feature #3715 (Rejected): Enumerator#size and #size=https://bugs.ruby-lang.org/issues/37152010-08-19T05:02:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
It would be useful to be able to ask an Enumerator for the number of times it will yield, without having to actually iterate it.</p>
<p>For example:</p>
<p>(1..1000).to_a.permutation(4).size # => 994010994000 (instantly)</p>
<p>It would allow nice features like:</p>
<p>class Enumerator<br>
def with_progress<br>
return to_enum :with_progress unless block_given?<br>
out_of = size || "..."<br>
each_with_index do |obj, i|<br>
puts "Progress: #{i} / #{out_of}"<br>
yield obj<br>
end<br>
puts "Done"<br>
end<br>
end</p>
<a name="To-display-the-progress-of-any-iterator-one-can-daisy-chain-with_progress"></a>
<h1 >To display the progress of any iterator, one can daisy-chain with_progress:<a href="#To-display-the-progress-of-any-iterator-one-can-daisy-chain-with_progress" class="wiki-anchor">¶</a></h1>
<p>20.times.with_progress.map do<br>
# do stuff here...<br>
end</p>
<p>This would print out "Progress: 1 / 20", etc..., while doing the stuff.</p>
<p>*** Proposed changes ***</p>
<ul>
<li>Enumerator#size *</li>
</ul>
<p>call-seq:<br>
e.size -> int, Float::INFINITY or nil<br>
e.size {block} -> int</p>
<p>Returns the size of the enumerator.<br>
The form with no block given will do a lazy evaluation of the size without going through the enumeration. If the size can not be determined then +nil+ is returned.<br>
The form with a block will always iterate through the enumerator and return the number of times it yielded.</p>
<p>(1..100).to_a.permutation(4).size # => 94109400<br>
loop.size # => Float::INFINITY</p>
<p>a = [1, 2, 3]<br>
a.keep_if.size # => 3<br>
a # => [1, 2, 3]<br>
a.keep_if.size{false} # => 3<br>
a # => []</p>
<p>[1, 2, 3].drop_while.size # => nil<br>
[1, 2, 3].drop_while.size{|i| i < 3} # => 2</p>
<ul>
<li>Enumerator#size= *</li>
</ul>
<p>call-seq:<br>
e.size = sz</p>
<p>Sets the size of the enumerator. If +sz+ is a Proc or a Method, it will be called each time +size+ is requested, otherwise +sz+ is returned.</p>
<p>first = [1, 2, 3]<br>
second = [4, 5]<br>
enum = Enumerator.new do |y|<br>
first.each{|o| y << o}<br>
second.each{|o| y << o}<br>
end<br>
enum.size # => nil<br>
enum.size = ->(e){first.size + second.size}<br>
enum.size # => 5<br>
first << 42<br>
enum.size # => 6</p>
<ul>
<li>Kerne#to_enum / enum_for *</li>
</ul>
<p>The only other API change is for #to_enum/#enum_for, which can accept a block for size calculation:</p>
<p>class Date<br>
def step(limit, step=1)<br>
unless block_given?<br>
return to_enum(:step, limit, step){|date| (limit - date).div(step) + 1}<br>
end<br>
# ...<br>
end<br>
end</p>
<p>*** Implementation ***</p>
<p>I implemented the support for #size for most builtin enumerator producing methods (63 in all).</p>
<p>It is broken down in about 20 commits: <a href="http://github.com/marcandre/ruby/commits/enum_size" class="external">http://github.com/marcandre/ruby/commits/enum_size</a></p>
<p>It begins with the implementation of Enumerator#size{=}: <a href="http://github.com/marcandre/ruby/commit/a92feb0" class="external">http://github.com/marcandre/ruby/commit/a92feb0</a></p>
<p>A combined patch is available here: <a href="http://gist.github.com/535974" class="external">http://gist.github.com/535974</a></p>
<p>Still missing are Dir#each, Dir.foreach, ObjectSpace.each_object, Range#step, Range#each, String#upto, String#gsub, String#each_line.</p>
<p>The enumerators whose #size returns +nil+ are:<br>
Array#{r}index, {take|drop}_while<br>
Enumerable#find{_index}, {take|drop}_while<br>
IO: all methods</p>
<p>*** Notes ***</p>
<ul>
<li>Returning +nil+ *</li>
</ul>
<p>I feel it is best if IO.each_line.size and similar return +nil+ to avoid side effects.</p>
<p>We could have Array#find_index.size return the size of the array with the understanding that this is the maximum number of times the enumerator will yield. Since a block can always contain a break statement, size could be understood as a maximum anyways, so it can definitely be argued that the definition should be the maximum number of times.</p>
<ul>
<li>Arguments to size proc/lambda *</li>
</ul>
<p>My implementation currently passes the object that the enumerator will call followed with any arguments given when building the enumerator.</p>
<p>If Enumerator had getters (say Enumerator#base, Enumerator#call, Enumerator#args, see feature request <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Add getters for Enumerator (Closed)" href="https://bugs.ruby-lang.org/issues/3714">#3714</a>), passing the enumerator itself might be a better idea.</p>
<ul>
<li>Does not dispatch through name *</li>
</ul>
<p>It might be worth noting that the size dispatch is decided when creating the enumerator, not afterwards in function of the class & method name:</p>
<p>[1,2,3].permutation(2).size # => 6<br>
[1,2,3].to_enum(:permutation, 2).size # => nil</p>
<ul>
<li>Size setter *</li>
</ul>
<p>Although I personally like the idea that #size= can accept a Proc/Lambda for later call, this has the downside that there is no getter, i.e. no way to get the Proc/Lambda back. I feel this is not an issue, but an alternative would be to have a #size_proc and #size_proc= setters too (like Hash).</p>
<p>I believe this addresses feature request <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: the length for an enumerator generated by Array#permutation and Array#combination (Closed)" href="https://bugs.ruby-lang.org/issues/2673">#2673</a>, although maybe in a different fashion. <a href="http://redmine.ruby-lang.org/issues/show/2673" class="external">http://redmine.ruby-lang.org/issues/show/2673</a><br>
=end</p> Backport191 - Backport #3506 (Closed): Kernel::URI with optional parserhttps://bugs.ruby-lang.org/issues/35062010-06-30T05:43:40Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Kernel::URI could accept an optional parameter to specify a parser.</p>
<p>It could then be used in a couple of places in the library itself.</p>
<p>Patch follows:</p>
<p>diff --git a/lib/uri/common.rb b/lib/uri/common.rb<br>
index bda6718..f9f0a6a 100644<br>
--- a/lib/uri/common.rb<br>
+++ b/lib/uri/common.rb<br>
@@ -185,14 +185,7 @@ module URI<br>
end</p>
<pre><code> def join(*uris)
</code></pre>
<ul>
<li>
<pre><code> case uris[0]
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> uris[0] = self.parse(uris[0])
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> uris[0] = URI(uris[0], self)
uris.inject :merge
</code></pre>
end</li>
</ul>
<p>@@ -845,12 +838,12 @@ module Kernel<br>
#<br>
# Returns +uri+ converted to a URI object.<br>
#</p>
<ul>
<li>def URI(uri)</li>
</ul>
<ul>
<li>def URI(uri, parser = URI::DEFAULT_PARSER)<br>
case uri<br>
when URI::Generic<br>
uri<br>
when String</li>
</ul>
<ul>
<li>
<pre><code> URI.parse(uri)
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> parser.parse(uri)
</code></pre>
else<br>
raise ArgumentError,<br>
"bad argument (expected URI object or URI string)"<br>
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb<br>
index 4fdfd14..4084b56 100644<br>
--- a/lib/uri/generic.rb<br>
+++ b/lib/uri/generic.rb<br>
@@ -783,14 +783,7 @@ module URI
<a name="return-base-and-rel"></a>
<h1 >return base and rel.<a href="#return-base-and-rel" class="wiki-anchor">¶</a></h1>
<a name="you-can-modify-base-but-can-not-rel"></a>
<h1 >you can modify <code>base', but can not </code>rel'.<a href="#you-can-modify-base-but-can-not-rel" class="wiki-anchor">¶</a></h1>
def merge0(oth)</li>
</ul>
<ul>
<li>
<pre><code> case oth
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> oth = parser.parse(oth)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> oth = URI(oth, parser)
if self.relative? && oth.relative?
raise BadURIError,
</code></pre>
</li>
</ul>
<p>@@ -854,15 +847,7 @@ module URI<br>
private :route_from_path</p>
<pre><code> def route_from0(oth)
</code></pre>
<ul>
<li>
<pre><code> case oth
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> oth = parser.parse(oth)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
</ul>
<ul>
<li>
<pre><code> oth = URI(oth, parser)
if self.relative?
raise BadURIError,
"relative URI: #{self}"
</code></pre>
</li>
</ul>
<p>@@ -966,16 +951,7 @@ module URI<br>
# #=> #<URI::Generic:0x2020c2f6 URL:/main.rbx?page=1><br>
#<br>
def route_to(oth)</p>
<ul>
<li>
<pre><code> case oth
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> oth = parser.parse(oth)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<li>
<pre><code> oth.route_from(self)
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> URI(oth, parser).route_from(self)
</code></pre>
<p>end</p>
<h1></h1>
</li>
</ul>
<p>=end</p> Backport191 - Backport #3505 (Closed): URI.join and Kernel::URI should accept URI objectshttps://bugs.ruby-lang.org/issues/35052010-06-30T05:38:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
URI.join accepts strings or URI objects, except for the first parameter which must be a string:</p>
<p>rubydev -r uri -e 'p URI.join("<a href="http://ruby-lang.org" class="external">http://ruby-lang.org</a>", URI("/foo"))'<br>
#<URI::HTTP:0x0000010109b418 URL:<a href="http://ruby-lang.org/foo%3E" class="external">http://ruby-lang.org/foo></a></p>
<p>rubydev -r uri -e 'p URI.join(URI("<a href="http://ruby-lang.org" class="external">http://ruby-lang.org</a>"), "/foo")'<br>
/usr/local/rubydev/lib/ruby/1.9.1/uri/common.rb:156:in `split': bad URI(is not URI?): <a href="http://ruby-lang.org" class="external">http://ruby-lang.org</a> (URI::InvalidURIError)</p>
<p>I believe it should accept URI object as first parameter too.</p>
<p>Also, Kernel::URI accept uri strings, but not URI objects:</p>
<p>rubydev -r uri -e 'URI(URI("<a href="http://ruby-lang.org" class="external">http://ruby-lang.org</a>"))'<br>
/usr/local/rubydev/lib/ruby/1.9.1/uri/common.rb:156:in `split': bad URI(is not URI?): <a href="http://ruby-lang.org" class="external">http://ruby-lang.org</a> (URI::InvalidURIError)</p>
<p>This corresponds to the documentation, but it is contrary to Kernel::String, Integer, Float, etc... that all accept their own type. The error message is clearly buggy (an URI object is not an invalid uri!).</p>
<p>I believe that Kernel::URI should accept URI objects (and return them).</p>
<p>The patch below corrects both and has no impact on test-all nor rubyspec.</p>
<p>I plan to commit it unless there is objection.</p>
<p>Yugui: should I commit it in the 1.9.2 branch too?</p>
<p>Thanks</p>
<p>diff --git a/lib/uri/common.rb b/lib/uri/common.rb<br>
index 58fd422..bda6718 100644<br>
--- a/lib/uri/common.rb<br>
+++ b/lib/uri/common.rb<br>
@@ -184,12 +184,16 @@ module URI<br>
end<br>
end</p>
<ul>
<li>def join(*str)</li>
<li>
<pre><code> u = self.parse(str[0])
</code></pre>
</li>
<li>
<pre><code> str[1 .. -1].each do |x|
</code></pre>
</li>
<li>
<pre><code> u = u.merge(x)
</code></pre>
</li>
</ul>
<ul>
<li>def join(*uris)</li>
<li>
<pre><code> case uris[0]
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> uris[0] = self.parse(uris[0])
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument (expected URI object or URI string)"
end
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> u
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> uris.inject :merge
</code></pre>
<p>end</p>
<p>def extract(str, schemes = nil, &block)<br>
@@ -837,11 +841,20 @@ module URI<br>
end</p>
</li>
</ul>
<p>module Kernel</p>
<ul>
<li>
<a name="alias-for-URIparse"></a>
<h1 >alias for URI.parse.<a href="#alias-for-URIparse" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<ul>
<li>
<h1></h1>
</li>
</ul>
<ul>
<li>
<a name="This-method-is-introduced-at-182"></a>
<h1 >This method is introduced at 1.8.2.<a href="#This-method-is-introduced-at-182" class="wiki-anchor">¶</a></h1>
</li>
<li>def URI(uri_str) # :doc:</li>
<li>URI.parse(uri_str)</li>
</ul>
<ul>
<li>
<a name="Returns-uri-converted-to-a-URI-object"></a>
<h1 >Returns +uri+ converted to a URI object.<a href="#Returns-uri-converted-to-a-URI-object" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>def URI(uri)</li>
<li>case uri</li>
<li>when URI::Generic</li>
<li>
<pre><code> uri
</code></pre>
</li>
<li>when String</li>
<li>
<pre><code> URI.parse(uri)
</code></pre>
</li>
<li>else</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument (expected URI object or URI string)"
</code></pre>
</li>
<li>end<br>
end<br>
module_function :URI<br>
end<br>
=end</li>
</ul> Ruby master - Bug #3448 (Rejected): broken iconv libraryhttps://bugs.ruby-lang.org/issues/34482010-06-17T13:08:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Texts longer than ~8160 characters can create problems with iconv on some distributions:</p>
<p>require 'iconv'<br>
Iconv.conv("iso-8859-1//ignore", "utf-8", "\305\253" + "a"*8159).size #=> 8159<br>
Iconv.conv("iso-8859-1//ignore", "utf-8", "\305\253" + "a"*8160).size # => Iconv::IllegalSequence: "a"</p>
<p>The code above is from Debian 4 and 5 (on Heroku...), but it works as expected on OS X. As such, it affects Ruby 1.8 and 1.9</p>
<p>A google search reassured me I was not crazy, e.g. my_iconv_open in:<br>
<a href="http://www.opensource.apple.com/source/vim/vim-6/vim/src/mbyte.c" class="external">http://www.opensource.apple.com/source/vim/vim-6/vim/src/mbyte.c</a></p>
<a name="I-realize-this-is-somewhat-a-third-party-issue-but-Im-logging-this-nevertheless-as-a-brave-soul-might-bypass-the-bug-in-the-Ruby-library-andor-report-this-to-the-proper-authorities"></a>
<h2 >I realize this is somewhat a third party issue, but I'm logging this nevertheless, as a brave soul might bypass the bug in the Ruby library and/or report this to the proper authorities.<a href="#I-realize-this-is-somewhat-a-third-party-issue-but-Im-logging-this-nevertheless-as-a-brave-soul-might-bypass-the-bug-in-the-Ruby-library-andor-report-this-to-the-proper-authorities" class="wiki-anchor">¶</a></h2>
<p>Marc-André<br>
=end</p> Ruby 1.8 - Backport #3273 (Closed): Float string conversionhttps://bugs.ruby-lang.org/issues/32732010-05-11T14:12:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
For any float f, the two following conditions should hold:<br>
(1) f.to_s.to_f == f (round trips)<br>
(2) f.to_s.chop.to_f != f (minimal)</p>
<p>The second condition is a simplification; if the string representation is in scientific notation, than the character to remove would be the one just before the "e". Also, if the string representation ends with ".0", then it is minimal.</p>
<p>Currently, the first condition fails in Ruby 1.8, and the second fails in Ruby 1.9</p>
<p>$ ruby18dev -ve 'f = 0.21611564636388508; puts f.to_s.to_f == f'<br>
ruby 1.8.8dev (2010-05-11) [i386-darwin10.3.0]<br>
false</p>
<p>$ rubydev -ve 'f = 0.56; puts f.to_s.chop.to_f != f'<br>
ruby 1.9.3dev (2010-05-11 trunk 27730) [x86_64-darwin10.3.0]<br>
false</p>
<p>Note that this implies that Ruby 1.8 and 1.9 do not output the same string representation for either of these two floats.</p>
<p>The conversion algorithm currently checks two precisions. In Ruby 1.9, it tries 16 digits and if that's not enough it then uses 17. In 1.8, it's the same but with 15 and 16.</p>
<p>The fact is that 17 can be necessary (e.g. 0.21611564636388508 is not equal to either 0.2161156463638851 or 0.2161156463638850) and 16 can be too much (e.g. 0.5600000000000001 == 0.56), so three precisions must be checked.</p>
<p>The following patch fixes this issue for trunk (although it can probably be made nicer and/or faster).</p>
<p>Let me know if there are any objections to fixing both the 1.9 and 1.8 lines.</p>
<p>diff --git a/numeric.c b/numeric.c<br>
index f2c8c13..442b069 100644<br>
--- a/numeric.c<br>
+++ b/numeric.c<br>
@@ -569,7 +569,8 @@ flo_to_s(VALUE flt)<br>
else if (isnan(value))<br>
return rb_usascii_str_new2("NaN");</p>
<p>-# define FLOFMT(buf, size, fmt, prec, val) snprintf(buf, size, fmt, prec, val), <br>
+# define FLOFMT(buf, size, fmt, prec, val) snprintf(buf, size, fmt, prec-1, val), \</p>
<ul>
<li>
<p>(void)((atof(buf) == val) || snprintf(buf, size, fmt, (prec), val)), <br>
(void)((atof(buf) == val) || snprintf(buf, size, fmt, (prec)+1, val))</p>
<p>FLOFMT(buf, sizeof(buf), "%#.<em>g", float_dig, value); /</em> ensure to print decimal point */<br>
=end</p>
</li>
</ul> Ruby master - Bug #3081 (Closed): lib/http wrong behavior for chunked readinghttps://bugs.ruby-lang.org/issues/30812010-04-03T02:25:06Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Take the following code:</p>
<p>require 'net/http'<br>
uri = URI.parse("<a href="http://banners.wunderground.com/banner/krd_condV2/language/www/US/FL/Miami.gif" class="external">http://banners.wunderground.com/banner/krd_condV2/language/www/US/FL/Miami.gif</a>")<br>
http = Net::HTTP.new(uri.host, uri.port)</p>
<p>http.request_get(uri.request_uri) do |res|<br>
res.read_body do |chunk|<br>
puts "read #{chunk.size} bytes"<br>
break<br>
end<br>
puts "Done"<br>
end<br>
puts "Bye"</p>
<p>in Ruby 1.8.7 or in 1.9.2dev, it outputs the following:</p>
<p>read 1024 bytes<br>
Done<br>
/usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2433:in <code>read_chunked': wrong chunk size line: (Net::HTTPBadResponse) from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2411:in </code>read_body_0'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2371:in <code>read_body' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2396:in </code>body'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2335:in <code>reading_body' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1185:in </code>transport_request'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1169:in <code>request' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1162:in </code>block in request'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:627:in <code>start' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1160:in </code>request'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1073:in <code>request_get' from b.rb:5:in </code>'</p>
<p>There's apparently nothing wrong with the server; remove the 'break' statement and you get instead:</p>
<p>read 1024 bytes<br>
read 597 bytes<br>
read 2 bytes<br>
Done<br>
Bye<br>
=end</p> Ruby master - Bug #3027 (Closed): Random#rand(nil)https://bugs.ruby-lang.org/issues/30272010-03-28T09:06:42Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Hi Nobu.</p>
<p>Looking at Random#rand, I notice that passing nil has the same result as not passing any argument.</p>
<p>Either it should raise an ArgumentError like the documentation implies, or else the documentation should be modified.</p>
<p>I would argue to raise an error because:</p>
<ul>
<li>it is easy to pass nothing, or pass 1.0 instead, and get the same result if that is what is desired</li>
<li>it could hide an error in the code, where the result is unexpectedly nil but the programmer didn't think about it (like whiny nils in rails)<br>
=end</li>
</ul> Ruby master - Bug #3016 (Rejected): Enumerable#slice_before and duphttps://bugs.ruby-lang.org/issues/30162010-03-26T14:01:58Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
When writing the specs for slice_before, I was surprised that it doesn't call #dup.</p>
<p>class X<br>
def dup<br>
raise "Hi!"<br>
end<br>
end</p>
<p>[:foo].slice_before(X.new){}.to_a</p>
<a name="gt-foo-I-expected-it-to-raise"></a>
<h1 >==> [[:foo]], I expected it to raise<a href="#gt-foo-I-expected-it-to-raise" class="wiki-anchor">¶</a></h1>
<p>The implementation calls directly rb_obj_dup.</p>
<p>It's a minor issue, but would it not be best to call dup on the argument? Most special needs for #dup can be addressed by initialize_dup, but maybe there are some reasonable cases where some user classes will redefine #dup?</p>
<p>The same question is valid for Enumerable#chunk.</p>
<p>diff --git a/enum.c b/enum.c<br>
index b69d8c9..e6e6adb 100644<br>
--- a/enum.c<br>
+++ b/enum.c<br>
@@ -14,7 +14,7 @@<br>
#include "node.h"</p>
<p>VALUE rb_mEnumerable;<br>
-static ID id_each, id_eqq, id_cmp, id_next, id_size;<br>
+static ID id_each, id_eqq, id_cmp, id_next, id_size, id_dup;</p>
<p>static VALUE<br>
enum_values_pack(int argc, VALUE *argv)<br>
@@ -2189,7 +2189,7 @@ chunk_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)<br>
arg.yielder = yielder;</p>
<pre><code> if (!NIL_P(arg.state))
</code></pre>
<ul>
<li>
<pre><code> arg.state = rb_obj_dup(arg.state);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> arg.state = rb_funcall(arg.state, id_dup, 0, 0);
</code></pre>
<p>rb_block_call(enumerable, id_each, 0, 0, chunk_ii, (VALUE)&arg);<br>
if (!NIL_P(arg.prev_elts))<br>
@@ -2364,7 +2364,7 @@ slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)<br>
arg.yielder = yielder;</p>
<p>if (!NIL_P(arg.state))</p>
</li>
</ul>
<ul>
<li>
<pre><code> arg.state = rb_obj_dup(arg.state);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> arg.state = rb_funcall(arg.state, id_dup, 0, 0);
</code></pre>
<p>rb_block_call(enumerable, id_each, 0, 0, slicebefore_ii, (VALUE)&arg);<br>
if (!NIL_P(arg.prev_elts))<br>
@@ -2606,5 +2606,6 @@ Init_Enumerable(void)<br>
id_cmp = rb_intern("<=>");<br>
id_next = rb_intern("next");<br>
id_size = rb_intern("size");</p>
</li>
<li>
<p>id_dup = rb_intern("dup");<br>
}<br>
=end</p>
</li>
</ul> Ruby 1.8 - Bug #3011 (Closed): caller for recursive functionhttps://bugs.ruby-lang.org/issues/30112010-03-25T10:38:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
For some reason, Ruby 1.8 will skip multiple copies of the same method. In case of a recursive function call, the behavior is different from Ruby 1.9 and seems wrong.</p>
<p>Here's the rubyspec I just committed:</p>
<pre><code> it "returns one entry per call, even for recursive methods" do
def recurse(n)
return caller if n <= 0
recurse(n-1)
end
(recurse(3).size - recurse(2).size).should == 1
end
</code></pre>
<p>The following patch doesn't seem to yield any new failure with make test, make test-all, nor the caller specs:</p>
<p>diff --git a/eval.c b/eval.c<br>
index 3407548..65fb970 100644<br>
--- a/eval.c<br>
+++ b/eval.c<br>
@@ -6468,9 +6468,6 @@ backtrace(lev)<br>
}<br>
for (; frame && (n = frame->node); frame = frame->prev) {<br>
if (frame->prev && frame->prev->last_func) {</p>
<ul>
<li>
<pre><code> if (frame->prev->node == n) {
</code></pre>
</li>
<li>
<pre><code> if (frame->prev->last_func == frame->last_func) continue;
</code></pre>
</li>
<li>
<pre><code> }
snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
n->nd_file, nd_line(n),
rb_id2name(frame->prev->last_func));
</code></pre>
</li>
</ul>
<p>Nobu, can you recall what was the reason for these lines ( r10593 ) ?<br>
=end</p> Ruby master - Bug #2601 (Closed): BasicObject.initialize should raise an errorhttps://bugs.ruby-lang.org/issues/26012010-01-13T11:55:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
While having fun cloning BasicObject (see issue 2443), I found the amusing bug that :initialize could successfully be sent to BasicObject, creating all sorts of havoc.</p>
<p>$ rubydev -e "BasicObject.send :initialize; puts Object.ancestors" # => Loops indefinitely</p>
<p>$ rubydev -e "BasicObject.send :initialize, String; puts 42.upcase" # => Segmentation Fault</p>
<p>It was even possible to change the root of all Ruby classes without running into trouble:<br>
$ rubydev -e '<br>
SuperBasicObject = BasicObject.clone<br>
BasicObject.send :initialize, SuperBasicObject<br>
puts BasicObject.superclass<br>
'</p>
<a name="gt-SuperBasicObject"></a>
<h1 >==> SuperBasicObject<a href="#gt-SuperBasicObject" class="wiki-anchor">¶</a></h1>
<p>I fixed it, although changes might be required depending on the outcome of issue #2443.<br>
=end</p> Ruby master - Feature #2542 (Closed): URI lib should be updated to RFC 3986https://bugs.ruby-lang.org/issues/25422010-01-01T03:45:44Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
RFC 2396 has been obsolete for nearly 5 years now.</p>
<p>It was replaced by RFC 3986 which aims at clarifying aspects that were not previously clear.<br>
=end</p> Backport187 - Backport #2519 (Closed): __method__ can return NULL (and therefore crash ruby)https://bugs.ruby-lang.org/issues/25192009-12-23T15:23:30Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
In Ruby 1.8.7 and latest 1.8.8:</p>
<p>$ cat ohoh.rb<br>
puts <strong>method</strong></p>
<p>$ ruby18dev -e "load 'ohoh.rb'"<br>
val (null) id 140734799802560/Users/work/test/ohoh.rb:1:in <code>to_s': NULL pointer given (ArgumentError) from /Users/work/test/ohoh.rb:1:in </code>puts'<br>
from /Users/work/test/ohoh.rb:1<br>
from -e:1:in `load'<br>
from -e:1</p>
<p>Doing <strong>method</strong>.inspect instead will crash Ruby<br>
=end</p> Ruby master - Bug #2497 (Closed): Matrix: Vector#each2 with no block returns unusable enumeratorhttps://bugs.ruby-lang.org/issues/24972009-12-19T11:04:05Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Fixed in r26125<br>
=end</p> Backport187 - Backport #2450 (Closed): Array#sample can loop forever [patched]https://bugs.ruby-lang.org/issues/24502009-12-07T06:41:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
[:hello].sample(42) # ==> loops on Ruby 1.8.8</p>
<p>Fixed.</p>
<p>Other backports pass RubySpec.<br>
=end</p> Backport186 - Backport #2364 (Closed): Float conversion of NaN in 1.8.xhttps://bugs.ruby-lang.org/issues/23642009-11-14T09:36:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Trying to fix issue <a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: lib/bigdecimal: errors in comparisons [patch] (Closed)" href="https://bugs.ruby-lang.org/issues/2349">#2349</a> for 1.8.8 but running into a small problem: conversion to a float will fail if the value converted corresponds to NaN:</p>
<p>$ ruby19 -r bigdecimal -e "p Float(BigDecimal('NaN'))"<br>
NaN<br>
$ ruby18 -r bigdecimal -e "p Float(BigDecimal('NaN'))"<br>
ArgumentError: invalid value for Float()</p>
<p>This is true of any class for which #to_f returns NaN.</p>
<p>This makes it impossible for BigDecimal("NaN") to be converted to a float in 1.8.</p>
<p>Can anyone think of a reason not to bring 1.8 inline with 1.9 (by allowing NaN)?</p>
<p>diff --git a/object.c b/object.c<br>
index 4704ebf..dd67039 100644<br>
--- a/object.c<br>
+++ b/object.c<br>
@@ -2486,13 +2486,7 @@ rb_Float(val)<br>
break;</p>
<pre><code> default:
</code></pre>
<ul>
<li>
<pre><code> {
</code></pre>
</li>
<li>
<pre><code> VALUE f = rb_convert_type(val, T_FLOAT, "Float", "to_f");
</code></pre>
</li>
<li>
<pre><code> if (isnan(RFLOAT(f)->value)) {
</code></pre>
</li>
<li>
<pre><code> rb_raise(rb_eArgError, "invalid value for Float()");
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> return f;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> return rb_convert_type(val, T_FLOAT, "Float", "to_f");
</code></pre>
}<br>
}</li>
</ul>
<p>(Doesn't generate any error in make test or test-all)<br>
=end</p> Backport186 - Backport #2349 (Closed): lib/bigdecimal: errors in comparisons [patch]https://bugs.ruby-lang.org/issues/23492009-11-09T15:33:34Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ ruby -r bigdecimal -e 'p BigDecimal.new("1") < nil'<br>
nil</p>
<p>expected: an error like with any other mathematical type:<br>
-e:1:in `<': comparison of BigDecimal with nil failed (ArgumentError)</p>
<hr>
<p>$ ruby -r bigdecimal -e 'p BigDecimal.new("1") == nil'<br>
nil</p>
<p>expected: false like with any other Ruby object</p>
<hr>
<p>$ ruby -r bigdecimal -e 'p BigDecimal.new("NaN") < 1'<br>
nil</p>
<p>expected: false, like with any other mathematical comparison</p>
<p>I'll commit the attached patch in a few days (for 1.8 & 1.9) unless there are arguments against it.<br>
=end</p> Ruby master - Bug #2276 (Closed): Array#<=> should not raise when comparison failshttps://bugs.ruby-lang.org/issues/22762009-10-26T20:03:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Since the addition of Object#<=>, the only comparison that raised an error was Array#<=>(not_an_array).</p>
<p>Array#<=>(obj) now returns nil if obj is not array-like.</p>
<p>Maybe this should also be applied in the 1.8 line?</p>
<p>Note: neither test-all nor rubyspec were testing for this.<br>
=end</p> Ruby master - Bug #2221 (Closed): lib/delegate: freeze has odd effectshttps://bugs.ruby-lang.org/issues/22212009-10-16T15:43:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Freeze doesn't quite freeze, and can't be cloned:</p>
<p>require 'delegate'<br>
d = SimpleDelegator.new([1,2,3])<br>
d.freeze<br>
d[0] = :hello; d # ==> [:hello, 2, 3], I expected a runtime error<br>
d.clone # ==> RuntimeError, I expected some kind of copy of d</p>
<p>Maybe #freeze and #frozen should be forwarded:</p>
<p>diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index 57c479c..f4bd453 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -115,7 +115,7 @@</p>
<a name="implementation-see-SimpleDelegator"></a>
<h1 >implementation, see SimpleDelegator.<a href="#implementation-see-SimpleDelegator" class="wiki-anchor">¶</a></h1>
<h1></h1>
<p>class Delegator</p>
<ul>
<li>[:to_s,:inspect,:=~,:!~,:===].each do |m|</li>
</ul>
<ul>
<li>[:to_s,:inspect,:=~,:!~,:===, :freeze, :frozen?].each do |m|<br>
undef_method m<br>
end</li>
</ul>
<p>But maybe the Delegator itself should also be frozen? I mean should a call to #<strong>setobj</strong> raise a runtime error or not?</p>
<p>Also, there are other methods that should probably be forwarded (eql?, hash, etc...); see issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Delegator < BasicObject (Rejected)" href="https://bugs.ruby-lang.org/issues/1333">#1333</a>.<br>
=end</p> Ruby master - Bug #2207 (Closed): lib/delegate: #method doesn't delegate to its objecthttps://bugs.ruby-lang.org/issues/22072009-10-14T13:45:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'<br>
d = SimpleDelegator.new("hello")<br>
d.method(:upcase) # ==> NameError: undefined method <code>upcase' for class </code>SimpleDelegator'</p>
<p>Note that in Ruby 1.8, this does not create an error.<br>
This is fixed by defining respond_to_missing? instead of respond_to?</p>
<p>diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index 57c479c..6b9f91a 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -143,12 +143,11 @@ class Delegator<br>
end</p>
<pre><code>#
</code></pre>
<ul>
<li>
<a name="Checks-for-a-method-provided-by-this-the-delegate-object-by-fowarding-the"></a>
<h1 >Checks for a method provided by this the delegate object by fowarding the<a href="#Checks-for-a-method-provided-by-this-the-delegate-object-by-fowarding-the" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<ul>
<li>
<a name="Checks-for-a-method-provided-by-this-the-delegate-object-by-forwarding-the"></a>
<h1 >Checks for a method provided by this the delegate object by forwarding the<a href="#Checks-for-a-method-provided-by-this-the-delegate-object-by-forwarding-the" class="wiki-anchor">¶</a></h1>
<a name="call-through-__getobj__"></a>
<h1 >call through __getobj__.<a href="#call-through-__getobj__" class="wiki-anchor">¶</a></h1>
<h1></h1>
</li>
</ul>
<ul>
<li>def respond_to?(m, include_private = false)</li>
<li>return true if super</li>
<li>return self.<strong>getobj</strong>.respond_to?(m, include_private)</li>
</ul>
<ul>
<li>def respond_to_missing?(m, include_private = false)</li>
<li>
<strong>getobj</strong>.respond_to?(m, include_private)<br>
end</li>
</ul>
<pre><code>#
</code></pre>
<p>Only caveat is that after a change of object of different class, the method can produce a NoMethodError when called. (same as Ruby 1.8)<br>
Any objection?<br>
=end</p> Ruby master - Bug #2206 (Closed): lib/delegate: inconsistency between respond_to? and sendhttps://bugs.ruby-lang.org/issues/22062009-10-14T13:06:05Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'<br>
class A<br>
private<br>
def private_method<br>
:bar<br>
end<br>
end</p>
<p>x = SimpleDelegator.new(A.new)<br>
x.respond_to?(:private_method, true) # ==> true<br>
x.send(:private_method) # ==> NoMethodError</p>
<p>I expected the call to private_method to be delegated. The attached patch fixes the problem. It is not very elegant but I couldn't think of anything better.<br>
=end</p> Ruby master - Bug #2173 (Closed): rake missing rake/contrib/*https://bugs.ruby-lang.org/issues/21732009-10-03T15:53:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Builtin rake is missing components that were part of the gem.</p>
<p>ruby187 -v -e "require 'rubygems'; require 'rake'; p require 'rake/contrib/sshpublisher'"<br>
ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]<br>
true</p>
<p>ruby19 -v -e "require 'rubygems'; require 'rake'; p require 'rake/contrib/sshpublisher'"<br>
ruby 1.9.2dev (2009-08-30 trunk 24705) [i386-darwin10.0.0]<br>
-e:1:in <code>require': no such file to load -- rake/contrib/sshpublisher (LoadError) from -e:1:in </code>'</p>
<p>This affects, among others, some popular gems (some of which have been fixed, others not). Unless there's a compelling reason not to, the contrib rake tasks should be included in core.<br>
=end</p> Ruby 1.8 - Bug #2107 (Closed): Matrix: 1/any_matrix bug (fixed)https://bugs.ruby-lang.org/issues/21072009-09-17T13:43:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin</p>
<blockquote>
<p>ruby -r matrix -e "p 1/Matrix<a class="wiki-page new" href="https://bugs.ruby-lang.org/projects/ruby-18/wiki/1">1</a>"</p>
</blockquote>
<p>/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/matrix.rb:931:in <code>/': undefined local variable or method </code>_M' for #<Matrix::Scalar:0x1001199b8 @value=1> (NameError)<br>
from -e:1</p>
<p>Fixed in revision 24953</p>
<p><a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=24953" class="external">http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=24953</a><br>
=end</p> Ruby master - Bug #1885 (Closed): Proper comparison of recursive Struct & Rangehttps://bugs.ruby-lang.org/issues/18852009-08-05T05:30:15Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The following code freezes the latest ruby 1.9:</p>
<p>MyClass = Struct.new(:foo)<br>
x = MyClass.new; x[:foo] = x<br>
y = MyClass.new; y[:foo] = y<br>
x == y # Loops forever (can not be interrupted)</p>
<p>Solution: rb_struct_equal & rb_struct_eql should handle recursion in a similar fashion as Array and Hash (i.e. by calling rb_exec_recursive_paired and returning Qtrue if recursion is detected). I could make a patch if needed.</p>
<p>Searching the source code for rb_exec_recursive revealed that Range is potentially recursive too (see range_inspect). The ==, eql? and === methods do not call rb_exec_recursive_paired and are thus also potentially troublesome. To build a recursive Range is not trivial though; either some intermediate container class is needed or else some crazy thing like:</p>
<p>class CrazyRange < Range<br>
def initialize<br>
super(self..self)<br>
end</p>
<pre><code> def <=>(x)
0 # Needed so CrazyRange can be the begin and end values of a range...
end
</code></pre>
<p>end</p>
<p>CrazyRange.new == CrazyRange.new # Loops forever (can not be interrupted)</p>
<p>I'm not sure that it is worth modifying ==, eql? and === to use rb_exec_recursive_paired and make them bulletproof.</p>
<p>Note that both Struct#hash and Range#hash face the same issue than Array#hash & Hash#hash (see issue <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Enumerable's #hash Raises ArgumentError When Recursive Values are Present (Closed)" href="https://bugs.ruby-lang.org/issues/1852">#1852</a>)<br>
=end</p> Ruby master - Bug #1686 (Closed): Enumerable#first brokenhttps://bugs.ruby-lang.org/issues/16862009-06-25T03:25:09Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Enumerable#first is broken in the current HEAD. If 4 <= n < enum_length + 4, enum.first(n) returns the (n-4)th element instead of an array of n elements. E.g.:</p>
<p>to6 = (1..6).to_enum # necessary so Enumerable#first is used<br>
p to6.first(2) # ==> [1, 2]<br>
p to6.first(4) # ==> 1<br>
p to6.first(9) # ==> 6<br>
p to6.first(10) # ==> [1, 2, 3, 4, 5, 6]</p>
<p>This is due to <a href="http://redmine.ruby-lang.org/repositories/diff/ruby-19/enum.c?rev=23622" class="external">http://redmine.ruby-lang.org/repositories/diff/ruby-19/enum.c?rev=23622</a> , after which ary[0] holds "n" as a long instead of a Fixnum. The comparison to Qnil isn't working as desired.</p>
<p>Either ary[0] holds INT2NUM(len) and first_i calls NUM2LONG + INT2NUM (as per my original patch, see <a href="http://redmine.ruby-lang.org/issues/show/1554" class="external">http://redmine.ruby-lang.org/issues/show/1554</a> ) or alternatively, enum_first could use take_i or enum_take when there is an argument, since they behave the same way in that case.<br>
=end</p> Ruby master - Feature #1667 (Closed): IO#codepoints, IO#each_codepoint, and StringIOhttps://bugs.ruby-lang.org/issues/16672009-06-20T21:47:52Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Almost all "iterators" of <code>String</code> are present in <code>IO</code> and <code>StringIO</code>: <code>#each_char</code>, <code>#each_byte</code>, <code>#each_line</code> and their corresponding <code>#chars</code>, <code>#bytes</code>, <code>#lines</code>. Only <code>#each_codepoint</code> and <code>#codepoints</code> are not defined in <code>IO</code> and <code>StringIO</code>.</p>
<p>Unless there is a compelling reason not to, it would be useful if these were defined. This would mirror the coherence with all other <code>each_</code>* methods that exist in both <code>String</code>, <code>IO</code> and <code>StringIO</code>.</p> Ruby master - Bug #1666 (Closed): Confusion in documentation for lines vs each_line, etc...https://bugs.ruby-lang.org/issues/16662009-06-20T21:44:22Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Currently, IO#lines is defined as "to_enum(:each_line, *args)" and thus will ignore a block if one is given.<br>
On the other hand, String#lines and String#each_line are aliases, and thus will both execute the block, if one given. The same is true for StringIO#lines and StringIO#each_line.</p>
<p>The same distinction exist in IO for #bytes vs #each_byte, #chars vs #each_char, while these pairs are aliases in String and StringIO.</p>
<p>To add to the confusion, the documentation is different for String#lines vs String#each_line, #bytes vs #each_byte, #chars vs #each_char (although they are aliases). StringIO#bytes, #lines & #chars are not documented at all.</p>
<p>So either:</p>
<ol>
<li>there should not be a distinction (and IO's implementation and doc should be changed to reflect that)<br>
or 2) the distinction is intentional (and String + StringIO's implementation should be changed to relect that)<br>
or 3) there is a compelling reason why the behavior in IO should be different than in String and StringIO and that should be spelled out in the doc.</li>
</ol>
<p>In all cases, the documentation for String should be cleaned up; for example String#each_char doesn't state that an enumerator is returned if no block is given (contrary to the doc for String#chars) and the examples are wrong since they use #each (which no longer exists) instead of #each_char.</p>
<p>Finally, the pair #codepoints and #each_codepoint is in a similar mismatch of documentation in String. I'll post a separate feature request to add IO#codepoints, etc...<br>
=end</p> Ruby master - Bug #1665 (Closed): Enumerable#reverse_each, #entries, #to_a documentation [patch]https://bugs.ruby-lang.org/issues/16652009-06-20T20:40:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The following are missing from the 1.8.7 release News:<br>
Enumerable#reverse_each (new method)<br>
Enumerable#to_a, #entries (takes optional arguments)</p>
<p>Since the 1.9 release News refer to the 1.8.7 news, this fixes both 1.8.7 and 1.9 release news.</p>
<p>Moreover the documentation for Enumerable#to_a, #entries needs to be updated in both the 1.8.7 and 1.9 releases (patches for both included).<br>
=end</p> Ruby master - Bug #1664 (Closed): Kernel#define_singleton_method not documented [patch]https://bugs.ruby-lang.org/issues/16642009-06-20T19:58:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Kernel#define_singleton_method is currently missing its documentation.<br>
I propose the following:</p>
<p>call-seq:<br>
define_singleton_method(symbol, method) => new_method<br>
define_singleton_method(symbol) { block } => proc</p>
<p>Defines a singleton method in the receiver. The <em>method</em><br>
parameter can be a +Proc+ or +Method+ object.<br>
If a block is specified, it is used as the method body. This block<br>
is evaluated using <code>instance_eval</code>.</p>
<pre><code>class A
class << self
def class_name
to_s
end
end
end
A.define_singleton_method(:who_am_i) do
"I am: #{class_name}"
end
A.who_am_i # ==> "I am: A"
guy = "Bob"
guy.define_singleton_method(:hello) { "#{self}: Hello there!" }
guy.hello # => "Bob: Hello there!"
</code></pre>
<p>I've included the corresponding patch. This method should also be documented in the 1.8.7 branch.<br>
=end</p> Ruby master - Bug #1663 (Closed): Small documentation fixes [patch]https://bugs.ruby-lang.org/issues/16632009-06-20T19:53:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
This patch improves the documentation for:<br>
String#partition, String#rpartition (argument can be regexp)<br>
Module#<=> (for modules without relationship, returns nil, not -1)<br>
Range#==, Struct.new, Array#hash: typos</p>
<p>These should be backported to the 1.8 branch.<br>
=end</p> Ruby master - Bug #1554 (Closed): Enumerator#first & #take should consume only what is needed [pa...https://bugs.ruby-lang.org/issues/15542009-06-02T05:38:59Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Currently, in Ruby 1.9.x:</p>
<p>require 'stringio'<br>
s = StringIO.new("first \n second \n third")</p>
<p>s.rewind<br>
p s.take(1), s.take(1)</p>
<a name="Prints-first-n-and-second-n"></a>
<h1 >Prints "[first \n]" and "[ second \n]"<a href="#Prints-first-n-and-second-n" class="wiki-anchor">¶</a></h1>
<p>s.rewind<br>
p [s.first], [s.first]</p>
<a name="Prints-first-n-and-second-n-2"></a>
<h1 >Prints "[first \n]" and "[ second \n]"<a href="#Prints-first-n-and-second-n-2" class="wiki-anchor">¶</a></h1>
<p>s.rewind<br>
p s.first(1), s.first(1)</p>
<a name="Prints-first-n-and-third"></a>
<h1 >Prints "[first \n]" and "[third]"<a href="#Prints-first-n-and-third" class="wiki-anchor">¶</a></h1>
<p>I believe most people would expect that [s.first], s.first(1) and s.take(1) should be the same and have the same side effects, if any. It is also more efficient that :each yields just the right number of times necessary to complete the request. As such it would be preferable if the last printout was the same as the previous two.</p>
<p>Note that in Ruby 1.8.7, the output for Enumerable#take is also wrong.</p>
<p>The included patches fix this issue for both versions.</p>
<p>I took the opportunity to change #first so that it calls :to_int on its argument only once if it needs to be converted. Before the patch it is called twice. This brings it in line with Array#first and Enumerable#take.</p>
<p>Note: rubyspecs have been updated.<br>
=end</p> Ruby master - Bug #1510 (Closed): [patch] String#partition can return wrong result or crashhttps://bugs.ruby-lang.org/issues/15102009-05-25T07:36:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The attached patch fixes a problem that occurs when the argument of String#partition needs to be converted using :to_str.</p>
<p>E.g:</p>
<p>class C<br>
def to_str<br>
"foo"<br>
end<br>
end<br>
p "foo-bar".partition(C.new)</p>
<p>Before patch:<br>
["", #<C:0x2c62a8>, "foo-bar"]</p>
<p>After patch:<br>
["", "foo", "-bar"]</p>
<p>RubySpecs has been updated. Without the version guard, it crashes Ruby.<br>
=end</p> Ruby master - Bug #1487 (Closed): String#each_char must return selfhttps://bugs.ruby-lang.org/issues/14872009-05-19T14:27:48Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
str.each_char{} currently returns a copy of str. It should return self. This also affects Ruby 1.8.7</p>
<p>Poor man's diff for rb_str_each_char:</p>
<pre><code> rb_encoding *enc;
</code></pre>
<ul>
<li>VALUE orig = str;<br>
RETURN_ENUMERATOR(str, 0, 0);<br>
str = rb_str_new4(str);<br>
...</li>
</ul>
<ul>
<li>return str;</li>
</ul>
<ul>
<li>return orig;<br>
=end</li>
</ul> Ruby master - Bug #1448 (Closed): [patch] Proper handling of recursive arrayshttps://bugs.ruby-lang.org/issues/14482009-05-09T11:47:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Dealing with recursive arrays & hashes can be tricky.</p>
<p>The current handling of recursive arrays is much improved over that of Ruby 1.8.6. Array comparison still has some bugs though.</p>
<p>For instance:<br>
x = []; x << x<br>
y = [[x]]<br>
x == y # ==> true<br>
y == x # ==> false, should be true!</p>
<p>Morevoer, recursive arrays that are built the same way are not recognized as equal:<br>
z = []; z << z<br>
x == z # ==> false, should be true!</p>
<p>Needless to say, arrays that have the same elements (e.g. a single element, containing a single element, ...) but built differently way are not recognized as equal:<br>
stone = []; stepping = [stone]; stone << stepping<br>
x == stepping # ==> false, would be nice to be true!</p>
<p>The attached patch fixes all of these problems :-)</p>
<ul>
<li>How:<br>
The function rb_exec_recursive handles the recursivity by pushing and poping the elements it encounters for a given method (for example eql?). For such comparisons, instead of keeping track of the elements it encounters, I modified it so that it keeps track of both the elements being compared. A recursion is detected only when a matching pair is found.</li>
</ul>
<p>This takes care of the first problem. For the next two, we only need to observe that if we have a recursion on the pair (x,y) when comparing x and y, then it is because they are not different! Changing the return value for recursive cases from nil (not comparable) / false (different) to Qundef (unknown yet) makes comparison of complex recursive "trees" work beautifully. I've added some cute samples in rubyspecs (core/array/shared/equal.rb)</p>
<ul>
<li>Implementation details:<br>
Previous recursive_push/pop/check maintained a hash of encountered object ids, setting hash[obj] = true. I modified them so that in "paired" cases, it sets hash[obj] = paired_obj. If a pair (obj, different_paired_obj) is encountered later on, I set hash[obj] to {paired_obj => true, different_paired_obj => true}.</li>
</ul>
<p>This way, there is basically no runtime cost to this technique, except in the complex recursive cases. Only for these complex cases is there a small additional cost for the hash creation/destruction.</p>
<ul>
<li>Last problem:<br>
There is one more problem that my patch doesn't cover (lack of mri-fu): hashes for recursive structures are incorrect. As per the official doc, "a.eql? b" should imply "a.hash == b.hash". On the other hand, we have (before or after my patch):<br>
a = [x]<br>
x.eql? a # ==> true<br>
a.eql? x # ==> true<br>
x.hash == a.hash # ==> false, should have same hash</li>
</ul>
<p>The solution is that when calculating the hash for an array, if a recursion is detected, then the hash should return a fixed value (say 0 or -length) <em>for the original</em> array. Currently, 0 is returned but at the level that the recursion is detected. In Ruby pseudo-code, it would look like:</p>
<pre><code> static VALUE
recursive_hash(VALUE ary, VALUE dummy, int recur)
{
long i, h;
VALUE n;
if (recur) {
</code></pre>
<ul>
<li>
<pre><code> raise HashingRecursionDetected
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> return LONG2FIX(0);
}
h = rb_hash_start(RARRAY_LEN(ary));
for (i=0; i<RARRAY_LEN(ary); i++) {
n = rb_hash(RARRAY_PTR(ary)[i]);
h = rb_hash_uint(h, NUM2LONG(n));
}
h = rb_hash_end(h);
return LONG2FIX(h);
</code></pre>
<p>}</p>
<p>static VALUE<br>
rb_ary_hash(VALUE ary)<br>
{<br>
return rb_exec_recursive(recursive_hash, ary, 0);</p>
</li>
</ul>
<ul>
<li>rescue HashingRecursionDetected</li>
<li>
<pre><code> return -length
</code></pre>
}</li>
</ul>
<p>A similar modification must be made for hash.c.</p>
<p>Thanks</p>
<p>Marc-André Lafortune<br>
=end</p> Ruby master - Bug #1440 (Closed): Array#flatten!(0) should return nil, not selfhttps://bugs.ruby-lang.org/issues/14402009-05-07T15:42:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
As per doc, flatten!(0) does not make modifications and should thus return nil.</p>
<p>[].flatten! # ==> nil<br>
[].flatten!(42) # ==> nil<br>
[].flatten!(-1) # ==> nil<br>
[].flatten!(0) # ==> []</p>
<p>Poor man's diff for "rb_ary_flatten_bang"</p>
<ul>
<li>
<pre><code>if (level == 0) return ary;
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code>if (level == 0) return Qnil;
</code></pre>
</li>
</ul>
<p>=end</p> Ruby master - Bug #1439 (Closed): Array#sample returns wrong results for negative argumenthttps://bugs.ruby-lang.org/issues/14392009-05-07T12:27:25Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ ruby1.9 -v -e "p [1,2].sample(-1)"<br>
ruby 1.9.2dev (2009-05-06 trunk 23352) [i386-darwin9.6.0]<br>
[1, 2, false]<br>
=end</p> Ruby master - Bug #1385 (Closed): Wonderful undocumented feature in Ruby 1.8.7 & 1.9https://bugs.ruby-lang.org/issues/13852009-04-17T13:40:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
6 months ago, I begged for a natural way to construct a Hash from key-value pairs: <a href="http://redmine.ruby-lang.org/issues/show/666" class="external">http://redmine.ruby-lang.org/issues/show/666</a><br>
Maybe because of a lack of superstitious devil worshippers, there was no additional comment on this issue # 666, which seems even stranger after a discovery I made by pure random luck (hey, my last name is not Lafortune for nothing!). It appears there <em>already is</em> a way, using Hash::[]</p>
<p>Example:<br>
Hash[[[:i_like, :ruby], [:hello, "world!"], [:answer, 42]]]<br>
=> {:i_like => :ruby, :hello => "world!", :answer => 42}</p>
<p>Wouhou, exciting! This works in both Ruby 1.8.7 and 1.9.1, but it is not documented <em>anywhere</em> where it should:<br>
<a href="http://www.ruby-doc.org/core-1.9/classes/Hash.html#M002653" class="external">http://www.ruby-doc.org/core-1.9/classes/Hash.html#M002653</a><br>
<a href="http://www.ruby-doc.org/core-1.8.7/classes/Hash.html#M000148" class="external">http://www.ruby-doc.org/core-1.8.7/classes/Hash.html#M000148</a><br>
<a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7/NEWS" class="external">http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7/NEWS</a><br>
<a href="http://eigenclass.org/hiki/Changes+in+Ruby+1.9" class="external">http://eigenclass.org/hiki/Changes+in+Ruby+1.9</a><br>
The Ruby Programming Language (section 9.5.3.1)</p>
<p>At first I thought maybe my satanic incantations were to thank for this hidden feature, but the huge 1.9 changelog reads:</p>
<p>Fri Oct 26 01:48:28 2007 Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a></p>
<pre><code>* hash.c (rb_hash_s_create): Hash#[] now takes assocs as source of
hash conversion.
</code></pre>
<p>So, thank you Matz!</p>
<p>I'm thus filing a bug report for the missing documentation, praying that the reason it is not documented is a simple oversight and that we can officially count on this for the future. In any case I eagerly included this cool feature in my backports for 1.8.x (<a href="http://github.com/marcandre/backports" class="external">http://github.com/marcandre/backports</a> ) since I still don't get the point of 1.8.7 (<a href="http://blog.marc-andre.ca/2009/04/whats-point-of-ruby-187.html" class="external">http://blog.marc-andre.ca/2009/04/whats-point-of-ruby-187.html</a> ) and I'll use Hash::[] until we get (one day maybe) my dreamed Enumerable#to_hash which I still favor.</p>
<p>I'd propose an updated doc similar to the following:</p>
<p>/*</p>
<ul>
<li>call-seq:</li>
<li>
<pre><code>Hash[ key, value, ... ] => hash
</code></pre>
</li>
<li>
<pre><code>Hash[ [ [key, value], ... ] ] => hash
</code></pre>
</li>
<li>
<pre><code>Hash[ object ] => hash
</code></pre>
</li>
<li>
<li>Creates a new hash populated with the given objects. Equivalent to</li>
<li>the literal <code>{ <i>key</i> => <i>value</i>, ... }</code>. In the first</li>
<li>form, keys and values occur in pairs, so there must be an even number of arguments.</li>
<li>The second and third form take a single argument which is either</li>
<li>an array of key-value pairs or an object convertible to a hash.</li>
<li>
<li>
<pre><code>Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200}
</code></pre>
</li>
<li>
<pre><code>Hash[ [ ["a" => 100], ["b" => 200] ] ] #=> {"a"=>100, "b"=>200}
</code></pre>
</li>
<li>
<pre><code>Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200}
</code></pre>
</li>
<li>
<pre><code>{"a" => 100, "b" => 200} #=> {"a"=>100, "b"=>200}
</code></pre>
</li>
</ul>
<p>*/</p>
<p>Is it just me or is the last example not quite insightful? In any case, if a different text than mine is used, note that the present version still mentions the old 1.8 syntax: <code>{ <i>key</i>, <i>value</i>, ... }</code></p>
<p>Is there a prize for the most long-winded bug report just for the documentation? To be a sure winner, I'll add that I find interesting that my infamous feature request # 666 would make the second form merge naturally into the third, since an array of key-value pairs would be convertible to a hash!</p>
<p>Thank you for your attention,</p>
<p>Marc-André Lafortune<br>
=end</p> Ruby master - Bug #1165 (Closed): Range.eql? and Range.== bug with subclasseshttps://bugs.ruby-lang.org/issues/11652009-02-17T05:10:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Contrary to the documentation (and to what I would expect):</p>
<p>class TrivialRangeSubclass < Range<br>
end</p>
<p>TrivialRangeSubclass.new(0,1) == Range.new(0,1) # ==> false</p>
<p>This bug is present in the current versions of ruby 1.8.7 and 1.9.1. As a matter of curiosity, I checked both JRuby (1.1.6) and rubinius (0.10.0) and they both return true (as they should).</p>
<p>Although I'm not familiar with the source code, it seams like a simple change, so I've included a patch for the 1.9.1 version. I hope I did things correctly! Changelog could read like:</p>
<p>Mon Feb 16 14:35:35 2009 Marc-Andre Lafortune <a href="mailto:ruby-lang@marc-andre.ca" class="email">ruby-lang@marc-andre.ca</a></p>
<pre><code>* range.c (range_eql, range_eq): fixed equality to work for
subclasses of Range.
* test/ruby/test_range.rb: add assertions for above.
</code></pre>
<p>Thank you!<br>
=end</p>