Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17097754782023-04-26T06:13:55ZRuby Issue Tracking System
Redmine Test - Feature #19618 (Open): hash#dig testshttps://bugs.ruby-lang.org/issues/196182023-04-26T06:13:55Zhdiwan415 (Hasan Diwan)
<p>diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb<br>
index 2ccb483120..3b583b338b 100644<br>
--- a/spec/ruby/core/hash/hash_spec.rb<br>
+++ b/spec/ruby/core/hash/hash_spec.rb<br>
@@ -1,4 +1,4 @@<br>
-require_relative '../../spec_helper'<br>
+require_relative "../../spec_helper"</p>
<p>describe "Hash" do<br>
it "includes Enumerable" do<br>
@@ -6,9 +6,18 @@<br>
end<br>
end</p>
<p>+describe "Hash#dig" do</p>
<ul>
<li>it "handles nested hash" do</li>
<li>{ foo: { bar: { baz: 2 } } }.dig(:foo).should == { :bar => { :baz => 2 } }</li>
<li>{ foo: { bar: { baz: 2 } } }.dig(:foo, :bar).should == { :baz => 2 }</li>
<li>{ foo: { bar: { baz: 2 } } }.dig(:foo, :bar, :baz).should == 2</li>
<li>{ foo: { bar: { baz: 2 } } }.dig(:BAZ).should.nil?</li>
<li>end<br>
+end</li>
<li>
</ul>
<p>describe "Hash#hash" do<br>
it "returns a value which doesn't depend on the hash order" do</p>
<ul>
<li>{ 0=>2, 11=>1 }.hash.should == { 11=>1, 0=>2 }.hash</li>
</ul>
<ul>
<li>{ 0 => 2, 11 => 1 }.hash.should == { 11 => 1, 0 => 2 }.hash<br>
end</li>
</ul>
<p>it "returns a value in which element values do not cancel each other out" do<br>
@@ -26,9 +35,9 @@<br>
end</p>
<p>it "returns the same hash for recursive hashes" do</p>
<ul>
<li>h = {} ; h[:x] = h</li>
<li>h.hash.should == {x: h}.hash</li>
<li>h.hash.should == {x: {x: h}}.hash</li>
</ul>
<ul>
<li>h = {}; h[:x] = h</li>
<li>h.hash.should == { x: h }.hash</li>
<li>h.hash.should == { x: { x: h } }.hash
<a name="This-is-because-heqlx-h"></a>
<h1 >This is because h.eql?(x: h)<a href="#This-is-because-heqlx-h" class="wiki-anchor">¶</a></h1>
<a name="Remember-that-if-two-objects-are-eql"></a>
<h1 >Remember that if two objects are eql?<a href="#Remember-that-if-two-objects-are-eql" class="wiki-anchor">¶</a></h1>
<a name="then-the-need-to-have-the-same-hash"></a>
<h1 >then the need to have the same hash.<a href="#then-the-need-to-have-the-same-hash" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<p>@@ -36,9 +45,9 @@<br>
end</p>
<p>it "returns the same hash for recursive hashes through arrays" do</p>
<ul>
<li>h = {} ; rec = [h] ; h[:x] = rec</li>
<li>h.hash.should == {x: rec}.hash</li>
<li>h.hash.should == {x: [h]}.hash</li>
</ul>
<ul>
<li>h = {}; rec = [h]; h[:x] = rec</li>
<li>h.hash.should == { x: rec }.hash</li>
<li>h.hash.should == { x: [h] }.hash
<a name="Like-above-because-heqlx-h"></a>
<h1 >Like above, because h.eql?(x: [h])<a href="#Like-above-because-heqlx-h" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<p>end</p>
<p>@@ -47,7 +56,7 @@<br>
a = 1<br>
b = 2</p>
<ul>
<li>
<pre><code>eval('{a:, b:}.should == { a: 1, b: 2 }')
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> eval("{a:, b:}.should == { a: 1, b: 2 }")
</code></pre>
end<br>
end<br>
end</li>
</ul>
<a name="adds-tests-forHashdig"></a>
<h1 >adds tests for.Hash#dig<a href="#adds-tests-forHashdig" class="wiki-anchor">¶</a></h1> Test - Bug #19186 (Open): test2https://bugs.ruby-lang.org/issues/191862022-12-06T01:25:49Zshugo (Shugo Maeda)
<p>Hello, this is a test issue.<br>
This is a second line with umlaut: ü</p> Test - Bug #19185 (Open): testhttps://bugs.ruby-lang.org/issues/191852022-12-06T01:24:24Zshugo (Shugo Maeda)
<p>hello, this is a test issue.<br>
This is a second line.</p> Ruby master - Misc #18840 (Open): Top-level #using and other methods docshttps://bugs.ruby-lang.org/issues/188402022-06-18T19:12:56Zzverok (Victor Shepelev)zverok.offline@gmail.com
<p>I was looking into some docs problems, and the question I have is that we don't have any place where <code>main</code>'s methods documentation is rendered?</p>
<p>The <code>#using</code>, for example, is <a href="https://github.com/ruby/ruby/blob/ruby_3_1/eval.c#L1960" class="external">defined</a> on <code>main</code>'s singleton class (if I am reading the code correctly), and it has <a href="https://github.com/ruby/ruby/blob/ruby_3_1/eval.c#L1687" class="external">RDoc defined</a> in <code>*.c</code>, but for all I can tell it is rendered nowhere.</p>
<p>Theoretically, it would've been nice to have a place where <code>main</code> object's concept would be explained and the methods available in it, listed, right?..</p>
<p>Or am I missing something obvious?</p> Ruby master - Misc #18725 (Open): IO#write and IO#wait_writable block for write pipe if read pipe...https://bugs.ruby-lang.org/issues/187252022-04-13T23:20:52Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<p>I'm not sure whether this is a Ruby issue, an OpenBSD issue, or something else, but <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/3344">@ioquatix (Samuel Williams)</a> asked me to post this here. The following program hangs on OpenBSD:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'io/wait'</span>
<span class="n">rd</span><span class="p">,</span> <span class="n">wr</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">pipe</span>
<span class="n">thread_pass</span> <span class="o">=</span> <span class="no">ARGV</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'pass'</span>
<span class="n">write</span> <span class="o">=</span> <span class="no">ARGV</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'write'</span>
<span class="n">thread</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">longer</span> <span class="o">=</span> <span class="s2">"0"</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span>
<span class="p">(</span><span class="mi">1024</span> <span class="o">*</span> <span class="mi">4</span><span class="p">).</span><span class="nf">times</span> <span class="k">do</span>
<span class="k">if</span> <span class="n">write</span>
<span class="n">wr</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">longer</span><span class="p">)</span>
<span class="k">else</span>
<span class="k">while</span> <span class="n">wr</span><span class="p">.</span><span class="nf">write_nonblock</span><span class="p">(</span><span class="n">longer</span><span class="p">,</span> <span class="ss">:exception</span><span class="o">=></span><span class="kp">false</span><span class="p">)</span> <span class="o">==</span> <span class="ss">:wait_writable</span>
<span class="n">thread_pass</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="n">wr</span><span class="p">.</span><span class="nf">wait_writable</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="ss">:finished</span>
<span class="k">rescue</span> <span class="o">=></span> <span class="n">e</span>
<span class="n">e</span>
<span class="k">end</span>
<span class="nb">sleep</span> <span class="mi">1</span>
<span class="n">rd</span><span class="p">.</span><span class="nf">close</span>
<span class="nb">puts</span> <span class="ss">:rd_close</span>
<span class="nb">puts</span> <span class="n">thread</span><span class="p">.</span><span class="nf">value</span>
</code></pre>
<p>This program will also hang if <code>write</code> is given as the argument, using <code>wr.write</code> instead of <code>wr.write_nonblock</code>/<code>wr.wait_writable</code>. However, if <code>pass</code> is given as the argument, using <code>Thread.pass</code> instead of <code>wr.wait_writable</code>, the program will not hang.</p>
<p>From testing, the hang when called without an argument is in <code>wait_writable</code>, and the hang with a <code>write</code> argument is in <code>write</code>.</p>
<p>Is Ruby supposed to guarantee that a closing the read end of a pipe in one thread causes a raise of EPIPE to the write end of the pipe in a different thread if already inside <code>IO#write</code>/<code>IO#wait_writable</code>? Or is this platform-specific behavior?</p>
<p>This example was extracted from one of Rack's tests, which was causing non-deterministic hangs on OpenBSD.</p> Ruby master - Misc #18587 (Open): What was the reason behind Ruby choosing SipHash for Hash?https://bugs.ruby-lang.org/issues/185872022-02-16T15:42:48Zmidnight (Sarun R)
<p>Hello</p>
<p>I am digging into the history behind Ruby using SipHash for its Hash.<br>
I found that in 2012 there were CVE-2012-5371 showing up;<br>
the Ruby maintainers went with the decision to switch algorithms, probably, because we wanted something quick to implement at the time.<br>
The change went live in late 2012.</p>
<p>Fast forward with the Ruby 3x3 initiative, we now seem to care about the performance again.<br>
And hash DoSing does not seem to be an urgent threat now; we have time to be deliberate about Hash again.</p>
<p>I can't find the old discussion related to Ruby's SipHash decision.<br>
I just found that SipHash is not the only solution to prevent hashtable DoSing.<br>
There is an interesting discussion on golang side in late 2015:<br>
<a href="https://github.com/golang/go/issues/9365" class="external">https://github.com/golang/go/issues/9365</a></p>
<p>Just to recap, Go's authors argue that:</p>
<ul>
<li>Cryptographic hash is not needed to construct a DoS-resistant hashtable.</li>
<li>If the random seed is per-hashtable bases, the attack vector exploitable from a remote adversary seems unlikely.</li>
<li>If we want to be extra careful about it, and since the collision is unlikely, when collision actually does occur despite the per-hashtable seed, we can handle that as a special case where we can rerandom the seed and rehash the key.</li>
<li>The way random seeds are folded into the hash does matter, for example, CityHash does f(g(msg), seed); in such case, collision in g will cause a collision in f because the output of g is independent of the seed.</li>
<li>Slowing down hashtable for everyone to prevent hard-to-exploit DoS doesn't seem to be a good trade-off.</li>
</ul>
<p>On the actual implementation, they use AES-NI to achieve good pseudo-random functions' properties. And use some fallback non-cryptographic hashing function on the platform without AES-NI.</p>
<p>Now, I read the rationale on golang side, I want to understand the rationale on the Ruby side too.<br>
I am not there 10-years-ago, and I can't find records or discussions at the time. There might be some Ruby limitations that the approach described by go's authors does not apply.</p>
<p>So, I asked in the hope of someone still remembering what was happening, the situation we are in 10 years ago, or the limitation of Ruby that prevents per-Hash seeds.</p> Ruby master - Misc #18420 (Open): Question about how to handle IO.pipe reader and writer when for...https://bugs.ruby-lang.org/issues/184202021-12-22T00:04:00Zestolfo (Emily S)
<p>I don't think this is a bug but I'm not sure. It could be just a limitation of forking with a IO.pipe reader and writer.</p>
<p>I work on the Elastic Ruby APM agent (<a href="https://github.com/elastic/apm-agent-ruby" class="external">https://github.com/elastic/apm-agent-ruby</a>). The Ruby agent is a singleton and uses a IO.pipe to send data to the APM server. The writer we wrap in a GzipWriter. When the parent process is forked, the child inherits the readers and (gzip)writers. I detect the forking by comparing PIDs when an event is created and create new readers and writers in the child process so that I don't interfere with the parent's streams.<br>
When the fork exits, I close the child's readers and writers but I see the follow error</p>
<p>zlib(finalizer): Zlib::GzipWriter object must be closed explicitly.<br>
zlib(finalizer): the stream was freed prematurely.</p>
<p>because the parent's writer is still considered living in the child process.<br>
One option to address this error is to create a finalizer on the writer that closes it. But then I get intermittent errors from the APM server saying the gzipped data's header is invalid. I'm assuming this is because the parent's writer is closed by the child before the compression is complete in the parent.</p>
<p>Is there a proper way to handle forking when the parent is using a pipe? Both options I have to handle the writer result in an error/warning: I can't close the GzipWriter in the child because of the corrupted data issue but if I don't close it, I get the "Zlib::GzipWriter object must be closed explicitly" warning.</p>
<p>If I close the reader and writer in a "before_fork" hook run in the parent, I avoid both issues. But I don't want to recreate the reader/writer objects every time the parent is forked.</p>
<p>I've been testing with ruby 2.7.0 and Resque (<a href="https://github.com/resque/resque" class="external">https://github.com/resque/resque</a>) primarily but this issue is observed with Puma and other frameworks that use forking.</p> Ruby master - Misc #18371 (Assigned): Release branches (release information in general)https://bugs.ruby-lang.org/issues/183712021-11-30T22:52:11Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<p>Hi,</p>
<p>I was trying to learn about Ruby's release process. I noticed that we don't create a release branch until the final version is shipped. Is there a reason we don't create the release branch when the first preview is shipped? The reason I'm asking is because I'm worried about merging things to master after the first preview. Do we have any documentation on the release process? (I was searching and couldn't find much info, but maybe I didn't search correctly)</p>
<p>Thanks!</p> Ruby master - Misc #18352 (Open): What is the Hash#grep expected?https://bugs.ruby-lang.org/issues/183522021-11-20T09:50:09Zzw963 (Wei Zheng)
<p>Current ruby implement, When use Array#grep, the method name means is expected.</p>
<pre><code>[19] pry(#<App>)> [:foo1, :foo2, :bar].grep /foo/
[
:foo1,
:foo2
]
</code></pre>
<p>But when use with hash, the result is really confusing ...</p>
<pre><code class="rb syntaxhl" data-language="rb"><span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="c1">#<App>)> {foo: '100', bar: '200'}.grep /foo/ </span>
<span class="p">[]</span>
</code></pre>
<p>This result almost make Include Enumerable#grep into Hash is totally meaningless, right?</p>
<p>so, i consider if we should introduce a <code>Hash#grep</code> method instead.</p>
<p>Following is what is expected. (=== is matching on hash key, as Hash#slice)</p>
<pre><code class="rb syntaxhl" data-language="rb"><span class="p">[</span><span class="mi">20</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="c1">#<App>)> {foo1: '100', foo2: '200', bar: '200'}.grep /foo/ </span>
<span class="p">{</span>
<span class="ss">:foo1</span> <span class="o">=></span> <span class="s2">"100"</span><span class="p">,</span>
<span class="ss">:foo2</span> <span class="o">=></span> <span class="s2">"200"</span>
<span class="p">}</span>
</code></pre> Ruby master - Misc #18248 (Open): Add Feature Triaging Guidehttps://bugs.ruby-lang.org/issues/182482021-10-11T16:14:14Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<p>Ruby added a bug triaging guide in June 2019, and since then I've used it to reduce the number of open bugs in the tracker from over 1400 to about 300. Ruby currently has over 1200 open feature requests on the issue tracker. From a cursory review, many of these have already been implemented, and many are unlikely to be desired. I would like to add a feature triaging guide to Ruby and start triaging feature requests, with the goal of having open feature requests be features not yet implemented that the Ruby core team would like implemented or would consider patches for. By doing so, we can make it easier for potential contributors to Ruby to easily see possible contributions they could make.</p>
<p>I've added a pull request with a draft of the proposed guide: <a href="https://github.com/ruby/ruby/pull/4953" class="external">https://github.com/ruby/ruby/pull/4953</a></p> Ruby master - Misc #18150 (Open): Proposal: Deprecate leading zero syntax to declare octals, sinc...https://bugs.ruby-lang.org/issues/181502021-09-03T17:10:05ZProGM (Piero Dotti)
<p>Hi there,<br>
I'd like to open a discussion about the leading zeros syntax to declare octal numbers.</p>
<p>Let me give you a little bit of context.</p>
<p>It seems like ruby considers all integers with leading zeros as octal.<br>
For instance, if you write 012, ruby reads it as 10 in decimal.<br>
There is an alternative syntax for this, using an "o" character after the zero, i.e. 0o12</p>
<p>I've discovered this behavior by chance a couple of days ago.<br>
I was declaring a new Date object:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">START_DATE</span> <span class="o">=</span> <span class="no">Date</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">2021</span><span class="p">,</span> <span class="mi">09</span><span class="p">,</span> <span class="mo">01</span><span class="p">)</span>
</code></pre>
<p>In my mind, I was thinking of ISO 8601 ("2021-09-01") and I wrote it in that way without even thinking about it.</p>
<p>I immediately got a weird error:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">SyntaxError</span> <span class="p">((</span><span class="n">irb</span><span class="p">):</span><span class="mi">2</span><span class="p">:</span> <span class="no">Invalid</span> <span class="n">octal</span> <span class="n">digit</span><span class="p">)</span>
</code></pre>
<p>That was astonishing. "What the heck does this error mean?", I thought.</p>
<p>After a brief research, I've discovered that many languages that come from C have this "weird" behavior.<br>
Javascript, Go, Java, and ruby itself all treat leading zeros like this.<br>
Rust and Elixir, instead, are parsing 00123 like 123, as math notation suggests.<br>
Finally, Python 3+ raises an error.</p>
<hr>
<p>My proposal is: throw a deprecation warning in ruby 3.x when using this syntax and treat 0011 as 11 from ruby 4+.</p>
<p>Why?</p>
<ul>
<li>Because it's extremely confusing</li>
<li>There is an alternative syntax that is much more explicit (0o11 vs 011)</li>
<li>It leads to weird behaviors (like 011 != 11)</li>
<li>Because Python 2.x was treating leading zeros numbers as octals like ruby does, but this has been changed in python 3+: <a href="https://medium.com/techmacademy/leading-zeros-in-python-a-hidden-mystery-revealed-ee3e3065634d" class="external">https://medium.com/techmacademy/leading-zeros-in-python-a-hidden-mystery-revealed-ee3e3065634d</a>
</li>
</ul>
<p>Ruby's claim is "A PROGRAMMER'S BEST FRIEND". As a programmer, I don't consider this behavior very friendly. :(</p>
<p>Let me know what you think about this!</p> Ruby master - Misc #18082 (Open): FileUtils.remove_entry_secure has inconsistent documenthttps://bugs.ruby-lang.org/issues/180822021-08-17T16:26:38Zpocke (Masataka Kuwabara)
<p><code>FileUtils.remove_entry_secure</code> and <code>FileUtils.rm_r</code> have inconsistency about the vulnerability condition the in the documentations.</p>
<p><code>remove_entry_secure</code> document:<br>
<a href="https://github.com/ruby/ruby/blob/6a9bfa4d9387b9d8f07f43f4546437be57f9e27c/lib/fileutils.rb#L660-L664" class="external">https://github.com/ruby/ruby/blob/6a9bfa4d9387b9d8f07f43f4546437be57f9e27c/lib/fileutils.rb#L660-L664</a></p>
<blockquote>
<p>#rm_r causes security hole when:</p>
<ul>
<li>Parent directory is world writable (including /tmp).</li>
<li>Removing directory tree includes world writable directory.</li>
<li>The system has symbolic link.</li>
</ul>
</blockquote>
<p><code>rm_r</code> document:<br>
<a href="https://github.com/ruby/ruby/blob/6a9bfa4d9387b9d8f07f43f4546437be57f9e27c/lib/fileutils.rb#L614-L618" class="external">https://github.com/ruby/ruby/blob/6a9bfa4d9387b9d8f07f43f4546437be57f9e27c/lib/fileutils.rb#L614-L618</a></p>
<blockquote>
<p>WARNING: This method causes local vulnerability<br>
if one of parent directories or removing directory tree are world<br>
writable (including /tmp, whose permission is 1777), and the current<br>
process has strong privilege such as Unix super user (root), and the<br>
system has symbolic link.</p>
</blockquote>
<p>The differences are following.</p>
<ul>
<li>
<code>rm_r</code> describes about strong privilege, but <code>remove_entry_secure</code> doesn't.</li>
<li>
<code>rm_r</code> describes "one of parent directories <strong>OR</strong> removing directory tree are world writable", but the conditions are just listed in <code>remove_entry_secure</code> doc, it seems <strong>AND</strong> condition.</li>
</ul>
<p>I couldn't understand the prerequisites of the vulnerability from the documents.<br>
I think both documents should describe the same prerequisites.</p>
<p>I don't know what is the right prerequisites, so I didn't make a patch.</p> Ruby master - Misc #17829 (Open): Clang/LLVM correctness of x64-mingw32 build (`shorten-64-to-32`...https://bugs.ruby-lang.org/issues/178292021-04-26T16:23:26Zxtkoba (Tee KOBAYASHI)
<p>The attached log is from <code>make miniruby</code> for x64-mingw32 with Clang/LLVM. Warnings are silenced except for <code>-Wshorten-64-to-32</code>.</p>
<p>This might not be an issue solely for Clang/LLVM, because the size of each type is the same as that in GCC.</p>
<p>I believe most of them are false positive. It would be easy to silence these warnings by explicit type casting. But before doing so, it must be checked whether each shortening is legitimate or not.</p>
<p>Version: <code>ruby 3.1.0dev (2021-04-26T13:46:51Z master 203eeeefdd) [x64-mingw32]</code></p> Ruby master - Misc #17720 (Assigned): Cirrus CI to check non-x86_64 architecture cases by own mac...https://bugs.ruby-lang.org/issues/177202021-03-12T17:50:05Zjaruga (Jun Aruga)
<p>Hello!</p>
<p>This ticket is related to the tickets <a class="issue tracker-5 status-5 priority-4 priority-default closed" title="Misc: Enabling ARM 64/32-bit cases by Drone CI (Closed)" href="https://bugs.ruby-lang.org/issues/16234">#16234</a> <a class="issue tracker-5 status-5 priority-4 priority-default closed" title="Misc: Enabling IBM PowerPC/Z cases in Travis CI (Closed)" href="https://bugs.ruby-lang.org/issues/16360">#16360</a>. But I opened a new ticket because it is related to general non-x86_64 architecture CI cases.</p>
<p>I have a suggestion.</p>
<p>I see the <code>.travis.yml</code> was removed [1], and I also saw another open source project remove their <code>.travis.yml</code> because they could not get the credits to continue to run Travis [2]. I feel Travis is not really a possible option for every open source project for now.</p>
<p>While we have RubyCI, I think we still have a motivation to run a CI on non-x86_64 architectures at a pull-request timing. So, I investigated alternative CI. When checking GitHub Actions, I do not feel it will happen soon on GitHub Actions [3]. Then I found an interesting CI called "Cirrus CI", that might enable us to run CI on non-x86_64 architectures such as Mac M1 (arm) ppc64le and s390x beyond the cloud.</p>
<p>Cirrus CI has 2 types of features: "cloud" and "persistent workers". I see the Cirrus CI "cloud" feature has been used in the QEMU and podman projects [4][5]. It has a unique freeBSD host. However the remarkable feature for the Ruby project is the "persistent workers" [6] announced a few months ago, that is beyond the cloud. Because this feature enables us to use our own machines as a CI running host. You can see the examples running the CI with the machines such as Mac M1, iPhone, ppc64le and s390x on the page [6]. Maybe the used machine does not even have the global static IP. You can see other articles [7][8] too.</p>
<p>I can see some benefits to start Cirrus CI for the Ruby project.</p>
<ul>
<li>Possibly we can check Mac M1 (arm), ppc64le, s390x cases using machines used in RubyCI [9] and someone's machine such as @ReiOdaira's ppc64le/s390x machines at the pull-request timing.</li>
<li>When we face the CI issue, we can login to the machine and use the interactive debugging tool such as gdb to fix it.</li>
<li>The config file is YAML format and it has the matrix feature [10]. We are familiar with the YAML and matrix.</li>
</ul>
<p>What do you think? Positive or negative?<br>
Thank you.</p>
<p>[1] ruby removed .travis.yml: <a href="https://github.com/ruby/ruby/commit/6b978d542704a5614af5e9375c4b31b8d2618652" class="external">https://github.com/ruby/ruby/commit/6b978d542704a5614af5e9375c4b31b8d2618652</a><br>
[2] simde removed .travis.yml: <a href="https://github.com/simd-everywhere/simde/commit/17a27e7f2c3114225899f2ace14010cbbb2139b5" class="external">https://github.com/simd-everywhere/simde/commit/17a27e7f2c3114225899f2ace14010cbbb2139b5</a><br>
[3] GitHub Actions and ppc64le: <a href="https://github.community/t/self-hosted-runner-on-ppc64el-architecture/155337" class="external">https://github.community/t/self-hosted-runner-on-ppc64el-architecture/155337</a><br>
[4] QEMU: <a href="https://gitlab.com/qemu-project/qemu/-/blob/master/.cirrus.yml" class="external">https://gitlab.com/qemu-project/qemu/-/blob/master/.cirrus.yml</a><br>
[5] Podman: <a href="https://github.com/containers/podman/blob/master/.cirrus.yml" class="external">https://github.com/containers/podman/blob/master/.cirrus.yml</a><br>
[6] The issue ticket of Persistent Workers: <a href="https://github.com/cirruslabs/cirrus-ci-docs/issues/263#issuecomment-746900845" class="external">https://github.com/cirruslabs/cirrus-ci-docs/issues/263#issuecomment-746900845</a><br>
[7] Persistent Workers blog: <a href="https://medium.com/cirruslabs/announcing-public-beta-of-cirrus-ci-persistent-workers-7327a38004be" class="external">https://medium.com/cirruslabs/announcing-public-beta-of-cirrus-ci-persistent-workers-7327a38004be</a><br>
[8] Persistent Workers guide: <a href="https://cirrus-ci.org/guide/persistent-workers/" class="external">https://cirrus-ci.org/guide/persistent-workers/</a><br>
[9] RubyCI: <a href="https://rubyci.org/" class="external">https://rubyci.org/</a><br>
[10] Cirrus CI matrix feature: <a href="https://cirrus-ci.org/guide/writing-tasks/#matrix-modification" class="external">https://cirrus-ci.org/guide/writing-tasks/#matrix-modification</a></p> Ruby master - Misc #17683 (Open): Current status of beginless range (experimental or not)https://bugs.ruby-lang.org/issues/176832021-03-10T09:40:02Zjnchito (Junichi Ito)
<p>A beginless range was experimentally introduced in Ruby 2.7.0:<br>
<a href="https://github.com/ruby/ruby/blob/v2_7_0/NEWS#label-Other+miscellaneous+changes" class="external">https://github.com/ruby/ruby/blob/v2_7_0/NEWS#label-Other+miscellaneous+changes</a></p>
<p>Is it still experimental feature or not?</p> Ruby master - Misc #17662 (Assigned): The heredoc pattern used in tests does not syntax highlight...https://bugs.ruby-lang.org/issues/176622021-02-27T16:22:19ZEregon (Benoit Daloze)
<p>This heredoc pattern</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">assert_ruby_status</span><span class="p">([],</span> <span class="s2">"</span><span class="si">#{</span><span class="o"><<-</span><span class="s2">"begin;"</span><span class="si">}</span><span class="se">\n</span><span class="si">#{</span><span class="o"><<-</span><span class="s1">'end;'</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span> <span class="n">bug</span><span class="p">)</span>
<span class="k">begin</span><span class="p">;</span>
<span class="nb">exit</span><span class="p">(</span><span class="s2">"1"</span> <span class="o">==</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">start</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="o">&</span><span class="ss">:to_s</span><span class="p">).</span><span class="nf">value</span><span class="p">)</span>
<span class="k">end</span><span class="p">;</span>
</code></pre>
<p>completely breaks syntax highlighting in at least:</p>
<ul>
<li>GitHub: <a href="https://github.com/ruby/ruby/blob/36dde35e029c7a6607e6c674062ce6fc7a51c0bd/test/ruby/test_string.rb#L697" class="external">there</a> <a href="https://github.com/ruby/ruby/blob/36dde35e029c7a6607e6c674062ce6fc7a51c0bd/test/ruby/test_process.rb#L1545" class="external">are</a> <a href="https://github.com/ruby/ruby/blob/565aeb81e0886c835888a425e5d05ed99fb03238/test/ruby/test_thread.rb#L201" class="external">many</a> <a href="https://github.com/ruby/ruby/blob/36dde35e029c7a6607e6c674062ce6fc7a51c0bd/test/ruby/test_require.rb#L21" class="external">examples</a>
</li>
<li>Atom</li>
<li>RubyMine (and IntelliJ)</li>
<li>Likely many more editors based on TextMate grammars</li>
</ul>
<p>Could another pattern be used in tests inside the ruby/ruby repository (at least for <code>test/ruby</code>)?</p>
<p>Due to this issue, it is very annoying and inconvenient to look at/read/investigate many tests.</p>
<p>I think this pattern is also very complicated to understand (and using <code>;</code> is quite weird for this).<br>
I suggest to replace it with this obvious and simple pattern many people use:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">assert_ruby_status</span><span class="p">([],</span> <span class="o"><<~</span><span class="no">'RUBY'</span><span class="p">,</span> <span class="n">bug</span><span class="p">)</span><span class="sh">
exit("1" == Thread.start(1, &:to_s).value)
</span><span class="no"> RUBY</span>
</code></pre>
<p>This syntax highlights correctly in most (all?) editors, and as an added bonus the code inside the heredoc is also highlighted in some editors (due to the label being <code>RUBY</code>).</p> Ruby master - Misc #17637 (Open): Endless ranges with `nil` boundary weird behaviorhttps://bugs.ruby-lang.org/issues/176372021-02-17T10:49:17Zgud (gud gud)
<p>Basically it's about this <a href="https://andycroll.com/ruby/watch-out-for-nils-in-ranges/" class="external">https://andycroll.com/ruby/watch-out-for-nils-in-ranges/</a></p>
<p>Since Ruby 2.6 we have this weird syntax (0..nil) which is really really bug prone</p>
<p>e.g. we have dynamic upper boundary like</p>
<pre><code>lower = 0
upper = some_method(arg1, arg2)
(lower..upper).each do { |s| some_method2(s) }
</code></pre>
<p>We rarely do <code>nil</code> checks in Ruby so it's really easy to have Infinity loop in the end.<br>
Previous Argument error was more intuitive since it throws exception instead of silently looping forever.</p>
<ul>
<li>some additional strange behavior:</li>
</ul>
<pre><code>(0..nil).count
=> Infinity
(0..Float::INFINITY).count
=> hangs, I guess same infinity loop
</code></pre>
<p>Having explicit parameter <code>Float::INFINITY</code> (as in previous versions) looks more like a proper design instead of allowing <code>nil</code> as a valid parameter.</p>
<p>You may think of it as <strong>I would like to have a range from 0 to nothing, what is it actually ?</strong><br>
And I guess the answer is <strong>Nothing</strong>.<br>
Fixing <code>(0..Float::INFINITY).count</code> this case it also important I believe.</p>
<p>Tested on <code>ruby 2.7.1p83</code></p> Ruby master - Misc #17586 (Open): Please run Windows CI in all std-lib reposhttps://bugs.ruby-lang.org/issues/175862021-01-27T17:40:41ZMSP-Greg (Greg L)
<p>Please consider adding Windows CI to all std-lib repos.</p>
<p>Having ruby/ruby CI fail due to std-lib commits merged from their respective repos causes downstream issues, wasted time, etc.</p>
<p>See <a href="https://github.com/ruby/irb/pull/179" class="external">https://github.com/ruby/irb/pull/179</a> for an example adding Windows to Actions CI.</p>
<p>Re Actions matrix:</p>
<ol>
<li>The os change from <code>*-latest</code> to <code>*-<numeric></code> (eg, <code>macos-latest</code> to <code>macos-11.0</code>). The <code>-latest</code> designation changes, so some may prefer a <code>-<numeric></code> tag. See <a href="https://github.com/actions/virtual-environments#available-environments" class="external">https://github.com/actions/virtual-environments#available-environments</a> for available environments and their naming.</li>
<li>Using numeric versions for Ruby causes an issue with 3.0, as it’s interpreted as 3, which is only a sematic major requirement. Hence, quote all numeric versions.</li>
</ol> 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 - Misc #17565 (Open): Prefer use of access(2) in rb_file_load_ok() to check for exist...https://bugs.ruby-lang.org/issues/175652021-01-20T20:05:56Zleehambley (Lee Hambley)
<p>When using Ruby in Docker (2.5 in our case, but the code is unchanged in 15 years across all versions) with a large $LOAD_PATH some millions of calls are made to <code>open(2)</code> with a mean cost of 130µsec per call, where a call to <code>access(2)</code> has a cost around 5× lower (something around 28µsec).</p>
<p>With a Rails 5 app, without Zeitwerk, the load path is searched iteratively looking for a file to define a constant, this causes something like 2,000,000 calls to <code>open(2)</code> of which 97.5% are failing with <code>ENOENT</code>.</p>
<p>I believe that the cost of two syscalls (<code>open(2)</code> only after successful <code>access(2)</code>) would, in our case, at least because we would shave-off something like 1,900,000×90µsec (2.85 minutes) from the three minute boot time for our application.</p>
<p>I prepared a very naïve patch with a simple early-return in <code>rb_file_load_ok</code>:</p>
<pre><code>diff --git a/file.c b/file.c
index 3bf092c05c..c7a7635125 100644
--- a/file.c
+++ b/file.c
@@ -5986,6 +5986,16 @@ rb_file_load_ok(const char *path)
O_NDELAY |
#endif
0);
+ if (access(path, R_OK) == -1) return 0;
int fd = rb_cloexec_open(path, mode, 0);
if (fd == -1) return 0;
rb_update_max_fd(fd);
</code></pre>
<p>This hasn't been exhaustively tested as I simply haven't had time yet, but at least it compiled and passed <code>make check</code>.</p>
<p>I spoke with Aaron Patterson on Twitter, who suggested maybe a wiser approach would be a heuristic approach one level higher (<code>rb_find_file</code>?) which switches the strategy based on the length of the LOAD_PATH.</p>
<p>Alternatively, maybe the patch could be conditional, guarded somehow, and conditionally compiled only into the Rubies built for Docker, in a way that is portable to the common Ruby version managers.</p>
<p>I am opening this ticket to track my own work, as much as anything, with no expectation that someone implement this on my behalf. I am eager to contribute to Ruby for all the benefit I have seen from it in my career.</p>
<p>If someone knows hints why this may be an unsuccessful adventure, I gratefully receive any and all feedback.</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 - Misc #17376 (Assigned): Reduce number of GitHub Actionshttps://bugs.ruby-lang.org/issues/173762020-12-08T09:45:17Znaruse (Yui NARUSE)naruse@airemix.jp
<p>At this time we have 127 checks for GitHub commits, but unfortunately GitHub UI only shows 100 checks.<br>
It sometimes makes we don't see a failed check.<br>
Could you reduce number of GitHub actions at least less than 100?</p> Ruby master - Misc #17309 (Open): URI.escape being deprecated, yet there is no replacementhttps://bugs.ruby-lang.org/issues/173092020-11-07T01:26:10Zchucke (Tiago Cardoso)
<p>I'm on ruby 2.7.2 . The moment I do</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">uri</span> <span class="o">=</span> <span class="s2">"http://bücher.ch"</span>
<span class="no">URI</span><span class="p">.</span><span class="nf">escape</span> <span class="n">uri</span>
<span class="p">(</span><span class="n">irb</span><span class="p">):</span><span class="mi">5</span><span class="p">:</span> <span class="ss">warning: </span><span class="no">URI</span><span class="p">.</span><span class="nf">escape</span>
<span class="s2">"http://b%C3%BCcher.ch"</span>
</code></pre>
<p>I get that warning. Rubocop also tells me:</p>
<p>"""<br>
URI.escape method is obsolete and should not be used. Instead, use CGI.escape, URI.encode_www_form or URI.encode_www_form_component depending on your specific use case.<br>
"""</p>
<p>However, none of the suggestions does the same as <code>URI.escape</code>.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">CGI</span><span class="p">.</span><span class="nf">escape</span> <span class="n">uri</span>
<span class="o">=></span> <span class="s2">"http%3A%2F%2Fb%C3%BCcher.ch"</span>
<span class="no">URI</span><span class="p">.</span><span class="nf">encode_www_form_component</span> <span class="n">uri</span>
<span class="o">=></span> <span class="s2">"http%3A%2F%2Fb%C3%BCcher.ch"</span>
<span class="no">URI</span><span class="p">.</span><span class="nf">encode_www_form</span> <span class="n">uri</span>
<span class="no">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="no">NoMethodError</span> <span class="p">(</span><span class="n">undefined</span> <span class="nb">method</span> <span class="sb">`map' for "http://bücher.ch":String)
Did you mean? tap
</span></code></pre>
<p>So my question is: why is this being deprecated? And if there's still reason, what to exactly replace it for, so I can keep the exact same behaviour?</p> Ruby master - Misc #17199 (Open): id outputed by inspect and to_s output does not allow to find a...https://bugs.ruby-lang.org/issues/171992020-09-28T11:40:39ZAnnih (Baptiste Courtois)
<p>Hello, here is my first ruby issue sorry in advance if it is incorrectly filled.</p>
<a name="Issue"></a>
<h1 >Issue<a href="#Issue" class="wiki-anchor">¶</a></h1>
<p>The value returned by <code>#object_id</code> is not aligned anymore with displayed info in <code>#inspect</code> and <code>#to_s</code> methods.</p>
<a name="with-ruby-lt-27"></a>
<h2 >with ruby < 2.7<a href="#with-ruby-lt-27" class="wiki-anchor">¶</a></h2>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Object</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">tap</span> <span class="p">{</span> <span class="o">|</span><span class="n">o</span><span class="o">|</span> <span class="nb">p</span> <span class="s2">"#to_s=</span><span class="si">#{</span><span class="n">o</span><span class="p">.</span><span class="nf">to_s</span><span class="si">}</span><span class="s2">, #inspect=</span><span class="si">#{</span><span class="n">o</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">, #__id__=</span><span class="si">#{</span><span class="n">o</span><span class="p">.</span><span class="nf">__id__</span><span class="si">}</span><span class="s2">, shifted_id=</span><span class="si">#{</span><span class="p">(</span><span class="n">o</span><span class="p">.</span><span class="nf">__id__</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">).</span><span class="nf">to_s</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span>
<span class="s2">"#to_s=#<Object:0x0000000000d202a8>, #inspect=#<Object:0x0000000000d202a8>, #__id__=6881620, shifted_id=d202a8"</span>
</code></pre>
<a name="with-ruby-gt-27"></a>
<h2 >with ruby >= 2.7<a href="#with-ruby-gt-27" class="wiki-anchor">¶</a></h2>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">tap</span> <span class="p">{</span> <span class="o">|</span><span class="n">o</span><span class="o">|</span> <span class="nb">p</span> <span class="s2">"#to_s=</span><span class="si">#{</span><span class="n">o</span><span class="p">.</span><span class="nf">to_s</span><span class="si">}</span><span class="s2">, #inspect=</span><span class="si">#{</span><span class="n">o</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">, #__id__=</span><span class="si">#{</span><span class="n">o</span><span class="p">.</span><span class="nf">__id__</span><span class="si">}</span><span class="s2">, shifted_id=</span><span class="si">#{</span><span class="p">(</span><span class="n">o</span><span class="p">.</span><span class="nf">__id__</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">).</span><span class="nf">to</span>
<span class="n">s</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span>
<span class="s2">"#to_s=#<Object:0x0000555dc8640b88>, #inspect=#<Object:0x0000555dc8640b88>, #__id__=220, shifted_id=1b8"</span>
</code></pre>
<a name="Consequences"></a>
<h1 >Consequences<a href="#Consequences" class="wiki-anchor">¶</a></h1>
<p>It makes harder:</p>
<ul>
<li>to implement a clean override of the <code>#inspect</code> method. i.e. How to keep the same output without ability to compute to the same "object_id" value.</li>
<li>to debug the object using the inspect output. i.e. <code>ObjectSpace._id2ref(id_from_inspect >> 1)</code> used to work, now it doesn't (<code>RangeError: <xXx> is not id value</code>).</li>
</ul>
<a name="Suggestion"></a>
<h1 >Suggestion<a href="#Suggestion" class="wiki-anchor">¶</a></h1>
<p>IMHO either:</p>
<ul>
<li>the <code>#to_s</code> and <code>#inspect</code> documentation are obsolete <code>The default [...] [shows|prints] [...] an encoding of the object id</code> and the change could have been a bit more advertised</li>
<li>they should use the result of <code>#object_id</code> instead of displaying the object pointer address</li>
</ul>
<p>Another solution could be to provide a method to get access to the address, but I'm not sure you want that.</p>
<p>P.S. While debugging my problem I found <a href="https://www.ruby-forum.com/t/understanding-object-id-in-ruby-2-7/260268/4" class="external">this ruby-forum thread</a> where people dived a bit more than me into ruby's code.</p> Ruby master - Misc #17174 (Open): "Error relocating, symbol not found" error when compiling a nat...https://bugs.ruby-lang.org/issues/171742020-09-16T05:29:49ZNakilon (Victor Maslov)nakilon@gmail.com
<p>My native extension gem compiles fine with all versions of Ruby on macOS but only with Ruby 2.3 on Alpine. It throws various <code>Error relocating</code>, <code>symbol not found</code> when I require the <code>.o</code> file. Here I made a branch to reproduce it in Docker quickly.</p>
<pre><code>git clone https://github.com/Nakilon/dhash-vips.git --branch alpine-compilation-issues alpine-compilation-issues && cd alpine-compilation-issues
</code></pre>
<pre><code># compiles and does not fail on require
docker build - -t temp-ruby2.3.8 --build-arg RUBY_VERSION=2.3.8 --build-arg ALPINE_VERSION=3.8 <Dockerfile
# Error relocating /dhash-vips/idhash.so: rb_deprecate_constant: symbol not found - /dhash-vips/idhash.so (LoadError)
docker build - -t temp-ruby2.4.10 --build-arg RUBY_VERSION=2.4.10 --build-arg ALPINE_VERSION=3.11 <Dockerfile
# Error relocating /dhash-vips/idhash.so: rb_int_modulo: symbol not found - /dhash-vips/idhash.so (LoadError)
docker build - -t temp-ruby2.5.8 --build-arg RUBY_VERSION=2.5.8 --build-arg ALPINE_VERSION=3.12 <Dockerfile
# Error relocating /dhash-vips/idhash.so: rb_int_pow: symbol not found - /dhash-vips/idhash.so (LoadError)
docker build - -t temp-ruby2.6.6 --build-arg RUBY_VERSION=2.6.6 --build-arg ALPINE_VERSION=3.12 <Dockerfile
</code></pre>
<p>I wanted to ask in the Mailing List but for some reason my email didn't reach it. Guy on Freenode recommended to post here.</p> Ruby master - Misc #17154 (Open): Update Pathname Documentation to Clarify Expected Behaviorhttps://bugs.ruby-lang.org/issues/171542020-09-05T02:29:29Zresperat (Ralph Esperat)
<p>I would like to suggest adding a sentence to the documentation for <a href="https://ruby-doc.org/stdlib-2.7.1/libdoc/pathname/rdoc/Pathname.html" class="external">Pathname</a> to make clear the unusual behavior of <code>Pathname#+</code> when an absolute path is included in the arguments. In such a situation, <code>Pathname#+</code> drops the paths prior to the last absolute path which I understand to be the intended behavior, but it is not obviously intended, only showing up tangentially as an example in the documentation.</p>
<pre><code>p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
</code></pre>
<p>The Pathname documentation states that " <strong>All functionality</strong> from File, FileTest, and some from Dir and FileUtils is included, <strong>in an unsurprising way</strong> ..." and later when referring to core methods such as <code>Pathname#+</code> "These methods are <strong>effectively manipulating a String</strong> , because that's all a path is." However, similar uses of both <a href="https://ruby-doc.org/core-2.7.1/File.html" class="external">File</a> and <a href="https://ruby-doc.org/core-2.7.1/String.html" class="external">String</a> would produce the expected result of including all of the arguments:</p>
<pre><code>s1 = "/usr"
s2 = s1 + "/etc/passwd" # "/usr/etc/passwd"
f1 = File.new("/usr" + "/etc/passwd") # (No such file or directory @ rb_sysopen - /usr/etc/passwd)
</code></pre>
<p>A bug report was previously filed to "fix" this functionality (<a class="issue tracker-1 status-6 priority-4 priority-default closed" title="Status: Rejected" href="https://bugs.ruby-lang.org/issues/15564">Bug #15564: Pathname#+(pathpart) returns pathpart when pathpart is absolute</a>), not understanding it to be intentional. Other common help websites such as <a href="https://stackoverflow.com/questions/12464361/concatenating-absolute-paths-with-the-pathname-class" class="external">Stack Overflow</a> also show users who do not expect this behavior from this method. Adding a statement to the documentation for the <a href="https://ruby-doc.org/stdlib-2.7.1/libdoc/pathname/rdoc/Pathname.html#method-i-2B" class="external">Pathname#+</a> method will make it clear to users exactly what to expect and that this is the intended behavior. I would suggest simply the following, the first sentence of which is already present:</p>
<p><code>Appends a pathname fragment to self to produce a new Pathname object. If an absolute path is provided as any of the arguments, discards all arguments prior to the last absolute path provided.</code></p>
<p>I appreciate your consideration of this request.</p>
<p>ruby -v: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]</p> Ruby master - Misc #17053 (Open): RDoc for Hash Keyshttps://bugs.ruby-lang.org/issues/170532020-07-27T15:42:50Zburdettelamar@yahoo.com (Burdette Lamar)burdettelamar@example.com
<p>marcandre <a href="https://github.com/ruby/ruby/pull/3139#issuecomment-663281047" class="external">comments</a> on my pull request regarding <a href="https://docs.ruby-lang.org/en/master/Hash.html#class-Hash-label-Hash+Keys" class="external">documentation of Hash in Rdoc</a>:</p>
<blockquote>
<p>The only thing I would change is that I would shorten the doc on the "Invalid Hash Keys". As far as I know, this is simply not a[n] important concern as nearly all Ruby objects respond_to? :hash and :eql?</p>
</blockquote>
<blockquote>
<p>I personally would recommend adding a single example in the Hash.html#class-Hash-label-Hash+Keys section and I would remove the rest, or at least remove the examples. They burden the reader with something that is of no use to them.</p>
</blockquote>
<p>I have misgivings about it:</p>
<ul>
<li>Some of the material, for example, the text and example for user-defined hash keys, is very old.</li>
<li>I consolidated some material from earlier doc for individual methods, which now link to the relevant sections.</li>
<li>All are factual and not repeated elsewhere in the page.</li>
</ul>
<p>This is an API reference documentation. Ruby should have a <em>reference documentation</em>, and therefore should not omit anything.</p>
<p>If such material is to be included, I see three possibilities:</p>
<ul>
<li>Include inline, as is now.</li>
<li>Link to a footnote on the same page, with a back link.</li>
<li>Link to another rdoc page in <code>doc/</code> dir.</li>
</ul>
<p>I'd love to hear some opinions on this.</p> Ruby master - Misc #16805 (Assigned): Coroutine's license is unclearhttps://bugs.ruby-lang.org/issues/168052020-04-21T10:23:49Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<p>Files under <code>coroutine/</code> start like this:</p>
<pre><code class="C syntaxhl" data-language="C"><span class="o">/*</span>
<span class="o">*</span> <span class="n">This</span> <span class="n">file</span> <span class="n">is</span> <span class="n">part</span> <span class="n">of</span> <span class="n">the</span> <span class="s">"Coroutine"</span> <span class="n">project</span> <span class="n">and</span> <span class="n">released</span> <span class="n">under</span> <span class="n">the</span> <span class="n">MIT</span> <span class="n">License</span><span class="p">.</span>
<span class="o">*</span>
</code></pre>
<p>The problem is, there is no definition of "the MIT License" throughout the entire project.</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/3344">@ioquatix (Samuel Williams)</a> can you add your terms somewhere inside of LEGAL? There are several other materials also under the MIT license. You can follow how they are listed up.</p> Ruby master - Misc #16803 (Open): Discussion: those internal macros reside in public API headershttps://bugs.ruby-lang.org/issues/168032020-04-21T07:45:49Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<p>A while ago I merged <a href="https://github.com/ruby/ruby/pull/2991" class="external">https://github.com/ruby/ruby/pull/2991</a> ("Split ruby.h"). This seems working. But the changeset raised several questions.</p>
<p>The biggest one relates to those newly publicised macros and inline functions. For instance <code>RUBY3_STATIC_ASSERT</code> is a macro that expands to either <code>_Static_assert</code> (for C) or <code>static_assert</code> (for C++). A similar mechanism has been implemented inside of our repository for a while. The pull request moved the definition around to be visible outside.</p>
<a name="Discussion-1"></a>
<h4 >Discussion #1<a href="#Discussion-1" class="wiki-anchor">¶</a></h4>
<p>Is it a good idea or a bad idea, to make them visible worldwide?</p>
<a name="Discussion-2"></a>
<h4 >Discussion #2<a href="#Discussion-2" class="wiki-anchor">¶</a></h4>
<p>Why not publicise everything? For instance debuggers could benefit from ruby internal symbols.</p>
<a name="Discussion-3"></a>
<h4 >Discussion #3<a href="#Discussion-3" class="wiki-anchor">¶</a></h4>
<p>It is relatively hard for us to change public APIs (doing so could break 3rd party gems). We don't want that happen for internal APIs. How do we achieve future flexibility?</p> Ruby master - Misc #16750 (Open): Change typedef of VALUE for better type checkinghttps://bugs.ruby-lang.org/issues/167502020-04-01T18:22:10ZDan0042 (Daniel DeLorme)
<p>VALUE is currently defined as <code>typedef unsigned long VALUE</code>, but as we all know that only creates an <em>alias</em>, not an actual <em>type</em>. Since the compiler gives no warnings when comparing with other integer values, it's easy to have bugs such as <code>v == 42</code> which should have been <code>v == INT2FIX(42)</code>. Actually not so long ago I saw nobu fixing a bug of that kind where an ID had been mixed up with a VALUE.</p>
<p>So in order to prevent these kinds of bugs I propose changing VALUE to a non-scalar type such as:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">//example for 64-bit system</span>
<span class="k">typedef</span> <span class="k">union</span> <span class="n">VALUE</span> <span class="p">{</span>
<span class="k">struct</span> <span class="n">RBasic</span><span class="o">*</span> <span class="n">as_basic</span><span class="p">;</span> <span class="c1">//easy access to obj.as_basic->klass and obj.as_basic->flags</span>
<span class="kt">void</span><span class="o">*</span> <span class="n">as_ptr</span><span class="p">;</span> <span class="c1">//can assign ptr = obj.as_ptr without a cast</span>
<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">i</span><span class="p">;</span> <span class="c1">//raw int value for bitwise operations</span>
<span class="kt">int</span> <span class="n">immediate</span> <span class="o">:</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">//obj.immediate != 0 if obj is immediate type such as fixnum, flonum, static symbol</span>
<span class="kt">int</span> <span class="n">is_fixnum</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//obj.is_fixnum == 1 if obj is fixnum</span>
<span class="k">struct</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">flag</span> <span class="o">:</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">//obj.flonum.flag == 2 if obj is flonum</span>
<span class="kt">int</span> <span class="n">bits</span> <span class="o">:</span> <span class="mi">62</span><span class="p">;</span>
<span class="p">}</span> <span class="n">flonum</span><span class="p">;</span>
<span class="k">struct</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">flag</span> <span class="o">:</span> <span class="mi">8</span><span class="p">;</span> <span class="c1">//obj.symbol.flag == 0x0c if obj is a static symbol</span>
<span class="kt">int</span> <span class="n">id</span> <span class="o">:</span> <span class="mi">56</span><span class="p">;</span> <span class="c1">//-> obj.symbol.id == STATIC_SYM2ID(obj)</span>
<span class="p">}</span> <span class="n">symbol</span><span class="p">;</span>
<span class="p">}</span> <span class="n">VALUE</span><span class="p">;</span>
</code></pre>
<p>This will allow proper type-checking via the compiler.</p>
<p>A little-known fact, structs and unions can be passed (and returned) by value to functions; this 64-bit union has the same performance as a 64-bit int. This approach also allows to simplify code like <code>((struct RBasic*)obj)->flags</code> into the much more readable <code>obj.as_basic->flags</code>, and <code>FIXNUM_P(obj)</code> can be expressed directly as <code>obj.is_fixnum</code>. The only downside is that direct comparison of union variables is not possible, so you would need to use for example <code>obj.i == Qfalse.i</code></p>
<p>To summarize, stricter type-checking would eliminate an entire class of bugs, and I estimate this change would require modifications to <strong>no more than 14%</strong> of the codebase (62,213 lines). Very much worth it I believe.</p> Ruby master - Misc #16747 (Assigned): Repository reorganization requesthttps://bugs.ruby-lang.org/issues/167472020-04-01T06:58:09Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<p>Back in 0.49, there were only 60 files and 3 directories at the root of this project. This was already at some level, but OK-ish. Now, as we are reaching 3.0, we currently have 167 files and 26 directories. The project has grown up. I believe we need some housekeeping.</p>
<p>I would like to introduce directories and move things around, like <a href="https://github.com/jemalloc/jemalloc/" class="external">what they do for jemalloc</a>.</p>
<ul>
<li>Create directory named <code>src</code> and move sources there.</li>
</ul>
<p>There is no need to cargo-cult them so suggestions are welcome.</p> Ruby master - Misc #16678 (Open): Array#values_at has unintuitive behavior when supplied a range ...https://bugs.ruby-lang.org/issues/166782020-03-07T06:21:48Zprajjwal (Prajjwal Singh)
<p>Consider the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># frozen_string_literal: true</span>
<span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">5</span><span class="p">).</span><span class="nf">to_a</span>
<span class="nb">p</span> <span class="n">a</span><span class="p">.</span><span class="nf">values_at</span><span class="p">(</span><span class="mi">3</span><span class="o">..</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># => [4, 5, nil]</span>
<span class="nb">p</span> <span class="n">a</span><span class="p">.</span><span class="nf">values_at</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="o">..</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># => []</span>
</code></pre>
<p>When the range begins with a negative <code>(-1, 0, 1, 2, 3)</code>, it returns an empty array, which surprised me because I was expecting <code>[1, 2, 3, 4]</code>.</p>
<p>The argument for this is that it cold be confusing to allow this because the index <code>-1</code> could refer to the last argument and it would be unintuitive to return an array <code>[5, 1, 2, 3, 4]</code> with jumbled values.</p>
<p>The argument against it is that it makes perfect sense to account for this case and return <code>[nil, 1, 2, 3, 4]</code>.</p>
<p>Opening a dialog to see what others think of this.</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 - Misc #16630 (Assigned): Deprecate pub/ruby/*snapshot* and use pub/ruby/snapshot/* i...https://bugs.ruby-lang.org/issues/166302020-02-13T08:51:43Zznz (Kazuhiro NISHIYAMA)
<p>In <a href="https://www.ruby-lang.org/en/downloads/" class="external">https://www.ruby-lang.org/en/downloads/</a>, snapshots links to <code>pub/ruby/snapshot.*</code> and <code>pub/ruby/stable-snapshot.*</code> as official snapshot tarballs now.</p>
<p>I want to change links to snapshot tarballs in <a href="https://cache.ruby-lang.org/pub/ruby/snapshot/" class="external">https://cache.ruby-lang.org/pub/ruby/snapshot/</a>.</p>
<p>They created by <a href="https://github.com/ruby/actions/" class="external">https://github.com/ruby/actions/</a> now.</p>
<p>Tarballs under <code>pub/ruby/snapshot/</code> have branch name (e.g. <code>ruby_2_7</code>) in filenames.<br>
And they are tested. (but they remain even if tests failed.)</p>
<p><code>pub/ruby/*snapshot.*</code> are not tested.<br>
And there are fewer files under <code>pub/ruby/</code> without sub-directory recently. (e.g. <code>ruby- 2.7.*</code> are in <code>pub/ruby/2.7/</code> only.)<br>
So I want to remove them.</p>
<p>Because of the plan, <code>stable-snapshot.*</code> are still snapshot of <code>ruby_2_6</code> instead of <code>ruby_2_7</code>.</p> Ruby master - Misc #16487 (Open): Potential for SIMD usage in ruby-corehttps://bugs.ruby-lang.org/issues/164872020-01-08T09:48:29Zbyroot (Jean Boussier)byroot@ruby-lang.org
<a name="Context"></a>
<h3 >Context<a href="#Context" class="wiki-anchor">¶</a></h3>
<p>There are several ruby core methods that could be optimized with the use of SIMD instructions.</p>
<p>I experimented a bit on <code>coderange_scan</code> <a href="https://github.com/Shopify/ruby/pull/2" class="external">https://github.com/Shopify/ruby/pull/2</a>, and Pavel Rosický experimented on <code>String#strip</code> <a href="https://github.com/ruby/ruby/pull/2815" class="external">https://github.com/ruby/ruby/pull/2815</a>.</p>
<a name="Problem"></a>
<h3 >Problem<a href="#Problem" class="wiki-anchor">¶</a></h3>
<p>The downside of SIMD instructions is that they are not universally available.<br>
So it means maintaining several versions of the same code, and switching them either statically or dynamically.</p>
<p>And since most Ruby users use precompiled binaries from repositories and such, it would need to be dynamic if we want most users to benefit from it.</p>
<p>So it's not exactly "free speed", as it means a complexified codebase.</p>
<a name="Question"></a>
<h3 >Question<a href="#Question" class="wiki-anchor">¶</a></h3>
<p>So the question is to know wether ruby-core is open to patches using SIMD instructions ? And if so under which conditions.</p>
<p>cc <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/10">@shyouhei (Shyouhei Urabe)</a></p> Ruby master - Misc #16436 (Open): hash missing #last method, make it not so consistent (it has #f...https://bugs.ruby-lang.org/issues/164362019-12-19T16:21:35Zzw963 (Wei Zheng)
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span> <span class="o">=</span> <span class="p">{</span><span class="n">x</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span> <span class="n">z</span><span class="p">:</span><span class="mi">3</span><span class="p">}</span>
<span class="p">{</span>
<span class="ss">:x</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span>
<span class="ss">:y</span> <span class="o">=></span> <span class="mi">2</span><span class="p">,</span>
<span class="ss">:z</span> <span class="o">=></span> <span class="mi">3</span>
<span class="p">}</span>
<span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">first</span>
<span class="p">[</span>
<span class="ss">:x</span><span class="p">,</span>
<span class="mi">1</span>
<span class="p">]</span>
<span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">first</span><span class="p">.</span><span class="nf">first</span>
<span class="ss">:x</span>
<span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">first</span><span class="p">.</span><span class="nf">last</span>
<span class="mi">1</span>
</code></pre>
<p>last method not exist.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">last</span>
<span class="no">Exception</span><span class="p">:</span> <span class="no">NoMethodError</span><span class="p">:</span> <span class="n">undefined</span> <span class="nb">method</span> <span class="sb">`last' for {:x=>1, :y=>2, :z=>3}:Hash
</span></code></pre>
<p>We have to use #to_a to make last working.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">last</span>
<span class="p">[</span>
<span class="ss">:z</span><span class="p">,</span>
<span class="mi">3</span>
<span class="p">]</span>
<span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">last</span><span class="p">.</span><span class="nf">first</span>
<span class="ss">:z</span>
<span class="p">(</span><span class="n">pry</span><span class="p">)</span><span class="ss">:main</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">></span> <span class="n">h</span><span class="p">.</span><span class="nf">to_a</span><span class="p">.</span><span class="nf">last</span><span class="p">.</span><span class="nf">last</span>
<span class="mi">3</span>
</code></pre> Ruby master - Misc #16408 (Open): Ruby docs list incorrect method signatures for PTY::getpty/PTY:...https://bugs.ruby-lang.org/issues/164082019-12-08T18:30:18Zyarmiganosca (Chris Hoffman)
<p>Ruby documentation says the method signature for <code>PTY::getpty</code>/<code>PTY::spawn</code> is</p>
<pre><code> * PTY.spawn(command_line) { |r, w, pid| ... }
* PTY.spawn(command_line) => [r, w, pid]
* PTY.spawn(command, arguments, ...) { |r, w, pid| ... }
* PTY.spawn(command, arguments, ...) => [r, w, pid]
</code></pre>
<p>However, running the following command with any Ruby since at least 2.1.9 (and based on git history, I believe since 2.0.0) will demonstrate that these method signatures are incorrect:</p>
<pre><code>ruby -rpty -e 'r, w, pid = PTY.spawn({"GREETING" => "hello"}, "echo $GREETING world"); puts r.gets(11); r.close; w.close'
</code></pre>
<p>(it will output <code>hello world</code>)</p>
<p>Further testing confirms that, aside from the block, <code>PTY::spawn</code> has the same method signature as <code>Kernel#exec</code>, <code>Kernel#system</code>, <code>Kernel#spawn</code>, and <code>Process::spawn</code>. This makes sense given that their C implementations all call the C method <code>rb_execarg_new</code> to handle the complex argument possibilities they all have to deal with.</p>
<p>I have a branch with tests that verify this: <a href="https://github.com/yarmiganosca/ruby/tree/fix-PTY-getpty-and-spawn-docs-and-tests" class="external">https://github.com/yarmiganosca/ruby/tree/fix-PTY-getpty-and-spawn-docs-and-tests</a></p>
<p>Travis isn't running CI on this branch, but I'm assuming that's account related and not an issue with my code, especially since the UI just informs me that I'm not allowed to.</p>
<p>I'm happy to also change the docs for <code>PTY::spawn</code> in this branch, but I wasn't sure which docs to emulate. The docs for this "family" of methods are inconsistent in how they explain the complicated options available to users:</p>
<ul>
<li>
<code>Kernel#spawn</code> explains in full the argument possibilities.</li>
<li>
<code>Kernel#exec</code> and <code>Kernel#system</code> both link to the docs for <code>Kernel#spawn</code>.</li>
<li>
<code>Process::spawn</code> explains in full (I think it might be a copy-paste job from the <code>Kernel#spawn</code> docs).</li>
<li>The docs for <code>IO::popen</code> (another method that uses the "execargs signature" with some modifications) list, but don't explain all the argument possibilities. They also don't do all that great a job at explaining where the other arguments from <code>IO::popen</code>'s signature fit alongside the "execargs signature".</li>
</ul>
<p>So it seems that there isn't consensus on the best way to explain this complex method signature (and modifications of it) to readers of the docs. Like I said, I'm happy to fix the <code>PTY::spawn</code> docs in this branch, but I was hoping for some guidance on which of the above documentation approaches to emulate.</p> Ruby master - Misc #16396 (Open): What is the reason for this behaviour of Find.find?https://bugs.ruby-lang.org/issues/163962019-12-03T13:03:26Zstiuna (Juan Gregorio)cart4for1@mail.com
<p>When I have a script at <code>D:\Downloads\Ruby 2.5.3\rbL\comp\codeShort.rb</code> with few other files in the same folder, the following searches only the folder where the <code>.rb</code> script is located:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Find</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="s1">'D:'</span><span class="p">)</span>
</code></pre>
<p>When I have a script at <code>D:\Downloads\Ruby 2.5.3\rbL\codeShort.rb</code> with many other files in the same folder, the same code as above searches the entire disk D.</p>
<p>To search the entire disk D in the first case, I did this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Find</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="s1">'D:/'</span><span class="p">)</span>
</code></pre>
<p>But I don't understand why the two cases behave differently with the same instruction just because they script are in different directories.</p> Ruby master - Misc #16346 (Open): Confusing macro name: RUBY_MARK_NO_PIN_UNLESS_NULLhttps://bugs.ruby-lang.org/issues/163462019-11-13T07:39:44Zy_kojima (Yohei Kojima)
<p>function <code>rb_gc_mark_no_pin</code> is renamed to <code>rb_gc_mark_movable</code> in the commit <code>aac4d9d6c7e6b6b0742f3941b574f6006ccb5672</code>.<br>
But macro <code>RUBY_MARK_NO_PIN_UNLESS_NULL</code> is not renamed then.</p>
<p>Now, <code>RUBY_MARK_NO_PIN_UNLESS_NULL</code> calls <code>rb_gc_mark_movable</code>; this is a bit confusing.<br>
So I suggest renaming <code>RUBY_MARK_NO_PIN_UNLESS_NULL</code> to <code>RUBY_MARK_MOVABLE_UNLESS_NULL</code> like this patch.</p> Ruby master - Misc #16267 (Open): MinGW CI - add to Actions ?https://bugs.ruby-lang.org/issues/162672019-10-21T01:10:18ZMSP-Greg (Greg L)
<p>Actions has three embedded MSYS2 installs, as they currently install the three Windows Rubies with 'DevKits'. So, MinGW could be built/tested on Actions.</p>
<p>I have a GH action at <a href="https://github.com/MSP-Greg/msys2-action" class="external">https://github.com/MSP-Greg/msys2-action</a> that's used in Puma's CI, it allows updating the 'toolchain' and additional packages (typically things like ragel, openssl, etc).</p>
<p>JFYI...</p> Ruby master - Misc #16235 (Open): ENV.assoc spec test does not test invalid namehttps://bugs.ruby-lang.org/issues/162352019-10-03T21:05:12Zburdettelamar@yahoo.com (Burdette Lamar)burdettelamar@example.com
<p>The most important thing here is an added test for an invalid name argument to ENV.assoc, which should raise TypeError.</p>
<p>I've also added to spec_helper.rb:</p>
<ul>
<li>Methods :reserve_names and :release_names, to reserve and release names used in the test.</li>
<li>Method :mock_to_str, to return a mock object that responds to :to_str.</li>
</ul>
<p>The updated assoc_spec.rb uses all of these, as will many other spec tests for ENV, as I get to them.</p>
<p>It's known that some of the ENV spec tests do not test a method's return value, and that some do not test error conditions (as above), so more to come. All in good time.</p> Ruby master - Misc #16188 (Open): What are the performance implications of the new keyword argume...https://bugs.ruby-lang.org/issues/161882019-09-29T18:27:43ZEregon (Benoit Daloze)
<p>In <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: "Real" keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/14183">#14183</a>, keyword arguments became further separated from positional arguments.</p>
<p>Contrary to the original design though, keyword and positional arguments are not fully separated for methods not accepting keyword arguments.<br>
Example: <code>foo(key: :value)</code> will <code>def foo(hash)</code> will pass a positional argument.<br>
This is of course better for compatibility, but I wonder what are the performance implications.</p>
<p>The block argument is completely separate in all versions, so no need to concern ourselves about that.</p>
<p>In Ruby <= 2.6:</p>
<ul>
<li>The caller never needs to know about the callee's arguments, it can just take all arguments and pass them as an array.<br>
The last argument might be used to extract keyword, but this is all done at the callee side.</li>
<li>Splitting kwargs composed of Symbol and non-Symbol keys can be fairly expensive, but it is a rare occurrence.<br>
If inlining the callee and kwargs are all passed as a literal Hash at the call site, there shouldn't be any overhead compared to positional arguments once JIT'ed.</li>
</ul>
<p>In Ruby 2.7:</p>
<ul>
<li>The caller needs to pass positional and keyword arguments separately, at least when calling a method accepting kwargs.<br>
But, if it calls a methods not accepting kwargs, then the "kwargs" (e.g. <code>foo(key: :value)</code>) should be treated just like a final Hash positional argument.</li>
<li>(If we had complete separation, then we could always pass positional and keyword arguments separately, so the caller could once again ignore the callee)</li>
</ul>
<p>How is the logic implemented in MRI for 2.7?</p>
<p>Specializing the caller for a given callee is a well-known technique.<br>
However, it becomes more difficult if different methods are called from the same callsite (polymorphic call), especially if one accepts kwargs and another does not.<br>
In that case, I think we will see a performance cost to this approach, by having to pass arguments differently based on the method to be called.</p>
<p>What about delegation using <code>ruby2_keywords</code>?<br>
Which checks does that add (compared to 2.6) in the merged approach with the Hash flag?</p> Ruby master - Misc #16160 (Open): Lazy init thread local storagehttps://bugs.ruby-lang.org/issues/161602019-09-09T21:36:28Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>References PR <a href="https://github.com/ruby/ruby/pull/2295" class="external">https://github.com/ruby/ruby/pull/2295</a></p>
<a name="Why"></a>
<h3 >Why?<a href="#Why" class="wiki-anchor">¶</a></h3>
<p>The <code>local_storage</code> member of execution context is lazy initialized and drives the <code>Thread#[]</code> and <code>Thread#[]=</code> APIs, which are Fiber local and not Thread local storage. I think the same lazy init pattern should be applied to the APIs below as well - reduces one <code>Hash</code> alloc per thread created that does not use thread locals.</p>
<a name="Lazy-allocates-thread-local-storage-for-the-following-APIs"></a>
<h3 >Lazy allocates thread local storage for the following APIs<a href="#Lazy-allocates-thread-local-storage-for-the-following-APIs" class="wiki-anchor">¶</a></h3>
<ul>
<li>
<code>Thread#thread_variable_get</code> - early returns <code>nil</code> on locals Hash not initialised</li>
<li>
<code>Thread#thread_variable_set</code> - forces allocation of the locals Hash if not initilalised</li>
<li>
<code>Thread#thread_variables</code> - early returns the empty array AND saves on Hash iteration if locals Hash not initialised</li>
<li>
<code>Thread#thread_variable?</code> - early returns <code>false</code> on locals Hash not initialised</li>
</ul>
<a name="Other-notes"></a>
<h3 >Other notes<a href="#Other-notes" class="wiki-anchor">¶</a></h3>
<ul>
<li>Moved initial implementation from <code>internal.h</code> to <code>thread.c</code> local to call sites.</li>
<li>Preferred <code>defs/id.def</code> for the <code>locals</code> ID (seeing this pattern used more often, but not sure if that is preferred to inline <code>rb_intern</code> yet. Either way there's quite a few different conventions around IDs in the codebase at the moment and happy to help converging to a standard instead.</li>
<li>Maybe a flag is overkill and <code>NIL_P</code> on <code>locals</code> ivar could also work ...</li>
</ul>
<p>Thoughts?</p> Ruby master - Misc #16157 (Open): What is the correct and *portable* way to do generic delegation?https://bugs.ruby-lang.org/issues/161572019-09-09T14:10:42ZDan0042 (Daniel DeLorme)
<p>With the keyword argument changes in 2.7 we must now specify keyword arguments explicitly when doing generic delegation. But this change is not compatible with 2.6, where it adds an empty hash to the argument list of methods that do not need/accept keyword arguments.</p>
<p>To illustrate the problem:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">ProxyWithoutKW</span> <span class="o"><</span> <span class="no">BasicObject</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
<span class="vi">@target</span> <span class="o">=</span> <span class="n">target</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">)</span>
<span class="vi">@target</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">ProxyWithKW</span> <span class="o"><</span> <span class="no">BasicObject</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
<span class="vi">@target</span> <span class="o">=</span> <span class="n">target</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">o</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">)</span>
<span class="vi">@target</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">o</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Test</span>
<span class="k">def</span> <span class="nf">args</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">)</span> <span class="n">a</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">arg</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="n">a</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">opts</span><span class="p">(</span><span class="o">**</span><span class="n">o</span><span class="p">)</span> <span class="n">o</span> <span class="k">end</span>
<span class="k">end</span>
<span class="c1"># 2.6 2.7 3.0</span>
<span class="no">ProxyWithoutKW</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Test</span><span class="p">.</span><span class="nf">new</span><span class="p">).</span><span class="nf">args</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="c1"># [42] [42] [42] ok</span>
<span class="no">ProxyWithoutKW</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Test</span><span class="p">.</span><span class="nf">new</span><span class="p">).</span><span class="nf">arg</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="c1"># 42 42 42 ok</span>
<span class="no">ProxyWithoutKW</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Test</span><span class="p">.</span><span class="nf">new</span><span class="p">).</span><span class="nf">opts</span><span class="p">(</span><span class="ss">k: </span><span class="mi">42</span><span class="p">)</span> <span class="c1"># {:k=>42} {:k=>42} +warn [{:k=>42}] incompatible with >= 2.7</span>
<span class="no">ProxyWithKW</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Test</span><span class="p">.</span><span class="nf">new</span><span class="p">).</span><span class="nf">args</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="c1"># [42, {}] [42] [42] incompatible with <= 2.6</span>
<span class="no">ProxyWithKW</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Test</span><span class="p">.</span><span class="nf">new</span><span class="p">).</span><span class="nf">arg</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="c1"># error 42 42 incompatible with <= 2.6</span>
<span class="no">ProxyWithKW</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Test</span><span class="p">.</span><span class="nf">new</span><span class="p">).</span><span class="nf">opts</span><span class="p">(</span><span class="ss">k: </span><span class="mi">42</span><span class="p">)</span> <span class="c1"># {:k=>42} {:k=>42} +warn {:k=>42} must ignore warning? cannot use pass_positional_hash in 2.6</span>
</code></pre>
<p>I don't know how to solve this, so I'm asking for the <strong>official</strong> correct way to write portable delegation code. And by <strong>portable</strong> I mean code that can be used in gems that target ruby 2.6 and above.</p> Ruby master - Misc #16130 (Open): [Discussion / Ideas] Finding a good name for the concept of/beh...https://bugs.ruby-lang.org/issues/161302019-08-27T11:59:08Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>In recent presentions this year, and perhaps prior to that as well if I<br>
remember correctly, matz mentioned that the core team (and matz) may be<br>
looking for a good name to the concept of/behind guilds.</p>
<p>The thread here, this issue, is PRIMARILY confined with this, the name -<br>
if you have any good suggestion for names in this context, or discussions<br>
that may relate to this secondarily, please feel free to chime in and<br>
comment. This is primarily meant to give some ideas, possibly.</p>
<p>Since koichi is also heavily involved here (matz pointed out that koichi<br>
likes the name guilds, and came up with the idea/proposal/implementation),<br>
I think this should be considered too. And of course how ruby users may<br>
want to use/view the concept behind guilds, and actually use them in<br>
their own code - the best idea is not great if nobody is using the<br>
concept. Like with refinements ... great idea but I found the API<br>
somewhat strange. :D (May also be because subclassing is so easy with<br>
"Foo < Bar"; ideally we could have something like this with refinements<br>
too, but this is for another proposal or discussion - this here is<br>
about the name for the concept behind guilds.)</p>
<p>Anyway.</p>
<p>I'll give my opinion too, on the names, but I will decouple this from<br>
the initial suggestion here, and reply to my own issue.</p>
<p>Note that this here really is primarily concerned with finding a good<br>
NAME, which is not trivial, since names may have different meanings<br>
in different contexts.</p>
<p>Furthermore, some links for those who may be curious - some of which<br>
are old, and I really just randomly linked these in:</p>
<p><a href="http://www.atdot.net/~ko1/activities/2016_rubykaigi.pdf" class="external">http://www.atdot.net/~ko1/activities/2016_rubykaigi.pdf</a><br>
<a href="https://mensfeld.pl/2016/11/getting-ready-for-new-concurrency-in-ruby-3-with-guilds/" class="external">https://mensfeld.pl/2016/11/getting-ready-for-new-concurrency-in-ruby-3-with-guilds/</a><br>
<a href="https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/" class="external">https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/</a></p> Ruby master - Misc #16124 (Assigned): Let the transient heap belong to objspacehttps://bugs.ruby-lang.org/issues/161242019-08-24T12:41:53Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>As per comment from Nobu in <a href="https://github.com/ruby/ruby/pull/2303#issuecomment-523248875" class="external">https://github.com/ruby/ruby/pull/2303#issuecomment-523248875</a> , I took an initial stab @ a tighter integration between objspace and the transient heap in <a href="https://github.com/ruby/ruby/pull/2400" class="external">https://github.com/ruby/ruby/pull/2400</a></p>
<a name="Benefits"></a>
<h3 >Benefits<a href="#Benefits" class="wiki-anchor">¶</a></h3>
<ul>
<li>Multi-VM (MVM) friendly - ( vm -> objspace -> theap )</li>
<li>The 32MB (current size) arena lazy allocated on ruby init is now properly freed on shutdown as well</li>
<li>It feels strange that the evacuation from the current global theap is to objspace, whereas the space evacuated from is a global arena.</li>
</ul>
<a name="Not-so-great"></a>
<h3 >Not so great<a href="#Not-so-great" class="wiki-anchor">¶</a></h3>
<ul>
<li>A fast reference to a global variable <code>global_transient_heap</code> becomes a function call to <code>rb_objspace_get_theap()</code> and related pointer chasing from vm -> objspace -> theap</li>
<li>Some internal transient heap structs moved to the header file now leaks into all other reference sites where this source file (<code>transient_heap.c</code>) as previously just used for API</li>
<li>I'm not sure exactly of the boundary Koichi had in mind for the GC compile module and how tightly it should (or shouldn't) be coupled to the transient heap. <code>struct rb_objspace*</code> declarations elsewhere for example reveals nothing about the structure members for example, whereas with this PR a lot of transient heap internals are exposed via the header file now</li>
<li>Also possible to move <code>transient_heap.c</code> into <code>gc.c</code> - I feel theap is not an experimental feature anymore and has been stable for quite some time with plausible performance benefits. The downside of that is <code>gc.c</code> is quite dense already, but then all ruby heap management concerns belong to one compile unit.</li>
</ul>
<p>In a similar vein the global method cache could perhaps belong to the VM instance as well, effectively better alignment with MVM and also easier to have a balanced VM setup and teardown sequence without anything left dangling on ruby shutdown.</p>
<p>Thoughts?</p> Ruby master - Misc #16114 (Open): Naming of "beginless range"https://bugs.ruby-lang.org/issues/161142019-08-21T23:34:44Zpwim (Paul McMahon)paul@doorkeeper.jp
<p><a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Startless range (Closed)" href="https://bugs.ruby-lang.org/issues/14799">#14799</a> introduces a "beginless range" to complement the already existing "endless range". However, "beginless" isn't an existing word in English. Since the term for something without a beginning is "beginingless", I'd propose renaming "beginless range" to "beginningless range".</p> Ruby master - Misc #16025 (Assigned): 'st_check_for_sizeof_st_index_t' declared as array with a n...https://bugs.ruby-lang.org/issues/160252019-07-27T05:32:44Zvadimp (Vadim Peretokin)
<p>Compilation of st.h with Emscripten 1.38.30 fails:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="n">st</span><span class="p">.</span><span class="n">h</span><span class="o">:</span><span class="mi">65</span><span class="o">:</span><span class="mi">45</span><span class="o">:</span> <span class="n">error</span><span class="o">:</span> <span class="err">'</span><span class="n">st_check_for_sizeof_st_index_t</span><span class="err">'</span> <span class="n">declared</span> <span class="n">as</span> <span class="n">an</span>
<span class="n">array</span> <span class="n">with</span> <span class="n">a</span> <span class="n">negative</span> <span class="n">size</span>
<span class="k">typedef</span> <span class="kt">char</span> <span class="n">st_check_for_sizeof_st_index_t</span><span class="p">[</span><span class="n">SIZEOF_VOIDP</span> <span class="o">==</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="k">sizeof</span><span class="p">(</span><span class="n">st_index_t</span><span class="p">)</span> <span class="o">?</span> <span class="mi">1</span> <span class="o">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">];</span>
<span class="o">^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span class="mi">3</span><span class="n">rdparty</span><span class="o">/</span><span class="n">edbee</span><span class="o">-</span><span class="n">lib</span><span class="o">/</span><span class="n">vendor</span><span class="o">/</span><span class="n">onig</span><span class="o">/</span><span class="n">config</span><span class="p">.</span><span class="n">h</span><span class="o">:</span><span class="mi">109</span><span class="o">:</span><span class="mi">22</span><span class="o">:</span> <span class="n">note</span><span class="o">:</span> <span class="n">expanded</span> <span class="n">from</span> <span class="n">macro</span> <span class="err">'</span><span class="n">SIZEOF_VOIDP</span><span class="err">'</span>
<span class="cp">#define SIZEOF_VOIDP 8
</span> <span class="o">^</span>
<span class="mi">1</span> <span class="n">error</span> <span class="n">generated</span><span class="p">.</span>
<span class="n">shared</span><span class="o">:</span><span class="n">ERROR</span><span class="o">:</span> <span class="n">compiler</span> <span class="n">frontend</span> <span class="n">failed</span> <span class="n">to</span> <span class="n">generate</span> <span class="n">LLVM</span> <span class="n">bitcode</span><span class="p">,</span> <span class="n">halting</span>
<span class="n">Makefile</span><span class="o">:</span><span class="mi">36871</span><span class="o">:</span> <span class="n">recipe</span> <span class="k">for</span> <span class="n">target</span> <span class="err">'</span><span class="n">regcomp</span><span class="p">.</span><span class="n">o</span><span class="err">'</span> <span class="n">failed</span>
</code></pre>
<p>Both sizeof are set to 8:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="n">onig</span><span class="err">$</span> <span class="n">cat</span> <span class="n">config</span><span class="p">.</span><span class="n">h</span> <span class="o">|</span> <span class="n">grep</span> <span class="n">SIZEOF_LONG</span>
<span class="cp">#define SIZEOF_LONG 8
#define SIZEOF_LONG_LONG 8
</span></code></pre>
<p>Is there a way to fix this issue or add a workaround for emscripten (<code>__EMSCRIPTEN__</code>)?</p> Ruby master - Misc #15806 (Assigned): Explicitly initialise encodings on init to remove branches ...https://bugs.ruby-lang.org/issues/158062019-04-27T23:41:34Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>References Github PR <a href="https://github.com/ruby/ruby/pull/2128" class="external">https://github.com/ruby/ruby/pull/2128</a></p>
<p>I noticed that the encoding table is loaded on startup of even just <code>miniruby</code> (minimal viable interpreter use case) through this backtrace during ruby setup:</p>
<pre><code>/home/lourens/src/ruby/ruby/miniruby(rb_enc_init+0x12) [0x56197b0c0c72] encoding.c:587
/home/lourens/src/ruby/ruby/miniruby(rb_usascii_encoding+0x1a) [0x56197b0c948a] encoding.c:1357
/home/lourens/src/ruby/ruby/miniruby(Init_sym+0x7a) [0x56197b24810a] symbol.c:42
/home/lourens/src/ruby/ruby/miniruby(rb_call_inits+0x1d) [0x56197b11afed] inits.c:25
/home/lourens/src/ruby/ruby/miniruby(ruby_setup+0xf6) [0x56197b0ec9d6] eval.c:74
/home/lourens/src/ruby/ruby/miniruby(ruby_init+0x9) [0x56197b0eca39] eval.c:91
/home/lourens/src/ruby/ruby/miniruby(main+0x5a) [0x56197b051a2a] ./main.c:41
</code></pre>
<p>Therefore I think it makes sense to instead initialize encodings explicitly just prior to symbol init, which is the first entry point into the interpreter loading that currently triggers <code>rb_enc_init</code> and remove the initialization check branches from the various lookup methods.</p>
<p>Some of the branches collapsed, <code>cachegrind</code> output, columns are <code>Ir Bc Bcm Bi Bim</code> with <code>Ir</code> (instructions retired), <code>Bc</code> (branches taken) and <code>Bcm</code> (branches missed) relevant here as there are no indirect branches (function pointers etc.):</p>
<p>(hot function, many instructions retired and branches taken and missed)</p>
<pre><code> . . . . . rb_encoding *
. . . . . rb_enc_from_index(int index)
835,669 0 0 0 0 {
13,133,536 6,337,652 50,267 0 0 if (!enc_table.list) {
3 0 0 0 0 rb_enc_init();
. . . . . }
23,499,349 8,006,202 293,161 0 0 if (index < 0 || enc_table.count <= (index &= ENC_INDEX_MASK)) {
. . . . . return 0;
. . . . . }
30,024,494 0 0 0 0 return enc_table.list[index].enc;
1,671,338 0 0 0 0 }
</code></pre>
<p>(cold function, representative of the utf8 variant more or less too)</p>
<pre><code> . . . . . rb_encoding *
. . . . . rb_ascii8bit_encoding(void)
. . . . . {
27,702 9,235 955 0 0 if (!enc_table.list) {
. . . . . rb_enc_init();
. . . . . }
9,238 0 0 0 0 return enc_table.list[ENCINDEX_ASCII].enc;
9,232 0 0 0 0 }
</code></pre>
<p>I think lazy loading encodings and populating the table is fine, but initializing it can be done more explicitly in the boot process.</p> Ruby master - Misc #15802 (Open): Reduce the minimum string buffer size from 127 to 63 byteshttps://bugs.ruby-lang.org/issues/158022019-04-27T16:40:14Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>References Github PR <a href="https://github.com/ruby/ruby/pull/2151" class="external">https://github.com/ruby/ruby/pull/2151</a> - another small change, but posting here for further discussion.</p>
<p>While having a look through <code>String</code> specific allocation paths with <a href="http://valgrind.org/docs/manual/dh-manual.html#dh-manual.overview" class="external">dhat</a> on redmine I noticed many string buffer use cases actually need way less than the current <code>128</code> byte minimum size (127 current minimum size + sentinel).</p>
<p>These auxiliary buffers are malloc heap specific as the <code>String</code> type is not supported by the transient heap due to complexity.</p>
<a name="How-to-interpret-the-DHAT-output"></a>
<h4 >How to interpret the DHAT output<a href="#How-to-interpret-the-DHAT-output" class="wiki-anchor">¶</a></h4>
<p>From the example output below, we can draw the following conclusions for the specific allocation site leading up to <code>rb_str_buf_new</code>:</p>
<ul>
<li>Total allocated size of <code>434944</code> bytes with a very low read and write access ratio under 25%</li>
<li>The buffer is thus 75% larger than it should be for this particular site (more examples further down below)</li>
<li>Short lived as expected from a buffer use case, but did occupy non-insignificant heap space still for a fair amount of time</li>
<li>The <code>0</code>s at the tail end of the output represent memory never accessed (rows are byte offsets)</li>
<li>As an aside, this particular string's first few characters are <code>hot</code> (accessed more frequently than the tail end)</li>
</ul>
<pre><code>==26579== -------------------- 95 of 300 --------------------
==26579== max-live: 330,368 in 2,581 blocks
==26579== tot-alloc: 434,944 in 3,398 blocks (avg size 128.00)
==26579== deaths: 3,347, at avg age 368,102,626 (2.64% of prog lifetime)
==26579== acc-ratios: 0.22 rd, 0.25 wr (97,275 b-read, 110,341 b-written)
==26579== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==26579== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==26579== by 0x284A9B: rb_str_buf_new (string.c:1331)
==26579== by 0x31B9F7: rb_ary_join (array.c:2331)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7C7C: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7C7C: vm_exec_core (insns.def:789)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579== by 0x2EEEED: invoke_iseq_block_from_c (vm.c:1104)
==26579== by 0x2EEEED: invoke_block_from_c_bh (vm.c:1122)
==26579== by 0x2EEEED: vm_yield (vm.c:1167)
==26579== by 0x2EEEED: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEEED: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEEED: rb_yield (vm_eval.c:996)
==26579== by 0x31153B: rb_ary_each (array.c:2087)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7D2B: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7D2B: vm_exec_core (insns.def:771)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579==
==26579== Aggregated access counts by offset:
==26579==
==26579== [ 0] 11407 8731 9660 11112 11171 11724 13165 13609 10826 10998 11436 11420 11405 10295 9710 9316
==26579== [ 16] 5664 4959 3874 3607 2965 2395 1908 1509 1285 967 597 261 149 141 140 124
==26579== [ 32] 73 57 56 55 55 55 54 52 51 51 51 51 51 51 51 51
==26579== [ 48] 34 34 34 34 34 34 17 0 0 0 0 0 0 0 0 0
==26579== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<a name="Why-lower-is-better"></a>
<h4 >Why lower is better<a href="#Why-lower-is-better" class="wiki-anchor">¶</a></h4>
<p>The easiest reproducible case from the benchmark suite is the <code>require</code> benchmark (the allocation site below is from Rails though - DHAT is very slow and doesn't make sense in context of a benchmark):</p>
<pre><code>==28383== -------------------- 572 of 600 --------------------
==28383== max-live: 36,992 in 289 blocks
==28383== tot-alloc: 91,520 in 715 blocks (avg size 128.00)
==28383== deaths: 553, at avg age 908,212,488 (8.68% of prog lifetime)
==28383== acc-ratios: 6.15 rd, 0.41 wr (563,074 b-read, 37,525 b-written)
==28383== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==28383== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==28383== by 0x284A9B: rb_str_buf_new (string.c:1331)
==28383== by 0x290D56: str_gsub (string.c:5163)
==28383== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==28383== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==28383== by 0x2F7C7C: vm_sendish (vm_insnhelper.c:3623)
==28383== by 0x2F7C7C: vm_exec_core (insns.def:789)
==28383== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==28383== by 0x18B336: rb_load_internal0 (load.c:612)
==28383== by 0x18E1B0: rb_require_internal (load.c:1028)
==28383== by 0x18E3B2: rb_require_safe (load.c:1074)
==28383== by 0x18E3B2: rb_f_require (load.c:821)
==28383== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==28383== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==28383== by 0x2F1F42: vm_call_method (vm_insnhelper.c:2712)
==28383==
==28383== Aggregated access counts by offset:
==28383==
==28383== [ 0] 17936 15574 14945 15051 14538 15487 15599 15077 14658 14483 14826 14849 15232 15238 15522 15310
==28383== [ 16] 15055 15020 15143 15156 15271 14807 14656 14271 14051 13761 13365 13156 12756 12530 12302 12002
==28383== [ 32] 7652 7427 7106 6807 6594 6315 6044 5932 5750 5606 5520 5439 5347 5237 5174 5095
==28383== [ 48] 2252 2211 2158 2128 2117 2088 2075 2045 2034 2018 2006 1992 1974 1973 1964 1964
==28383== [ 64] 183 183 183 183 183 183 183 183 183 183 183 183 183 183 183 183
==28383== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28383== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28383== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ /usr/local/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver --executables="compare-ruby::~/src/ruby/trunk/ruby --disable=gems -I.ext/common --disable-gem" --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" -v --repeat-count=24 -r ips $(ls ./benchmark/*require.{yml,rb} 2>/dev/null)
compare-ruby: ruby 2.7.0dev (2019-04-25 trunk 9bfc185a0d) [x86_64-linux]
built-ruby: ruby 2.7.0dev (2019-04-25 lower-str-buf-.. 9bfc185a0d) [x86_64-linux]
Calculating -------------------------------------
compare-ruby built-ruby
require 1.870 2.408 i/s - 1.000 times in 0.534865s 0.415268s
Comparison:
require
built-ruby: 2.4 i/s
compare-ruby: 1.9 i/s - 1.29x slower
lourens@CarbonX1:~/src/ruby/ruby$ /usr/local/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver --executables="compare-ruby::~/src/ruby/trunk/ruby --disable=gems -I.ext/common --disable-gem" --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" -v --repeat-count=24 -r memory $(ls ./benchmark/*require.{yml,rb} 2>/dev/null)
compare-ruby: ruby 2.7.0dev (2019-04-25 trunk 9bfc185a0d) [x86_64-linux]
built-ruby: ruby 2.7.0dev (2019-04-25 lower-str-buf-.. 9bfc185a0d) [x86_64-linux]
Calculating -------------------------------------
compare-ruby built-ruby
require 28.128M 26.932M bytes - 1.000 times
Comparison:
require
built-ruby: 26932000.0 bytes
compare-ruby: 28128000.0 bytes - 1.04x larger
</code></pre>
<p>Also the <code>hash_aref_dsym_long</code> benchmark has significant memory reduction:</p>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ /usr/local/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver --executables="compare-ruby::~/src/ruby/trunk/ruby --disable=gems -I.ext/common --disable-gem" --executables="built-ruby::./miniruby -I./lib -I. -I.ext/common -r./prelude --disable-gem" -v --repeat-count=6 -r memory $(ls ./benchmark/hash_aref_dsym_long.{yml,rb} 2>/dev/null)
compare-ruby: ruby 2.7.0dev (2019-04-26 trunk 5689c46457) [x86_64-linux]
built-ruby: ruby 2.7.0dev (2019-04-26 lower-str-buf-.. 9abd605533) [x86_64-linux]
last_commit=Reduce the minimum string buffer size from 127 to 63 bytes
Calculating -------------------------------------
compare-ruby built-ruby
hash_aref_dsym_long 117.580M 104.984M bytes - 1.000 times
Comparison:
hash_aref_dsym_long
built-ruby: 104984000.0 bytes
compare-ruby: 117580000.0 bytes - 1.12x larger
</code></pre>
<a name="Other-allocation-sites-of-note"></a>
<h4 >Other allocation sites of note<a href="#Other-allocation-sites-of-note" class="wiki-anchor">¶</a></h4>
<pre><code>==26579== -------------------- 98 of 300 --------------------
==26579== max-live: 323,456 in 2,527 blocks
==26579== tot-alloc: 402,816 in 3,147 blocks (avg size 128.00)
==26579== deaths: 3,147, at avg age 377,614,197 (2.71% of prog lifetime)
==26579== acc-ratios: 0.21 rd, 0.16 wr (87,620 b-read, 64,622 b-written)
==26579== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==26579== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==26579== by 0x284A9B: rb_str_buf_new (string.c:1331)
==26579== by 0x294584: rb_str_inspect (string.c:5911)
==26579== by 0x2F33F8: vm_call0_cfunc_with_frame (vm_eval.c:86)
==26579== by 0x2F33F8: vm_call0_cfunc (vm_eval.c:100)
==26579== by 0x2F33F8: vm_call0_body.constprop.410 (vm_eval.c:132)
==26579== by 0x2FE4CE: rb_vm_call0 (vm_eval.c:60)
==26579== by 0x2FE4CE: rb_call0 (vm_eval.c:309)
==26579== by 0x2FE4CE: rb_call (vm_eval.c:603)
==26579== by 0x2FE4CE: rb_funcall_with_block (vm_eval.c:857)
==26579== by 0x2EEFBE: vm_yield_with_symbol (vm_insnhelper.c:2869)
==26579== by 0x2EEFBE: invoke_block_from_c_bh (vm.c:1131)
==26579== by 0x2EEFBE: vm_yield (vm.c:1167)
==26579== by 0x2EEFBE: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEFBE: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEFBE: rb_yield (vm_eval.c:996)
==26579== by 0x317627: rb_ary_collect_bang (array.c:3052)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7D2B: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7D2B: vm_exec_core (insns.def:771)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579== by 0x2EEEED: invoke_iseq_block_from_c (vm.c:1104)
==26579== by 0x2EEEED: invoke_block_from_c_bh (vm.c:1122)
==26579== by 0x2EEEED: vm_yield (vm.c:1167)
==26579== by 0x2EEEED: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEEED: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEEED: rb_yield (vm_eval.c:996)
==26579==
==26579== Aggregated access counts by offset:
==26579==
==26579== [ 0] 13063 14338 12631 14007 13323 12720 11984 11344 9232 7280 6288 5776 4256 3856 3584 2976
==26579== [ 16] 1968 1216 1296 720 160 48 48 48 64 16 0 0 0 0 0 0
==26579== [ 32] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==26579== -------------------- 186 of 300 --------------------
==26579== max-live: 155,136 in 1,212 blocks
==26579== tot-alloc: 155,136 in 1,212 blocks (avg size 128.00)
==26579== deaths: 651, at avg age 245,150,551 (1.75% of prog lifetime)
==26579== acc-ratios: 1.63 rd, 0.33 wr (253,660 b-read, 51,700 b-written)
==26579== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==26579== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==26579== by 0x284A9B: rb_str_buf_new (string.c:1331)
==26579== by 0x13AA2E: rb_file_join (file.c:4732)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579== by 0x2F7C7C: vm_sendish (vm_insnhelper.c:3623)
==26579== by 0x2F7C7C: vm_exec_core (insns.def:789)
==26579== by 0x2EE34D: rb_vm_exec (vm.c:1892)
==26579== by 0x2EEEED: invoke_iseq_block_from_c (vm.c:1104)
==26579== by 0x2EEEED: invoke_block_from_c_bh (vm.c:1122)
==26579== by 0x2EEEED: vm_yield (vm.c:1167)
==26579== by 0x2EEEED: rb_yield_0 (vm_eval.c:980)
==26579== by 0x2EEEED: rb_yield_1 (vm_eval.c:986)
==26579== by 0x2EEEED: rb_yield (vm_eval.c:996)
==26579== by 0x374412: dir_yield (dir.c:803)
==26579== by 0x374412: dir_each_entry (dir.c:860)
==26579== by 0x374412: dir_each (dir.c:830)
==26579== by 0x1355D2: rb_ensure (eval.c:1076)
==26579== by 0x373447: dir_foreach (dir.c:2955)
==26579== by 0x2E5B4E: vm_call_cfunc_with_frame (vm_insnhelper.c:2207)
==26579== by 0x2E5B4E: vm_call_cfunc (vm_insnhelper.c:2225)
==26579==
==26579== Aggregated access counts by offset:
==26579==
==26579== [ 0] 17075 17890 16143 17188 15855 18234 17616 19067 13136 11474 10379 11350 10094 9420 8556 7614
==26579== [ 16] 5325 5125 5030 4865 3582 2982 3010 3018 2997 3011 3056 3104 2695 2748 2696 2680
==26579== [ 32] 1741 1726 1664 1612 1285 1191 1138 1067 1043 1008 984 983 971 985 972 970
==26579== [ 48] 565 562 568 559 560 557 557 557 557 557 557 557 557 557 557 557
==26579== [ 64] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
==26579== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==26579== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==28716== -------------------- 64 of 300 --------------------
==28716== max-live: 273,280 in 2,135 blocks
==28716== tot-alloc: 446,464 in 3,488 blocks (avg size 128.00)
==28716== deaths: 2,277, at avg age 365,758,007 (3.44% of prog lifetime)
==28716== acc-ratios: 0.21 rd, 0.15 wr (96,380 b-read, 71,208 b-written)
==28716== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==28716== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==28716== by 0x284A9B: rb_str_buf_new (string.c:1331)
==28716== by 0x294584: rb_str_inspect (string.c:5911)
==28716==
==28716== Aggregated access counts by offset:
==28716==
==28716== [ 0] 14382 15824 13909 15391 14767 14067 13241 12472 10180 7932 6842 6270 4714 4213 3909 3280
==28716== [ 16] 2173 1349 1386 810 216 63 54 55 68 20 1 0 0 0 0 0
==28716== [ 32] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==28716== -------------------- 276 of 300 --------------------
==28716== max-live: 19,712 in 154 blocks
==28716== tot-alloc: 146,432 in 1,144 blocks (avg size 128.00)
==28716== deaths: 1,115, at avg age 150,688,929 (1.41% of prog lifetime)
==28716== acc-ratios: 0.06 rd, 0.08 wr (9,024 b-read, 12,049 b-written)
==28716== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==28716== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==28716== by 0x284A9B: rb_str_buf_new (string.c:1331)
==28716== by 0x23B70C: rb_reg_regsub (re.c:3820)
==28716==
==28716== Aggregated access counts by offset:
==28716==
==28716== [ 0] 3569 4271 3304 1590 670 640 673 692 537 526 525 518 502 482 465 443
==28716== [ 16] 223 203 182 153 127 113 101 85 71 63 57 52 49 48 44 38
==28716== [ 32] 14 9 7 6 5 4 4 4 3 1 0 0 0 0 0 0
==28716== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==28716== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<pre><code>==29686== -------------------- 391 of 600 --------------------
==29686== max-live: 8,192 in 64 blocks
==29686== tot-alloc: 9,472 in 74 blocks (avg size 128.00)
==29686== deaths: 74, at avg age 207,459,973 (1.96% of prog lifetime)
==29686== acc-ratios: 0.21 rd, 0.17 wr (1,998 b-read, 1,628 b-written)
==29686== at 0x4C2DECF: malloc (in /usr/lib/valgrind/vgpreload_exp-dhat-amd64-linux.so)
==29686== by 0x1521D3: objspace_xmalloc0 (gc.c:9407)
==29686== by 0x284A9B: rb_str_buf_new (string.c:1331)
==29686== by 0x30BB8A: inspect_ary (array.c:2379)
==29686==
==29686== Aggregated access counts by offset:
==29686==
==29686== [ 0] 296 296 296 370 370 370 370 370 296 222 296 74 0 0 0 0
==29686== [ 16] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 32] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 48] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 64] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 80] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 96] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
==29686== [ 112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</code></pre>
<a name="Rails-specific-redmine-boot"></a>
<h4 >Rails specific - redmine boot<a href="#Rails-specific-redmine-boot" class="wiki-anchor">¶</a></h4>
<p>Booting redmine only, no real work done otherwise - about <code>101720</code> bytes different in current malloc sizes. I understand <code>GC.malloc_allocated_size</code> to reflect the current delta between <code>xmalloc</code> and <code>xfree</code>, but may be wrong. And that value is not representative of total malloc heap churn, judging by the much higher total allocated values coming back from <a href="https://github.com/ruby/ruby/pull/2151#issuecomment-487300456" class="external">valgrind</a>.</p>
<pre><code>lourens@CarbonX1:~/src/redmine$ bundle exec rails c -e production
/home/lourens/src/redmine/vendor/bundle/ruby/2.7.0/gems/activerecord-5.2.1.1/lib/active_record/associations/builder/collection_association.rb:26: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
Loading production environment (Rails 5.2.1.1)
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 2.7.0dev (2019-04-26 trunk 5689c46457) [x86_64-linux]"
irb(main):002:0> GC.start
=> nil
irb(main):003:0> GC.malloc_allocated_size
=> 74907128
</code></pre>
<pre><code>lourens@CarbonX1:~/src/redmine$ bundle exec rails c -e production
/home/lourens/src/redmine/vendor/bundle/ruby/2.7.0/gems/activerecord-5.2.1.1/lib/active_record/associations/builder/collection_association.rb:26: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
Loading production environment (Rails 5.2.1.1)
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 2.7.0dev (2019-04-26 lower-str-buf-.. 9abd605533) [x86_64-linux]"
irb(main):002:0> GC.start
=> nil
irb(main):003:0> GC.malloc_allocated_size
=> 74805408
</code></pre>
<a name="Rails-specific-some-requests-workload"></a>
<h4 >Rails specific - some requests / workload<a href="#Rails-specific-some-requests-workload" class="wiki-anchor">¶</a></h4>
<p>Same sequence of redmine requests - 6 for this branch and trunk respectively using this as a simple initializer for reporting on exit, a <code>228600</code> bytes difference.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">if</span> <span class="no">GC</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="ss">:malloc_allocated_size</span><span class="p">)</span>
<span class="nb">at_exit</span> <span class="k">do</span>
<span class="nb">p</span> <span class="s2">"</span><span class="si">#{</span><span class="no">RUBY_DESCRIPTION</span><span class="si">}</span><span class="s2"> GC.malloc_allocated_size: </span><span class="si">#{</span><span class="no">GC</span><span class="p">.</span><span class="nf">malloc_allocated_size</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<pre><code>[2019-04-25 23:42:43] INFO WEBrick 1.4.2
[2019-04-25 23:42:43] INFO ruby 2.7.0 (2019-04-26) [x86_64-linux]
[2019-04-25 23:42:43] INFO WEBrick::HTTPServer#start: pid=31335 port=3000
127.0.0.1 - - [25/Apr/2019:23:42:48 WEST] "GET / HTTP/1.1" 200 4373
http://localhost:3000/news -> /
127.0.0.1 - - [25/Apr/2019:23:42:49 WEST] "GET /projects HTTP/1.1" 200 5470
http://localhost:3000/ -> /projects
127.0.0.1 - - [25/Apr/2019:23:42:51 WEST] "GET /activity HTTP/1.1" 200 7373
http://localhost:3000/projects -> /activity
127.0.0.1 - - [25/Apr/2019:23:42:51 WEST] "GET /issues HTTP/1.1" 200 19195
http://localhost:3000/activity -> /issues
127.0.0.1 - - [25/Apr/2019:23:42:52 WEST] "GET /time_entries HTTP/1.1" 200 12508
http://localhost:3000/issues -> /time_entries
127.0.0.1 - - [25/Apr/2019:23:42:53 WEST] "GET /issues/gantt HTTP/1.1" 200 22597
http://localhost:3000/time_entries -> /issues/gantt
127.0.0.1 - - [25/Apr/2019:23:42:54 WEST] "GET /issues/calendar HTTP/1.1" 200 16712
http://localhost:3000/issues/gantt -> /issues/calendar
127.0.0.1 - - [25/Apr/2019:23:42:54 WEST] "GET /news HTTP/1.1" 200 5472
http://localhost:3000/issues/calendar -> /news
^C[2019-04-25 23:42:58] INFO going to shutdown ...
[2019-04-25 23:42:59] INFO WEBrick::HTTPServer#start done.
Exiting
"ruby 2.7.0dev (2019-04-26 trunk 5689c46457) [x86_64-linux] GC.malloc_allocated_size: 84901440"
</code></pre>
<pre><code>[2019-04-25 23:41:51] INFO WEBrick 1.4.2
[2019-04-25 23:41:51] INFO ruby 2.7.0 (2019-04-26) [x86_64-linux]
[2019-04-25 23:41:51] INFO WEBrick::HTTPServer#start: pid=31029 port=3000
127.0.0.1 - - [25/Apr/2019:23:41:59 WEST] "GET / HTTP/1.1" 200 4373
http://localhost:3000/activity -> /
127.0.0.1 - - [25/Apr/2019:23:42:02 WEST] "GET /projects HTTP/1.1" 200 5470
http://localhost:3000/ -> /projects
127.0.0.1 - - [25/Apr/2019:23:42:04 WEST] "GET /activity HTTP/1.1" 200 7373
http://localhost:3000/projects -> /activity
127.0.0.1 - - [25/Apr/2019:23:42:05 WEST] "GET /issues HTTP/1.1" 200 19195
http://localhost:3000/activity -> /issues
127.0.0.1 - - [25/Apr/2019:23:42:06 WEST] "GET /time_entries HTTP/1.1" 200 12508
http://localhost:3000/issues -> /time_entries
127.0.0.1 - - [25/Apr/2019:23:42:07 WEST] "GET /issues/gantt HTTP/1.1" 200 22597
http://localhost:3000/time_entries -> /issues/gantt
127.0.0.1 - - [25/Apr/2019:23:42:07 WEST] "GET /javascripts/raphael.js?1543965852 HTTP/1.1" 200 90648
http://localhost:3000/issues/gantt -> /javascripts/raphael.js?1543965852
127.0.0.1 - - [25/Apr/2019:23:42:08 WEST] "GET /issues/calendar HTTP/1.1" 200 16712
http://localhost:3000/issues/gantt -> /issues/calendar
127.0.0.1 - - [25/Apr/2019:23:42:09 WEST] "GET /news HTTP/1.1" 200 5472
http://localhost:3000/issues/calendar -> /news
^C[2019-04-25 23:42:14] INFO going to shutdown ...
[2019-04-25 23:42:15] INFO WEBrick::HTTPServer#start done.
Exiting
"ruby 2.7.0dev (2019-04-26 lower-str-buf-.. 9abd605533) [x86_64-linux] GC.malloc_allocated_size: 84672840"
</code></pre> Ruby master - Misc #15744 (Open): Improvement needed to documentation of 'Literals'https://bugs.ruby-lang.org/issues/157442019-04-02T17:34:46ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<p>Documentation of "Literals" for v2.6.0 is given here: <a href="https://docs.ruby-lang.org/en/2.6.0/syntax/literals_rdoc.html" class="external">https://docs.ruby-lang.org/en/2.6.0/syntax/literals_rdoc.html</a>. (I don't think it has been changed for some time.) It gives examples of literals but does not provide a definition. It is comparable to defining an array by giving a few examples. I believe a definition is needed.</p>
<p>I would like to suggest a definition, but I confess I don't know what a Ruby literal is. A definition is attempted at this Wiki for computer programming generally: <a href="https://en.wikipedia.org/wiki/Literal_(computer_programming)" class="external">https://en.wikipedia.org/wiki/Literal_(computer_programming)</a>.</p>
<p>I suspect a Ruby literal is an object whose value is in some sense "known" at compile-time. For example, I would think <code>1</code>, <code>1.0</code> and <code>{ a: [1, 'cat', ['dog', ['pig', ..10]]] }</code> are literals but <code>{ v=>1, 2=>3 }</code> in <code>h = { v=>1, 2=>3 }</code>, <code>v</code> being a variable, is not. Or is it? If the previous line of code had been <code>v=3</code>, Ruby could, at compile-time, infer that the line could be replaced with <code>h = {3=>1, 2=>3}</code>, in which case it would be "known". This example is meant to illustrate why I earlier said "in some sense".</p> Ruby master - Misc #15654 (Open): Documentation for Complex is wrong or misleadinghttps://bugs.ruby-lang.org/issues/156542019-03-11T08:43:36Zsawa (Tsuyoshi Sawada)
<p>The documentation for <code>Complex</code> <a href="https://ruby-doc.org/core-2.6/Complex.html" class="external">https://ruby-doc.org/core-2.6/Complex.html</a> says or implies that a complex can be created by literal like <code>2+1i</code>, but that is actually calling the method <code>+</code> on receiver <code>2</code> with argument <code>1i</code>. The description should be changed to make it clear that <code>2+ 1i</code> is not a literal but is applying a method.</p> Ruby master - Misc #15568 (Open): TracePoint(:raise)#parameters raises RuntimeErrorhttps://bugs.ruby-lang.org/issues/155682019-01-26T21:10:29Zbaweaver (Brandon Weaver)keystonelemur@gmail.com
<p>Currently trying to get the <code>trace.parameters</code> of a method in a <code>raise</code> event will lead to a RuntimeError. I would contend that it should not, and that it would be perfectly valid to ask for the parameters in the case of an exception.</p>
<p>The reason I do this is to see the arguments at the time of exception:</p>
<pre><code>def extract_args(trace)
trace.parameters.map(&:last).to_h do |name|
[name, trace.binding.eval(name.to_s)]
end
end
</code></pre>
<p>I've noticed that I can technically "cheat" and get these same values like this:</p>
<pre><code>def extract_args(trace)
trace.binding.eval('local_variables').to_h do |name|
[name, trace.binding.eval(name.to_s)]
end
end
</code></pre>
<p>Having the ability to get the parameters in a <code>raise</code> context would be very useful for debugging.</p>
<p>I'm tempted to also suggest <code>TracePoint#local_variables</code> as it would provide additional context in a more exposed way than <code>TracePoint#binding.eval('local_variables')</code></p> Ruby master - Misc #15514 (Open): Add documentation for implicit array decompositionhttps://bugs.ruby-lang.org/issues/155142019-01-07T10:26:51Zsos4nt (Stefan Schüßler)mail@stefanschuessler.de
<p>The documentation for <a href="http://ruby-doc.org/core/doc/syntax/assignment_rdoc.html#label-Array+Decomposition" class="external">Array Decomposition</a> says: <em>"[...] you can decompose an Array during assignment using parenthesis [sic]"</em> and gives an example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">=</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="nb">p</span> <span class="ss">a: </span><span class="n">a</span><span class="p">,</span> <span class="ss">b: </span><span class="n">b</span> <span class="c1"># prints {:a=>1, :b=>2}</span>
</code></pre>
<p>But – as we all know – it's also possible <em>without</em> parentheses, i.e.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</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="nb">p</span> <span class="ss">a: </span><span class="n">a</span> <span class="p">,</span> <span class="ss">b: </span><span class="n">b</span> <span class="c1">#=> {:a=>1, :b=>2}</span>
</code></pre>
<p>This also applies to block arguments when yielding multiple values vs. yielding a single array:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span>
<span class="k">yield</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="k">yield</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="k">end</span>
<span class="n">foo</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">|</span> <span class="nb">p</span> <span class="ss">a: </span><span class="n">a</span><span class="p">,</span> <span class="ss">b: </span><span class="n">b</span> <span class="p">}</span>
<span class="c1">#=> {:a=>1, :b=>2}</span>
<span class="n">bar</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">|</span> <span class="nb">p</span> <span class="ss">a: </span><span class="n">a</span><span class="p">,</span> <span class="ss">b: </span><span class="n">b</span> <span class="p">}</span>
<span class="c1">#=> {:a=>1, :b=>2}</span>
</code></pre>
<p>In both cases, parentheses are optional.</p>
<p>This implicit array decomposition could be quite surprising for newcomers. The documentation should cover it.</p> Ruby master - Misc #15510 (Open): Easter egg in Thread.handle_interrupthttps://bugs.ruby-lang.org/issues/155102019-01-05T20:42:12Zlarskanis (Lars Kanis)
<p>The docs of <code>Thread.handle_interrupt</code> are quite clear about the argument to be passed. It must be a hash of <code>ExceptionClass => :TimingSymbol</code> pairs. I never thought that anything other than a <code>Exception</code> derivation would be accepted.</p>
<p>But then I read the tests to this method and wondered: <a href="https://github.com/ruby/ruby/blob/trunk/test/ruby/test_thread.rb#L783" class="external">Some of the tests</a> set <code>Object</code> as <code>ExceptionClass</code>. Moreover the method is not covered by ruby-spec and JRuby <a href="https://github.com/jruby/jruby/blob/66d2905ae233a39e36fcbe3ade6382c2892ade8e/test/mri/excludes/TestThread.rb" class="external">excludes several failing tests</a>.</p>
<p>So I inspected the code and found some obscure behavior: There are actually <a href="https://github.com/ruby/ruby/blob/trunk/thread.c#L115-L116" class="external">two non-exceptions</a> which can be masked by <code>Thread.handle_interrupt(Integer => :TimingSymbol)</code>. It is main thread termination and <code>Thread#kill</code>. Now this <a href="https://github.com/ruby/ruby/blob/trunk/thread.c#L1891-L1894" class="external">blur sentence in the docs</a> makes some more sense:</p>
<blockquote>
<p>interrupt means asynchronous event and corresponding procedure by Thread#raise, Thread#kill, signal trap (not supported yet) and main thread termination (if main thread terminates, then all other thread will be killed).</p>
</blockquote>
<p>So they are implemented as integers internally. However IMHO <code>Thread.handle_interrupt(Integer => :TimingSymbol)</code> is ... ugly.</p>
<p>Some proposals are:</p>
<ol>
<li>Make non-exceptions an ruby implementation specific feature, adjusts current tests and optionally add tests which are tagged as implementation specific.</li>
<li>Document it officially, but choose some more meaningful class names instead of <code>Integer</code>
</li>
</ol> Ruby master - Misc #15487 (Assigned): Clarify default gems maintanance policyhttps://bugs.ruby-lang.org/issues/154872018-12-29T12:30:23Zzverok (Victor Shepelev)zverok.offline@gmail.com
<p>In addition to <a class="issue tracker-5 status-7 priority-4 priority-default closed" title="Misc: Default gems README.md (Feedback)" href="https://bugs.ruby-lang.org/issues/15486">#15486</a>, I'd like to raise the question of the general <em>maintanance policy</em> for "default" Ruby gems, in particular:</p>
<ul>
<li>who is responsible for each gem and how they should be contacted?</li>
<li>what are goals and policies for gems code quality and documentation?</li>
<li>where do default gems are discussed?</li>
<li>what are some promises/guarantees default gems maintainers try to fulfill?</li>
</ul>
<p>The most demonstrative example I'd like to point is <code>json</code> gem:</p>
<ul>
<li>The source at <a href="https://github.com/ruby/json" class="external">ruby/json</a> is NOT authoritative as far as I can tell, the authoritative one is <a href="https://github.com/flori/json" class="external">flori/json</a>
</li>
<li>The gem still holds signs of the times it was independent (<code>Pure</code> and <code>Ext</code> JSON implementations, but <code>Pure</code> is not copied into the <code>ruby/lib</code> on releases, rendering standard docs pretty weird), and has NO mention it is THE json gem of Ruby</li>
<li>The gem seems unmaintained, considering the amount of <a href="https://github.com/flori/json/pulls" class="external">PRs</a> and <a href="https://github.com/flori/json/issues" class="external">issues</a>, lot of them without any reaction for months</li>
<li>When I tried to update JSON docs, in <a href="https://bugs.ruby-lang.org/issues/14581" class="external">core tracker issue</a> I was asked to make a PR to "upstream repository", but there, the PRs (<a href="https://github.com/flori/json/pull/347" class="external">#347</a>, <a href="https://github.com/flori/json/pull/349" class="external">#349</a>) was simply ignored; Ruby 2.6 was released without new docs, despite the fact PRs were made at <strong>March</strong> and require almost no code review (unlike even some promising optimization PRs, that were also hanging there since Feb/Mar)</li>
</ul>
<p>It is just one unfortunate case (TBH, my experience with contributing to other libraries, like <code>csv</code> and <code>psych</code> was much smoother), but it demonstrates some common lack of transparency in maintaining of Ruby's standard library</p> Ruby master - Misc #15431 (Open): Hashes and arrays should not require commas to seperate values ...https://bugs.ruby-lang.org/issues/154312018-12-18T04:14:25Znsuchy (Nathaniel Suchy)me@lunorian.is
<p>Ruby should not require commas for hash and array values if using new lines. I think the syntax would look cleaner without.</p>
<p><strong>Example</strong></p>
<pre><code>myHash = {
:key => “value”,
:anotherKey => “another value”
}
</code></pre>
<p><strong>Could be</strong></p>
<pre><code>myHash = {
:key => “value”
:anotherKey => “another value”
}
</code></pre>
<p><strong>And</strong></p>
<pre><code>myArray = [
1,
2,
3
]
</code></pre>
<p>Could be:</p>
<pre><code>myArray = [
1
2
3
]
</code></pre>
<p>The syntax looks a bit cleaner, with the new lines is there a need to require a comma? I look forward to hearing the community’s thoughts on this idea :)</p> Ruby master - Misc #15418 (Open): Date.parse('2018')https://bugs.ruby-lang.org/issues/154182018-12-15T18:43:56Zfoonlyboy (Eike Dierks)
<p>Date.parse('2018')<br>
ArgumentError: invalid date</p>
<p>I did expect that to return the same as:<br>
Date.parse('2018-1-1')<br>
=> Mon, 01 Jan 2018</p>
<p>working with dates and times is really weird and complicated,<br>
so it makes sense to be strict with parsing.</p>
<p>I watched this one:<br>
<a href="https://www.youtube.com/watch?v=-5wpm-gesOY" class="external">https://www.youtube.com/watch?v=-5wpm-gesOY</a><br>
He's really coming up with some some crazy test cases.</p>
<p>In ruby this is split between Time and DateTime,<br>
some in the core, some in in the standard lib.</p>
<hr>
<p>Im looking forward for the new version,<br>
let's freeze the strings!</p>
<p>~eike</p> Ruby master - Misc #15402 (Open): Shrinking excess retained memory of container types on promotio...https://bugs.ruby-lang.org/issues/154022018-12-11T20:43:38Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>I've been toying with the idea of the viability of attempting to reclaim over provisioned memory from buffer capacity of container objects like <code>Array</code> and <code>String</code>, effectively reducing the footprint of retained memory of such objects.</p>
<p>GC at the moment covers these dominant paths:</p>
<ul>
<li>Collection of shallow memory: unreferenced object slot with values encoded on the object</li>
<li>Collection of retained memory: unreferenced object slot with off ruby object heap pointer to String buffer, Array buffer etc. (<code>heap.aux</code>)</li>
<li>Finalization hooks like reclaiming resources for <code>Tempfile</code> for example</li>
</ul>
<p>I explored in <a href="https://github.com/ruby/ruby/pull/2037" class="external">https://github.com/ruby/ruby/pull/2037</a> (more details and data points on the PR) a forth one:</p>
<ul>
<li>Shrinking over provisioned buffer capacity of <code>Array</code> (also applies to <code>String</code> and likely others) on promotion to uncollectible (<code>Also garbage collect excess retained space from types with a first class capacity and buffer on promotion to uncollectible</code>)</li>
</ul>
<p>Sharing here for feedback in case anyone has ideas for a more appropriate hook, or additional precondition for such a hook. Or if excess buffer capacity can even be considered first class garbage in a GC context.</p>
<p>I chose <code>Array</code> as a proof of concept because the type already have this optimization through <code>ary_shrink_capa</code> through <code>ary_make_shared</code> and the threshold for not encoding members on the object is quite low at 3 elements. Plausible that many framework / boot specific long lived arrays are larger than that and because the growth factor on expansion is <code>2x</code>, also likely a fair amount of over provisioned capacity.</p>
<p>Results of the changeset:</p>
<ul>
<li>Benchmark <code>so_binary_trees</code> - <code>26%</code> reduction in total memory usage</li>
<li>Also a very noticeable <code>24%</code> difference with <code>app_lc_fizzbuzz</code>
</li>
<li>General few bytes reduction for almost all core benchmarks</li>
<li>Mainline <code>redmine</code> after boot - <code>1.5%</code> or <code>45kb</code> reduction in <code>Array</code> retained memory size</li>
</ul>
<p>Implementation caveats:</p>
<ul>
<li>Promotion to uncollectible may be a bad heuristic for shrinking buffer capacity.</li>
<li>Needed to create a new <code>rb_ary_shrink_capa</code> function as <code>ary_shrink_capa</code> is private API and has several assertions (frozen and shared check) that hard fails during GC. That way shrinking responsibility and accounting remains the responsibility of <code>array.c</code> - the GC just calls it (same as with the <code>memsize</code> APIs)</li>
<li>I tried running it during GC which worked fine for benchmarks like <code>so_binary_trees</code> but failed under GC stress and larger heaps because of <code>TRY_WITH_GC</code> via <code>objspace_xrealloc</code>, which can invoke GC</li>
<li>A reasonable workaround for this was to use the postponed job API which is used by GC for object finalization, but that's one job per object space, not 1 per Array being shrinked, which may hit the 1000 item postponed job buffer for some heaps. It degrades gracefully though with fallback being the optimization simply not being applied to the excess objects in the set.</li>
<li>Have no idea about the future of the postponed job API and if this is an appropriate use case</li>
<li>
<code>RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET</code> only special cases <code>Array</code> at the moment - it's easy to support other types</li>
</ul>
<p>Outliers to still evaluate:</p>
<ul>
<li>Fragmentation does not get significantly worse through <code>reallocs</code> for specific rare cases post GC (no data)</li>
<li>The effect of <code>objspace_malloc_increase</code> called by <code>objspace_xrealloc</code> on GC frequency (I think not much given the small reduction on retained usage, but have no data to prove yet)</li>
<li>How well the postponed job pattern scales to large heaps and how much of the job slots are consumed (no data)</li>
</ul>
<p>Thoughts on exploring more types or is the pattern tainted / broken to begin with?</p> Ruby master - Misc #15249 (Open): Documentation for attr_accessor and attr_reader should be corre...https://bugs.ruby-lang.org/issues/152492018-10-23T20:09:02ZCaryInVictoria (Cary Swoveland)cary@swoveland.com
<p>The documentation for <a href="http://ruby-doc.org/core-2.5.1/Module.html#method-i-attr_accessor" class="external">Module#attr_accessor</a> (v2.5.1) begins, "Defines a named attribute for this module, where the name is symbol.id2name, creating an instance variable (@name) and...". Similarly, the documentation for <a href="http://ruby-doc.org/core-2.5.1/Module.html#method-i-attr_reader" class="external">Module#attr_reader</a> states, "Creates instance variables and...". These statements do not appear to be correct:</p>
<pre><code>class C
attr_accessor :dog
attr_reader :cat
end
C.new.instance_variables #=> []
</code></pre> Ruby master - Misc #15224 (Open): [DOCs] Minor inconsistency in class Array #initialize_copy - ht...https://bugs.ruby-lang.org/issues/152242018-10-13T10:18:57Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>Today I looked at:</p>
<p><a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-initialize_copy" class="external">https://ruby-doc.org/core-2.5.1/Array.html#method-i-initialize_copy</a></p>
<p>The example to this method is this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">"a"</span><span class="p">,</span> <span class="s2">"b"</span><span class="p">,</span> <span class="s2">"c"</span><span class="p">,</span> <span class="s2">"d"</span><span class="p">,</span> <span class="s2">"e"</span> <span class="p">]</span>
<span class="n">a</span><span class="p">.</span><span class="nf">replace</span><span class="p">([</span> <span class="s2">"x"</span><span class="p">,</span> <span class="s2">"y"</span><span class="p">,</span> <span class="s2">"z"</span> <span class="p">])</span> <span class="c1">#=> ["x", "y", "z"]</span>
<span class="n">a</span> <span class="c1">#=> ["x", "y", "z"]</span>
</code></pre>
<p>What confused me was that I was looking at the method called <code>initialize_copy</code><br>
but the example showed <code>.replace()</code>.</p>
<p>I then looked at <code>#replace</code> there:</p>
<p><a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-replace" class="external">https://ruby-doc.org/core-2.5.1/Array.html#method-i-replace</a></p>
<p>And it was virtually identical to <code>initialize_copy</code>.</p>
<p>I assume the examples for <code>.replace()</code> are correct; and perhaps <code>initialize_copy</code><br>
is just an alias? I am not sure, but I would like to suggest to make the documentation,<br>
in particular the example, a bit more consistent.</p>
<p>When you click on "view source" to look at the C code, they show the very same<br>
content, so I believe that initialize_copy is merely an alias to replace; but I tried<br>
this and they are not fully equivalent:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">x</span> <span class="o">=</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"># => [1, 2, 3]</span>
<span class="n">x</span><span class="p">.</span><span class="nf">initialize_copy</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">]</span>
</code></pre>
<pre><code>Traceback (most recent call last):
2: from /System/Index/bin/irb:11:in `<main>'
1: from (irb):2
NoMethodError (private method `initialize_copy' called for [1, 2, 3]:Array)
</code></pre>
<p>Yet:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">x</span><span class="p">.</span><span class="nf">replace</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">]</span> <span class="c1"># => [4, 5, 6]</span>
</code></pre>
<p>works. So I assume that <code>initialize_copy</code> is like <code>.replace()</code> but is a private<br>
method instead.</p>
<p>Perhaps it may help to add a sentence below the documentation of<br>
<code>replace()</code>, to explain what the use case for <code>initialize_copy</code> is. Or to perhaps<br>
mention that it is an alias.</p>
<p>At the least how it is right now is that people may read <code>initialize_copy</code>,<br>
but then see an example of <code>#replace</code>. (Perhaps an example for<br>
<code>initialize_copy</code> may help, but either way, I think the current docu-example<br>
is not ideal).</p> Ruby master - Misc #15202 (Open): Adding Coverity Scan to CI to see the result casuallyhttps://bugs.ruby-lang.org/issues/152022018-10-04T14:06:33Zjaruga (Jun Aruga)
<p>Recently I reported issues detected by code analysis tool mainly using Coverity Scan.</p>
<p>The 9 issues categorized as "important" was fixed by <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Fixing issues detected by an Analysis tool. (Closed)" href="https://bugs.ruby-lang.org/issues/15116">#15116</a>. (Thank you!)</p>
<blockquote>
<p><a href="https://bugs.ruby-lang.org/issues/15116" class="external">https://bugs.ruby-lang.org/issues/15116</a></p>
<p>However as a "not important" issues, around 1000 issues were detected by the tool for the ruby 2.5.1.<br>
I am considering how to deal with this or report those.<br>
I might open an another ticket for that.</p>
</blockquote>
<p>However there are around 1000 "not important" issues.</p>
<p>Right now I do not share the report file (840KByte) for that, because it makes people tired.<br>
If someone want to see it, I am happy to share it here as an attachment.</p>
<p>Instead of that, It looks good to me that someone could see the result of coverity scan casually anytime to fix those in long term.</p>
<p>What I want to propose is to add coverity scan test on rubyci or Travis CI.</p>
<p>I do not know how coverity scan is used on current Ruby project as a regular workflow.<br>
But I could see it is actually used from the setting [2] and some tickets. [3]</p>
<p>I found how to use Coverity Scan on Travis CI [4], and the used cases [5][6].</p>
<p>How do you think?</p>
<ul>
<li>[1] rubyci: <a href="https://www.rubyci.org/" class="external">https://www.rubyci.org/</a>
</li>
<li>[2] coverity scan ruby project: <a href="https://scan.coverity.com/projects/ruby" class="external">https://scan.coverity.com/projects/ruby</a>
</li>
<li>[3] coverity scan used tickets:
<ul>
<li><a href="https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/61862" class="external">https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/61862</a></li>
<li><a href="https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/55763" class="external">https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/55763</a></li>
<li><a href="https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/50734" class="external">https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/50734</a></li>
</ul>
</li>
<li>[4] How to use Coverity Scan on Travis CI: <a href="https://scan.coverity.com/travis_ci" class="external">https://scan.coverity.com/travis_ci</a>
</li>
<li>[5] The cases for coverity scan on Travis CI:
<ul>
<li><a href="https://github.com/nanoporetech/scrappie/blob/master/.travis.yml" class="external">https://github.com/nanoporetech/scrappie/blob/master/.travis.yml</a></li>
<li><a href="https://github.com/JanusGraph/janusgraph/blob/master/.travis.yml" class="external">https://github.com/JanusGraph/janusgraph/blob/master/.travis.yml</a></li>
</ul>
</li>
</ul> Ruby master - Misc #15136 (Open): Fix -Wparentheses warningshttps://bugs.ruby-lang.org/issues/151362018-09-18T14:43:35Zjaruga (Jun Aruga)
<p>Currently the <code>-Wno-parentheses</code> was set.<br>
I assumed if we could fix the warning, we could remove the <code>-Wno-parentheses</code>.</p>
<p>I fixed the warnings, because the warning is used as a default on Fedora Project build environment.<br>
I sent pull-request. <a href="https://github.com/ruby/ruby/pull/1958" class="external">https://github.com/ruby/ruby/pull/1958</a></p>
<p>I would show you the explanation of <code>-Wparentheses</code>.</p>
<pre><code>$ man gcc (or gcc --help --verbose)
...
-Wparentheses
Warn if parentheses are omitted in certain contexts, such as when there is an
assignment in a context where a truth value is expected, or when operators are
nested whose precedence people often get confused about.
Also warn if a comparison like "x<=y<=z" appears; this is equivalent to "(x<=y ?
1 : 0) <= z", which is a different interpretation from that of ordinary
mathematical notation.
Also warn for dangerous uses of the GNU extension to "?:" with omitted middle
operand. When the condition in the "?": operator is a boolean expression, the
omitted value is always 1. Often programmers expect it to be a value computed
inside the conditional expression instead.
For C++ this also warns for some cases of unnecessary parentheses in
declarations, which can indicate an attempt at a function call instead of a
declaration:
{
// Declares a local variable called mymutex.
std::unique_lock<std::mutex> (mymutex);
// User meant std::unique_lock<std::mutex> lock (mymutex);
}
This warning is enabled by -Wall.
...
</code></pre> Ruby master - Misc #15007 (Open): Let all Init_xxx and extension APIs frequently called from init...https://bugs.ruby-lang.org/issues/150072018-08-18T23:17:31Zmethodmissing (Lourens Naudé)lourens@bearmetal.eu
<p>References Github PR <a href="https://github.com/ruby/ruby/pull/1934" class="external">https://github.com/ruby/ruby/pull/1934</a></p>
<a name="Why"></a>
<h3 >Why?<a href="#Why" class="wiki-anchor">¶</a></h3>
<p>An incremental extraction from PR <a href="https://github.com/ruby/ruby/pull/1922" class="external">https://github.com/ruby/ruby/pull/1922</a>, specifically addressing the feedback from Yui Naruse in <a href="https://github.com/ruby/ruby/pull/1922#issuecomment-413796710" class="external">https://github.com/ruby/ruby/pull/1922#issuecomment-413796710</a></p>
<p>The <a href="https://github.com/torvalds/linux/blob/ca04b3cca11acbaf904f707f2d9ca9654d7cc226/include/linux/compiler-gcc.h#L191-L206" class="external">Linux kernel</a>, <a href="https://github.com/php/php-src/blob/2d71a28954a4f20709718ee7cb2b850d334c561c/Zend/zend_portability.h#L220" class="external">PHP 7</a> and other projects use the <code>hot</code> and <code>cold</code> function attributes to help with better code layout.</p>
<p>I noticed Ruby is very much CPU frontend bound (not feeding instructions into the CPU pipelines as fast as it maybe could) and therefore even most micro benchmarks have a high CPI (cycles per instruction) rate. This PR is part of a larger chunk of work I'd like to do around improving CPU frontend throughput and can take a stab at formally writing up those ideas if there's any interest from the community. I don't know.</p>
<a name="Implementation"></a>
<h3 >Implementation<a href="#Implementation" class="wiki-anchor">¶</a></h3>
<p>This PR has an exclusive focus on having the <code>Init_xxx</code> functions for the core classes and those bundled in <code>ext</code> being flagged to be optimized for size as they're called only once at runtime.</p>
<p>The GCC specific <a href="https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Function-Attributes.html" class="external">cold</a> function attribute works in the following way (from GCC docs):</p>
<pre><code>The cold attribute is used to inform the compiler that a function is unlikely executed. The function is optimized for size rather than speed and on many targets it is placed into special subsection of the text section so all cold functions appears close together improving code locality of non-cold parts of program. The paths leading to call of cold functions within code are marked as unlikely by the branch prediction mechanism. It is thus useful to mark functions used to handle unlikely conditions, such as perror, as cold to improve optimization of hot functions that do call marked functions in rare occasions.
When profile feedback is available, via -fprofile-use, hot functions are automatically detected and this attribute is ignored.
</code></pre>
<p>By declaring a function as <code>cold</code> when defined we get the following benefits:</p>
<ul>
<li>No-op on platforms that does not support the attribute</li>
<li>Size optimization of cold functions with a smaller footprint in the instruction cache</li>
<li>Therefore CPU frontend throughput increases due to a lower ratio of instruction cache misses and a lower ITLB overhead - see <a href="https://user-images.githubusercontent.com/379/44204858-4c085100-a14c-11e8-86b8-d87fcb5e4985.png" class="external">original chunky PR</a> VS <a href="https://user-images.githubusercontent.com/379/44204870-4f9bd800-a14c-11e8-9bee-14c8ad8d3a7d.png" class="external">then trunk</a>
</li>
<li>This effect can further be amplified in future work with the <code>hot</code> attribute</li>
</ul>
<a name="Extension-APIs-flagged-as-cold"></a>
<h4 >Extension APIs flagged as cold<a href="#Extension-APIs-flagged-as-cold" class="wiki-anchor">¶</a></h4>
<p>These are and should typically only be called on extension init, and thus safe to optimize for size as well.</p>
<ul>
<li><code>void rb_define_method_id(VALUE, ID, VALUE (*)(ANYARGS), int));</code></li>
<li><code>void rb_undef(VALUE, ID));</code></li>
<li><code>void rb_define_protected_method(VALUE, const char*, VALUE (*)(ANYARGS), int));</code></li>
<li><code>void rb_define_private_method(VALUE, const char*, VALUE (*)(ANYARGS), int));</code></li>
<li><code>void rb_define_singleton_method(VALUE, const char*, VALUE(*)(ANYARGS), int));</code></li>
<li><code>void rb_define_alloc_func(VALUE, rb_alloc_func_t));</code></li>
<li><code>void rb_undef_alloc_func(VALUE));</code></li>
<li><code>VALUE rb_define_class(const char*,VALUE));</code></li>
<li><code>VALUE rb_define_module(const char*));</code></li>
<li><code>VALUE rb_define_class_under(VALUE, const char*, VALUE));</code></li>
<li><code>VALUE rb_define_module_under(VALUE, const char*));</code></li>
<li><code>void rb_define_variable(const char*,VALUE*));</code></li>
<li><code>void rb_define_virtual_variable(const char*,VALUE(*)(ANYARGS),void(*)(ANYARGS)));</code></li>
<li><code>void rb_define_hooked_variable(const char*,VALUE*,VALUE(*)(ANYARGS),void(*)(ANYARGS)));</code></li>
<li><code>void rb_define_readonly_variable(const char*,const VALUE*));</code></li>
<li><code>void rb_define_const(VALUE,const char*,VALUE));</code></li>
<li><code>void rb_define_global_const(const char*,VALUE));</code></li>
<li><code>void rb_define_method(VALUE,const char*,VALUE(*)(ANYARGS),int));</code></li>
<li><code>(void rb_define_module_function(VALUE,const char*,VALUE(*)(ANYARGS),int));</code></li>
<li><code>void rb_define_global_function(const char*,VALUE(*)(ANYARGS),int));</code></li>
<li><code>void rb_undef_method(VALUE,const char*));</code></li>
<li><code>void rb_define_alias(VALUE,const char*,const char*));</code></li>
<li><code>void rb_define_attr(VALUE,const char*,int,int));</code></li>
<li><code>void rb_global_variable(VALUE*));</code></li>
<li><code>void rb_gc_register_mark_object(VALUE));</code></li>
<li><code>void rb_gc_register_address(VALUE*));</code></li>
<li><code>void rb_gc_unregister_address(VALUE*));</code></li>
</ul>
<a name="Text-segment-reductions"></a>
<h4 >Text segment reductions<a href="#Text-segment-reductions" class="wiki-anchor">¶</a></h4>
<p>Small changes (<code>3144</code> bytes reduction of the text segment) because this is incremental groundwork and and initial low risk PR.</p>
<p>this branch:</p>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ size ruby
text data bss dec hex filename
3462153 21056 71344 3554553 363cf9 ruby
</code></pre>
<p>trunk:</p>
<pre><code>lourens@CarbonX1:~/src/ruby/trunk$ size ruby
text data bss dec hex filename
3465297 21056 71344 3557697 364941 ruby
</code></pre>
<p>Diffs for individual object files: <a href="https://www.diffchecker.com/T0GVzX1q" class="external">https://www.diffchecker.com/T0GVzX1q</a></p>
<p>Default <code>text.unlikely</code> section where init functions are moved to:</p>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ readelf -S vm.o
There are 34 section headers, starting at offset 0x2a04f8:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
000000000001c37f 0000000000000000 AX 0 0 16
[ 2] .rela.text RELA 0000000000000000 00114100
000000000000a7d0 0000000000000018 I 31 1 8
[ 3] .data PROGBITS 0000000000000000 0001c3c0
0000000000000030 0000000000000000 WA 0 0 16
[ 4] .bss NOBITS 0000000000000000 0001c400
00000000000002b0 0000000000000000 WA 0 0 32
[ 5] .rodata.str1.8 PROGBITS 0000000000000000 0001c400
0000000000000d6f 0000000000000001 AMS 0 0 8
[ 6] .text.unlikely PROGBITS 0000000000000000 0001d16f <<<<<<<<<<<<<<<
0000000000001aa9 0000000000000000 AX 0 0 1
</code></pre>
<p>The relocations for <code>vm.o</code>:</p>
<pre><code>lourens@CarbonX1:~/src/ruby/ruby$ ld -M vm.o
--- truncated ---
.text 0x0000000000400120 0x1de2f
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
.text.unlikely
0x0000000000400120 0x1aa9 vm.o
0x000000000040038f rb_define_alloc_func
0x00000000004003bf rb_undef_alloc_func
0x00000000004003c5 Init_Method
0x0000000000400512 Init_vm_eval
0x00000000004007a1 Init_eval_method
0x0000000000400a54 rb_undef
0x0000000000400c1d Init_VM
0x000000000040185f Init_BareVM
0x0000000000401b16 Init_vm_objects
0x0000000000401b61 Init_top_self
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
*fill* 0x0000000000401bc9 0x7
.text 0x0000000000401bd0 0x1c37f vm.o
0x00000000004022f0 rb_f_notimplement
0x0000000000404780 rb_vm_ep_local_ep
0x00000000004047b0 rb_vm_frame_block_handler
0x00000000004047e0 rb_vm_cref_new_toplevel
0x0000000000404870 rb_vm_block_ep_update
0x0000000000404890 ruby_vm_special_exception_copy
0x0000000000406960 rb_ec_stack_overflow
0x00000000004069c0 rb_vm_push_frame
0x0000000000406b20 rb_vm_pop_frame
0x0000000000406b30 rb_error_arity
0x0000000000407180 rb_vm_frame_method_entry
0x00000000004075e0 rb_vm_rewrite_cref
0x00000000004076f0 rb_simple_iseq_p
0x0000000000407700 rb_vm_opt_struct_aref
0x0000000000407730 rb_vm_opt_struct_aset
0x0000000000407750 rb_clear_constant_cache
--- truncated ---
</code></pre>
<p>I also dabbled with the idea of an <code>INITFUNC</code> macro that also places the <code>Init_xxx</code> functions into a <code>text.init</code> section as the <a href="https://linuxgazette.net/157/amurray.html" class="external">kernel does</a> for a possible future optimization of stripping out ELF sections for setup / init specific functions. I don't think that makes sense for now and possibly only interesting for mruby or embedded.</p>
<a name="Possible-next-units-of-work"></a>
<h3 >Possible next units of work<a href="#Possible-next-units-of-work" class="wiki-anchor">¶</a></h3>
<a name="Cold-code-specific"></a>
<h4 >Cold code specific<a href="#Cold-code-specific" class="wiki-anchor">¶</a></h4>
<ul>
<li>Incrementally PR corner case error handling functions such as <code>rb_bug</code> from <a href="https://github.com/ruby/ruby/pull/1922" class="external">https://github.com/ruby/ruby/pull/1922</a>
</li>
<li>Ditto for generic error handling functions (<code>rb_raise</code> and friends) from <a href="https://github.com/ruby/ruby/pull/1922" class="external">https://github.com/ruby/ruby/pull/1922</a>
</li>
<li>Class specific error handling functions (load errors, encoding errors in the IO module, sys errors etc.) from <a href="https://github.com/ruby/ruby/pull/1922" class="external">https://github.com/ruby/ruby/pull/1922</a>
</li>
<li>GCC 5+ also supports <code>cold</code> <a href="https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html" class="external">labels</a> , which I took a stab with in the bloated <a href="https://github.com/ruby/ruby/pull/1922" class="external">https://github.com/ruby/ruby/pull/1922</a>
</li>
</ul>
<a name="TLB-translation-lookaside-buffer-specific"></a>
<h4 >TLB (translation lookaside buffer) specific<a href="#TLB-translation-lookaside-buffer-specific" class="wiki-anchor">¶</a></h4>
<ul>
<li>Further ITLB overhead investigation</li>
<li>Ruby binaries built with O3 and debug symbols come in at just short of 18MB, or roughly 9 hugepages on linux. PHP core developers were able to squeeze a few % by remapping code to hugepages on supported systems - <a href="http://developers-club.com/posts/270685/" class="external">http://developers-club.com/posts/270685/</a> . Implementation <a href="https://github.com/php/php-src/blob/fb0389b1010de5a6459bcf286409423f69e74aaf/ext/opcache/ZendAccelerator.c#L2645-L2750" class="external">here</a>
</li>
</ul>
<a name="Bytecode-specific"></a>
<h4 >Bytecode specific<a href="#Bytecode-specific" class="wiki-anchor">¶</a></h4>
<ul>
<li>The <a href="https://software.intel.com/en-us/vtune-amplifier-help-task-api" class="external">Intel Tracing Task API</a> is very well suited for the instruction sequences YARV generates and to infer better per instruction CPU utilization and identify any stalls (frontend, backend, branches etc.) to drive further work.</li>
</ul> Ruby master - Misc #14917 (Assigned): Add RDoc documents to tar ballhttps://bugs.ruby-lang.org/issues/149172018-07-18T04:08:50Zaycabta (aycabta .)aycabta@gmail.com
<p>I guess that distribution packages should include RDoc documents' files because RDoc documents installation step needs too long time.</p>
<p>There is the other reason. RDoc sometimes fails during "generating RDoc documentation" phase of installation.</p>
<p>Some case examples:</p>
<ul>
<li><a href="https://bugs.ruby-lang.org/issues/11494" class="external">https://bugs.ruby-lang.org/issues/11494</a></li>
<li><a href="https://bugs.ruby-lang.org/issues/14663" class="external">https://bugs.ruby-lang.org/issues/14663</a></li>
<li><a href="https://bugs.ruby-lang.org/issues/14874" class="external">https://bugs.ruby-lang.org/issues/14874</a></li>
<li><a href="https://bugs.ruby-lang.org/issues/11514" class="external">https://bugs.ruby-lang.org/issues/11514</a></li>
</ul>
<p>Maybe, generating RDoc documentation is so heavy task for low memory situation, and other tasks are lighter than it.</p> Ruby master - Misc #14825 (Open): When redefining `attr_xx` methods the visibility becomes `public` https://bugs.ruby-lang.org/issues/148252018-06-05T05:57:56Zy-yagi (Yuji Yaginuma)
<p>Hi.</p>
<p>If redefine <code>attr_xx</code> methods, the original visibility is lost and all visibility is public.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># attr.rb</span>
<span class="k">module</span> <span class="nn">ClassMethods</span>
<span class="k">def</span> <span class="nf">attr_reader</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">attr_writer</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">attr_accessor</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Foo</span>
<span class="kp">extend</span> <span class="no">ClassMethods</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">method_visibility</span><span class="p">(</span><span class="nb">method</span><span class="p">)</span>
<span class="k">case</span>
<span class="k">when</span> <span class="nb">private_method_defined?</span><span class="p">(</span><span class="nb">method</span><span class="p">)</span>
<span class="ss">:private</span>
<span class="k">when</span> <span class="nb">protected_method_defined?</span><span class="p">(</span><span class="nb">method</span><span class="p">)</span>
<span class="ss">:protected</span>
<span class="k">else</span>
<span class="ss">:public</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">attr_reader</span> <span class="ss">:pub</span>
<span class="kp">protected</span>
<span class="nb">attr_reader</span> <span class="ss">:prot</span>
<span class="k">alias</span> <span class="n">protalias</span> <span class="n">prot</span>
<span class="kp">alias_method</span> <span class="ss">:protaliasmethod</span><span class="p">,</span> <span class="ss">:prot</span>
<span class="kp">private</span>
<span class="nb">attr_reader</span> <span class="ss">:priv</span>
<span class="k">alias</span> <span class="n">privalias</span> <span class="n">priv</span>
<span class="kp">alias_method</span> <span class="ss">:privaliasmethod</span><span class="p">,</span> <span class="ss">:priv</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="nb">puts</span> <span class="s2">"Public"</span>
<span class="n">f</span><span class="p">.</span><span class="nf">pub</span>
<span class="nb">puts</span>
<span class="nb">puts</span> <span class="s2">"Protected"</span>
<span class="nb">puts</span> <span class="s2">"prot: </span><span class="si">#{</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method_visibility</span><span class="p">(</span><span class="ss">:prot</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"protalias: </span><span class="si">#{</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method_visibility</span><span class="p">(</span><span class="ss">:protalias</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"protaliasmethod </span><span class="si">#{</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method_visibility</span><span class="p">(</span><span class="ss">:protaliasmethod</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span>
<span class="nb">puts</span> <span class="s2">"Private"</span>
<span class="nb">puts</span> <span class="s2">"priv: </span><span class="si">#{</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method_visibility</span><span class="p">(</span><span class="ss">:priv</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"privalias: </span><span class="si">#{</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method_visibility</span><span class="p">(</span><span class="ss">:privalias</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"privaliasmethod: </span><span class="si">#{</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method_visibility</span><span class="p">(</span><span class="ss">:privaliasmethod</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
</code></pre>
<pre><code>$ ruby -v attr.rb
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
Public
Protected
prot: public
protalias: public
protaliasmethod public
Private
priv: public
privalias: public
privaliasmethod: public
</code></pre>
<p>Is this intentional?</p> Ruby master - Misc #14770 (Open): [META] DevelopersMeetinghttps://bugs.ruby-lang.org/issues/147702018-05-17T12:28:50Znaruse (Yui NARUSE)naruse@airemix.jp
<p>A meta ticket to organize DevelopersMeeting tickets.<br>
<a href="https://bugs.ruby-lang.org/projects/ruby/wiki#Developer-Meetings" class="external">https://bugs.ruby-lang.org/projects/ruby/wiki#Developer-Meetings</a></p> Ruby master - Misc #14768 (Open): Add documentation for || and &&https://bugs.ruby-lang.org/issues/147682018-05-17T08:41:39Zsos4nt (Stefan Schüßler)mail@stefanschuessler.de
<p>The Ruby documentation doesn't seem to cover <code>||</code> and <code>&&</code>.</p>
<p>The only references I could find are:</p>
<p><a href="http://ruby-doc.org/core-2.5.1/doc/keywords_rdoc.html" class="external">http://ruby-doc.org/core-2.5.1/doc/keywords_rdoc.html</a></p>
<blockquote>
<p><strong>and</strong> – Short-circuit Boolean and with lower precedence than <code>&&</code><br>
<strong>or</strong> – Short-circuit Boolean and with lower precedence than <code>||</code></p>
</blockquote>
<p><a href="http://ruby-doc.org/core-2.5.1/doc/syntax/assignment_rdoc.html" class="external">http://ruby-doc.org/core-2.5.1/doc/syntax/assignment_rdoc.html</a></p>
<blockquote>
<p>There are also <code>||=</code> and <code>&&=</code>. The former makes an assignment if ...</p>
</blockquote>
<p>But there's no documentation for the operators themselves.</p> Ruby master - Misc #14760 (Open): cross-thread IO#close semanticshttps://bugs.ruby-lang.org/issues/147602018-05-15T10:04:52Znormalperson (Eric Wong)normalperson@yhbt.net
<p>I wrote about cross-thread IO#close in ruby-core, but I'm not sure if it's a bug<br>
or not to have missing support for IO.select and IO.copy_stream:</p>
<p>IO.select -<br>
<a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/86655" class="external">http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/86655</a><br>
<a href="https://public-inbox.org/ruby-core/20180423133946.GA6019@dcvr/" class="external">https://public-inbox.org/ruby-core/20180423133946.GA6019@dcvr/</a></p>
<p>IO.copy_stream -<br>
<a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/87040" class="external">http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/87040</a><br>
<a href="https://public-inbox.org/ruby-core/20180515095315.GA15909@dcvr/" class="external">https://public-inbox.org/ruby-core/20180515095315.GA15909@dcvr/</a></p>
<p>I know the IO.select case in 1.9+ differs from 1.8, and IO.copy_stream wasn't in<br>
1.8, but I guess the current behavior is that it isn't consistent with normal IO<br>
methods. IO.copy_stream will also behave "normally" and raise IOError if it<br>
somehow hits non-optimized cases and ends up calling Ruby methods, but my<br>
example in <a href="https://blade.ruby-lang.org/ruby-core/87040">[ruby-core:87040]</a> did not hit that case.</p>
<p>On one hand, I'm not a fan of "nanny features" like deadlock detection for<br>
threading. On the other hand, I value consistency and we already went down the<br>
rabbit hole of supporting current users of rb_thread_io_blocking_region.</p>
<p>Anyways, I can implement these if desired since I have additional work planned<br>
in this area anyways (auto-fiber).</p> Ruby master - Misc #14735 (Open): thread-safe operations in a hash could be documentedhttps://bugs.ruby-lang.org/issues/147352018-05-03T18:55:46Zrosenfeld (Rodrigo Rosenfeld Rosas)rr.rosas@gmail.com
<p>Hi, sometimes I find myself fetching data from the database through multiple queries concurrently. For example, suppose the application support multiple data-types which are independent from each other and we need to perform a set of operations per data-type. Usually I'd run one method for extracting the related data per data-type and would run them concurrently. Something like this:</p>
<pre><code>require 'thread'
result = {} # assume this is thread-safe in MRI for now
data_types.map do |data_type, processor|
Thread.start{ result[data_type] = processor.call }
end.each &:join
</code></pre>
<p>This code is quite simple and seems to always work with MRI. A more explicit equivalent code that should also work on other Ruby implementations without GIL would be probably written like:</p>
<pre><code>require 'thread'
result = {}
result_semaphore = Mutex.new
data_types.map do |data_type, processor|
Thread.start do
result_for_data_type = processor.call # expensive call
result_semaphore.synchronize{ result[data_type] = result_for_data_type }
end
end.each &:join
</code></pre>
<p>As you can see, it's much more code than the previous one. As I said initially, I use such pattern every now and then, so I'd love to be able to write the first code and being confident that it would always work as expected in MRI.</p>
<p>I've tried the following in order to see if I could cause an thread-unsafe case with MRI but it always return "[ 100000, 100000, nil ]":</p>
<pre><code>require 'thread'
h = {}
(1..100000).map do |i|
Thread.start{ h[i] = i }
end.each &:join
p h.keys.uniq.size, h.values.uniq.size, h.find{|k, v| k != v }
</code></pre>
<p>Is it just by chance? Or may I assume that will always be the case. Maybe it would be interesting to document somewhere what could be assumed to be true regarding thread-safeness for many methods. For example, there could be some link in the Hash documentation such as: "If you'd like to understand how each method behave in a multi-thread environment read this document" and point to another page explaining how it works.</p>
<p>By the way, the 'concurrent' gem seems to assume Hash is thread-safe in MRI as you can see here:</p>
<p><a href="https://github.com/ruby-concurrency/concurrent-ruby/blob/master/lib/concurrent/hash.rb#L5-L16" class="external">https://github.com/ruby-concurrency/concurrent-ruby/blob/master/lib/concurrent/hash.rb#L5-L16</a></p>
<pre><code>module Concurrent
if Concurrent.on_cruby?
class Hash < ::Hash;
end
#...
end
end
</code></pre>
<p>Is this officially documented somewhere?</p> Ruby master - Misc #14692 (Open): Question: Ruby stdlib's Option Parserhttps://bugs.ruby-lang.org/issues/146922018-04-17T16:30:09Zxz0r (xz0r xz0r)
<p>Hi,</p>
<p>The documentation of OptionParser says for further I can ask questions here.</p>
<p>Is there way to disable command/option completion ? I don't want a short "-f" option defined automatically if I declare "--file-name" , I have searched the internet and couldn't find a solution.</p> Ruby master - Misc #14673 (Open): Documentation for `Array#drop` / `drop_while` unclear in regard...https://bugs.ruby-lang.org/issues/146732018-04-10T09:51:49Zsos4nt (Stefan Schüßler)mail@stefanschuessler.de
<p>The documentation for <a href="http://ruby-doc.org/core-2.5.0/Array.html#method-i-drop" class="external"><code>Array#drop</code></a> says:</p>
<blockquote>
<p>Drops first <code>n</code> elements from <code>ary</code> and returns the rest of the elements in an array.</p>
</blockquote>
<p>It's unclear if the receiver is being changed or not (it is not). The documentation should be more explicit in that regard.</p>
<p>Maybe something like <em>"Returns a new array containing all except the first <code>n</code> elements from <code>ary</code>"</em>.</p>
<p>This also applies to <code>Array#drop_while</code>.</p> Ruby master - Misc #14190 (Open): What are the semantics of $SAFE?https://bugs.ruby-lang.org/issues/141902017-12-15T16:29:10ZEregon (Benoit Daloze)
<p>$SAFE is documented in many places as thread-local, but it seems more than that.<br>
For example:</p>
<pre><code># a.rb
$SAFE=1
p $SAFE
require "#{Dir.pwd.untaint}/b.rb"
# b.rb
p [:in_b, $SAFE]
</code></pre>
<p>gives:</p>
<pre><code>$ ruby -r./a -e 'p $SAFE'
1
[:in_b, 0]
0
</code></pre>
<p>So in b and in -e, $SAFE is 0.<br>
Is it file-based somehow?</p>
<p>I was trying to understand what<br>
<a href="https://github.com/ruby/ruby/blob/7c4306e6e9c3c4a255f4ad20134c1832dbe45ba2/test/rubygems/test_gem.rb#L9-L13" class="external">https://github.com/ruby/ruby/blob/7c4306e6e9c3c4a255f4ad20134c1832dbe45ba2/test/rubygems/test_gem.rb#L9-L13</a><br>
is supposed to do.<br>
Does it make sense? What does it do?<br>
It seems the test_* methods in that file actually read $SAFE as 0, not 1.</p> Ruby master - Misc #14149 (Open): Ruby Birthday Thread - 25th years anniversaryhttps://bugs.ruby-lang.org/issues/141492017-12-02T01:07:30Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>Hello Ruby-people in general,</p>
<p>Matz recently gave a keynote presentation and he mentioned that ruby's birthday will be<br>
in 2018 (25 years; I think matz mentioned that he counts when the name was chosen but<br>
ruby itself may have already been existing before that in one way or another perhaps).</p>
<p>I suggest that in this thread here, people can give feedback, give ideas, chat about<br>
things ... the party will be in Japan though, so not everyone can participate. :D</p>
<p>However had, as this here can be a thread where people can "virtually" add/contribute<br>
anything, I thought that it may be a good idea to start a thread here.</p>
<p>In order to not have this thread be active for too long, I suggest that it should<br>
be closed some time in 2018, after the ruby birthday party. :D</p>
<p>(I think the official birthday will be around February 2018, so I suggest that<br>
this thread should perhaps "fade out" some time in June or July 2018 or so?<br>
Something like that perhaps, but do feel free to ignore this too when appropriate,<br>
it is just a suggestion.)</p>
<p>I'll start with some feedback next from my point of view, but this thread should be<br>
general, not "just" my opinion. People really should give feedback, matz said so<br>
specifically in the keynote presentation.</p> Ruby master - Misc #14037 (Open): Writing doxygen document comments to static functionshttps://bugs.ruby-lang.org/issues/140372017-10-21T07:46:19Zsonots (Naotoshi Seo)sonots@gmail.com
<p>I often feel that C API documents are lacked in C source codes, especially for <code>static</code> functions.</p>
<p>With <a href="https://bugs.ruby-lang.org/issues/904" class="external">https://bugs.ruby-lang.org/issues/904</a>, <code>make install-capi</code> target was introduced to generate c api documents using Doxygen.<br>
However, I feel that it is not utilized among C Ruby developers.</p>
<p>I propose to turn <code>EXTRACT_STATIC = YES</code> flag of Doxygen to YES, and write document comments for static functions as much as possible.</p> Ruby master - Misc #13968 (Open): [Ruby 3.x perhaps] - A (minimal?) static variant of rubyhttps://bugs.ruby-lang.org/issues/139682017-10-03T20:42:16Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>Hello ruby core team and everyone else,</p>
<p>I think this has been brought up before, in one way or the other, but<br>
just in case it was not, or not in this context, I would like to <strong>propose<br>
that ruby can be compiled statically</strong>.</p>
<p>Matz explained how this can be done for mruby:</p>
<p><a href="https://github.com/mruby/mruby/issues/3707" class="external">https://github.com/mruby/mruby/issues/3707</a></p>
<p>This is not so difficult; allow me to copy/paste the major<br>
steps for mruby (I modified it a bit):</p>
<p>Option A:</p>
<pre><code>(1) compile your.rb files into a C file via mrbc. Example: "mrbc -Binit_yourlib -o mrblib.c *.rb"
(2) your code/application has to call "init_yourlib(mrb)" after "mrb_open()"
(3) compile your code/application with the generated C file
(4) link via "libmruby.a"
(5) static link options may have to be specified to the linker
</code></pre>
<p>Option B</p>
<pre><code>(1) Create a binary "mrbgem". See mrbgems/mruby-bin-mirb for example.
</code></pre>
<p>And nobu added better support for statically linked extensions some years<br>
ago:</p>
<p><a href="https://bugs.ruby-lang.org/issues/9018" class="external">https://bugs.ruby-lang.org/issues/9018</a></p>
<p>Since time is a limited resource by the ruby core team, I understand that<br>
you have to prioritize on issues that are more important, or needed more;<br>
and a statically compiled ruby may not be of highest priority. Additionally,<br>
you may want to know the use case of people, as to why they may want to<br>
have a statically compiled variant of ruby.</p>
<p>I have a (small) use case which I think has not been explained before.</p>
<p>I often break stuff on my linux system when I compile programs. I use many<br>
ruby helper scripts to compile programs, so I need ruby. :)</p>
<p>When I have a ruby available then I can often batch-compile, batch-install<br>
and so on. This works very well so far for most programs out there.</p>
<p>Not always is there a host system available with ruby though; sometimes<br>
I may be in a confined environment, such as workspaces at university<br>
and a central server cluster to which I have no access (or rather,<br>
permission to change files/directory). So I tend to compile into the<br>
user directory there (home directory).</p>
<p>Anyway. Since I tend to break stuff, but sometimes other stuff is also<br>
broken on such environments (looking at centos ...), I made it a habit<br>
to compile some of the core utilities in a static manner into my home<br>
directory; "make" for example or "sed". Both work very well. Others<br>
are a bit misbehaving or stubborn, such as awk - I haven't managed<br>
a statically compiled variant of awk yet.</p>
<p>Of course I also use "busybox," a statically compiled busybox that is.</p>
<p>This allows me to recover from many problems or errors if things go<br>
awry (I can also use a live-DVD for recovery, at the least at home;<br>
or also download some binaries that I know will work on the target<br>
platform, so I have more ways to recover).</p>
<p>Now the thing is - most of what I do with busybox, has to do with<br>
file manipulation of some sort; setting new symlinks, removing,<br>
moving, creating files or directories.</p>
<p>Here I thought - I could use ruby rather than busybox. :)</p>
<p>But I'd want or need a statically compiled ruby, so that it does not<br>
break depending on other programs there on the system.</p>
<p>I hope I could explain my use case. And I agree, only very few<br>
people may ever want to have this perhaps.</p>
<p>I looked at my self-compiled MRI ruby, via "ldd", and these are the<br>
libraries that ruby depends on:</p>
<pre><code> linux-vdso.so.1
libpthread.so.0 => /lib64/libpthread.so.0
libgmp.so.10 => /usr/lib/libgmp.so.10
libdl.so.2 => /lib64/libdl.so.2
libcrypt.so.1 => /lib64/libcrypt.so.1
libm.so.6 => /lib64/libm.so.6
libc.so.6 => /lib64/libc.so.6
/lib64/ld-linux-x86-64.so.2
</code></pre>
<p>I guess this is not minimal; I could probably re-compile ruby<br>
from a sandbox, to reduce the amount of .so objects that are<br>
needed, but the above is only an example anyway.</p>
<p>I assume that making available a ruby that can be statically compiled,<br>
is not trivial. It is probably easier for mruby, but mruby is, as far<br>
as I understand it, more aimed towards knowledgable C/C++ hackers. I<br>
am a bit too scared to try mruby when I do not really know C.</p>
<p>I should also state that I do not need a "full" ruby by the way. I can<br>
live without the extension stuff, such as "readline" or "openssl" probably<br>
(though I'd love to have open-uri since that may help in recovery; ruby's<br>
open() functionality for remote data/websites is great).</p>
<p>I guess the core functionality I would need is, mostly, file manipulation.</p>
<p>So perhaps my request could be titled:</p>
<p>"A minimal variant of ruby - that is statically linked."</p>
<p>Now this may fit to mruby perhaps but I am a bit scared of mruby also<br>
because I do not know mruby very well; I mostly work with MRI ruby. (I<br>
did manage to compile mruby without problem and I could run ruby code<br>
too but I am not sure how much is available on mruby by default "out<br>
of the box". If I remember correctly, not every MRI ruby .rb file<br>
will work "out of the box")</p>
<p>I also thought of filing an issue request at github-mruby but then I<br>
thought that perhaps it may also fit into MRI ruby one day, which is<br>
why I prepended with the ruby 3.x label. (I suppose that it may not<br>
fit towards 2.x anymore since 2.x will probably focus on stability,<br>
bug fixing and so forth.)</p>
<p>I hope I could explain my use case. I am not sure if it is a good<br>
use case; I can probably just keep on using busybox ... but I would<br>
prefer to actually work within a "ruby environment" in general,<br>
simply because ruby is a LOT nicer to work with, in particular for<br>
batch-automated tasks (I always prefer to use ruby rather than shell<br>
scripts, for example).</p>
<p>If possible it would be nice if this issue could remain open for a<br>
bit longer, if only to see if there is anyone else who may want to<br>
have some statically compiled variant of ruby.</p>
<p>I see this sometimes in other issue requests, or similar suggestions,<br>
so perhaps if there may be a seizable amount of people who may want<br>
it, it could be put on a "long-term goal". Perhaps even past 3.x.</p>
<p>Last but not least I would like to repeat that I do not need a full<br>
featured ruby per se, a minimal may suffice - but that minimal ruby<br>
should ideally be easy to use+install. It's a bit like a mix<br>
between "MRI ruby" and "mruby" what I want, I think. :D</p>
<p>That way, I could both have a MRI ruby that uses .so, but also e. g<br>
a binary called "static-ruby" or "ruby-static" or something like<br>
that, that can be used a bit like a "recovery ruby".</p>
<p>I wrote a lot so now it's time to close without much further ado -<br>
thank you for reading!</p> Ruby master - Misc #13804 (Open): Protected methods cannot be overriddenhttps://bugs.ruby-lang.org/issues/138042017-08-10T21:41:24Zdavidarnold (David Arnold)
<p>In Ruby, the main reason you would use protected instead of private is because you want different instances of the same class lineage to be able to access the method.</p>
<p>However, the rules around protected (callable only where self of the context is the same as the [...] method definition) means that protected method effectively cannot be overridden by subclasses. The redefinition of the method resets the protected access check to the subclass, so that instances of the parent class (or other subclasses) cannot call the method anymore.</p>
<p>Is the recommendation that using protected is just bad practice and should be avoided? Or is there a way to make the protected behavior aware of the parent method that is being overridden and keep the access check at the same level in the class hierarchy?</p>
<p>Example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Person</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">ssn</span><span class="p">)</span>
<span class="vi">@ssn</span> <span class="o">=</span> <span class="n">ssn</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">same?</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="n">tax_id</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="nf">tax_id</span>
<span class="k">end</span>
<span class="kp">protected</span>
<span class="k">def</span> <span class="nf">tax_id</span>
<span class="vi">@ssn</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">HappyPerson</span> <span class="o"><</span> <span class="no">Person</span>
<span class="k">def</span> <span class="nf">shout</span>
<span class="s1">'yay!'</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># corporations are people now</span>
<span class="k">class</span> <span class="nc">Corporation</span> <span class="o"><</span> <span class="no">Person</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">ein</span><span class="p">)</span>
<span class="vi">@ein</span> <span class="o">=</span> <span class="n">ein</span>
<span class="k">end</span>
<span class="kp">protected</span>
<span class="k">def</span> <span class="nf">tax_id</span>
<span class="vi">@ein</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">bob</span> <span class="o">=</span> <span class="no">Person</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s1">'000-00-0001'</span><span class="p">)</span>
<span class="n">sally</span> <span class="o">=</span> <span class="no">HappyPerson</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s1">'000-00-0002'</span><span class="p">)</span>
<span class="n">acme</span> <span class="o">=</span> <span class="no">Corporation</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s1">'00-0000001'</span><span class="p">)</span>
<span class="nb">puts</span> <span class="n">bob</span><span class="p">.</span><span class="nf">same?</span> <span class="n">bob</span> <span class="c1"># true</span>
<span class="nb">puts</span> <span class="n">bob</span><span class="p">.</span><span class="nf">same?</span> <span class="n">sally</span> <span class="c1"># false</span>
<span class="nb">puts</span> <span class="n">sally</span><span class="p">.</span><span class="nf">same?</span> <span class="n">bob</span> <span class="c1"># false</span>
<span class="nb">puts</span> <span class="n">acme</span><span class="p">.</span><span class="nf">same?</span> <span class="n">bob</span> <span class="c1"># false</span>
<span class="nb">puts</span> <span class="n">bob</span><span class="p">.</span><span class="nf">same?</span> <span class="n">acme</span> <span class="c1">#=> protected method `tax_id' called ... (NoMethodError)</span>
</code></pre> Ruby master - Misc #13787 (Open): The path to Ruby 3.x - would it be useful to have a separate th...https://bugs.ruby-lang.org/issues/137872017-08-07T21:09:14Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>Hello everyone but especially so the whole ruby-core team,</p>
<p>This is very long, so if you just want the short gist, please<br>
jump to the:</p>
<p>TL;DR line closer to the bottom.</p>
<p>Matz gave several presentations in the last ~3 years or so (and of course<br>
before that as well; but I am mostly focusing only on the 3 recent years,<br>
in particular because due to the path towards ruby 3.x).</p>
<p>I lately watched the presentation matz gave in Singapore and he made<br>
some references to things that will, quite likely, go into ruby 3.x,<br>
while he also said that there is a ton of work ahead - JIT compile<br>
strategies; the (optional, I guess) type system; better concurrency<br>
and so on and so forth. These are probably the big ideas - while this<br>
is nice, and I agree with comments such as "nobody minds if ruby gets<br>
faster" (everyone loves when things get done instantly rather than<br>
when you must wait), I myself am actually even more interested in<br>
smaller things. Even when they are incompatible with ruby 2.x, but<br>
I think that matz said that backwards-compatibility breaking changes<br>
may happen in ruby 3.x but not in ruby 2.x. Which is both good<br>
and bad - good because people do not have to rewrite stuff to<br>
run in ruby 2.x; bad if there are some habits or anything that<br>
isn't that great when writing software in ruby.</p>
<p>Sorry for my lengthy introduction so far - I wanted to explain the<br>
angle I am coming from here.</p>
<p>Now ...</p>
<p>I have wanted to make some smaller changes and suggestions towards<br>
ruby 3.x. And matz once said that the core team (and, well, matz,<br>
since he is the boss :D ) is open to ideas. In ruby 2.x, often the<br>
core team asks for use cases, which is fine - some proposals have<br>
not been thought through and others are purely theoretical; whereas<br>
others are also originating from some real use case. For ruby 3.x,<br>
it is obviously ... difficult to get a real use case out. :)</p>
<p>But one can actually try to make the argument about this or that<br>
in ruby 2.x not working very well, or being confusing.</p>
<p>For example, some days ago, I wanted to suggest a simplified<br>
API and usage for running external programs in ruby. We have<br>
system(), backticks, IO, popen, open3 ... and I do not know<br>
what else. All of which works slightly differently and it is,<br>
at the least to me, quite confusing sometimes. So I wanted<br>
to suggest a simplification... but I realized that this is<br>
not really a good topic for the ruby 2.x branch because I think<br>
that matz wants to retain compatibility, so such a proposal<br>
probably has not a big chance to be implemented. Perhaps for<br>
some minor changes, but I'd actually also suggest to get rid<br>
of some of the duplicate ways, while retaining flexibility<br>
still (so I'd say... system and backticks remain, and then<br>
perhaps only one or two more ways for more advanced use<br>
cases, via a simpler API than this strange ... open2 open3<br>
and what not...).</p>
<p>Anyway.</p>
<p>If you think this through then it probably does not fit much<br>
into "Features" for ruby 2.x because ruby 2.x will remain<br>
backwards compatible, I think.</p>
<p>But for ruby 3.x, it may it.</p>
<p>There are many more smaller ideas like this... for example, I'd<br>
like to see the warning/error situation be improved in ruby<br>
3.x in particular.</p>
<p>I'd also like case/when objects to become full objects and be<br>
passable/convertable ad-hoc into a hash or hash-like object,<br>
and re-used in different .rb files. (The workarounds I know<br>
about are usually to use a hash, with these aliases, but I<br>
found case/when menu to be so much more readable and nicer<br>
to use, especially as you can also use regexes).</p>
<p>And many more ideas like that!</p>
<p>But they all do not really fit into the "Bug" section, neither into<br>
the "Feature" subsection... they may fit somewhat into "Misc" but<br>
it's not a good category.</p>
<p>So, without any further explanation and further ado, here is the<br>
summary and proposal:</p>
<p>TL;DR - Would it be useful to have a separate thread here at the<br>
issue tracker, for discussions and issues and ideas related to<br>
ruby 3.x?</p>
<p>This can be kept primarily as an ideas section for the time being;<br>
at a later time, when ruby 3.x becomes the official ruby one day,<br>
the subsection can be closed and archived for, say, 3 years or so<br>
as read-only, before it would then be deleted (when ruby 3.x<br>
is eventually used more frequently than ruby 2.x, which I guess<br>
may take a few years ... there is a LOT of inertia in general,<br>
we can see this in perl, python etc..).</p>
<p>The reason why I think that this would be useful is because it<br>
could potentially foster some idea discussions. Getting early<br>
ideas in may be good, because ruby 3.x, while it is still<br>
quite far away I think (2020 or beyond?), getting ideas in early<br>
may help to see that they, or a variation, is considered for<br>
inclusion. Otherwise we then may have to wait for more years<br>
because ruby 3.x may be frozen and people would have to wait<br>
for ruby 4.x - this is the primary reason why I'd like to see<br>
a separate thread.</p>
<p>I can not say if this is useful or not to anyone else, and I<br>
can not say if this leads to more ideas or discussion for ruby<br>
3.x features (aside from the big ideas matz already mentioned<br>
several times before, such as better concurrency/guilds, JIT<br>
and speed improves in general or any optional type system -<br>
that's already quite a lot to work on, and all this in addition<br>
to mruby ... but I think ideas are not bad, even if it is not<br>
possible to implement several of them due to lack of time. When<br>
matz approves of an idea, who knows, perhaps someone else may<br>
see that the approved idea will be worked on).</p>
<p>Sorry for this lengthy note - feel free to close this at<br>
any moment in time, for any reason!</p> Ruby master - Misc #13634 (Open): NilClass is lying about respond_to?(:clone)https://bugs.ruby-lang.org/issues/136342017-06-06T08:12:46Zrovf (Ronald Fischer)ynnor@mm.st
<p>I put this under "Misc", because I'm not sure, whether this is a bug, a feature request, or maybe a deliberate (but for me obscure) decision in language design:</p>
<p>NilClass (and Fixnum) do not support clone. That's fine. However,</p>
<p>nil.respons_to?(:clone) returns true.</p>
<p>This means that we <em>can</em> ask nil to clone itself (we don't get a NoMethod error), it's just trying to do so throws an exception.</p>
<p>I stumbled over this problem when I had an collection of objects of different types, and wanted to apply :clone to some of them. My code went approximately like this:</p>
<p>object = collection[key]<br>
return object.respond_to?(:clone) ? object.clone : object</p>
<p>This doesn't work, if object is nil, true, false, a Symbol or a Fixnum, because all of them claim to respond to :clone.</p>
<p>Of course, there is a trivial workaround (I just have to rescue the exception), but I find this language design not really intuitive. I think there are two possibilites, how this can be made better:</p>
<p>(1) If we decide, that nil is not clonable (because there can be only one nil), then respond_to?(:clone) should IMHO simply be false.</p>
<p>(2) However, there might be even be a reason why :clone should be applicable. Note that the usual semantics of clone is to do a shallow copy (for instance, when we 'clone' a nested array). If we want to have a deep copy, the usual approach is Marshal.load(Marshal.dump(object)). Now the odd thing is that we can not "shallowly copy" nil, i.e. nil.clone is forbidden, but we can do a deep copy, i.e. Marshal.load(Marshal.dump(nil)) works. So, an alternative would be to have nil.clone simply return the identical object.</p>
<p>Both (1) seems to me a sound solution. The solution (2) has the drawback that we can't guarantee anymore that x.clone has a different object id than x, but is probably the behaviour a programmer would intuitively expect.</p> Ruby master - Misc #13622 (Assigned): Documentation missinghttps://bugs.ruby-lang.org/issues/136222017-06-02T14:08:27Zsergzhum (Sergey Zhumatiy)
<p>In documentation for method IO.nread important information is missing: you must do 'require "io/wait"' before using it. May be some other methods of IO in 'io/wait' are missed this IMPORTANT notice.</p> Ruby master - Misc #13497 (Open): Docs, code samples, Ripper examplehttps://bugs.ruby-lang.org/issues/134972017-04-23T04:27:52ZMSP-Greg (Greg L)
<p>I think it's fair to say that virtually all Ruby documentation today is created by doc generation systems based either on YARD or RDoc. Code samples/examples are common. YARD uses Ripper to parse samples for highlighting, I believe RDoc uses its own parser.</p>
<p>Although I recall previous RDoc parsers to be flexible as to code highlighting, but some seem to be similar to Ripper. Hence, if it can't be pasted into an .rb file and run, it won't highlight.</p>
<p>With many samples, this isn't an issue, but with samples that display multi-line output, there are two options -</p>
<ol>
<li>
<p>Comment the whole output section - this will always work, but all lines will render in the commment color.</p>
</li>
<li>
<p>Use an assignment - this will highlight the output (if desired).</p>
</li>
</ol>
<p>Ripper Examples --</p>
<p>RDoc - <a href="http://ruby-doc.org/stdlib-trunk/libdoc/ripper/rdoc/Ripper.html" class="external">ruby-doc.org</a></p>
<p>RDoc - <a href="https://docs.ruby-lang.org/en/trunk/Ripper.html" class="external">docs.ruby-lang.org</a></p>
<p>YARD - <a href="https://msp-greg.github.io/ruby_trunk/ripper/Ripper.html" class="external">msp-greg.github.io</a></p>
<p>Notice how the first two do not highlight the code sample in the overview, or the <code>.lex</code>, <code>.sexp</code>, or <code>.sexp_raw</code> methods.</p>
<p>I edited three source files for the highlighted output, it does require some kind of line similar to 'below is output, shown as assignment to allow highlighting'. The code in the sample doc is exactly as shown. I believe the two RDoc sites will highlight the code if redone in the style shown on msp-greg.github.io. I'd be happy to submit the changes if people find the highlighting helpful.</p> Ruby master - Misc #13209 (Open): fact.rb in ruby/sample variationshttps://bugs.ruby-lang.org/issues/132092017-02-13T00:59:46Zjzakiya (Jabari Zakiya)
<p>I was looking at some of the Sample files that come with Ruby and<br>
saw the example for doing factorials. It's an old example that I<br>
thought I could make simpler/faster. Below are the results.</p>
<p>Maybe upgrading to show the difference between coding idioms can<br>
be instructive to newer Ruby programmers.</p>
<pre><code>def fact(n)
return 1 if n == 0
f = 1
n.downto(1) do |i|
f *= i
end
return f
end
def fact1(n)
return 1 if n | 1 == 1 # if n 0 or 1
f = 2
n.downto(3) do |i|
f *= i
end
return f
end
def fact2(n)
return 1 if n | 1 == 1 # if n 0 or 1
(2..n).reduce(:*)
end
require 'benchmark/ips'
Benchmark.ips do |x|
x.report("original factorial") { fact 100 }
x.report("modified factorial") { fact1 100 }
x.report("enhanced factorial") { fact2 100 }
x.compare!
end
</code></pre>
<p>Timings using ruby-2.4.0 on Linux 64-bit, on I7 cpu system.</p>
<pre><code>2.4.0 :001 > load 'factversiontest.rb'
Warming up --------------------------------------
original factorial 4.501k i/100ms
modified factorial 4.594k i/100ms
enhanced factorial 5.271k i/100ms
Calculating -------------------------------------
original factorial 44.962k (± 4.2%) i/s - 225.050k in 5.015176s
modified factorial 46.288k (± 3.2%) i/s - 234.294k in 5.066948s
enhanced factorial 53.425k (± 3.1%) i/s - 268.821k in 5.036635s
Comparison:
enhanced factorial: 53424.9 i/s
modified factorial: 46288.0 i/s - 1.15x slower
original factorial: 44961.5 i/s - 1.19x slower
=> true
2.4.0 :002 >
</code></pre> Ruby master - Misc #12751 (Open): Incompatibility of Ruby 3https://bugs.ruby-lang.org/issues/127512016-09-12T06:38:38Znaruse (Yui NARUSE)naruse@airemix.jp
<p>META ticket for Ruby 3's breakages</p>
<ul>
<li>Encoding on Windows
<ul>
<li>[Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: On Windows use UTF-8 as filesystem encoding (Closed)" href="https://bugs.ruby-lang.org/issues/12654">#12654</a>]</li>
<li>[Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Use UTF-8 encoding for ENV on Windows (Closed)" href="https://bugs.ruby-lang.org/issues/12650">#12650</a>]</li>
</ul>
</li>
</ul> Ruby master - Misc #12277 (Open): Coding rule: colum numberhttps://bugs.ruby-lang.org/issues/122772016-04-13T07:54:01Zko1 (Koichi Sasada)
<p>Eric proposed that code should be limited in 80 column.<br>
<a href="https://bugs.ruby-lang.org/issues/12236#note-1" class="external">https://bugs.ruby-lang.org/issues/12236#note-1</a></p>
<p>At today's developer's meeting, I asked how long column is suitable.</p>
<ul>
<li>declaration can over limitation.</li>
<li>logic should have some limitation (permit exceptional cases)</li>
</ul>
<p>This is an survey at today's meeting.</p>
<pre><code>Expected column limitation:
80 none
100 2 people
120 some people
over 120 only ko1
</code></pre> Ruby master - Misc #11783 (Open): Do you have any idea if you have a budgets?https://bugs.ruby-lang.org/issues/117832015-12-07T10:29:55Zko1 (Koichi Sasada)
<p>Do you have any idea about Ruby interpreter implementation to do with budgets?</p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>Now, we are summarizing many contributions from many people, organizations and companies.</p>
<p><a href="https://docs.google.com/document/d/1y1sQc40qeuWjF84rVrTmH-ogZ_iNGqU-RUSE8GDlRuk/edit?usp=sharing" class="external">https://docs.google.com/document/d/1y1sQc40qeuWjF84rVrTmH-ogZ_iNGqU-RUSE8GDlRuk/edit?usp=sharing</a></p>
<p>(please let me know if you know any other contributes)<br>
(sorry we wrote contributions especially for MRI, because we don't know)</p>
<p>The great recent news is we get new mac mini machine to run CI on El Capitan. We already have a mac mini machine running CI, but on Yosemite. So we can run CI on both Yosemite and El Capitan.</p>
<p>This new mac mini machine was sponsored by YassLab, Japanese small company.</p>
<p>At first, we ask Nihon-Ruby-no-Kai to prepare this machine, and Takahashi-san (chair man of this organization) tweet about it ("anyone can support it?"). Yasukawa-san, the president of YassLab answers "ok, we'll support it".</p>
<p>We learned that if we show requirements explicitly, anyone may help us.<br>
Listing is important.</p>
<a name="Any-idea"></a>
<h1 >Any idea?<a href="#Any-idea" class="wiki-anchor">¶</a></h1>
<p>Today's developers meeting, we had discussed about that and itemize some dreams.</p>
<blockquote>
<p>nurse: VPS severs for CI are welcome. Especially for Azure.<br>
ko1: travel fee (1,000,000 JPY?) for hackathon to gather MRI developers in one place<br>
ko1: physical machines for development and benchmarks (300,000 JPY)<br>
nobu: development machine (400,000 JPY) because he has several trouble on current machine.<br>
nurse: icc (and other softwares) to try.<br>
martin: grant project for MRI development topics<br>
ko1: education to grow other MRI developer (no estimation)</p>
</blockquote>
<p>Do you have any other idea?<br>
I'll show these list at RubyKaigi, and someone may consider to support us.</p>
<p>(IMO, maybe sponsoring nobu's machine is great contribution for Ruby worlds.<br>
Nobu will put companies logo stickers on his laptop)</p>
<p>Thanks,<br>
Koichi</p> Ruby master - Misc #11570 (Open): Clarify autoload chaining behavior https://bugs.ruby-lang.org/issues/115702015-10-06T16:52:25Zmwpastore (Mike Pastore)mike@oobak.org
<p>I've discovered a discrepancy between how MRI 2.1.7 and 2.2.3 handle autoload "chaining" (which I'll describe below) cf. RBX 2.5.8. I opened <a href="https://github.com/rubinius/rubinius/issues/3513" class="external">an issue</a> with them but the lead contributor of Rubinius is pushing back on me to clarify the expected behavior with you guys. Any guidance you can provide would be appreciated.</p>
<p>Essentially:</p>
<ul>
<li>File A autoloads <code>:Foo</code> from file B, and attempts to invoke methods on class <code>Foo</code>.</li>
<li>File B autoloads <code>:Foo</code> from file C, and attempts to reopen class <code>Foo</code> in order to define additional methods and attributes.</li>
<li>File C defines the base <code>Foo</code> class.</li>
</ul>
<p>In MRI 2.1.7 and 2.2.3, file A can see the methods defined in the base class defined in file C, as well as the extended methods and attributes added in file B. Both autoloads fire in the expected order and the composite class is computed and made available to the caller.</p>
<p>In RBX 2.5.8, file A can only see the extended methods and attributes defined in file B. Only the first autoload fires and the base class definition is never loaded or used.</p>
<p>Which is the correct behavior?</p> Ruby master - Misc #11355 (Open): Exceptions inheriting from Timeout::Error should behave the sam...https://bugs.ruby-lang.org/issues/113552015-07-15T16:59:01Zastratto (Stefano Tortarolo)stefano.tortarolo@gmail.com
<p>Bug <a class="issue tracker-1 status-6 priority-4 priority-default closed" title="Bug: "rescue Exception" rescues Timeout::ExitException (Rejected)" href="https://bugs.ruby-lang.org/issues/8730">#8730</a> addressed a common issue when using Timeout#timeout [*], but I think that the current behaviour is at the very least surprising.</p>
<p>Right now, exceptions provided to Timeout#timeout are rescuable from the inner block and that applies to Timeout::Error too.<br>
The confusing aspect is that there's no way to provide a custom exception that inherits from Timeout::Error and make it not rescuable by the inner block (i.e., <a class="issue tracker-1 status-2 priority-4 priority-default" title="Bug: Logger traps all exceptions; breaks Timeout (Assigned)" href="https://bugs.ruby-lang.org/issues/9115">#9115</a>).</p>
<p>Basically what I would expect is a way to provide a custom exception that's treated calling #catch on it in Timeout#timeout</p>
<pre><code># This could be applied to every exception that inherits from Timeout::Error
# but we need a different interface to provide it, in order to maintain the behaviour that a provided exception is rescuable
bt = Error.catch(message, &bl)
</code></pre>
<p>I'm filing this as Misc and not Bug exactly because reading the code it's expected behaviour, so I'm mainly trying to foster a conversation about whether there's a nice way to support both scenarios.</p>
<p>[*] I don't speak Japanese and I cannot fully trust Google Translate, so forgive me if I lost some fundamental concepts in that thread.</p> Ruby master - Misc #11295 (Open): Request for comments about error messageshttps://bugs.ruby-lang.org/issues/112952015-06-23T01:09:56Zko1 (Koichi Sasada)
<p>(This is not a proposal, bug reports)</p>
<p>Ruby shows error messages when something wrong.</p>
<p>There are several proposals to extend error messages.</p>
<ul>
<li><a href="https://github.com/charliesome/better_errors" class="external">https://github.com/charliesome/better_errors</a></li>
<li><a href="https://github.com/yuki24/did_you_mean" class="external">https://github.com/yuki24/did_you_mean</a></li>
<li><a href="https://github.com/ko1/pretty_backtrace" class="external">https://github.com/ko1/pretty_backtrace</a></li>
</ul>
<p>And some requests.</p>
<ul>
<li>Reverse backtrace and show error messages at the bottom (to avoid scroll up terminal)</li>
<li>Translation error messages to other languages</li>
</ul>
<p>If you have any idea, please tell us.<br>
We can consider about Ruby's error message APIs to realize your ideas.<br>
(I can't guarantee we can implement your ideas :p)</p> Ruby master - Misc #10983 (Open): Why blocks make Ruby methods 439% slower ?https://bugs.ruby-lang.org/issues/109832015-03-19T09:03:44ZSega100500 (Сергей Е)Sergey.V.Ezhov@gmail.com
<p><a href="https://www.omniref.com/ruby/2.2.0/symbols/Proc/yield#annotation=4087638&line=711&hn=1" class="external">https://www.omniref.com/ruby/2.2.0/symbols/Proc/yield#annotation=4087638&line=711&hn=1</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'benchmark/ips'</span>
<span class="k">def</span> <span class="nf">block_call</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="n">block</span><span class="p">.</span><span class="nf">call</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">just_yield</span>
<span class="k">yield</span>
<span class="k">end</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"call"</span><span class="p">)</span> <span class="k">do</span>
<span class="n">block_call</span> <span class="p">{</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"just yield"</span><span class="p">)</span> <span class="k">do</span>
<span class="n">just_yield</span> <span class="p">{</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">x</span><span class="p">.</span><span class="nf">compare!</span>
<span class="k">end</span>
</code></pre>
<p>I run on Ruby 2.2.1</p>
<pre><code>Calculating -------------------------------------
call 40.754k i/100ms
just yield 69.031k i/100ms
-------------------------------------------------
call 814.929k (± 4.0%) i/s - 4.075M
just yield 2.871M (±25.1%) i/s - 12.909M
Comparison:
just yield: 2871127.3 i/s
call: 814929.3 i/s - 3.52x slower
</code></pre> Ruby master - Misc #10783 (Open): String#concat has an "appending" behaviorhttps://bugs.ruby-lang.org/issues/107832015-01-26T10:05:42Zas-cii (Antonio Scandurra)me@as-cii.com
<p>Ruby String documentation (<a href="http://www.ruby-doc.org/core-2.2.0/String.html" class="external">http://www.ruby-doc.org/core-2.2.0/String.html</a>) introduces the two terms <strong>Appending</strong> and <strong>Concatenation</strong>:</p>
<ul>
<li>Concatenation (aka <code>+</code>) —Returns a new String containing other_str concatenated to str.</li>
<li>Append (aka <code><<</code>) —Concatenates the given object to str.</li>
</ul>
<p>However, calling <code>concat</code> results in an appending operation. I find this particularly confusing and against the Principle of Least Surprise (e.g. I'd expect <code>concat</code> to actually concatenate something). On the other hand I understand that changing such a small method would result in a quite significant breaking change.</p>
<p>Do you see this as an inconsistency? If yes, is there any particular design (or historical) reason behind it?</p>
<p>Thank you.</p>
<p>P.s. Seems like this is the case for <code>Array</code> as well.</p> Ruby master - Misc #10628 (Open): Peformance of URI modulehttps://bugs.ruby-lang.org/issues/106282014-12-21T14:43:44Ztgxworld (Guo Xiang Tan)gxtan1990@gmail.com
<p>Please view attached screenshot or go to <a href="https://railsbench.herokuapp.com/tgxworld/ruby?utf8=%E2%9C%93&result_types%5B%5D=app_uri&commit=Submit" class="external">the following link</a> to see benchmark graph over time.</p>
<p>It got slower after this <a href="https://github.com/ruby/ruby/commit/bb83f32dc3e0424d25fa4e55d8ff32b061320e41" class="external">commit</a>.</p>
<p>Hope this helps.</p> Ruby master - Misc #10560 (Assigned): confusion between x=x+y, x+=y, x.concat(y) and y.each{|z| x...https://bugs.ruby-lang.org/issues/105602014-12-01T15:53:01Zmpapis (Michal Papis)mpapis@gmail.com
<p>while discussing a ticket I have noticed that there is no documentation for <code>+=</code></p>
<p>I was expecting <code>+=</code> to behave as <code>concat</code> but instead it behaves as <code>x=x+y</code> which for every operation clones the array and updates the variable with new value so it behaves similarly to <code>x=x.dup.concat(y)</code> and is slightly faster, but using plane <code>x.concat(y)</code> is a lot faster from both <code>each<<</code> and <code>+=</code></p>
<p>I would either like to get:</p>
<ul>
<li>updated docs that describe concept of <code>+=</code> and show the difference from <code>concat</code>
</li>
<li>or change <code>+=</code> to use <code>concat</code> which is faster - and add docs ;) (I would expect <code>+=</code> to use <code>concat</code> when available)</li>
</ul>
<p>here is a test:</p>
<pre><code>require 'benchmark'
rep = 10_000
Benchmark.bmbm do |x|
{
1..25 => [],
"a".."z" => "",
}.each do |base, storage|
base = base.to_a
basej = base
class_name = storage.class.to_s
x.report(class_name+'#concat') do
a = storage.dup
basej = base.join if storage == ""
rep.times { a.concat(basej) }
end
x.report(class_name+'#<<') do
a = storage.dup
basej = base.join if storage == ""
rep.times { base.each { |e| a << e } }
end
x.report(class_name+'#+=') do
a = storage.dup
basej = base.join if storage == ""
rep.times { a += basej }
end
x.report(class_name+'#dup.concat') do
a = storage.dup
basej = base.join if storage == ""
rep.times { a = a.dup.concat(basej) }
end
end
end
</code></pre>
<p>and here are results on my machine:</p>
<pre><code> user system total real
Array#concat 0.000000 0.000000 0.000000 ( 0.001422)
Array#<< 0.020000 0.000000 0.020000 ( 0.014356)
Array#+= 1.270000 0.230000 1.500000 ( 1.498558)
Array#dup.concat 2.720000 0.190000 2.910000 ( 2.915701)
String#concat 0.000000 0.000000 0.000000 ( 0.001072)
String#<< 0.030000 0.000000 0.030000 ( 0.025828)
String#+= 0.130000 0.010000 0.140000 ( 0.135143)
String#dup.concat 0.210000 0.020000 0.230000 ( 0.227470)
</code></pre> Ruby master - Misc #10541 (Open): Remove shorthand string interpolation syntaxhttps://bugs.ruby-lang.org/issues/105412014-11-25T16:15:58Zdanielmorrison (Daniel Morrison)daniel@collectiveidea.com
<p>I would like to see the shorthand string interpolation syntax, "foo#@bar" deprecated and then removed in 3.0.</p>
<p>My reasons:</p>
<ol>
<li>Most experienced Ruby developers I've talked to don't even know it exists.</li>
<li>It has been the cause of real problems. <a href="http://status.cloudamqp.com/incidents/vj62pnp62tj9" class="external">http://status.cloudamqp.com/incidents/vj62pnp62tj9</a>
</li>
</ol>
<p>When a syntax is not widely known and has the potential for problems, I think it makes sense to deprecate and remove.</p> Ruby master - Misc #10513 (Open): instance_eval yields the receiver, but is documented to yield n...https://bugs.ruby-lang.org/issues/105132014-11-14T22:29:49Zctm (Cliff Matthews)ctm@devctm.com
<p>instance_eval yields the receiver, but is documented as yielding no arguments.</p>
<p>I searched the bug reports before writing this up and found bug <a class="issue tracker-1 status-8 priority-4 priority-default closed" title="Bug: instance_eval ArgumentError (Third Party's Issue)" href="https://bugs.ruby-lang.org/issues/2476">#2476</a> which was closed with a message that contained "instance_eval yields the receiver in both 1.8 and 1.9. Unfortunately, a Proc object created by lambda raises ArgumentError when extra arguments are yielded in 1.9.". However such behavior is not expected when the calling sequence is:</p>
<pre><code> * call-seq:
* obj.instance_eval(string [, filename [, lineno]] ) -> obj
* obj.instance_eval {| | block } -> obj
</code></pre>
<p>This discrepancy surprised me, but once I realized what was going on I simply used instance_exec instead of instance_eval. All else equal, I would prefer for instance_eval to to not yield the receiver since I can pick up the receiver as self if I want to, but such a change could breaking existing code, so probably documenting the current behavior is better.</p>
<pre><code>bash-3.2$ ruby --version
ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-darwin14.0]
bash-3.2$ ./instance_eval
This is the lambda that *does* work.
arg = 32
self = 32
./instance_eval:6:in `block in <main>': wrong number of arguments (1 for 0) (ArgumentError)
from ./instance_eval:17:in `instance_eval'
from ./instance_eval:17:in `<main>'
</code></pre> Ruby master - Misc #10424 (Open): Error message when sorting NaNhttps://bugs.ruby-lang.org/issues/104242014-10-24T21:24:52Zjmthomas (Jason Thomas)
<p>When sorting an array of floats with a NaN you get a very confusing message:<br>
irb(main):001:0> [0.0/0.0,1.0,2.0].sort<br>
ArgumentError: comparison of Float with Float failed</p>
<p>Sorting a nil is much friendlier:<br>
irb(main):012:0> [nil,1.0,2.0].sort<br>
ArgumentError: comparison of NilClass with Float failed</p>
<p>This is confusing for many. Simply google for "comparison of Float with Float failed" and makes for a difficult debugging session for anyone who doesn't know that NaN produces this result. What I would expect is:<br>
irb(main):001:0> [0.0/0.0,1.0,2.0].sort<br>
ArgumentError: comparison of NaN with Float failed</p> Ruby master - Misc #10312 (Open): Give people more control over how the ruby parser sees code and...https://bugs.ruby-lang.org/issues/103122014-10-01T18:28:08Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>Hi,</p>
<p>I am aware that this proposal has most likely not a chance for<br>
implementation, but I'd still like to make it - this is why I<br>
put it here into misc rather than bugs or features. It's misc -<br>
like ideas!</p>
<p>So first allow me to introduce how I came up with this idea at<br>
all.</p>
<p>I have built a "web framework", which is pretty ugly, but<br>
useful to me. It is actually less of a web framework and<br>
more of a way to describe a "web app" - right now using<br>
valid ruby syntax, but hopefully one day I can transition<br>
into something that is even terser than what it is right<br>
now, and eventually becomes valid ruby (or css or javascript<br>
etc... a bit like HaXe <a href="http://haxe.org/" class="external">http://haxe.org/</a> but with a more<br>
elegant syntax resembling ruby rather than java)</p>
<p>I describe a web-page currently such as that way:</p>
<p>w {<br>
title 'My little page'<br>
css_style '<br>
body {<br>
padding: 0.20em;<br>
}'<br>
favicon 'foo/bar.png'<br>
font_size '20px'<br>
use_jquery<br>
}</p>
<p>Ok, w is simply a method call w() returning an instance of class<br>
WebObject, and we pass it a block. The block I use for a DSL-like<br>
approach to describe the page in question. For instance, use_jquery<br>
simply is in fact w.use_jquery - so it is a method call on that<br>
web object.</p>
<p>Before that, I was using this line here:</p>
<p>jquery :+</p>
<p>The + reminds me of "yes, enable jquery".</p>
<p>Obviously, to disable jquery, I would do:</p>
<p>jquery :-</p>
<p>Then I thought - "Hey, it would be cool if I could do this:</p>
<p>jquery +</p>
<p>instead. In other words, get rid of the : symbol identifier.</p>
<p>But here the ruby parser rightfully chokes because it does not<br>
understand what is meant with jquery +. Fair enough, this is<br>
not valid ruby.</p>
<p>But to my human eyes, jquery + reads nicer than jquery :+</p>
<p>I could get away doing this instead and treat it as a String:</p>
<p>'jquery +'</p>
<p>And simply parse that with ruby. But I already use:</p>
<p>use_jquery</p>
<p>above, so that is nicer IMO than using the two ' characters.</p>
<p>So now, sorry for that long introduction but perhaps you can<br>
understand my line of thought here.</p>
<p>So I was thinking it would be nice if people could get more<br>
control over the Ruby Parser itself.</p>
<p>For instance, in the above example and only for that file/class,<br>
I would like to tell the ruby parser "hey dude, don't mind if<br>
that specific block has invalid syntax, I'd parse on my own.</p>
<p>Possibly it would be enough if those invalid syntax elements<br>
could become strings - then I can parse those strings on my<br>
own.</p>
<p>Of course the net gain between:</p>
<p>jquery :+</p>
<p>and</p>
<p>jquery +</p>
<p>is minimal, but I love ruby's terse syntax.</p>
<p>Anyway, I am aware that this has no real chance for the ruby<br>
2.x era but perhaps considering all the ideas in regards to<br>
optional static type information and what-not for 3.x ruby era,<br>
more control over the ruby parser itself would be nice<br>
(lisp-like macros!).</p>
<p>Regards.</p> Ruby master - Misc #9832 (Open): better concurrency in threadshttps://bugs.ruby-lang.org/issues/98322014-05-12T12:31:12Zariveira (Alexandre Riveira)alexandre@objectdata.com.br
<p>My application runs on top of rainbows using workers with multi-threaded.<br>
I realized that in ruby running on linux (my kernel config is slackware, debian not work)<br>
not equal to distribute the processing threads.<br>
To test this I created the file that is attached test_thread_schedule.rb<br>
The more the final test result is between 20/21 seconds means he has distributed processing equally<br>
So when the road test with ruby 1.9.2 on linux it does not perform.<br>
This improved in ruby 1.9.3 and further in ruby 2.0.<br>
But it still is not the ideal</p>
<p>My tests:<br>
ruby 1.9.2p320 => not work<br>
ruby 1.9.3p545 => 68 secs<br>
ruby 2.0.0p451 => 29 secs<br>
ruby 2.1.2p95 => 29 secs</p>
<p>ruby without GVL workfine<br>
rubinius 2.2.6 => 21 secs<br>
jruby 1.7.12 => 21 secs</p>
<p>But if I apply taskset (uncomment line in the test file <code>taskset -c -p 2 #{Process.pid}</code>)<br>
the results are noticeably better especially in ruby 1.9.2</p>
<p>ruby 1.9.2p320 => 21 secs<br>
ruby 1.9.3p545 => 30 secs<br>
ruby 2.0.0p451 => 23 secs<br>
ruby 2.1.2p95 => 23 secs</p>
<p>This reflects directly in the application, if one thread is is using 100% cpu with rainbows application begins to degrade coming to answer the other threads 7-16 seconds based time passes. Taskset already applied it decreases considerably. The same test applied cougar, gets to be virtually no impact, but since taskset is applied to the process, follow my code</p>
<p>rainbows:</p>
<p>before_fork do |server, worker|<br>
<code>taskset -c -p 2 #{Process.pid}</code></p>
<p>puma:</p>
<p>on_worker_boot do |index|<br>
<code>taskset -c -p 2 #{Process.pid}</code></p>
<p>Could internally ruby linux treat in a special way so that the behavior of threads is improved ???<br>
If this behavior can not be improved through a new feature in ruby I am grateful for any help for<br>
fixing the process taskset on a particular processor which is not ideal.</p> Ruby master - Misc #9724 (Open): Warnings in Ruby: allow per-file directives to i.e. suppress war...https://bugs.ruby-lang.org/issues/97242014-04-10T18:21:31Zshevegen (Robert A. Heiler)shevegen@gmail.com
<p>Hi,</p>
<p>A bit of intro.</p>
<p>I usually run all my ruby code with -w. I feel that it gives me some more security if the<br>
ruby parser does not have to think about ambiguous code.</p>
<p>Now this works perfect for my own code - I know what I have written, I know how to fix it,<br>
so my code runs fine.</p>
<p>Problem is other people who do not use the -w switch, and in doing so their stuff outputs<br>
a lot of warnings if I require their project and use them.</p>
<p>This is somewhat annoying and there is no real good way to fix it as far as I know.</p>
<p>Modifying $VERBOSE and setting it to nil is of no real help because it works globally.<br>
But I'd rather want something to be used on a per-file basis.</p>
<p>Would it be possible to enable something that could be used on a per file<br>
basis? Kernel.no_warnings, or Kernel.be_silent or something like this?</p> Ruby master - Misc #9516 (Open): Consolidate all deprecation messages to one or more helper methodshttps://bugs.ruby-lang.org/issues/95162014-02-13T17:11:56Zenebo (Thomas Enebo)tom.enebo@gmail.com
<p>I was examining this blog entry: <a href="http://batsov.com/articles/2014/02/05/a-list-of-deprecated-stuff-in-ruby/" class="external">http://batsov.com/articles/2014/02/05/a-list-of-deprecated-stuff-in-ruby/</a> and I wanted to add these warning in JRuby. I thought it would be nice if I could make a higher level construct (e.g. @RubyDeprecated(use="Dir.exist?")) but then realized MRI does not consistently have the same warning string formats:</p>
<p>"Dir.exists? is a deprecated name, use Dir.exist? instead"<br>
"GDBM#index is deprecated; use GDBM#key"<br>
"Zlib::GzipReader#bytes is deprecated; use #each_byte instead"</p>
<p>Some helper methods could make these consistent and then I could make the higher level abstraction in JRuby as well. Since these are warnings I might still make an abstraction and let JRuby be a little inconsistent but I thought I would pass this idea along.</p> Ruby master - Misc #9136 (Assigned): Deprecated Enumerator.new(object, method) bad for BasicObjecthttps://bugs.ruby-lang.org/issues/91362013-11-21T22:18:28Zatlas (Atlas Prime)a7145@live.com
<p>=begin<br>
Documentation it says:</p>
<p>In the second, deprecated, form, a generated Enumerator iterates over the given object using the given method with the given arguments passed.</p>
<p>Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum instead.</p>
<pre><code> e = Enumerator.new(ObjectSpace, :each_object)
#-> ObjectSpace.enum_for(:each_object)
</code></pre>
<p>But (({#enum_for})) and (({#to_enum})) are not available to subclasses of (({BasicObject})). In fact, I was defining (({#to_enum})) for a class that is a subclass of (({BasicObject})), and now I get warning of deprecation.<br>
=end</p>