Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112021-09-02T22:18:11ZRuby Issue Tracking System
Redmine Ruby master - Feature #18145 (Closed): Rescue by nested exceptionhttps://bugs.ruby-lang.org/issues/181452021-09-02T22:18:11Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>The introduction of <code>Exception#cause</code> helps a lot when debugging nested errors.</p>
<p>Same goes for wrapped errors. I'm not really sure whether such wrapped errors are an advisable pattern to begin with, feel free to comment on this, but I've used it in a couple of vendored gems dealing with payment providers.</p>
<p>Here's some simplified code to illustrate. The <code>Payment</code> class deals with all the gory things such as authorization, coercion or API quirks. A simplified version might look like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'rest_client'</span>
<span class="k">module</span> <span class="nn">Provider</span>
<span class="k">class</span> <span class="nc">FindError</span> <span class="o"><</span> <span class="no">StandardError</span><span class="p">;</span> <span class="k">end</span>
<span class="k">class</span> <span class="nc">Payment</span>
<span class="nb">attr_reader</span> <span class="ss">:id</span><span class="p">,</span> <span class="ss">:amount</span>
<span class="nb">private_class_method</span> <span class="ss">:new</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">amount</span><span class="p">)</span>
<span class="vi">@id</span><span class="p">,</span> <span class="vi">@amount</span> <span class="o">=</span> <span class="nb">id</span><span class="p">,</span> <span class="n">amount</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">find</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
<span class="n">response</span> <span class="o">=</span> <span class="no">RestClient</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s1">'https://api.provider.com/payments'</span><span class="p">,</span> <span class="ss">params: </span><span class="p">{</span> <span class="ss">id: </span><span class="nb">id</span> <span class="p">})</span>
<span class="n">body</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="nf">body</span><span class="p">)</span>
<span class="n">new</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">body</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="s1">'amount'</span><span class="p">))</span>
<span class="k">rescue</span>
<span class="k">raise</span> <span class="no">FindError</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>You can easily <code>rescue</code> from anything going wrong when loading a payment:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="no">Provider</span><span class="o">::</span><span class="no">Payment</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="mi">123</span><span class="p">)</span>
<span class="k">rescue</span> <span class="no">FindError</span>
<span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>However, you might want to rescue differently for some specific causes (e.g. not found) but not for others (e.g. timeout):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="no">Provider</span><span class="o">::</span><span class="no">Payment</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="mi">123</span><span class="p">)</span>
<span class="k">rescue</span> <span class="no">FindError</span> <span class="o">=></span> <span class="n">error</span>
<span class="k">if</span> <span class="n">error</span><span class="p">.</span><span class="nf">cause</span><span class="p">.</span><span class="nf">instance_of?</span> <span class="no">RestClient</span><span class="o">::</span><span class="no">NotFound</span>
<span class="o">...</span>
<span class="k">else</span>
<span class="o">...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>How about allowing to rescue by nested exception with a syntax like?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="no">Provider</span><span class="o">::</span><span class="no">Payment</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="mi">123</span><span class="p">)</span>
<span class="k">rescue</span> <span class="no">FindError</span> <span class="o">&</span> <span class="no">RestClient</span><span class="o">::</span><span class="no">NotFound</span>
<span class="o">...</span>
<span class="k">rescue</span> <span class="no">FindError</span>
<span class="o">...</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #17844 (Open): Support list of methods to test with respond_to?https://bugs.ruby-lang.org/issues/178442021-05-01T13:01:28Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>Not sure whether this is a good idea at all, but I guess it doesn't hurt to put it up for debate.</p>
<p>The preferred way to check e.g. whether an argument is acceptable is by use of <code>respond_to?</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Don't</span>
<span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span> <span class="k">unless</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">instance_of?</span><span class="p">(</span><span class="no">User</span><span class="p">)</span> <span class="o">||</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">instance_of?</span><span class="p">(</span><span class="no">Follower</span><span class="p">)</span>
<span class="o">...</span>
<span class="k">end</span>
<span class="c1"># Do</span>
<span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span> <span class="k">unless</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">respond_to?</span> <span class="ss">:email</span>
<span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>However, sometimes the tested object has to respond to more than one method in order to be acceptable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span> <span class="k">unless</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="ss">:email</span><span class="p">)</span> <span class="o">&&</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span>
<span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>The refactored version doesn't look much nicer:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span> <span class="k">unless</span> <span class="sx">%i(email name)</span><span class="p">.</span><span class="nf">reduce</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">memo</span><span class="p">,</span> <span class="nb">method</span><span class="o">|</span>
<span class="n">memo</span> <span class="o">&&=</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">respond_to?</span> <span class="nb">method</span>
<span class="k">end</span>
<span class="o">...</span>
</code></pre>
<p>The limiting factor here is <code>respond_to?</code> which only accepts one method as String or Symbol. How about extending it to accept an Array (of String or Symbol) as well?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span> <span class="k">unless</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">respond_to?</span> <span class="sx">%i(email name)</span>
<span class="o">...</span>
</code></pre>
<p>Even nicer, but more complicated to implement due to the last and optional argument <code>include_all</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span> <span class="k">unless</span> <span class="n">recipient</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="ss">:email</span><span class="p">,</span> <span class="ss">:name</span><span class="p">)</span>
<span class="o">...</span>
</code></pre>
<p>What do you think?</p> Ruby master - Feature #17475 (Rejected): Implement arguments forwarding for blockshttps://bugs.ruby-lang.org/issues/174752020-12-26T18:57:43Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>In a gem, I create a bunch of initializer shortcuts as follows:</p>
<pre><code># Shortcut initializers
CLASSES.each do |element, class_name|
define_singleton_method(element) do |*args, **kwargs|
class_name.to_class.new(*args, **kwargs)
end
end
</code></pre>
<p>Given the new, cool arguments forwarding with <code>...</code>, it would be a real beauty if the following were possible:</p>
<pre><code># Shortcut initializers
CLASSES.each do |element, class_name|
define_singleton_method(element) do |...|
class_name.to_class.new(...)
end
end
</code></pre>
<p>(I'm sorry if this is a duplicate. In some dusty corner of my memory, I believe to have seen a similar issue in the past, but couldn't find it anymore... maybe just dreamt of it. :-)</p> Ruby master - Misc #16659 (Open): Documentation on Regexp missing for absence pattern (?~pat)https://bugs.ruby-lang.org/issues/166592020-02-27T16:16:20Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>The absence pattern <code>(?~pat)</code> available since Ruby 2.4.1 is <a href="https://git.ruby-lang.org/ruby.git/tree/doc/regexp.rdoc" class="external">not yet documented on <code>Regexp</code></a> as of today.</p>
<p>(Found it by coincidence reading <a href="https://medium.com/rubyinside/the-new-absent-operator-in-ruby-s-regular-expressions-7c3ef6cd0b99" class="external">this article by Peter Cooper</a>.</p> Ruby master - Feature #16605 (Rejected): Support argument delegation (...) with blocks/define_methodhttps://bugs.ruby-lang.org/issues/166052020-02-03T16:16:24Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>(I couldn't find anything on this in the bug tracker or other official sources, hope it's not a duplicate since it's kind of tricky to search for it.)</p>
<p>The following doesn't work on Ruby 2.7:</p>
<pre><code>define_method(:delegate) do |...| # <-- syntax error
target(...)
end
</code></pre>
<p>Are there any plans to support argument delegation in block arguments?</p> Ruby master - Misc #15364 (Closed): Suppress "shadowing outer local variable" warning for assignm...https://bugs.ruby-lang.org/issues/153642018-12-01T12:21:09Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>The following pattern is quite common when initializing a complex object where some attributes (attr1 and 2) can be set by the initializer, whereas others (attr3 and 4) cannot:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># the local variable "thing" does not exist up to this point</span>
<span class="n">thing</span> <span class="o">=</span> <span class="no">Thing</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
<span class="ss">attr1: </span><span class="s1">'foo'</span><span class="p">,</span>
<span class="ss">attr2: </span><span class="s1">'bar'</span><span class="p">,</span>
<span class="p">).</span><span class="nf">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">thing</span><span class="o">|</span>
<span class="n">attr3</span> <span class="o">=</span> <span class="s1">'foz'</span><span class="p">,</span>
<span class="n">attr4</span> <span class="o">=</span> <span class="s1">'baz'</span>
<span class="k">end</span>
</code></pre>
<p>The syntax check with <code>ruby -cw</code> won't like this:</p>
<pre><code>warning: shadowing outer local variable - thing
</code></pre>
<p>While a very useful warning in many situations, it is obsolete when the outer local variable doesn't exist up to this point and therefore no collision with the inner local variable of the same name can occur.</p>
<p>Of course, just change the inner variable name to silence the warning, but for the sake of readable code, it should be okay to "recycle" the same variable name both outer and inner (since they refer to the same thing).</p>
<p>(I don't know whether the syntax check is capable of telling whether "thing" is defined already or not though.)</p> Ruby master - Feature #1431 (Rejected): Object#__class__https://bugs.ruby-lang.org/issues/14312009-05-04T17:59:38Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>=begin<br>
Consider the following code using class instance variables:</p>
<p>class Car<br>
def self.total_count=(n)<br>
@total_count = n<br>
end</p>
<p>def initialize<br>
self.class.total_count = 0<br>
end<br>
end</p>
<p>The compile requires "self.class.total_count" as the more readable "class.total_count" is mistaken by the parser as a faulty class definition.</p>
<p>How about adding a <strong>class</strong> method to Object?</p>
<p>class Object<br>
def <strong>class</strong><br>
self.class<br>
end<br>
end</p>
<p>It would allow the use of "<strong>class</strong>" as a de facto prefix for class instance variables and would fit e.g. the id/<strong>id</strong> and send/<strong>send</strong> paradigm.<br>
=end</p> Ruby master - Bug #951 (Closed): "make DESTDIR=... install" creates dirs outside DESTDIRhttps://bugs.ruby-lang.org/issues/9512008-12-30T19:11:32Zsvoop (Sven Schwyn)svoop_he38hj327c@delirium.ch
<p>=begin<br>
While working on the Ruby 1.9 ebuilds for Gentoo Prefix on Mac, I came across the following oddity.</p>
<p>With 1.9.1-pre2 the installation to a DESTDIR is not working as expected. While all files are installed correctly below the DESTDIR, one empty directory is created below the filesystem root:</p>
<p>/usr/lib/ruby/site_ruby/1.9.1/i686-darwin9/</p>
<p>Although not dramatic, this renegade directory triggers a QA error by the Gentoo installer which causes the installation to fail altogether.</p>
<p>I've tried to track down the offending line of code (most likely in instruby.rb), but couldn't find it.<br>
=end</p>