Ruby Issue Tracking System: Issueshttps://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112024-03-06T17:32:40ZRuby Issue Tracking System
Redmine Ruby master - Feature #20326 (Feedback): Add an `undefined` for use as a default argument.https://redmine.ruby-lang.org/issues/203262024-03-06T17:32:40Zshan (Shannon Skipper)
<p>Variations around <code>UNDEFINED = Object.new</code> are a fairly common pattern to see used as default arguments to distinguish between <code>nil</code> and no argument provided. For example, a Ruby implementation of Array#count might look something like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Array</span>
<span class="no">UNDEFINED</span> <span class="o">=</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
<span class="k">def</span> <span class="nc">UNDEFINED</span><span class="o">.</span><span class="nf">inspect</span> <span class="o">=</span> <span class="s1">'UNDEFINED'</span>
<span class="no">UNDEFINED</span><span class="p">.</span><span class="nf">freeze</span>
<span class="k">def</span> <span class="nf">count</span><span class="p">(</span><span class="n">item</span> <span class="o">=</span> <span class="no">UNDEFINED</span><span class="p">)</span>
<span class="k">if</span> <span class="n">item</span> <span class="o">==</span> <span class="no">UNDEFINED</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I'd like to propose adding an <code>undefined</code> module function method on Kernel to remove the boilerplate for this fairly common use case. An <code>__undefined__</code> method or <code>__UNDEFINED__</code> keyword would be alternatives to <code>undefined</code>. An <code>undefined?</code> helper would also be an optional nicety:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Array</span>
<span class="k">def</span> <span class="nf">count</span><span class="p">(</span><span class="n">item</span> <span class="o">=</span> <span class="n">undefined</span><span class="p">)</span>
<span class="k">if</span> <span class="n">item</span><span class="p">.</span><span class="nf">undefined?</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>A Ruby implementation might look like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Kernel</span>
<span class="no">UNDEFINED</span> <span class="o">=</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
<span class="k">def</span> <span class="nc">UNDEFINED</span><span class="o">.</span><span class="nf">inspect</span> <span class="o">=</span> <span class="o">-</span><span class="s1">'undefined'</span>
<span class="no">UNDEFINED</span><span class="p">.</span><span class="nf">freeze</span>
<span class="n">private_constant</span> <span class="ss">:UNDEFINED</span>
<span class="k">def</span> <span class="nf">undefined?</span> <span class="o">=</span> <span class="nb">self</span> <span class="o">==</span> <span class="no">UNDEFINED</span>
<span class="kp">module_function</span>
<span class="k">def</span> <span class="nf">undefined</span> <span class="o">=</span> <span class="no">UNDEFINED</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #18762 (Open): Add an Array#undigits that compliments Integer#digitshttps://redmine.ruby-lang.org/issues/187622022-05-02T22:47:02Zshan (Shannon Skipper)
<p>I've found Integer#digits convenient and useful but several times have needed to go from the place-value notation back to an Integer after manipulation and wished there was a complimentary Array#undigits.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Array</span>
<span class="k">def</span> <span class="nf">undigits</span><span class="p">(</span><span class="n">base</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">each_with_index</span><span class="p">.</span><span class="nf">sum</span> <span class="k">do</span> <span class="o">|</span><span class="n">digit</span><span class="p">,</span> <span class="n">exponent</span><span class="o">|</span>
<span class="n">digit</span> <span class="o">*</span> <span class="n">base</span><span class="o">**</span><span class="n">exponent</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="mi">42</span><span class="p">.</span><span class="nf">digits</span><span class="p">.</span><span class="nf">undigits</span>
<span class="c1">#=> 42</span>
<span class="mi">42</span><span class="p">.</span><span class="nf">digits</span><span class="p">(</span><span class="mi">16</span><span class="p">).</span><span class="nf">undigits</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span>
<span class="c1">#=> 42</span>
</code></pre>
<p>Below is my stab at a Ruby implementation with behavior mirroring Integer#digits.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Array</span>
<span class="k">def</span> <span class="nf">undigits</span><span class="p">(</span><span class="n">base</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">base_int</span> <span class="o">=</span> <span class="n">base</span><span class="p">.</span><span class="nf">to_int</span>
<span class="k">raise</span> <span class="no">TypeError</span><span class="p">,</span> <span class="s2">"wrong argument type </span><span class="si">#{</span><span class="n">base_int</span><span class="p">.</span><span class="nf">class</span><span class="si">}</span><span class="s2"> (expected Integer)"</span> <span class="k">unless</span> <span class="n">base_int</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Integer</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">,</span> <span class="s1">'negative radix'</span> <span class="k">if</span> <span class="n">base_int</span><span class="p">.</span><span class="nf">negative?</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">,</span> <span class="s2">"invalid radix </span><span class="si">#{</span><span class="n">base_int</span><span class="si">}</span><span class="s2">"</span> <span class="k">if</span> <span class="n">base_int</span> <span class="o"><</span> <span class="mi">2</span>
<span class="n">each_with_index</span><span class="p">.</span><span class="nf">sum</span> <span class="k">do</span> <span class="o">|</span><span class="n">digit</span><span class="p">,</span> <span class="n">exponent</span><span class="o">|</span>
<span class="k">raise</span> <span class="no">MathDomainError</span><span class="p">,</span> <span class="s1">'out of domain'</span> <span class="k">if</span> <span class="n">digit</span><span class="p">.</span><span class="nf">negative?</span>
<span class="n">digit</span> <span class="o">*</span> <span class="n">base_int</span><span class="o">**</span><span class="n">exponent</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #18563 (Closed): Add "graphemes" and "each_grapheme" aliaseshttps://redmine.ruby-lang.org/issues/185632022-02-01T19:44:41Zshan (Shannon Skipper)
<p><a href="https://bugs.ruby-lang.org/issues/13780#note-10" class="external">https://bugs.ruby-lang.org/issues/13780#note-10</a></p>
<blockquote>
<p>grapheme sounds like an element in the grapheme cluster. How about each_grapheme_cluster?<br>
If everyone gets used to the grapheme as an alias of grapheme cluster, we'd love to add an alias each_grapheme.</p>
</blockquote>
<blockquote>
<p>Matz.</p>
</blockquote>
<p>Languages that have added grapheme cluster support seem to be almost exclusively opting for the shorter "graphemes" alias as a part that stands for the whole.</p>
<ul>
<li>JavaScript/TypeScript grapheme-splitter library: <code>splitGraphemes</code>
</li>
<li>PHP: <code>grapheme_extract</code>
</li>
<li>Zig ziglyph library: <code>GraphemeIterator</code>
</li>
<li>Golang uniseg library: <code>NewGraphemes</code>
</li>
<li>Matlab: <code>splitGraphemes</code>
</li>
<li>Python grapheme library: <code>graphemes</code>
</li>
<li>Elixir: <code>graphemes</code>
</li>
<li>Crystal uni_text_seg library: <code>graphemes</code>
</li>
<li>Nim nim-graphemes library: <code>graphemes</code>
</li>
<li>Rust unicode-segmentation library: <code>graphemes</code>
</li>
</ul>
<p>Now that some time has passed and the "graphemes" alias for "grapheme clusters" has been fairly widely adopted by languages and libraries, I'd like to go ahead and propose a <code>graphemes</code> alias for <code>grapheme_clusters</code> and an <code>each_grapheme</code> alias for <code>each_grapheme_cluster</code>.</p> Ruby master - Feature #18004 (Open): Add Async to the stdlibhttps://redmine.ruby-lang.org/issues/180042021-06-22T18:29:26Zshan (Shannon Skipper)
<p>Adding Async to the stdlib would signal a clear concurrency story for Ruby 3 to compliment Ractor-based parallelism. I don't know how ioquatix feels about adding Async to stdlib, but I wanted to propose it since we keep getting questions about concurrent I/O with Ruby 3 in the community.</p>
<p>Ractors get a fair amount of attention on the #ruby IRC channels and Ruby Discord. When Ractors are discussed, question around concurrent I/O in Ruby 3 often follow. Folk don't seem to be aware of Async, so we often cite the Ruby 3 release notes Async Net::HTTP example shown below.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'async'</span>
<span class="nb">require</span> <span class="s1">'net/http'</span>
<span class="nb">require</span> <span class="s1">'uri'</span>
<span class="no">Async</span> <span class="k">do</span>
<span class="p">[</span><span class="s2">"ruby"</span><span class="p">,</span> <span class="s2">"rails"</span><span class="p">,</span> <span class="s2">"async"</span><span class="p">].</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">topic</span><span class="o">|</span>
<span class="no">Async</span> <span class="k">do</span>
<span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="no">URI</span> <span class="s2">"https://www.google.com/search?q=</span><span class="si">#{</span><span class="n">topic</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The main downside I see for this proposal is the bloat from Async's several gem dependencies. For what it's worth, nio4r has been a staple for a long time and is also the only dependency of Puma.</p>
<pre><code>Async is a composable asynchronous I/O framework for Ruby based on nio4r and timers.
</code></pre>
<p>Async is just so useful it would be awesome to add to the stdlib. It fills and important gap for concurrent I/O with Ruby 3 and would be exciting to see included in a future release.</p>
<p>See <a href="https://github.com/socketry/async#readme" class="external">https://github.com/socketry/async#readme</a></p> Ruby master - Feature #16838 (Open): Enumerator::ArithmeticSequence missing allocator for #clone ...https://redmine.ruby-lang.org/issues/168382020-05-07T16:12:39Zshan (Shannon Skipper)
<p>In Ruby 2.5, with an Enumerator:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">1</span><span class="p">.</span><span class="nf">step</span><span class="p">.</span><span class="nf">clone</span>
<span class="c1">#=> Enumerator</span>
</code></pre>
<p>In Ruby 2.6, with an Enumerator::ArithmeticSequence:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">1</span><span class="p">.</span><span class="nf">step</span><span class="p">.</span><span class="nf">clone</span>
<span class="c1">#!> TypeError (allocator undefined for Enumerator::ArithmeticSequence)</span>
</code></pre>
<p>I've gotten around it in 2.6 and 2.7 by checking if an enum is an ArithmeticSequence and reconstituting a new one if so:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Range</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">enum</span><span class="p">.</span><span class="nf">begin</span><span class="p">,</span> <span class="n">enum</span><span class="p">.</span><span class="nf">end</span><span class="p">,</span> <span class="n">enum</span><span class="p">.</span><span class="nf">exclude_end?</span><span class="p">)</span> <span class="o">%</span> <span class="n">enum</span><span class="p">.</span><span class="nf">step</span>
</code></pre>
<p>Instead of cloning:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">enum</span><span class="p">.</span><span class="nf">clone</span>
</code></pre>
<p>I filed this as a bug rather than feature, since it seemed like a breaking change and I wasn't sure if it was intentional. Thank you!</p> Ruby master - Feature #16824 (Rejected): Follow RubyGems naming conventions for the stdlibhttps://redmine.ruby-lang.org/issues/168242020-05-01T03:33:01Zshan (Shannon Skipper)
<p>It's been really nice that most gems these days follow the RubyGems naming convention, so you know exactly what to require just from seeing the gem name: <a href="https://guides.rubygems.org/name-your-gem/" class="external">https://guides.rubygems.org/name-your-gem/</a></p>
<p>I wonder if it would be possible to add aliases for parts of the stdlib that don't follow the convention for Ruby 3.0. I was thinking maybe shims like lib/optionparser.rb, which just does a require_relative of lib/optparse.rb. The following files are what I'd expect, given the namespaces.</p>
<pre><code>new file: file_utils.rb
new file: getopt_long.rb
new file: ip_addr.rb
new file: open_struct.rb
new file: open_uri.rb
new file: option_parser.rb
new file: p_store.rb
new file: r_doc.rb
new file: secure_random.rb
new file: t_sort.rb
new file: weak_ref.rb
</code></pre>
<p>Eventually the old name could be the shim and new one actually contain the code on the path to deprecating old names in some future Ruby.</p>
<p>Anyway, I just wanted to put the suggestion out there to adopt naming conventions for the stdlib as it's gemified. Ruby 3 seems like a nice time. :)</p> Ruby master - Bug #14700 (Rejected): Endless ranges don't seem to work properly with case statementshttps://redmine.ruby-lang.org/issues/147002018-04-19T21:48:27Zshan (Shannon Skipper)
<p>I'm running into an unexpected error with this code</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="mi">1</span>
<span class="k">when</span> <span class="mi">0</span><span class="o">..</span>
<span class="k">end</span>
<span class="c1">#!> SyntaxError: unexpected keyword_end, expecting keyword_then or ',' or ';' or '\n'</span>
</code></pre>
<p>Thanks!</p> Ruby master - Feature #13562 (Closed): Use a sized enumerator with #yield_selfhttps://redmine.ruby-lang.org/issues/135622017-05-14T06:53:25Zshan (Shannon Skipper)
<p>The #yield_self Enumerator instance always has a #count of <code>1</code>. I think it might be nice to provide a lazy #size of <code>1</code> to match the #count for parity.</p>
<p>Currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">42</span><span class="p">.</span><span class="nf">yield_self</span><span class="p">.</span><span class="nf">count</span> <span class="c1">#=> 1</span>
<span class="mi">42</span><span class="p">.</span><span class="nf">yield_self</span><span class="p">.</span><span class="nf">size</span> <span class="c1">#=> nil</span>
</code></pre>
<p>I propose:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">42</span><span class="p">.</span><span class="nf">yield_self</span><span class="p">.</span><span class="nf">count</span> <span class="c1">#=> 1</span>
<span class="mi">42</span><span class="p">.</span><span class="nf">yield_self</span><span class="p">.</span><span class="nf">size</span> <span class="c1">#=> 1</span>
</code></pre> Ruby master - Bug #9440 (Closed): Calling methods on a `Queue.new.dup` or `Queue.new.clone` cause...https://redmine.ruby-lang.org/issues/94402014-01-22T05:32:57Zshan (Shannon Skipper)
<p>On all platforms with ruby-2.1.0 calling a Queue#method on a duped or cloned Queue results in a Segfault:</p>
<pre><code>queue = Queue.new.dup
queue.empty? # Segfault
</code></pre>
<p>The same issue occurs when calling other Queue#methods.</p>