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 - Feature #17785 (Open): Allow named parameters to be keywordshttps://bugs.ruby-lang.org/issues/177852021-04-08T15:08:40Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We should allow named parameters to be keywords and use add a trailing <code>_</code> to the corresponding variable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="k">class</span><span class="p">:)</span>
<span class="n">arg</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">class_</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">check</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="ss">class: </span><span class="no">Integer</span><span class="p">)</span> <span class="c1"># => true</span>
</code></pre>
<p>Currently, if we want such an API we have to use <code>**rest</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">rest</span><span class="p">)</span>
<span class="n">class_</span> <span class="o">=</span> <span class="n">rest</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="ss">:class</span><span class="p">)</span> <span class="p">{</span> <span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">(</span><span class="s1">'missing keyword: :class'</span><span class="p">)}</span>
<span class="k">if</span> <span class="n">rest</span><span class="p">.</span><span class="nf">size</span> <span class="o">></span> <span class="mi">1</span>
<span class="n">unknown</span> <span class="o">=</span> <span class="n">rest</span><span class="p">.</span><span class="nf">keys</span> <span class="o">-</span> <span class="p">[</span><span class="ss">:class</span><span class="p">]</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">(</span><span class="s2">"unknown keyword(s): :</span><span class="si">#{</span><span class="n">unknown</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">', :'</span><span class="p">)</span><span class="si">}</span><span class="s2">)
end
arg.is_a?(class_)
end
</span></code></pre>
<p>This is very verbose, much less convenient, much less readable, prevents <code>steep</code> from generating the proper signature, etc.</p>
<p>We should do the same for pattern match.</p> Ruby master - Misc #17569 (Open): `uri` lib maintainershiphttps://bugs.ruby-lang.org/issues/175692021-01-22T15:48:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I’d like to merge <a href="https://github.com/ruby/uri/pull/15" class="external">https://github.com/ruby/uri/pull/15</a> but it is an API change. I would release v1.0.0. <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/271">@akr (Akira Tanaka)</a> is the official maintainer of <code>uri</code>… Is he still interested in this role? Otherwise we could put “Ruby core team” in the listing…</p> Ruby master - Feature #17513 (Open): Methods of shareable objects and UnboundMethods should be sh...https://bugs.ruby-lang.org/issues/175132021-01-06T06:04:18Zmarcandre (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">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">f</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">shareable?</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> <span class="c1"># => true</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="n">f</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">to_proc</span><span class="p">)</span> <span class="c1"># => Proc, ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="n">f</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="c1"># => Ractor::Error, expected Method</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="no">Foo</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"># => Ractor::Error, expected UnboundMethod</span>
</code></pre> 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 - Misc #17502 (Open): C vs Rubyhttps://bugs.ruby-lang.org/issues/175022021-01-02T20:25:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Some features are coded in a mix of Ruby and C (e.g. ractor.rb).</p>
<p>External gems don't have access to this. The C-API to deal with keyword parameters is also very verbose the parsing and the engine does not know it.</p>
<p>Moreover, some optimization PRs are simply rewriting C-code into Ruby using pseudo C code.</p>
<p>I understand the intentions are great, but changes like <a href="https://github.com/ruby/ruby/pull/4018/files" class="external">https://github.com/ruby/ruby/pull/4018/files</a> seem a symptom that something needs to be improved with the C api.</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gd">-static VALUE
- flo_zero_p(VALUE num)
- {
- return flo_iszero(num) ? Qtrue : Qfalse;
- }
</span># in different file:
<span class="gi">+ def zero?
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'flo_iszero(self) ? Qtrue : Qfalse'
+ end
</span></code></pre>
<p>It seems to me that this is a way to circumvent a deeper issue. Is this the right direction?</p>
<p>Is there a plan for an API that would:</p>
<ol>
<li>be accessible to C extensions</li>
<li>can't be re-written any faster in pseuso-C in Ruby</li>
<li>has an easy way to define keyword parameters?</li>
</ol>
<p>I realize that RBS may give perfect signatures, but ideally <code>parameters</code> would be more informative for C-functions too.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:yield</span><span class="p">).</span><span class="nf">parameters</span>
<span class="c1"># => [[:req, :obj], [:key, :move]] # good!</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:initialize</span><span class="p">).</span><span class="nf">parameters</span>
<span class="c1"># => [[:rest]] # not good, should be [[:key, :blocking]]</span>
</code></pre> Ruby master - Feature #17414 (Open): Ractor should allow access to shareable attributes for Modul...https://bugs.ruby-lang.org/issues/174142020-12-21T01:55:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Current situation is <em>very</em> limiting.</p>
<p>Use-case: global config.</p>
<p>Example: <a href="https://github.com/ruby/psych/blob/master/lib/psych.rb#L637-L640" class="external">yaml has a global config</a> and it's not clear to me how to make that Ractor-aware (nicely).</p>
<p>It is possible to have the same effect but in ugly ways:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Using instance variables of Module not allowed:</span>
<span class="k">module</span> <span class="nn">Config</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="nb">attr_accessor</span> <span class="ss">:conf</span>
<span class="k">end</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">42</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">66</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => can not access instance variables from non-main Ractors</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">puts</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => can not access instance variables from non-main Ractors</span>
<span class="c1"># Same functionality using constants allowed:</span>
<span class="k">module</span> <span class="nn">Config</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">conf</span>
<span class="no">CONF</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">conf</span><span class="o">=</span><span class="p">(</span><span class="n">new_conf</span><span class="p">)</span>
<span class="n">remove_const</span><span class="p">(</span><span class="ss">:CONF</span><span class="p">)</span>
<span class="nb">const_set</span><span class="p">(</span><span class="ss">:CONF</span><span class="p">,</span> <span class="n">new_conf</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">CONF</span> <span class="o">=</span> <span class="mi">42</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">66</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">puts</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => 66</span>
<span class="c1"># Same functionality using methods allowed:</span>
<span class="k">module</span> <span class="nn">Config</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">conf</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">conf</span><span class="o">=</span><span class="p">(</span><span class="n">new_conf</span><span class="p">)</span>
<span class="n">singleton_class</span><span class="p">.</span><span class="nf">undef_method</span><span class="p">(</span><span class="ss">:conf</span><span class="p">)</span>
<span class="n">define_singleton_method</span><span class="p">(</span><span class="ss">:conf</span><span class="p">,</span> <span class="o">&</span><span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="no">Proc</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="n">new_conf</span> <span class="p">}))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="o">=</span> <span class="mi">66</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">puts</span> <span class="no">Config</span><span class="p">.</span><span class="nf">conf</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => 66</span>
</code></pre>
<p>The priority would be to allow reading these instance variables if they are shareable. Ideally writing would also be allowed, but limiting that to main ractor is less probablematic than with reading.</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 - Feature #17404 (Open): Ractor `move:` API to allow shareability checkhttps://bugs.ruby-lang.org/issues/174042020-12-17T18:29:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to <code>ractor.send(message)</code> and express that <code>message</code> should be shareable. Currently I'm given two choices: <code>move: true</code> and <code>move: false</code> / nothing, neither of which have an effect if my <code>message</code> is shareable, and neither of which will tell me in case there's a bug in my program and <code>message</code> is not shareable.</p>
<p>Could we consider a slightly different API (for 3.0 or 3.1)?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">pass: :copy</span><span class="p">)</span> <span class="c1"># => like current `move: false`</span>
<span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">pass: :move</span><span class="p">)</span> <span class="c1"># => like current `move: true`</span>
<span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="ss">pass: :share</span><span class="p">)</span> <span class="c1"># => raise in case message is not shareable</span>
<span class="n">ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="c1"># => same as `pass: :copy`</span>
</code></pre> Ruby master - Feature #17393 (Open): `Ractor::Moved#inspect`https://bugs.ruby-lang.org/issues/173932020-12-14T20:48:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It could be helpful to define <code>Ractor::Moved#inspect</code> and output the source location of when the data was moved. If preferred, it could raise an error with this information:</p>
<pre><code>x = []
Ractor.new{ receive }.send(x, move: true)
p x # => "Data was moved in `example.rb:4`"
# or
p x # => "Data was moved in `example.rb:4`" (Ractor::MovedError)
</code></pre>
<p>Also <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/710">@zverok (Victor Shepelev)</a> and myself were wondering if there was a technical reason to freeze <code>Ractor::Moved</code>? If not, is it only to "force" people to use refinements (which are allowed on frozen classes)? It's already known that it is in general a bad idea to modify builtin classes, so it's not clear to me that freezing that class is best.</p> Ruby master - Feature #17363 (Assigned): Timeoutshttps://bugs.ruby-lang.org/issues/173632020-12-03T14:58:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Builtin methods like <code>Queue.pop</code> and <code>Ractor.receive</code> have no timeout parameter.</p>
<p>We should either:</p>
<ul>
<li>provide such a parameter</li>
<li>and/or provide a <code>Timeout::wake</code> that raises an timeout error only if the block is currently sleeping.</li>
</ul>
<p>Details:</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="c1"># ...</span>
<span class="n">elem</span> <span class="o">=</span> <span class="no">Timeout</span><span class="o">::</span><span class="n">timeout</span><span class="p">(</span><span class="mi">42</span><span class="p">)</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="c1"># => It is possible that an element is retreived from the queue but never stored in `elem`</span>
<span class="n">elem</span> <span class="o">=</span> <span class="no">Timeout</span><span class="o">::</span><span class="n">wake</span><span class="p">(</span><span class="mi">42</span><span class="p">)</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="c1"># => Guaranteed that either element is retrieved from the queue or an exception is raised, never both</span>
<span class="no">Timeout</span><span class="o">::</span><span class="n">wake</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="p">{</span> <span class="kp">loop</span> <span class="p">{}</span> <span class="p">}</span> <span class="c1"># => infinite loop</span>
<span class="c1"># and/or</span>
<span class="n">elem</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="nf">pop</span><span class="p">(</span><span class="ss">timeout: </span><span class="mi">42</span><span class="p">)</span>
</code></pre>
<p>Currently, the only reliable way to have a Queue that accepts a timeout is to re-implement it from scratch. This post describe how involved that can be: <a href="https://spin.atomicobject.com/2017/06/28/queue-pop-with-timeout-fixed/" class="external">https://spin.atomicobject.com/2017/06/28/queue-pop-with-timeout-fixed/</a></p> Ruby master - Bug #17359 (Open): Ractor copy mode is not Ractor-safehttps://bugs.ruby-lang.org/issues/173592020-12-01T08:29:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It should not be possible to mutate an object across Ractors, but the copy mode allows it currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="nb">attr_accessor</span> <span class="ss">:x</span>
<span class="k">def</span> <span class="nf">initialize_copy</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="vg">$last</span> <span class="o">=</span> <span class="nb">self</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">o</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span>
<span class="n">o</span><span class="p">.</span><span class="nf">x</span> <span class="o">=</span> <span class="mi">42</span>
<span class="n">r</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">o</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">copy</span><span class="o">|</span>
<span class="nb">puts</span> <span class="n">copy</span><span class="p">.</span><span class="nf">x</span> <span class="c1"># => 42</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:sync</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:sync</span>
<span class="nb">puts</span> <span class="n">copy</span><span class="p">.</span><span class="nf">x</span> <span class="c1"># => 666</span>
<span class="k">end</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span> <span class="c1"># => :sync</span>
<span class="vg">$last</span><span class="p">.</span><span class="nf">x</span> <span class="o">=</span> <span class="mi">666</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span> <span class="c1"># => :sync</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Maybe the <code>copy</code> object should be marked as moved?</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 - 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 - Feature #17210 (Open): More readable and useful `Set#inspect`https://bugs.ruby-lang.org/issues/172102020-10-02T04:33:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I would like to change <code>Set#inspect</code>/<code>to_s</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># before</span>
<span class="nb">puts</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="c1"># => "#<Set: {1, 2, 3}>"</span>
<span class="c1"># after</span>
<span class="nb">puts</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="c1"># => "Set[1, 2, 3]"</span>
</code></pre>
<p>This output is shorter, readable, and has the property that it corresponds to Ruby code</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 #16992 (Open): Sets: officially orderedhttps://bugs.ruby-lang.org/issues/169922020-06-26T20:30:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Officially, set elements have uncertain order. This predades when Hash started being ordered (Ruby 1.9.0, Xmas 2007). Sets have since been de-facto insertion-ordered. FYI, in those 13 years, there have been about 70 commits to <code>lib/set.rb</code>.</p>
<p>I have the impression that a non-negligible amount of code in the wild rely on sets being ordered, at least under most circumstances. I feel that this should be officialized.</p>
<p>If sets are truly unordered, then why do we hesitate to make an optimization of <code>&</code> and <code>|</code>: <a href="https://bugs.ruby-lang.org/issues/15281" class="external">https://bugs.ruby-lang.org/issues/15281</a></p>
<p>See also: <a href="https://bugs.ruby-lang.org/issues/14069" class="external">https://bugs.ruby-lang.org/issues/14069</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 - Feature #16989 (Open): Sets: need ♥️https://bugs.ruby-lang.org/issues/169892020-06-26T20:18:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I am opening a series of feature requests on <code>Set</code>, all of them based on this usecase.</p>
<p>The main usecase I have in mind is my recent experience with <code>RuboCop</code>. I noticed a big number of frozen arrays being used only to later call <code>include?</code> on them. This is <code>O(n)</code> instead of <code>O(1)</code>.</p>
<p>Trying to convert them to <code>Set</code>s causes major compatibility issues, as well as very frustrating situations and some cases that would make them much less efficient.</p>
<p>Because of these incompatibilities, <code>RuboCop</code> is in the process of using a custom class based on <code>Array</code> with optimized <code>include?</code> and <code>===</code>. <code>RuboCop</code> runs multiple checks on Ruby code. Those checks are called cops. <code>RuboCop</code> performance is (IMO) pretty bad and some cops currently are in <code>O(n^2)</code> where n is the size of the code being inspected. Even given these extremely inefficient cops, optimizing the 100+ such arrays (most of which are quite small btw) gave a 5% speed boost.</p>
<p>RuboCop PRs for reference: <a href="https://github.com/rubocop-hq/rubocop-ast/pull/29" class="external">https://github.com/rubocop-hq/rubocop-ast/pull/29</a><br>
<a href="https://github.com/rubocop-hq/rubocop/pull/8133" class="external">https://github.com/rubocop-hq/rubocop/pull/8133</a></p>
<p>My experience tells me that there are many other opportunities to use <code>Set</code>s that are missed because <code>Set</code>s are not builtin, not known enough and have no shorthand notation.</p>
<p>In this issue I'd like to concentrate the discussion on the following request: <code>Set</code>s should be core objects, in the same way that <code>Complex</code> were not and are now. Some of the upcoming feature requests would be easier (or only possible) to implement were <code>Set</code>s builtin.</p> Ruby master - Feature #16985 (Open): Improve `pp` for `Hash` and `String`https://bugs.ruby-lang.org/issues/169852020-06-25T17:28:06Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Could we improve <code>pp</code> for <code>Hash</code> and <code>String</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">pp</span><span class="p">({</span><span class="ss">hello: </span><span class="s1">'My name is "Marc-André"'</span><span class="p">})</span>
<span class="c1"># =></span>
<span class="p">{</span><span class="ss">hello: </span><span class="s1">'My name is "Marc-André"'</span><span class="p">}</span>
<span class="c1"># instead of</span>
<span class="p">{</span><span class="ss">:hello</span><span class="o">=></span><span class="s2">"My name is </span><span class="se">\"</span><span class="s2">Marc-André</span><span class="se">\"</span><span class="s2">"</span><span class="p">}</span>
</code></pre>
<p>If any key is non-symbol, they would continue to be output as <code><key> => <value></code>. If a string contains single quotes, or characters that need escaping (e.g. <code>"\n"</code>), current format would be used.</p>
<p>I'll gladly provide a PR if this is deemed acceptable.</p>
<p>I would even like this for <code>String#inspect</code> and <code>Hash#inspect</code> but it's not clear if this could lead to much incompatibility (maybe test suites?)</p> Ruby master - Feature #15918 (Open): Pattern matching for Sethttps://bugs.ruby-lang.org/issues/159182019-06-12T13:44:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, <code>Set</code> does not respond to <code>deconstruct</code>. Shouldn't we implement it using <code>to_a</code>?</p>
<pre><code>require 'set'
case Set[1, 2, 3]
in [1, 2, 3]
p "match"
else
p "no match"
end
# => "no match", should be "match"
</code></pre> Ruby master - Feature #15881 (Open): Optimize deconstruct in pattern matchinghttps://bugs.ruby-lang.org/issues/158812019-05-27T16:19:35Zmarcandre (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">A</span>
<span class="k">def</span> <span class="nf">deconstruct</span>
<span class="nb">puts</span> <span class="s1">'deconstruct called'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">case</span> <span class="no">A</span><span class="p">.</span><span class="nf">new</span>
<span class="k">in</span> <span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="mi">2</span>
<span class="k">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="mi">1</span>
<span class="k">else</span>
<span class="k">end</span>
</code></pre>
<p>Currently this outputs:</p>
<pre><code>deconstruct called
deconstruct called
=> 1
</code></pre>
<p>Shouldn't <code>deconstruct called</code> print only once, whenever the first deconstruction needed occurs?</p> Ruby master - Feature #15330 (Open): autoload_relativehttps://bugs.ruby-lang.org/issues/153302018-11-21T23:43:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to propose a way to autoload a constant using a relative path.</p>
<p>It could look like:</p>
<pre><code>autoload_relative :MyConst, 'models/my_const'
</code></pre>
<p>My proposal raises two questions:</p>
<ol>
<li>what's the future of <code>autoload</code>?</li>
</ol>
<p>I believe that <code>autoload</code> has been there for years, it is used successfully and has no real alternative.</p>
<p>I looked at a sample of 430 top gems (took the 500 top ranked according to Libraries.io, removed those that I failed to process). The number of those gems that appear to use <code>autoload</code> at least once is 94 of those (22%).</p>
<p>The number of lines in the code where <code>autoload</code> is called can be quite big. The top 5 are:<br>
vagrant: 235<br>
yard: 206<br>
ffaker: 155<br>
aws-sdk: 152<br>
rdoc: 92</p>
<p>This is a minimum bound, as some gems might be using loops, my processing would only detect the one place in the code with <code>autoload</code>.</p>
<ol start="2">
<li>are many autoladed paths relative?</li>
</ol>
<p>My preliminary numbers indicate that of the 94 gems using autoload, at least 75 are autoloading some relative files. That's a lower bound, as my algorithm is pretty crude and will only count the simplest cases as being relative. An example of gem my algorithm does not detect is <code>yard</code>, because the author wrote a small method to map the relative paths to global paths (code here: <a href="https://github.com/lsegal/yard/blob/master/lib/yard/autoload.rb#L3" class="external">https://github.com/lsegal/yard/blob/master/lib/yard/autoload.rb#L3</a> )</p>
<p>Of those where my processing detects the relative requires, a vast majority are relative. The average is that 94% of autoloaded files are relative and would benefit from <code>require_relative</code></p>
<p>In summary: I am convinced that <code>autoload</code> should remain in Ruby indefinitely. <code>autoload_relative</code> would actually be more useful than <code>autoload</code>. Even if the future of <code>autoload</code> remains uncertain, I would recommend adding <code>autoload_relative</code>; if it is ever decided to actually remove <code>autoload</code>, removing <code>autoload_relative</code> would not really add to the (huge) burden of gem maintainers.</p> Ruby master - Feature #15277 (Open): at_exechttps://bugs.ruby-lang.org/issues/152772018-11-02T19:23:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>There's currently no easy way to have code executed before a subsequent call to <code>exec</code>. One has to monkey-patch the builtin method.</p>
<p>I'd like to propose a new method <code>at_exec</code> that would be very similar to <code>at_exit</code>, except that the callbacks are triggered before the current process is replaced by the external command.</p>
<pre><code># This would output "Hello", "Bye", and "Foo"
at_exec { puts "Bye!" }
puts "Hello"
exec "echo Foo"
</code></pre>
<p>Use case: we roll our own in <code>DeepCover</code>. Some test suites will call <code>exec</code>, and we need to store our counters before that happens.</p> Ruby master - Feature #11816 (Assigned): Partial safe navigation operatorhttps://bugs.ruby-lang.org/issues/118162015-12-14T18:19:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'm extremely surprised (and disappointed) that, currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">x</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="n">x</span><span class="o">&</span><span class="p">.</span><span class="nf">foo</span><span class="p">.</span><span class="nf">bar</span> <span class="c1"># => NoMethodError: undefined method `bar' for nil:NilClass</span>
</code></pre>
<p>To make it safe, you have to write <code>x&.foo&.bar</code>. But if <code>foo</code> is never supposed to return <code>nil</code>, then that code isn't "fail early" in case it actually does. <code>nil&.foo.bar</code> is more expressive, simpler and is perfect if you want to an error if <code>foo</code> returned <code>nil</code>. To actually get what you want, you have to resort using the old form <code>x && x.foo.bar</code>...</p>
<p>In CoffeeScript, you can write <code>x()?.foo.bar</code> and it will work well, since it gets compiled to</p>
<pre><code class="js syntaxhl" data-language="js"><span class="k">if </span><span class="p">((</span><span class="nx">_ref</span> <span class="o">=</span> <span class="nf">x</span><span class="p">())</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">_ref</span><span class="p">.</span><span class="nx">foo</span><span class="p">.</span><span class="nx">bar</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
<p>All the discussion in <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Introduce "Safe navigation operator" (Closed)" href="https://bugs.ruby-lang.org/issues/11537">#11537</a> focuses on <code>x&.foo&.bar</code>, so I have to ask:</p>
<p>Matz, what is your understanding of <code>x&.foo.bar</code>?</p>
<p>I feel the current implementation is not useful and should be changed to what I had in mind. I can't see any legitimate use of <code>x&.foo.bar</code> currently.</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> Ruby master - Feature #9347 (Open): Accept non callable argument to detecthttps://bugs.ruby-lang.org/issues/93472014-01-03T07:37:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, the only argument that <code>Enumerable#detect</code> accepts is a callable object.</p>
<p>Shouldn't we accept non callable objects too?</p>
<pre><code>[42].detect(:not_found){} # => NoMethodError: undefined method `call' for :not_found:Symbol
# would return :not_found instead.
</code></pre>
<p>I'd suggest that if the given argument does not <code>respond_to? :call</code>, then it would be returned as is instead of raising an error as currently.<br>
Wouldn't this be more flexible and possibly more performant?</p>
<p>Inspired by <a href="http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda" class="external">http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda</a></p> Backport21 - Backport #9299 (Closed): Required keyowrd arguments and arityhttps://bugs.ruby-lang.org/issues/92992013-12-26T06:33:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>While fixing <a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: Method#arity for keyword arguments (Closed)" href="https://bugs.ruby-lang.org/issues/8072">#8072</a>, I noticed another bug: a required keyword argument should add 1 to the arity:</p>
<pre><code>proc{|required:|}.arity # => 0, should be 1
</code></pre> 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> Backport200 - Backport #8463 (Closed): Proc auto-splat bug with named argumentshttps://bugs.ruby-lang.org/issues/84632013-05-30T03:51:46Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I'd expect a proc to either do an implicit splat or not, but right now it looks for options before doing the implicit splat. Should it not do it after doing the implicit splat?</p>
<p>I thought that when a proc had an argument list with more than one element, it was the same to call it with a single array argument than with the same array splatted:</p>
<p>Proc{|a, ...| ... }.call([...]) == Proc{|a, ...}| ... }.call(*[...]) # => Because of implicit splat</p>
<p>But we have currently:</p>
<p>Proc.new{|a, *b, **c| p a, b, c}.call(1,2, bar: 3)</p>
<a name="gt-1-2-bargt3-OK"></a>
<h1 >=> 1, [2], {:bar=>3} : OK<a href="#gt-1-2-bargt3-OK" class="wiki-anchor">¶</a></h1>
<p>Proc.new{|a, *b, **c| p a, b, c}.call([1,2, bar: 3])</p>
<a name="gt-1-2-bargt3-Expected-same-as-above"></a>
<h1 >=> 1, [2, {:bar=>3}], {}: Expected same as above<a href="#gt-1-2-bargt3-Expected-same-as-above" class="wiki-anchor">¶</a></h1>
<p>Proc.new{|(a, *b), **c| p a, b, c}.call([1,2], bar: 3)</p>
<a name="gt-1-2-bargt3-OK-2"></a>
<h1 >=> 1, [2], {:bar=>3} : OK<a href="#gt-1-2-bargt3-OK-2" class="wiki-anchor">¶</a></h1>
<p>Proc.new{|(a, *b), **c| p a, b, c}.call([[1,2], bar: 3])</p>
<a name="gt-1-2-bargt3-Expected-same-as-above-2"></a>
<h1 >=> [1, 2], [{:bar=>3}], {}: Expected same as above<a href="#gt-1-2-bargt3-Expected-same-as-above-2" class="wiki-anchor">¶</a></h1>
<p>As an additional note, this affects some methods of Enumerable when yielding multiple arguments.</p>
<p>For example:</p>
<pre><code>def each; yield 1, 2, bar: 3; end
include Enumerable
each{|a, *b, **c| p a, b, c} # => 1, [2], {:bar => 3}: ok
detect{|a, *b, **c| p a, b, c} # => 1, [2, {:bar => 3}], {}: should be the same, no?
</code></pre>
<p>=end</p> Backport200 - Backport #8236 (Closed): super & named parameters bughttps://bugs.ruby-lang.org/issues/82362013-04-08T13:45:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
class Base<br>
def foo(*args)<br>
p args<br>
end<br>
end</p>
<p>class A < Base<br>
def foo(arg, bar: 'x')<br>
super<br>
end<br>
end<br>
A.new.foo 42 # => [42, {:bar=>"x"}] (ok)</p>
<p>class B < Base<br>
def foo(*args, bar: 'x')<br>
super<br>
end<br>
end<br>
B.new.foo 42 # => [[42], [:bar, "x"]] (not ok, should be same)<br>
=end</p> Backport200 - Backport #8188 (Closed): Wrong warning about __attached__https://bugs.ruby-lang.org/issues/81882013-03-30T13:34:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>ruby -w -e "ARGF.singleton_class.instance_eval{}"</p>
<a name="gt-warning-instance-variable-attached-not-initialized"></a>
<h1 >=> warning: instance variable <strong>attached</strong> not initialized<a href="#gt-warning-instance-variable-attached-not-initialized" class="wiki-anchor">¶</a></h1>
<p>Here's the test, but I'm not sure how to fix. Should rb_ivar_get(..., id_attached) replaced with rb_attr_get?</p>
<pre><code>diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb
index 580d3e8..8e3bd8c 100644
--- a/test/ruby/test_eval.rb
+++ b/test/ruby/test_eval.rb
@@ -215,6 +215,12 @@ class TestEval < Test::Unit::TestCase
end
end
+ def test_instance_eval_on_argf_singleton_class
+ assert_warning('', '[ruby-core:xxx]') do
+ ARGF.singleton_class.instance_eval{}
+ end
+ end
+
class Foo
Bar = 2
end
</code></pre> Backport200 - Backport #8154 (Closed): Remove/fix rb_check_block_callhttps://bugs.ruby-lang.org/issues/81542013-03-23T07:54:32Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Looking back in the history, I found that commit r36989 (abeedb0875f3) introduced rb_check_block_call, but (1) it uses obsolete rb_iterate and (2) it created a strange bug [<a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: Problems with Enumerable#zip caused by overriding Object#respond_to? (Closed)" href="https://bugs.ruby-lang.org/issues/8153">#8153</a>].</p>
<p>In r39877, I used rb_respond_to + rb_block_call instead. This way Array#zip is similar to Enumerable#zip and Lazy#zip.</p>
<p>rb_check_block_call should either be removed or fixed to avoid r36989.</p> Backport21 - Backport #8072 (Closed): Method#arity for keyword argumentshttps://bugs.ruby-lang.org/issues/80722013-03-11T10:18:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I would expect the following two methods to have the same arity:</p>
<pre><code>def old_way(req, options = {}); end
def new_way(req, **options); end
method(:new_way).arity # => 1, should be -2
</code></pre> Backport200 - Backport #8043 (Closed): Marshal will dump some object with singleton methodshttps://bugs.ruby-lang.org/issues/80432013-03-08T09:47:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The check for "dumpability" is incorrect:</p>
<pre><code>o = Object.new
def o.foo; end
Marshal.dump(o) # => TypeError: singleton can't be dumped
o.singleton_class.send :prepend, Enumerable
Marshal.dump(o) # => "\x04\be:\x0FEnumerablee:\vObjecto;\x06\0", should fail
</code></pre>
<p>=end</p> Backport200 - Backport #8025 (Closed): Module#included_modules includes classeshttps://bugs.ruby-lang.org/issues/80252013-03-06T12:38:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I see two problems in the following code:</p>
<pre><code>module Mixin
end
class C
prepend Mixin
end
C.included_modules # => [Mixin, C, Kernel]
</code></pre>
<ol>
<li>
<p>C should definitely not be there, since no class should ever appear in that list.</p>
</li>
<li>
<p>I wonder if Mixin should be there, since it was prepended to C, not included.</p>
</li>
</ol> Backport200 - Backport #7935 (Closed): Array#sample with random generatorhttps://bugs.ruby-lang.org/issues/79352013-02-24T13:00:13Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The Random generator method's rand is called with the wrong limit.</p>
<p>Kernel::rand(n) returns integer between 0 and n-1, but generator is called with (n-1).</p>
<p>For example:</p>
<p>require 'delegate'<br>
[1, 2].sample(1, random: Random.new) # => [1], or [2]<br>
[1, 2].sample(1, random: SimpleDelegator.new(Random.new)) # => [1], never [2]</p>
<p>test_random_ulong_limited</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 - Feature #7444 (Open): Array#product_sethttps://bugs.ruby-lang.org/issues/74442012-11-27T14:44:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to propose <code>Array#product_set</code> to return the product set of arrays (aka cartesian product)</p>
<pre><code>deck = [1..13, %i(spades hearts diamond clubs)].product_set
# => <#Enumerator ...>
deck.first(2) # => [[1, :spades], [2, :spades]]
</code></pre>
<p><code>product_set</code> would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do.</p>
<p>Although <code>Array.product</code> would be acceptable too, I feel that an instance method of array is best in the case, in the same way that <code>transpose</code> is an instance method and not a class method.</p>
<p>The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than <code>product</code>; the first time I head of <code>product</code> I was convinced that <code>[2,3,7].product # => 42</code>.</p>
<p>Addressing objections raised in <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Array::zip (Rejected)" href="https://bugs.ruby-lang.org/issues/6499">#6499</a>:</p>
<ol>
<li>This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of.</li>
</ol>
<p>It is cumbersome to write <code>arrays.first.product(*arrays[1..-1])</code> or similar and it hides what is going on.</p>
<p>Writing <code>arrays.product_set</code> is much nicer.</p>
<ol start="2">
<li>
<p>The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-)</p>
</li>
<li>
<p>[].product_set.to_a # => [[]]</p>
</li>
</ol>
<p>This can be seen from a cardinality argument, or for example because <code>array.repeated_permutation(n) == Array.new(n, array).product_set.to_a</code> and <code>array.repeated_permutation(0) == [[]]</code>.</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> 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> 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 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 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 - Feature #2771 (Closed): Matrix: constructor to build with blockhttps://bugs.ruby-lang.org/issues/27712010-02-21T06:10:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I believe the following simple constructor could be a helpful addition to matrix.rb</p>
<p>class Matrix</p>
<h1></h1>
<a name="Creates-a-matrix-of-row_size-x-column_size"></a>
<h1 >Creates a matrix of +row_size+ x +column_size+.<a href="#Creates-a-matrix-of-row_size-x-column_size" class="wiki-anchor">¶</a></h1>
<a name="It-fills-the-values-by-calling-the-given-block"></a>
<h1 >It fills the values by calling the given block,<a href="#It-fills-the-values-by-calling-the-given-block" class="wiki-anchor">¶</a></h1>
<a name="passing-the-current-row-and-column"></a>
<h1 >passing the current row and column.<a href="#passing-the-current-row-and-column" class="wiki-anchor">¶</a></h1>
<h1></h1>
<a name="m-Matrixbuild2-4-row-col-col-row-"></a>
<h1 >m = Matrix.build(2, 4) {|row, col| col - row }<a href="#m-Matrixbuild2-4-row-col-col-row-" class="wiki-anchor">¶</a></h1>
<a name="gt-Matrix0-1-2-3-1-0-1-2"></a>
<h1 >=> Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]<a href="#gt-Matrix0-1-2-3-1-0-1-2" class="wiki-anchor">¶</a></h1>
<a name="m-Matrixbuild3-rand-"></a>
<h1 >m = Matrix.build(3) { rand }<a href="#m-Matrixbuild3-rand-" class="wiki-anchor">¶</a></h1>
<a name="gt-a-3x3-matrix-with-random-elements"></a>
<h1 >=> a 3x3 matrix with random elements<a href="#gt-a-3x3-matrix-with-random-elements" class="wiki-anchor">¶</a></h1>
<h1></h1>
<p>def self.build(row_size, column_size = row_size)<br>
raise ArgumentError if row_size < 0 || column_size < 0<br>
return to_enum :build, row_size, column_size unless block_given?<br>
rows = row_size.times.map do |i|<br>
column_size.times.map do |j|<br>
yield i, j<br>
end<br>
end<br>
new rows, column_size<br>
end<br>
end<br>
=end</p> Ruby master - Bug #2770 (Closed): Matrix: determinant for rectangular matrices should raise an er...https://bugs.ruby-lang.org/issues/27702010-02-21T04:46:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Keiju,</p>
<p>$ rubydev -r matrix -e "puts Matrix[[1], [2], [3]].determinant"<br>
0</p>
<p>This corresponds to the documentation, but is not mathematically valid, since the determinant for rectangular matrices is not defined (at least for now! <a href="http://bit.ly/bwW7Gs" class="external">http://bit.ly/bwW7Gs</a> )</p>
<p>I believe an error should be thrown, similar to:<br>
$ rubydev -r matrix -e "puts Matrix[[1], [2], [3]].trace"<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:837:in <code>trace': Matrix dimension mismatch (ExceptionForMatrix::ErrDimensionMismatch) from -e:1:in </code>'</p>
<p>Since this is an API change, I attached a patch and will wait for your approval before committing.<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> Ruby master - Bug #2525 (Closed): URI#normalize incompletehttps://bugs.ruby-lang.org/issues/25252009-12-24T16:38:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
"<a href="hTTp://example.com/" class="external">hTTp://example.com/</a>" and "<a href="http://exa%4dple.com/" class="external">http://exa%4dple.com/</a>" should both be normalized to "<a href="http://example.com/" class="external">http://example.com/</a>" as per RFC 3986.</p>
<p>They currently are not and thus not considered ==.</p>
<p>Tests added to RubySpec<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 #2499 (Closed): InstructionSequence.dissassemble can crashhttps://bugs.ruby-lang.org/issues/24992009-12-19T11:52:54Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I was trying to understand what InstructionSequence.disassemble is supposed to do when:</p>
<p>$ rubydev -e 'RubyVM::InstructionSequence.disassemble("x".method(:upcase))'<br>
-e:1: [BUG] Segmentation fault<br>
ruby 1.9.2dev (2009-12-19 trunk 26121) [x86_64-darwin10.2.0]</p>
<h2>-- control frame ----------<br>
c:0004 p:---- s:0010 b:0010 l:000009 d:000009 CFUNC :disassemble<br>
c:0003 p:0027 s:0006 b:0006 l:0022c8 d:001e98 EVAL -e:1<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:0000 s:0002 b:0002 l:0022c8 d:0022c8 TOP</h2>
<p>-e:1:in <code><main>' -e:1:in </code>disassemble'</p>
<p>-- C level backtrace information -------------------------------------------</p>
<p>[NOTE]<br>
You may have encountered a bug in the Ruby interpreter or extension libraries.<br>
Bug reports are welcome.<br>
For details: <a href="http://www.ruby-lang.org/bugreport.html" class="external">http://www.ruby-lang.org/bugreport.html</a></p>
<p>Abort trap<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> Ruby master - Bug #2496 (Closed): Delegate: #methods and #public_methods should return delegated ...https://bugs.ruby-lang.org/issues/24962009-12-19T10:38:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'<br>
s = SimpleDelegator.new "Hello, world!"<br>
s.respond_to? :upcase # => true<br>
s.method :upcase # => #<Method : SimpleDelegator#upcase><br>
s.methods.include? :upcase # => false, true expected</p>
<p>Similar problem with public_methods.<br>
I propose that they return the union of methods from the delegator object and the methods of the object delegated to (only the public ones, since other ones are not forwarded)</p>
<p>Patch:<br>
diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index 77804e4..2fd5b49 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -158,6 +158,22 @@ class Delegator<br>
end</p>
<pre><code>#
</code></pre>
<ul>
<li>
<a name="Returns-the-methods-available-to-this-delegate-object-as-the-union"></a>
<h1 >Returns the methods available to this delegate object as the union<a href="#Returns-the-methods-available-to-this-delegate-object-as-the-union" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="of-this-objects-methods-and-the-public-methods-of-__getobj__"></a>
<h1 >of this object's methods and the public methods of __getobj__.<a href="#of-this-objects-methods-and-the-public-methods-of-__getobj__" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>def methods</li>
<li>self.<strong>getobj</strong>.public_methods | super</li>
<li>end</li>
<li>
<li>
<h1></h1>
</li>
<li>
<a name="Returns-the-methods-available-to-this-delegate-object-as-the-union-of-this-object"></a>
<h1 >Returns the methods available to this delegate object as the union of this object<a href="#Returns-the-methods-available-to-this-delegate-object-as-the-union-of-this-object" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="and-the-methods-of-__getobj__"></a>
<h1 >and the methods of __getobj__.<a href="#and-the-methods-of-__getobj__" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>def public_methods(all=true)</li>
<li>self.<strong>getobj</strong>.public_methods(all) | super</li>
<li>end</li>
<li>
<li>
<h1></h1>
<a name="Returns-true-if-two-objects-are-considered-same"></a>
<h1 >Returns true if two objects are considered same.<a href="#Returns-true-if-two-objects-are-considered-same" class="wiki-anchor">¶</a></h1>
<h1></h1>
def ==(obj)<br>
=end</li>
</ul> Ruby master - Bug #2495 (Closed): Matrix: Vector#each2 should check its argumenthttps://bugs.ruby-lang.org/issues/24952009-12-19T10:35:22Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ rubydev -r matrix -e 'p Vector[*1..4].each2(nil){|x, y| p "#{x}, #{y}"}'<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:1149:in <code>each2': undefined method </code>size' for nil:NilClass (NoMethodError)</p>
<p>$ rubydev -r matrix -e 'p Vector[*1..4].each2(42){|x, y| p "#{x}, #{y}"}'<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:1149:in <code>each2': Vector dimension mismatch (ExceptionForMatrix::ErrDimensionMismatch) from -e:1:in </code>'</p>
<p>$ rubydev -r matrix -e 'p Vector[*1..8].each2(42){|x, y| p "#{x}, #{y}"}'<br>
"1, 0"<br>
"2, 1"<br>
"3, 0"<br>
"4, 1"<br>
"5, 0"<br>
"6, 1"<br>
"7, 0"<br>
"8, 0"</p>
<p>(or vice versa, if on a 32 bit platform)<br>
=end</p> Ruby master - Feature #2451 (Closed): BasicObject.initialize with variable number of argumenthttps://bugs.ruby-lang.org/issues/24512009-12-07T10:18:32Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
If one wants to write a class easily extensible (for some kind of library, say), then there is no nice way to have the initialize method be extensible other than through monkeypatching.</p>
<p>This could be made much more flexible if BasicObject.initialize accepted any number of arguments.</p>
<p>Would there be a downsize to have BasicObject.initialize accept many arguments?</p>
<p>Here's a more detailed example:</p>
<p>class NiceClass<br>
def initialize(arg1, arg2)<br>
# do some stuff with arg1 and arg2<br>
super # allow for included modules to initialize<br>
end<br>
end</p>
<a name="Someone-else"></a>
<h1 >Someone else:<a href="#Someone-else" class="wiki-anchor">¶</a></h1>
<p>class NiceClass<br>
module CoolExtension<br>
def initialize(arg1, arg2)<br>
# do cool stuff<br>
super # allow for more extensions<br>
end<br>
end</p>
<p>include CoolExtension<br>
end</p>
<p>This would not work unless BasicObject#initialize accepts any number of arguments. Currently, only super() -- i.e. passing none of the arguments -- can be called, so arg1 & arg2 must be copied to instance variables for included modules to access, or else monkeypatching becomes the only possibility.</p>
<p>The patch is trivial:</p>
<p>diff --git a/object.c b/object.c<br>
index 10eb983..33cae20 100644<br>
--- a/object.c<br>
+++ b/object.c<br>
@@ -2538,7 +2538,7 @@ Init_Object(void)<br>
#undef rb_intern<br>
#define rb_intern(str) rb_intern_const(str)</p>
<ul>
<li>rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);</li>
</ul>
<ul>
<li>rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, -1);<br>
rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);<br>
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);<br>
rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1);</li>
</ul>
<p>Notes:</p>
<ul>
<li>There is no documentation for BasicObject#initialize.</li>
<li>Ironically, the Ruby Draft Specification states that Object#initialize accepts any number of arguments! I'm glad I already have that team agree with me ;-)</li>
<li>No error is generated by make test-all</li>
<li>See also <a href="http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html" class="external">http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html</a> where Robert Klemme recommends calling super from constructors but has to use super(), i.e. passing no arguments</li>
</ul>
<p>Similarly, I also propose that Object#initialize accepts any number of arguments in Ruby 1.8.8<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> Ruby master - Bug #2365 (Closed): Matrix: poor handling of coercion errors [patch]https://bugs.ruby-lang.org/issues/23652009-11-14T10:35:04Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
rubydev -r matrix -e 'p Matrix.I(2) - nil'<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:533:in <code>-': undefined method </code>coerce' for nil:NilClass (NoMethodError)<br>
from -e:1:in `'</p>
<p>Expected:<br>
some_where_in_the/matrix.rb:in <code>-': nil can't be coerced into Matrix (TypeError) from -e:1:in </code>'</p>
<p>Same situation with Vector.</p>
<p>I'd be grateful if you could confirm the attached patch is ok.<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 - Feature #2347 (Closed): Math::INFINITYhttps://bugs.ruby-lang.org/issues/23472009-11-09T04:53:11Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
It is easy to get an infinity in Ruby (ex: 1.0/0) but that may not be obvious to everyone.</p>
<p>Could we have Math::INFINITY which would make code using it cleaner?</p>
<p>Thanks</p>
<p>diff --git a/math.c b/math.c<br>
index 51caf35..653a239 100644<br>
--- a/math.c<br>
+++ b/math.c<br>
@@ -764,6 +764,7 @@ Init_Math(void)<br>
#else<br>
rb_define_const(rb_mMath, "E", DBL2NUM(exp(1.0)));<br>
#endif</p>
<ul>
<li>
<p>rb_define_const(rb_mMath, "INFINITY", DBL2NUM(1.0/0.0));</p>
<p>rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);<br>
rb_define_module_function(rb_mMath, "cos", math_cos, 1);<br>
=end</p>
</li>
</ul> Ruby master - Bug #2330 (Closed): Non systematic segmentation fault with autoload rubyspechttps://bugs.ruby-lang.org/issues/23302009-11-04T14:36:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Starting from r25601, the following rubyspec will crash about half of the time (just repeat a couple of times):</p>
<p>$ mspec -t rubydev core/kernel/autoload_spec.rb<br>
ruby 1.9.2dev (2009-11-04 trunk 25641) [x86_64-darwin10.0.0]<br>
.........../Users/work/mspec/lib/mspec/mocks/proxy.rb:8: [BUG] Segmentation fault<br>
ruby 1.9.2dev (2009-11-04 trunk 25641) [x86_64-darwin10.0.0]</p>
<p>-- control frame ----------<br>
c:0036 p:0024 s:0121 b:0121 l:000120 d:000120 METHOD /Users/work/mspec/lib/mspec/mocks/proxy.rb:8<br>
c:0035 p:---- s:0115 b:0115 l:000114 d:000114 FINISH<br>
c:0034 p:---- s:0113 b:0113 l:000112 d:000112 CFUNC :autoload<br>
c:0033 p:0057 s:0108 b:0108 l:000208 d:000107 BLOCK /Users/work/ruby/dev/spec/rubyspec/core/kernel/autoload_spec.rb:105<br>
c:0032 p:---- s:0105 b:0105 l:000104 d:000104 FINISH<br>
c:0031 p:---- s:0103 b:0103 l:000102 d:000102 CFUNC :instance_eval<br>
c:0030 p:0017 s:0100 b:0100 l:000099 d:000099 METHOD /Users/work/mspec/lib/mspec/runner/mspec.rb:67<br>
c:0029 p:0021 s:0094 b:0094 l:000081 d:000093 BLOCK /Users/work/mspec/lib/mspec/runner/context.rb:135<br>
c:0028 p:---- s:0091 b:0091 l:000090 d:000090 FINISH<br>
c:0027 p:---- s:0089 b:0089 l:000084 d:000088 IFUNC :instance_variable_get<br>
c:0026 p:---- s:0087 b:0087 l:000086 d:000086 CFUNC :each<br>
c:0025 p:---- s:0085 b:0085 l:000084 d:000084 CFUNC :all?<br>
c:0024 p:0053 s:0082 b:0082 l:000081 d:000081 METHOD /Users/work/mspec/lib/mspec/runner/context.rb:135<br>
c:0023 p:0101 s:0076 b:0076 l:000065 d:000075 BLOCK /Users/work/mspec/lib/mspec/runner/context.rb:163<br>
c:0022 p:---- s:0071 b:0071 l:000070 d:000070 FINISH<br>
c:0021 p:---- s:0069 b:0069 l:000068 d:000068 CFUNC :each<br>
c:0020 p:0127 s:0066 b:0066 l:000065 d:000065 METHOD /Users/work/mspec/lib/mspec/runner/context.rb:155<br>
c:0019 p:0109 s:0063 b:0063 l:000062 d:000062 METHOD /Users/work/mspec/lib/mspec/runner/mspec.rb:36<br>
c:0018 p:0029 s:0056 b:0056 l:000055 d:000055 METHOD /Users/work/mspec/lib/mspec/runner/object.rb:11<br>
c:0017 p:0167 s:0049 b:0049 l:000208 d:000208 TOP /Users/work/ruby/dev/spec/rubyspec/core/kernel/autoload_spec.rb:69<br>
c:0016 p:---- s:0047 b:0047 l:000046 d:000046 FINISH<br>
</p>
<p>mspec version: 1.5.12<br>
rubyspec: current<br>
=end</p> Ruby master - Bug #2311 (Closed): [BUG] cfp consistency error - sendhttps://bugs.ruby-lang.org/issues/23112009-10-30T12:15:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Following r25521:</p>
<p>$rubydev -e '<br>
class X<br>
def method_missing(s); end<br>
end<br>
X.new.foo(:bar) rescue nil<br>
puts "hello"<br>
'</p>
<p>Generates<br>
-e:0:in <code>method_missing': wrong number of arguments (2 for 1) (ArgumentError) from -e:5:in </code>'<br>
Instead of "hello"</p>
<p>$ mspec core/file/stat/directory_spec.rb -t rubydev<br>
crashes ruby with [BUG] cfp consistency error - send<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 - Feature #2266 (Closed): Matrix and Complex [patch]https://bugs.ruby-lang.org/issues/22662009-10-25T07:36:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Now that Ruby 1.9 has Complex as a builtin type, it would be interesting if Matrix provided the following instance methods:<br>
#conj, alias conjugate<br>
#imag, alias imaginary<br>
#real,<br>
#real?,<br>
#rect, alias rectangular</p>
<p>Corresponding patch attached.</p>
<p>This patch could also be part of mathn in the ruby 1.8 branch.<br>
=end</p> Ruby master - Feature #2265 (Closed): Matrix#empty? [patch]https://bugs.ruby-lang.org/issues/22652009-10-25T07:33:01Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Now that the Matrix library handles well empty matrices, how about a new instance method #empty?</p>
<p>diff --git a/lib/matrix.rb b/lib/matrix.rb<br>
index b577ef3..45ef25e 100644<br>
--- a/lib/matrix.rb<br>
+++ b/lib/matrix.rb<br>
@@ -386,6 +386,14 @@ class Matrix<br>
#++</p>
<pre><code>#
</code></pre>
<ul>
<li>
<a name="Returns-true-if-this-is-an-empty-matrix-ie-if-the-number-of-rows"></a>
<h1 >Returns +true+ if this is an empty matrix, i.e. if the number of rows<a href="#Returns-true-if-this-is-an-empty-matrix-ie-if-the-number-of-rows" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="or-the-number-of-columns-is-0"></a>
<h1 >or the number of columns is 0.<a href="#or-the-number-of-columns-is-0" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>def empty?</li>
<li>column_size == 0 || row_size == 0</li>
<li>end</li>
<li>
<li>
<h1></h1>
<a name="Returns-true-if-this-is-a-regular-matrix"></a>
<h1 >Returns +true+ if this is a regular matrix.<a href="#Returns-true-if-this-is-a-regular-matrix" class="wiki-anchor">¶</a></h1>
<h1></h1>
</li>
</ul>
<p>def regular?<br>
@@ -924,7 +932,7 @@ class Matrix</p>
<a name="Overrides-Objectto_s"></a>
<h1 >Overrides Object#to_s<a href="#Overrides-Objectto_s" class="wiki-anchor">¶</a></h1>
<h1></h1>
<p>def to_s</p>
<ul>
<li>if row_size == 0 || column_size == 0</li>
</ul>
<ul>
<li>if empty?<br>
"Matrix.empty(#{row_size}, #{column_size})"<br>
else<br>
"Matrix[" + @rows.collect{|row|<br>
@@ -939,7 +947,7 @@ class Matrix</li>
</ul>
<a name="Overrides-Objectinspect"></a>
<h1 >Overrides Object#inspect<a href="#Overrides-Objectinspect" class="wiki-anchor">¶</a></h1>
<h1></h1>
<p>def inspect</p>
<ul>
<li>if row_size == 0 || column_size == 0</li>
</ul>
<ul>
<li>if empty?<br>
"Matrix.empty(#{row_size}, #{column_size})"<br>
else<br>
"Matrix#{@rows.inspect}"<br>
=end</li>
</ul> Ruby 1.8 - Backport #2261 (Closed): lib/matrix: following the extensive changeshttps://bugs.ruby-lang.org/issues/22612009-10-24T15:33:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
(a) Shouldn't r25412 (and other related commits) be also applied to the 1.8 branch?</p>
<p>(b) r25412 introduced Matrix#inspect_org. It is not documented.</p>
<p>Its output relies on the way the matrix information is stored internally by the Matrix class. Shouldn't this be considered implementation details and thus subject to change and not for public consumption?</p>
<p>It should either:</p>
<ul>
<li>be removed,</li>
<li>be made private (although it is not used by the implementation) or</li>
<li>be documented</li>
</ul>
<p>I recommend the first option</p>
<p>(c) #compare_by_row_vectors and #compare_by should either:</p>
<ul>
<li>be removed (they are not used by the implementation anymore),</li>
<li>be made private or</li>
<li>be documented.</li>
</ul>
<p>I recommend the first option<br>
=end</p> Ruby master - Bug #2224 (Closed): lib/delegate: operator delegationhttps://bugs.ruby-lang.org/issues/22242009-10-17T13:15:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The operators ==, =~, !~ are forwarded by Delegate. I presume the operators != and ~, new in 1.9, have simply been forgotten?</p>
<p>As for eql? and hash, this is probably intentional. I am still curious as to why, since this can yield surprising results (at least to me):</p>
<p>a = "foo"<br>
a1 = SimpleDelegator.new(a)<br>
a2 = a1.dup<br>
h = {}<br>
h[a] = :bar<br>
h[a1] = :bar<br>
h[a2] = :bar<br>
h # ==> {"foo"=>:bar, "foo"=>:bar, "foo"=>:bar}<br>
=end</p> Ruby master - Bug #2223 (Closed): lib/delegate: security model?https://bugs.ruby-lang.org/issues/22232009-10-17T12:39:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Take the following code:</p>
<p>require 'delegate'<br>
cat = "cat"<br>
dog = SimpleDelegator.new("dog")</p>
<p>cat.untrust<br>
dog.untrust</p>
<p>lambda {$SAFE = 4; cat.upcase!}.call # ==> "CAT"<br>
lambda {$SAFE = 4; dog.upcase!}.call # ==> Security Error</p>
<p>Is that expected?</p>
<p>Maybe #trust, #untrust, #taint and #untaint should both call 'super' and forward the call to <strong>getobj</strong>?</p>
<p>I'm even less sure as to what to do with #tainted? and #untrusted? for mixed cases (i.e. when self and <strong>getobj</strong> have different taintedness/trust). Disallow these cases? return "super || <strong>getobj</strong>.tainted?" ?<br>
=end</p> Ruby master - Bug #2222 (Closed): Regex creation error in safe modehttps://bugs.ruby-lang.org/issues/22222009-10-17T11:58:25Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ ruby -e '$SAFE=4; /#{}/o'<br>
-e:1:in `': Insecure: can't modify array (SecurityError)</p>
<p>Fairly recent since error not present in ruby 1.9.2dev (2009-08-30 trunk 24705)<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 #2199 (Closed): Object#method should call respond_to_missing?(sym, true)https://bugs.ruby-lang.org/issues/21992009-10-13T14:16:43Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Is there any reason I'm missing?</p>
<p>class A<br>
def respond_to_missing?(method, private = false)<br>
method == :is_private && private<br>
end</p>
<pre><code> def is_private2
end
private :is_private2
</code></pre>
<p>end</p>
<p>A.new.method(:is_private2) # ==> #<Method: A#is_private2>...<br>
A.new.method(:is_private) # ==> NameError: undefined method <code>is_private' for class </code>A'</p>
<p>If not:</p>
<p>diff --git a/proc.c b/proc.c<br>
index 5ed3c01..b7c632c 100644<br>
--- a/proc.c<br>
+++ b/proc.c<br>
@@ -902,7 +902,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)<br>
VALUE sym = ID2SYM(id);</p>
<pre><code> if (obj != Qundef && !rb_method_basic_definition_p(klass, rmiss)) {
</code></pre>
<ul>
<li>
<pre><code> if (RTEST(rb_funcall(obj, rmiss, 1, sym))) {
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if (RTEST(rb_funcall(obj, rmiss, 2, sym, Qtrue))) {
def = ALLOC(rb_method_definition_t);
def->type = VM_METHOD_TYPE_MISSING;
def->original_id = id;
</code></pre>
</li>
</ul>
<p>=end</p> Ruby master - Bug #2189 (Closed): Math.atanh(1) & Math.atanh(-1) should not raise an errorhttps://bugs.ruby-lang.org/issues/21892009-10-10T14:53:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Regression caught by RubySpec.</p>
<p>$ rubydev -v -e 'p Math.atanh(1)'<br>
ruby 1.9.2dev (2009-10-09 trunk 25274) [x86_64-darwin10.0.0]<br>
-e:1:in <code>atanh': Numerical argument out of domain - atanh (Errno::EDOM) from -e:1:in </code>'<br>
$ ruby187 -v -e 'p Math.atanh(1)'<br>
ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]<br>
Infinity</p>
<p>Fixed in r25279<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 master - Feature #2172 (Closed): Enumerable#chunk with no blockhttps://bugs.ruby-lang.org/issues/21722009-10-03T13:48:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
What should "(1..3).chunk" (i.e. without a block) do?</p>
<p>It issued an<br>
ArgumentError: tried to create Proc object without a block</p>
<p>I changed the error message to "no block given" which I hope to be more informative, but maybe there is something more useful to do here?</p>
<p>A default block of {|x| x} doesn't seem all that useful.</p>
<p>Returning an enumerator that, upon completion, will return an enumerator would probably be better, but could also be a bit confusing if someone doesn't realize he forgot to specify the block?</p>
<p>Thanks to Run Paint for raising the question when writing the rubyspec for #chunk.<br>
=end</p> Ruby master - Bug #2140 (Closed): Bignum#** broken by lib/mathnhttps://bugs.ruby-lang.org/issues/21402009-09-24T09:37:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
ruby -r mathn -e 'p (1<<66)**2'<br>
/usr/local/ruby19/lib/ruby/1.9.1/mathn.rb:50:in <code>**': undefined method </code>power!' for 73786976294838206464:Bignum (NoMethodError)<br>
from -e:1:in `'</p>
<p>Fixed in r25067<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 - Feature #1697 (Closed): Object#<=>https://bugs.ruby-lang.org/issues/16972009-06-28T10:48:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The definition of the <=> operator states:<br>
"... And if the two operands are not comparable, it returns nil" (The Ruby Programming Language, O'Reilly)</p>
<p>Attempting to compare objects, when one or both do not define the <=> operator, causes a NoMethodError to be raised. For example, "false <=> 0" raises in this way. This behavior is unexpected and runs counter to the principle defined above.</p>
<p>Further, "0 <=> false" returns nil. This is fundamentally inconsistent. The two comparisons are the other's converse, yet the raising of an exception in the first case implies that the programmer was in error; that the mere act of making this comparison was erroneous.</p>
<p>The solution is for Object to define a <=> operator. This will solve the case described above, along with the general case of comparing an object to another when one or both do not define <=>. Similarly to Time#<=>, it would return the converse of arg <=> self (i.e. nil => nil, num => -num). It needs to detect recursion, in which case it should return nil or 0 depending on the result of self == arg.</p>
<p>This change would make it always safe to call <=> without having to check first if it respond_to? :<=> (or rescuing NoMethodError).</p>
<p>The existence of Object#<=> would make it much easier for all programmers to define a good <=> operator for their classes. They can simply call super if they don't know how to handle some argument type. For example:</p>
<p>class MyClass<br>
include Comparable<br>
def <=> (arg)<br>
return super unless arg.is_a? MyClass<br>
# go on with comparison<br>
end<br>
end</p>
<p>With this simple line, the developper has enabled other classes to be comparable with MyClass. No need to monkeypatch MyClass to ensure that comparing its objects with objects of class ComparableToMyClass will work. Without a 'super', implementing this becomes quite difficult and requires the use of recursion guards (which are not defined in the standard library).</p>
<p>Note that neither String#<=> nor Time#<=> currently use recursion guards, which is not robust and can lead to problems. For instance:</p>
<p>class MyClass<br>
include Comparable<br>
def <=> (arg)<br>
return -1 if arg.is_a? MyClass<br>
cmp = arg <=> self<br>
cmp ? -cmp : nil<br>
end<br>
end</p>
<p>MyClass.new <=> Time.now</p>
<a name="gt-raises-a-SystemStackError"></a>
<h1 >==> raises a SystemStackError<a href="#gt-raises-a-SystemStackError" class="wiki-anchor">¶</a></h1>
<p>class Time<br>
alias_method :to_str, :to_s<br>
end<br>
"now" <=> Time.now</p>
<a name="gt-endless-loop-that-cant-be-interrupted-with-ctrl-C"></a>
<h1 >==> endless loop that can't be interrupted with ctrl-C.<a href="#gt-endless-loop-that-cant-be-interrupted-with-ctrl-C" class="wiki-anchor">¶</a></h1>
<p>In summary, defining Object#<=> would:</p>
<ol>
<li>bring consistency between a <=> b and b <=> a</li>
<li>provide a sensible default (nil) for objects that can't be compared</li>
<li>make it easier for generic methods to call <=> (no rescue or :respond_to? needed)</li>
<li>make it much easier for developpers to write extensible <=> methods for their classes.</li>
</ol>
<p>Side notes:</p>
<p>The proposition stands only for Object. BasicObject would still be available for developers preferring a class with a strict minimum of methods.</p>
<p>The only code that could break would have to be both checking respond_to? :<=> (or rescuing a NoMethodError) <em>and</em> behaving differently than if the <=> method had returned nil. Such code would be quite nonsensical, given the definition of <=></p>
<p>Other comparison operators like <, <=, >=, > would also gain in consistency if they were defined in terms of <=>. This way, 0 < nil and nil > 0 would raise the same errors instead of errors of different types. This is secondary to the main question: is it better to define Object#<=> or not?<br>
My vote is on 'yes'.</p>
<p>(Thanks to the readers of my first draft)<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 #1532 (Closed): Improved matrix.rb [patch]https://bugs.ruby-lang.org/issues/15322009-05-29T04:18:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The fact that the 'matrix' library is included in Ruby is very helpful.<br>
There are currently some open bugs, and some improvements could make it easier to use.</p>
<p>Propositions:</p>
<ol>
<li>Matrix#trace should raise an ErrDimensionMismatch if the matrix is not square</li>
</ol>
<p>Mathematically speaking, the trace is only defined for square matrices (ref: wikipedia, mathworld)<br>
Currently, Matrix[[1,2]].trace raises a NoMethodError: undefined method `[]' for nil:NilClass<br>
Note that Matrix[[1,2]].transpose.trace returns 1, although in mathematically, trace(M) = trace(transpose(M))</p>
<p>Raising an ErrDimensionMismatch would bring #trace in line with #inverse</p>
<ol start="2">
<li>Matrix creation methods should perform checks and conversion so that values are stored as an Array of Arrays.</li>
</ol>
<p>Currently, no checking is done, so the following will all be constructed without an error or a warning:<br>
Matrix[:hello]<br>
Matrix[nil]<br>
Matrix[4], etc...</p>
<p>Later on, confusing results or strange errors will happen. E.g.:<br>
Matrix[42].transpose # ==> Matrix[[42], [0], [0], [0]]</p>
<p>A TypeError should be raised if the argument is not convertible to an Array of Arrays.</p>
<p>Moreover, non arrays that should be converted using :to_ary, to be consistent<br>
with the builtin library methods that accept array arguments (e.g. Array#transpose)</p>
<p>Finally, conversion from Vector to arrays should be always be performed. Currently,<br>
a = Matrix[[1,2],[3,4]] # => Matrix[[1, 2], [3, 4]]<br>
b = Matrix.rows([a.row(0), a.row(1)]) # => Matrix[Vector[1, 2], Vector[3, 4]]<br>
a == b # => false<br>
It would be more useful, intuitive and mathematically correct if a == b and b.to_s == "Matrix[[1, 2], [3, 4]]"</p>
<p>The same is true for Vector creation methods. For example currently:<br>
Vector.elements(42, false).size # ==> 4<br>
Vector.elements(Vector[1,2,3]) == Vector.elements([1,2,3]) # ==> false<br>
It would be more useful, intuitive and correct if the first example raises an error and the second returns true</p>
<ol start="3">
<li>Matrix creators should enforce that a matrix is rectangular.</li>
</ol>
<p>Currently, a matrix with irregular rows can be created, e.g. x = Matrix[[1,2],[3]].<br>
Mathematically speaking, that is not a matrix.<br>
Basically none of the Matrix methods are of any use for non-rectangular matrices.<br>
Moreover, many strange errors can occur later on. For example, x.inverse will<br>
raise a "NoMethodError: undefined method `*' for nil:NilClass"</p>
<p>It would be helpful to catch these cases at creation time.<br>
Many creation methods don't have to make any extra checks (e.g. Matrix.scalar), and<br>
all methods of Matrix can bypass this extra check when they have created the arrays themselves<br>
(e.g. Matrix#*). There would be a small cost for creation using Matrix.[] and Matrix.rows,<br>
although it is in O(rows) while most other operations are usually in O(rows x columns),<br>
so the performance difference would be minimal.</p>
<ol start="4">
<li>Matrix should deal with empty matrices.</li>
</ol>
<p>Currently, empty matrices like Matrix[] cause problem.<br>
For example Matrix[].determinant raises an error, so does Matrix[] * Matrix[].</p>
<p>Moreover, if h = Matrix[[], []], then currently h.transpose.transpose != h</p>
<p>While an alternative would be to raise and error, the best solution is to handle<br>
empty matrices properly, both 0x0, 0xn and nx0, as does MatLab, GNU Octave, etc...<br>
See doc and references to the literature in:<br>
<a href="http://www.gnu.org/software/octave/doc/interpreter/Empty-Matrices.html" class="external">http://www.gnu.org/software/octave/doc/interpreter/Empty-Matrices.html</a></p>
<ol start="5">
<li>Out of bound indices should be dealt with.</li>
</ol>
<p>a) Matrix#[row,col] should behave in a consisten way if either row or col is out of bounds.<br>
Currently it returns nil vs raises an obscure error (See redmine #1518.)</p>
<p>b) Matrix[[1]].row(2) raises an obscure error, while Matrix[[1]].column(2) returns Vector[nil, nil]</p>
<p>c) In a similar vein, Matrix[[1]].minor(2..2,1..1) currently raises an error but not<br>
Matrix[[1]].minor(1..1,2..2)</p>
<p>Solutions:<br>
a) To be consistent with array lookup using [], Matrix#[] should return nil for out of bounds elements.<br>
A #fetch method could be added, but the fact that matrices normally won't contain nil or false<br>
makes it easy to deal with out of bounds references, e.g. m[r, c] || 0</p>
<p>b) Contrary to nil, it is not easy nor useful to deal with Vector[nil, nil, ...].<br>
#row, and #column could raise an IndexError, but it is more useful and<br>
more coherent with Array#at, etc... to return nil.</p>
<p>c) The same way Matrix#row and #col can be related to Array#at,<br>
Matrix#minor should have similar semantics to Array#slice. If either starting point<br>
is out of bounds, nil is returned. Otherwise a Matrix is returned, although it can<br>
be smaller than what was requested. This is similar to<br>
[:a, :b].slice(3..10) # => nil<br>
[:a, :b].slice(2..10) # => []<br>
[:a, :b].slice(1..10) # => [:b]<br>
Matrix[[1], [2]].minor(0..10, 2..10) # => nil<br>
Matrix[[1], [2]].minor(0..10, 1..10) # => Matrix[[], []]<br>
Matrix[[1], [2]].minor(1..10, 0..10) # => Matrix[[2]]</p>
<ol start="6">
<li>Matrix#collect, Vector#collect, #collect2, #map2 should return enumerators if no block is given</li>
</ol>
<p>This would be more useful and is consistent with Array#each, etc...</p>
<ol start="7">
<li>Matrix#hash should have less collisions</li>
</ol>
<p>Currently, the following matrices have the same hash:<br>
Matrix[]<br>
Matrix[[0,0], [0,0]]<br>
Matrix[[1,0], [0,1]]<br>
Matrix[[42,42], [666,666]]<br>
Matrix[[1,2,3,4], [5,6,1,2], [3,4,5,6]]</p>
<p>Ideally, these should have different hashes, since they are different matrices.</p>
<ol start="8">
<li>Matrix#compare_by_row_vectors, Vector#compare_by and Vector#init_elements should be made private or disappear.</li>
</ol>
<p>As per the documentation, these are not meant to be used.<br>
As such it would be best if they didn't appear in the list of methods.</p>
<p>The attached patch addresses all these issues.</p>
<p>Moreover, it addresses all matrix-related issues I could find on redmine:<br>
<a href="http://redmine.ruby-lang.org/issues/show/1020" class="external">http://redmine.ruby-lang.org/issues/show/1020</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1515" class="external">http://redmine.ruby-lang.org/issues/show/1515</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1516" class="external">http://redmine.ruby-lang.org/issues/show/1516</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1517" class="external">http://redmine.ruby-lang.org/issues/show/1517</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1518" class="external">http://redmine.ruby-lang.org/issues/show/1518</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1526" class="external">http://redmine.ruby-lang.org/issues/show/1526</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1531" class="external">http://redmine.ruby-lang.org/issues/show/1531</a></p>
<p>Also fixed a bug with #determinant and #determinant_e that would raise an error for some matrices<br>
(for instance any square matrix with m[0][0] == 0, e.g. Matrix[[0,1],[2,3]].determinant # => error raised)</p>
<p>Finally, the following methods are performing faster:<br>
Matrix#collect<br>
Matrix#transpose<br>
Matrix#==<br>
Matrix#eql?<br>
Matrix#hash<br>
Vector#collect<br>
Vector#map2</p>
<p>Note that the branch 'runpaint' of rubyspecs has specs to this patch.<br>
=end</p> Ruby master - Bug #1531 (Closed): Matrix#determinant fails on some matriceshttps://bugs.ruby-lang.org/issues/15312009-05-29T04:17:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
ruby1.9 -r matrix -e 'Matrix[[0,1],[1,0]].determinant'<br>
/usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:685:in <code>block (2 levels) in determinant': undefined method </code>+' for nil:NilClass (NoMethodError)<br>
from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:684:in <code>loop' from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:684:in </code>block in determinant'<br>
from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:681:in <code>loop' from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:681:in </code>determinant'<br>
from -e:1:in `'</p>
<p>Same with determinant_e.</p>
<p>To fix: gsub('ii','i') in matrix.rb<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>