Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112024-03-19T09:10:29ZRuby Issue Tracking System
Redmine Ruby master - Feature #20347 (Assigned): Separate docs task from allhttps://bugs.ruby-lang.org/issues/203472024-03-19T09:10:29Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>I would like to migrate RDoc as bundled gems at Ruby 3.5.</p>
<p>We need to handle <code>install-doc</code> and related task with that. I removed <code>docs</code> task from <code>all</code> and re-order <code>docs</code> task at <code>install-all</code>.</p>
<p><a href="https://github.com/ruby/ruby/pull/10282" class="external">https://github.com/ruby/ruby/pull/10282</a></p>
<p>It works with RDoc as bundled gems. We can keep current behavior with this migration.</p>
<p>I hope to merge changes for <code>all</code> task and re-order <code>install-all</code> task at Ruby 3.4.</p>
<p><a href="https://github.com/ruby/ruby/pull/10282/commits/b160083175aed062c320b8d76eafe1c8706309d4" class="external">https://github.com/ruby/ruby/pull/10282/commits/b160083175aed062c320b8d76eafe1c8706309d4</a></p>
<p>After that, the default <code>make</code> task will not generate rdoc. We need to add <code>make all docs</code> for that.</p> Ruby master - Feature #20309 (Assigned): Bundled gems for Ruby 3.5https://bugs.ruby-lang.org/issues/203092024-02-27T22:16:20Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>I propose migrate the following default gems to bundled gems at Ruby 3.5. So, It means users will get warnings if users try to load them.</p>
<p>(Update with 2024/03/14)</p>
<ul>
<li>ostruct
<ul>
<li>I make ostruct as optional on json at <a href="https://github.com/flori/json/pull/565" class="external">https://github.com/flori/json/pull/565</a>
</li>
</ul>
</li>
<li>logger
<ul>
<li>activesupport needs to add logger to its dependency same as bigdecimal, drb or etc.</li>
</ul>
</li>
<li>fiddle</li>
<li>pstore</li>
<li>win32ole</li>
</ul>
<p>I have a plan to migrate the following default gems too. But I need to more feedback from other committers about them.</p>
<ul>
<li>irb
<ul>
<li>We need to consider how works <code>binding.irb</code> after Ruby 3.5.</li>
<li>I consider to use <code>irb</code> without Gemfile.</li>
</ul>
</li>
<li>reline</li>
<li>readline (wrapper file for readline-ext and reline)</li>
<li>io-console
<ul>
<li>rubygems uses that. Should we make optional that?</li>
</ul>
</li>
<li>open-uri</li>
<li>yaml (wrapper file for psych)
<ul>
<li>syck is retired today. I'm not sure what people uses <code>psych</code> directly, not <code>yaml</code>.</li>
</ul>
</li>
<li>rdoc
<ul>
<li>We need to change build task like download rdoc gem before document generation.
<ul>
<li>extract <code>make doc</code> from <code>make all</code> and invoke <code>make doc</code> before <code>make install</code>.</li>
</ul>
</li>
<li>or We make document generation is optional from Ruby 3.5
<ul>
<li>We explicitly separate <code>make install</code> and <code>make install-doc</code>
</li>
</ul>
</li>
</ul>
</li>
<li>un
<ul>
<li>
<code>ruby -run</code> is one of cool feature of Ruby. Should we avoid uninstalling <code>un</code> gem?</li>
<li>mkmf uses <code>ruby -run</code> for that. I need to investigate that.</li>
</ul>
</li>
<li>singleton
<ul>
<li>This is famous design pattern. Should we enforce users add them to their Gemfile?</li>
</ul>
</li>
<li>forwadable
<ul>
<li>
<code>reline</code> needs to add forwardable their <code>runtime_dependency</code> after migration.</li>
</ul>
</li>
<li>weakref
<ul>
<li>I'm not sure how impact after migrating bundled gems.</li>
</ul>
</li>
<li>fcntl
<ul>
<li>Should we integrate these constants into ruby core?</li>
</ul>
</li>
</ul>
<p>I would like to migrate <code>ipaddr</code> and <code>uri</code> too. But these are used by webrick that is mock server for our test suite. We need to rewrite <code>webrick</code> with <code>TCPSocker</code> or extract <code>ipaddr</code> and <code>uri</code> dependency from <code>webrick</code></p>
<p>Other default gems depend on our build process or other libraries deeply. I will update this proposal if I could extract them from default gems.</p> Ruby master - Feature #19972 (Assigned): Install default/bundled gems into dedicated directorieshttps://bugs.ruby-lang.org/issues/199722023-10-25T15:30:22Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<p>I think that the current situation, where the same directory (lets call it <code>Gem.default_dir</code>) is used for default/bundled gems as well as for user installed gems, is suboptimal. During the times, this has caused us quite some issue on Fedora. Historically, we redefined the <code>Gem.default_dir</code> to user home directory, to avoid the mixing of system gems and user installed gems. Unfortunately, with advent of default/bundled gems, we were facing issues that these gems were suddenly not listed, etc. I am realizing this issue in full once again since the "user install" RubyGems feature has landed <a href="https://github.com/rubygems/rubygems/pull/5327" class="external">1</a>. I also think that we have arrived to this situation by evolution, not by design.</p>
<p>Therefore my proposal is:</p>
<p>Keep the <code>Gem.default_dir</code> for user <code>gem install</code>ed gems and lets install default and bundled gems into separate dedicated directories. Have separate <code>Gem.bundled_gems_dir</code> and <code>Gem.default_gems_dir</code> structures.</p>
<p>Of course, if <code>Gem.default_dir == Gem.bundled_gems_dir == Gem.default_gems_dir</code>, we still can have the current layout.</p>
<p>I have a simple POC here:</p>
<p><a href="https://github.com/ruby/ruby/pull/8761" class="external">https://github.com/ruby/ruby/pull/8761</a></p>
<p>BTW I have reported it here, because I think that RubyGems provides all it is needed. So it is not RubyGems ticket after all. However, I believe that RubyGems could benefit from this long term and some simplifications/cleanups would be possible.</p> Ruby master - Feature #19908 (Assigned): Update to Unicode 15.1https://bugs.ruby-lang.org/issues/199082023-10-02T06:55:45Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>The Unicode 15.1 is released.</p>
<p>The current enc-unicode.rb seems to fail because of <code>Indic_Conjunct_break</code> properties with values.</p>
<p>I'm not sure how these properties should be handled well.<br>
<code>/\p{InCB_Liner}/</code> or <code>/\p{InCB=Liner}/</code> as the comments in that file?<br>
<a href="https://github.com/nobu/ruby/tree/unicode-15.1" class="external">https://github.com/nobu/ruby/tree/unicode-15.1</a> is the former.</p> Ruby master - Feature #19465 (Assigned): [PATCH] reuse open(2) from rb_file_load_ok on POSIX-like...https://bugs.ruby-lang.org/issues/194652023-02-25T01:48:35Znormalperson (Eric Wong)normalperson@yhbt.net
<pre><code>When loading Ruby source files, we can save the result of
successful opens as open(2)/openat(2) are a fairly expensive
syscalls. This also avoids a time-of-check-to-time-of-use
(TOCTTOU) problem.
This reduces open(2) syscalls during `require'; but should be
most apparent when users have a small $LOAD_PATH. Users with
large $LOAD_PATH will benefit less since there'll be more
open(2) failures due to ENOENT.
With `strace -c -e openat ruby -e exit' under Linux, this
results in a ~14% reduction of openat(2) syscalls
(glibc uses openat(2) to implement open(2)).
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 296 110 openat
0.00 0.000000 0 254 110 openat
Additionally, the introduction of `struct ruby_file_load_state'
may make future optimizations more apparent.
This change cannot benefit binary (.so) loading since the
dlopen(3) API requires a filename and I'm not aware of an
alternative that takes a pre-existing FD. In typical
situations, Ruby source files outnumber the mount of .so
files.
I've only tested this lightly on small apps since I don't have
large codebases to test on. However, I think organizing various
on-stack variables into `struct ruby_file_load_state' can be
beneficial if we end up using io-uring on Linux.
</code></pre> Ruby master - Feature #19422 (Assigned): Make `--enabled-shared` mandatory on macOShttps://bugs.ruby-lang.org/issues/194222023-02-07T08:14:26Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>From the troubles around linker on macOS, I propose <code>--enable-shared</code> option mandatory on macOS.<br>
This patch enables the option by default, and abort if <code>--disable-shared</code> option is given explicitly.</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gh">diff --git i/configure.ac w/configure.ac
index 7db2ab5257c..923ac7d1199 100644
</span><span class="gd">--- i/configure.ac
</span><span class="gi">+++ w/configure.ac
</span><span class="p">@@ -504,6 +504,11 @@</span> AS_CASE(["$target_os"],
rb_cv_binary_elf=no
: ${enable_shared=yes}
],
<span class="gi">+[darwin*], [
+ AS_IF([test "${enable_shared=yes}" = no], [
+ AC_MSG_ERROR([--disable-shared is not supported on this platform])
+ ])
+],
</span> [hiuxmpp*], [AC_DEFINE(__HIUX_MPP__)]) # by TOYODA Eizi <toyoda@npd.kishou.go.jp>
AC_PROG_LN_S
<span class="p">@@ -3055,14 +3060,7 @@</span> AC_SUBST(EXTOBJS)
: ${LDFLAGS=""}
: ${LIBPATHENV=DYLD_FALLBACK_LIBRARY_PATH}
: ${PRELOADENV=DYLD_INSERT_LIBRARIES}
<span class="gd">- AS_IF([test x"$enable_shared" = xyes], [
- # Resolve symbols from libruby.dylib when --enable-shared
- EXTDLDFLAGS='$(LIBRUBYARG_SHARED)'
- ], [test "x$EXTSTATIC" = x], [
- # When building exts as bundles, a mach-o bundle needs to know its loader
- # program to bind symbols from the ruby executable
- EXTDLDFLAGS="-bundle_loader '\$(BUILTRUBY)'"
- ])
</span><span class="gi">+ EXTDLDFLAGS='$(LIBRUBYARG_SHARED)'
</span> rb_cv_dlopen=yes],
[aix*], [ : ${LDSHARED='$(CC)'}
AS_IF([test "$GCC" = yes], [
<span class="p">@@ -3356,10 +3354,6 @@</span> AS_IF([test x"$cross_compiling" = xyes], [
AC_SUBST(XRUBY_RUBYLIBDIR)
AC_SUBST(XRUBY_RUBYHDRDIR)
PREP='$(arch)-fake.rb'
<span class="gd">- AS_CASE(["$enable_shared:$EXTSTATIC:$target_os"], [no::darwin*], [
- # darwin target requires miniruby for linking ext bundles
- PREP="$PREP"' miniruby$(EXEEXT)'
- ])
</span> RUNRUBY_COMMAND='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
RUNRUBY='$(RUNRUBY_COMMAND)'
XRUBY='$(MINIRUBY)'
</code></pre> Ruby master - Feature #19326 (Assigned): Please add a better API for passing a Proc to a Ractorhttps://bugs.ruby-lang.org/issues/193262023-01-08T19:31:09Zsdwolfz (Codruț Gușoi)
<p>Example 1:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Worker</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="vi">@block</span> <span class="o">=</span> <span class="n">block</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">run</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="vi">@block</span><span class="p">,</span> <span class="o">&</span><span class="ss">:call</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">worker</span> <span class="o">=</span> <span class="no">Worker</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="mi">1</span> <span class="p">}</span>
<span class="nb">puts</span> <span class="n">worker</span><span class="p">.</span><span class="nf">run</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Errors with:</p>
<pre><code><internal:ractor>:271:in `new': allocator undefined for Proc (TypeError)
from scripts/run.rb:9:in `run'
from scripts/run.rb:14:in `<main>'
</code></pre>
<p>Example 2:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Worker</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="vi">@block</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">run</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="vi">@block</span><span class="p">,</span> <span class="o">&</span><span class="ss">:call</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">worker</span> <span class="o">=</span> <span class="no">Worker</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="mi">1</span> <span class="p">}</span>
<span class="nb">puts</span> <span class="n">worker</span><span class="p">.</span><span class="nf">run</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Errors with:</p>
<pre><code><internal:ractor>:820:in `make_shareable': Proc's self is not shareable: #<Proc:0x00007f00394c38b8 scripts/run.rb:13> (Ractor::IsolationError)
from scripts/run.rb:5:in `initialize'
from scripts/run.rb:13:in `new'
from scripts/run.rb:13:in `<main>'
</code></pre>
<p>Example 3:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Worker</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="vi">@block</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">make_shareable</span><span class="p">(</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">run</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="vi">@block</span><span class="p">,</span> <span class="o">&</span><span class="ss">:call</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">worker</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">instance_eval</span> <span class="p">{</span> <span class="no">Worker</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="mi">1</span> <span class="p">}</span> <span class="p">}</span>
<span class="nb">puts</span> <span class="n">worker</span><span class="p">.</span><span class="nf">run</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Works, but having <code>Ractor.current.instance_eval</code> as a wrapper around the block is not ideal, as Ractor is supposed to be only an implementation detail in Worker.</p>
<p>I know about <a href="https://bugs.ruby-lang.org/issues/18243" class="external">https://bugs.ruby-lang.org/issues/18243</a> and the discussion around <code>proc.bind(nil)</code>. That would actually be ideal, as for the purposes if why I want this functionality I don't care what <code>self</code> is in a block, and the less it has access to the better.</p>
<p>The general idea of Worker is to have a Ractor be able to lazily execute an arbitrary proc. And all the bindings it would need would be passed explicitly, either through <code>args</code> in the constructor or through <code>send</code>/<code>receive</code>, so <code>self</code> would really not matter.</p>
<p>The benefit: this would make it so concurrent code can be more easily be implemented with Ractors as currently you can execute an arbitrary proc by passing it to a Thread (but you don't get the nice data isolation).</p> Ruby master - Feature #19325 (Assigned): YJIT: Windows support lacking.https://bugs.ruby-lang.org/issues/193252023-01-08T18:09:41Zdsisnero (Dominic Sisneros)dsisnero@gmail.com
<p>Ruby's support on windows has always been second class. With some of the recent decisions, windows support is falling even more behind. Recent developments in mjit and yjit that exclude windows are two glaring issues that should be corrected. Googling 'percent of windows vs other operating systems' and it shows windows has a share of 76%. Ceding that users to python and other programming languages has to be one of the reasons python continues get more market share from ruby. With rust having first class windows support and threading support, is there a reason why yjit is not able to work on windows? Also, windows compiler support has matured enough and vcpkg support has evolved enough that it seems it should be possible to finally get a ruby version without having to use msys2. Even Crystal language has a version that runs on windows without needing msys2.</p> Ruby master - Feature #19317 (Assigned): Unicode ICU Full case mappinghttps://bugs.ruby-lang.org/issues/193172023-01-06T15:05:39Znoraj (Alexandre ZANNI)
<p>As announced in <a href="https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html#label-Default+Case+Mapping" class="external">Case Mapping</a>, Ruby support for Unicode case mapping is not complete yet.</p>
<p>Unicode supports in Ruby is pretty awesome, it works by default nearly everywhere, things are implemented the right way and works as expected by the UTRs.</p>
<p>But some features are still missing.</p>
<p>To reach <a href="https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#full-language-specific-case-mapping" class="external">ICU Full Case Mapping support</a>, a few points need to be enhanced.</p>
<a name="context-sensitive-case-mapping"></a>
<h3 >context-sensitive case mapping<a href="#context-sensitive-case-mapping" class="wiki-anchor">¶</a></h3>
<ul class="task-list">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> cf. <a href="https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf" class="external">Table 3-17 (Context Specification for Casing) of the Unicode standard</a> and <a href="https://www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt" class="external">ucd/SpecialCasing.txt</a>.</li>
</ul>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="s2">"ΣΣ"</span><span class="p">.</span><span class="nf">downcase</span> <span class="c1"># returns σσ instead of σς</span>
</code></pre>
<p>Output examples in ECMAScript:</p>
<pre><code>Σ ➡️ σ
Σa ➡️ σa
aΣ ➡️ aς
aΣa ➡️ aσa
ΣA ➡️ σa
aΣ a ➡️ aς a
Σ1 ➡️ σ1
aΣ1 ➡️ aς1
ΣΣ ➡️ σς
</code></pre>
<a name="language-sensitive-case-mapping"></a>
<h2 >language-sensitive case mapping<a href="#language-sensitive-case-mapping" class="wiki-anchor">¶</a></h2>
<ul class="task-list">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> Lithuanian rules</li>
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" checked disabled> Turkish and Azeri</li>
</ul>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="s2">"I"</span><span class="p">.</span><span class="nf">downcase</span> <span class="c1"># => "i"</span>
<span class="s2">"I"</span><span class="p">.</span><span class="nf">downcase</span><span class="p">(</span><span class="ss">:turkic</span><span class="p">)</span> <span class="c1"># => "ı"</span>
<span class="s2">"I</span><span class="se">\u</span><span class="s2">0307"</span><span class="p">.</span><span class="nf">upcase</span> <span class="c1"># => "İ"</span>
<span class="s2">"I</span><span class="se">\u</span><span class="s2">0307"</span><span class="p">.</span><span class="nf">upcase</span><span class="p">(</span><span class="ss">:lithuanian</span><span class="p">)</span> <span class="c1"># => "İ" instead of "I"</span>
</code></pre>
<ul class="task-list">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> using some standard locale / language codes</li>
</ul>
<p>Also, it's true that for now there are only a few language-sensitive rules (for Lithuanian, Turkish and Azeri) but why:</p>
<ul>
<li>adding a <code>:turkic</code> symbol and not a <code>:azeri</code>?</li>
<li>using full english arbitrary (why <code>turkic</code> and not <code>turkish</code>?) language name rather than some <a href="https://unicode-org.github.io/icu/userguide/locale/" class="external">ICU locale IDs</a>?
<ul>
<li>Language code ISO-639 standard</li>
<li>Script code Unicode ISO 15924 Registry</li>
<li>country code ISO-3166 standard</li>
</ul>
</li>
</ul>
<p>So I would rather see something like that</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="s2">"placeholder"</span><span class="p">.</span><span class="nf">upcase</span><span class="p">(</span><span class="ss">locale: :tr_TR</span><span class="p">)</span>
<span class="s2">"placeholder"</span><span class="p">.</span><span class="nf">upcase</span><span class="p">(</span><span class="ss">lang: :tr</span><span class="p">)</span>
</code></pre> Ruby master - Feature #19193 (Assigned): drop DOS TEXT mode supporthttps://bugs.ruby-lang.org/issues/191932022-12-09T16:38:20ZYO4 (Yoshinao Muramatsu)
<p>On Windows platform, <code>File.open(path, "r")</code> returns an object different from "rt" and "rb". I call that DOS TEXT mode here.</p>
<p>DOS TEXT mode does</p>
<ul>
<li>crlf conversion</li>
<li>0x1a treated EOF charactor on read</li>
</ul>
<p>and others (see Bug <a class="issue tracker-1 status-1 priority-4 priority-default" title="Bug: IO has third data mode, document is incomplete. (Open)" href="https://bugs.ruby-lang.org/issues/19192">#19192</a>).<br>
But DOS TEXT mode is almost unnecessary today and it seems to introduce lot of code complexities.</p>
<p>Now there is less need for dos text mode</p>
<ul>
<li>Microsoft's most apps works without CRLF newline.</li>
<li>Creating a crlf text file today should be explicit. (but that is default mode on windows now)</li>
<li>Interpreting EOF charactor can cause trouble.</li>
</ul>
<p>I think it's time to consider dropping DOS TEXT mode.<br>
What challenges are there and what preparation is needed?</p> Ruby master - Feature #19057 (Assigned): Hide implementation of `rb_io_t`.https://bugs.ruby-lang.org/issues/190572022-10-15T01:54:57Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>In order to make improvements to the IO implementation like <a href="https://bugs.ruby-lang.org/issues/18455" class="external">https://bugs.ruby-lang.org/issues/18455</a>, we need to add new fields to <code>struct rb_io_t</code>.</p>
<p>By the way, ending types in <code>_t</code> is not recommended by POSIX, so I'm also trying to rename the internal implementation to drop <code>_t</code> where possible during this conversion.</p>
<p>Anyway, we should try to hide the implementation of <code>struct rb_io</code>. Ideally, we don't expose any of it, but the problem is backwards compatibility.</p>
<p>So, in order to remain backwards compatibility, we should expose some fields of <code>struct rb_io</code>, the most commonly used one is <code>fd</code> and <code>mode</code>, but several others are commonly used.</p>
<p>There are many fields which should not be exposed because they are implementation details.</p>
<a name="Current-proposal"></a>
<h2 >Current proposal<a href="#Current-proposal" class="wiki-anchor">¶</a></h2>
<p>The current proposed change <a href="https://github.com/ruby/ruby/pull/6511" class="external">https://github.com/ruby/ruby/pull/6511</a> creates two structs:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// include/ruby/io.h</span>
<span class="cp">#ifndef RB_IO_T
</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="c1">// ... public fields ...</span>
<span class="p">};</span>
<span class="cp">#else
</span><span class="k">struct</span> <span class="n">rb_io</span><span class="p">;</span>
<span class="cp">#endif
</span>
<span class="c1">// internal/io.h</span>
<span class="cp">#define RB_IO_T
</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="c1">// ... public fields ...</span>
<span class="c1">// ... private fields ...</span>
<span class="p">};</span>
</code></pre>
<p>However, we are not 100% confident this is safe according to the C specification. My experience is not sufficiently wide to say this is safe in practice, but it does look okay to both myself, and <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a> + <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/73">@tenderlovemaking (Aaron Patterson)</a> have both given some kind of approval.</p>
<p>That being said, maybe it's not safe.</p>
<p>There are two alternatives:</p>
<a name="Hide-all-details"></a>
<h2 >Hide all details<a href="#Hide-all-details" class="wiki-anchor">¶</a></h2>
<p>We can make public <code>struct rb_io</code> completely invisible.</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// include/ruby/io.h</span>
<span class="cp">#define RB_IO_HIDDEN
</span><span class="k">struct</span> <span class="n">rb_io</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">rb_ioptr_descriptor</span><span class="p">(</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="o">*</span><span class="n">ioptr</span><span class="p">);</span> <span class="c1">// accessor for previously visible state.</span>
<span class="c1">// internal/io.h</span>
<span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="c1">// ... all fields ...</span>
<span class="p">};</span>
</code></pre>
<p>This would only be forwards compatible, and code would need to feature detect like this:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="cp">#ifdef RB_IO_HIDDEN
#define RB_IOPTR_DESCRIPTOR rb_ioptr_descriptor
#else
#define RB_IOPTR_DESCRIPTOR(ioptr) rb_ioptr_descriptor(ioptr)
#endif
</span></code></pre>
<a name="Nested-public-interface"></a>
<h2 >Nested public interface<a href="#Nested-public-interface" class="wiki-anchor">¶</a></h2>
<p>Alternatively, we can nest the public fields into the private struct:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// include/ruby/io.h</span>
<span class="k">struct</span> <span class="n">rb_io_public</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="c1">// ... public fields ...</span>
<span class="p">};</span>
<span class="c1">// internal/io.h</span>
<span class="cp">#define RB_IO_T
</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="k">struct</span> <span class="n">rb_io_public</span> <span class="n">public</span><span class="p">;</span>
<span class="c1">// ... private fields ...</span>
<span class="p">};</span>
</code></pre>
<a name="Considerations"></a>
<h2 >Considerations<a href="#Considerations" class="wiki-anchor">¶</a></h2>
<p>I personally think the "Hide all details" implementation is the best, but it's also the lest compatible. This is also what we are ultimately aiming for, whether we decide to take an intermediate "compatibility step" is up to us.</p>
<p>I think "Nested public interface" is messy and introduces more complexity, but it might be slightly better defined than the "Current proposal" which might create undefined behaviour. That being said, all the tests are passing.</p> Ruby master - Feature #18919 (Assigned): Ractor: can't share #Method objectshttps://bugs.ruby-lang.org/issues/189192022-07-15T22:07:09Zchucke (Tiago Cardoso)
<p>The following is not shareable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">></span> <span class="n">meth</span> <span class="o">=</span> <span class="o">::</span><span class="no">Kernel</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:BigDecimal</span><span class="p">)</span>
<span class="o">=></span> <span class="c1">#<Method: Kernel.BigDecimal(*)></span>
<span class="o"><</span><span class="n">internal</span><span class="ss">:ractor</span><span class="o">></span><span class="p">:</span><span class="mi">816</span><span class="ss">:in</span> <span class="sb">`make_shareable': can not make shareable object for #<Method: Kernel.BigDecimal(*)> (Ractor::Error)
</span></code></pre>
<p>I understand that procs have the issue of accessing outer-scope variables, but does the same apply to methods converted to procs?</p> Ruby master - Feature #18773 (Assigned): deconstruct to receive a rangehttps://bugs.ruby-lang.org/issues/187732022-05-11T17:13:54Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>Currently when you're pattern matching against a hash pattern, <code>deconstruct_keys</code> receives the keys that are being matched. This is really useful for computing expensive hashes.</p>
<p>However, when you're pattern matching against an array pattern, you don't receive any information. So if the array is expensive to compute (for instance loading an array of database records), you have no way to bail out. It would be useful to receive a range signifying how many records the pattern is specifying. It would be used like the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">ActiveRecord::Relation</span>
<span class="k">def</span> <span class="nf">deconstruct</span><span class="p">(</span><span class="n">range</span><span class="p">)</span>
<span class="p">(</span><span class="n">loaded?</span> <span class="o">||</span> <span class="n">range</span><span class="p">.</span><span class="nf">cover?</span><span class="p">(</span><span class="n">count</span><span class="p">))</span> <span class="p">?</span> <span class="n">records</span> <span class="p">:</span> <span class="kp">nil</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>It needs to be a range and not just a number to handle cases where <code>*</code> is used. You would use it like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="no">Person</span><span class="p">.</span><span class="nf">all</span>
<span class="k">in</span> <span class="p">[]</span>
<span class="s2">"No records"</span>
<span class="k">in</span> <span class="p">[</span><span class="n">person</span><span class="p">]</span>
<span class="s2">"Only </span><span class="si">#{</span><span class="n">person</span><span class="p">.</span><span class="nf">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="s2">"Multiple people"</span>
<span class="k">end</span>
</code></pre>
<p>In this way, you wouldn't have to load the whole thing into memory to check if it pattern matched. The patch is here: <a href="https://github.com/ruby/ruby/pull/5905" class="external">https://github.com/ruby/ruby/pull/5905</a>.</p> Ruby master - Feature #18459 (Assigned): IRB autocomplete dropdown colour optionshttps://bugs.ruby-lang.org/issues/184592022-01-04T19:28:54Zjohansenjaa (Joseph Johansen)
<p>It would be great to be able to specify bg/fg colours for the new autocomplete dropdown in irb in ruby 3.1. This could help for accessibility purposes, or for anyone who just wants to make it look more personalised for their terminal 😎</p>
<p>Perhaps irbrc could do the trick?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">IRB</span><span class="p">.</span><span class="nf">conf</span><span class="p">[</span><span class="ss">:AUTOCOMPLETE</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="no">BG_COLOR</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="no">FG_COLOR</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
<span class="p">}</span>
</code></pre> Ruby master - Feature #18450 (Assigned): Force break in prettyprinthttps://bugs.ruby-lang.org/issues/184502021-12-29T13:16:58Zfirasalkhalil (Firas al-Khalil)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>Support force-breaking a group in the std's <a href="https://github.com/ruby/prettyprint" class="external">prettyprint</a></p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>There is a need to forcibly break a group and transform breakables into<br>
newlines. The library doesn't provide this possibility, directly, through<br>
its public API.</p>
<a name="Proposal"></a>
<h1 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h1>
<p>Add a single convenience function to the library's public class <code>PrettyPrint</code></p>
<a name="Implementation"></a>
<h1 >Implementation<a href="#Implementation" class="wiki-anchor">¶</a></h1>
<p>An implementation was submitted to the project's github repository as a<br>
<a href="https://github.com/ruby/prettyprint/pull/2" class="external">pull request</a>.</p>
<p>Here's the patch:</p>
<pre><code>diff --git a/lib/prettyprint.rb b/lib/prettyprint.rb
index 188c2e6..1d675a7 100644
--- a/lib/prettyprint.rb
+++ b/lib/prettyprint.rb
@@ -236,6 +236,14 @@ class PrettyPrint
end
end
+ # This says "force a line break here".
+ #
+ # It will force the current group's "breakables" to break.
+ def break
+ breakable
+ current_group.break
+ end
+
# Groups line break hints added in the block. The line break hints are all
# to be used or not.
#
diff --git a/test/test_prettyprint.rb b/test/test_prettyprint.rb
index 27e7198..cf889d1 100644
--- a/test/test_prettyprint.rb
+++ b/test/test_prettyprint.rb
@@ -518,4 +518,31 @@ End
end
+
+class Break < Test::Unit::TestCase # :nodoc:
+ def format()
+ PrettyPrint.format(''.dup) {|q|
+ q.group {
+ q.text 'abc'
+ q.breakable
+ q.text 'def'
+ q.group {
+ q.break
+ q.text 'ghi'
+ }
+ q.breakable
+ q.text 'jkl'
+ }
+ }
+ end
+
+ def test_00_04
+ expected = <<'End'.chomp
+abc def
+ghi jkl
+End
+ assert_equal(expected, format())
+ end
+end
+
</code></pre>
<a name="Evaluation"></a>
<h1 >Evaluation<a href="#Evaluation" class="wiki-anchor">¶</a></h1>
<p>It's a simple implementation with no caveats.</p>
<a name="Discussion"></a>
<h1 >Discussion<a href="#Discussion" class="wiki-anchor">¶</a></h1>
<p>Even though it's a simple functionality, and the implementation is straightforward,<br>
getting to this point is not that obvious. This is why it might be helpful for other<br>
users who face such a need.</p>
<p>Indeed, an issue was <a href="https://github.com/ruby/prettyprint/issues/1" class="external">opened</a> not so long ago,<br>
and the proposed solution worked but not quite as expected. The provided implementation<br>
works as expected without tampering with the API's internals, and it's proven in production<br>
environment.</p>
<a name="Summary"></a>
<h1 >Summary<a href="#Summary" class="wiki-anchor">¶</a></h1>
<p>This is a feature request for the <code>prettyprint</code> library: adding support for <em>force breaking</em><br>
a group. An implementation is provided as both a patch and a PR on github.</p> Ruby master - Feature #18439 (Assigned): YJIT: Support Microsoft x86 calling conventionhttps://bugs.ruby-lang.org/issues/184392021-12-27T08:47:04Zusa (Usaku NAKAMURA)usa@garbagecollect.jp
<p>I heard that supporting YJIT for VC++ needs mmap from k0kubun-san, so I implemented tiny mmap emulation on Windows and committed it to master.<br>
And, I found we need more changes to actually enabled YJIT for VC++, at least:</p>
<ul>
<li>YJIT requires <code>OPT_DIRECT_THREADED_CODE</code> or <code>OPT_CALL_THREADED_CODE</code> in <code>rb_yjit_compile_iseq()</code>. Really?</li>
<li>Maybe ABI deffers between VC++ and YJIT's expectation.</li>
</ul>
<p>Can I get support to fix above?</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 #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 - Feature #17684 (Assigned): Remove `--disable-gems` from release version of Rubyhttps://bugs.ruby-lang.org/issues/176842021-03-10T12:51:46Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>In my understand, <code>--disable-gems</code> is only debugging feature for ruby-core team.</p>
<p>But some users enabled its option in test environment for performance or etc. So, <code>--disable-gems</code> option is wrong usage for some users.</p>
<ul>
<li><a href="https://github.com/rubygems/bundler/issues/7487#issuecomment-569901549" class="external">https://github.com/rubygems/bundler/issues/7487#issuecomment-569901549</a></li>
<li><a href="https://github.com/rubygems/rubygems/pull/4440#issue-587031184" class="external">https://github.com/rubygems/rubygems/pull/4440#issue-587031184</a></li>
</ul>
<p>We should remove it from package version of ruby.</p> Ruby master - Feature #17679 (Assigned): Ractor incoming channel can consume unlimited resourceshttps://bugs.ruby-lang.org/issues/176792021-03-08T16:22:37Zmarcotc (Marco Costa)
<a name="Background"></a>
<h2 >Background<a href="#Background" class="wiki-anchor">¶</a></h2>
<p>In the <a href="https://github.com/DataDog/dd-trace-rb" class="external">ddtrace</a> gem, we want to move telemetry trace sending to a separate background Ractor. We’re concerned that if something goes wrong/gets delayed in this background Ractor, more and more data will accumulate in the send/receive channel until the Ruby VM crashes because it runs out of memory.</p>
<a name="How-to-reproduce-Ruby-version-amp-script"></a>
<h2 >How to reproduce (Ruby version & script)<a href="#How-to-reproduce-Ruby-version-amp-script" class="wiki-anchor">¶</a></h2>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">receiver_ractor</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">message</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span>
<span class="nb">sleep</span> <span class="mi">1</span>
<span class="nb">puts</span> <span class="s2">"Processed </span><span class="si">#{</span><span class="n">message</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="kp">true</span>
<span class="n">counter</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">receiver_ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">counter</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<a name="Expectation-and-result"></a>
<h2 >Expectation and result<a href="#Expectation-and-result" class="wiki-anchor">¶</a></h2>
<p>The result is that the Ruby VM crashes due to out of memory.<br>
We expect the Ruby VM to not crash.</p>
<a name="Suggested-solutions"></a>
<h2 >Suggested solutions<a href="#Suggested-solutions" class="wiki-anchor">¶</a></h2>
<p>Some ideas on how this can be improved:</p>
<ul>
<li>Having a way for the sender of data to detect if the receiver Ractor is falling behind (approximate size of queue, timestamp of last processed item, or similar?).</li>
<li>Having a way to limit the Ractor message receive buffer.</li>
</ul> 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 - Feature #17638 (Assigned): Support backtracing with the libbacktrace libraryhttps://bugs.ruby-lang.org/issues/176382021-02-17T13:03:12Zxtkoba (Tee KOBAYASHI)
<p>It seems that Ruby's current <code>addr2line.c</code> has trouble with the DWARF 5 debugging format (Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: DWARF5 support? (Closed)" href="https://bugs.ruby-lang.org/issues/17585">#17585</a>).</p>
<p>I propose that there be an option to use the libbacktrace library instead of <code>addr2line.c</code>.</p>
<p>A patch is attached for that. When using libbacktrace, the C level backtrace information looks as follows:</p>
<pre><code>-- C level backtrace information -------------------------------------------
0x7f0cc2b3b372 rb_vm_bugreport
/var/tmp/ruby.build/ruby-devel-x86_64/vm_dump.c:1047
0x7f0cc291e188 rb_bug_for_fatal_signal
/var/tmp/ruby.build/ruby-devel-x86_64/error.c:801
0x7f0cc2a8a137 sigsegv
/var/tmp/ruby.build/ruby-devel-x86_64/signal.c:960
0x7f0cc281a9bf ???
???:0
0x7f0cc247ddf7 ???
???:0
0x7f0cc2a8990d rb_f_kill
/var/tmp/ruby.build/ruby-devel-x86_64/signal.c:481
0x7f0cc2a2e684 proc_rb_f_kill
/var/tmp/ruby.build/ruby-devel-x86_64/process.c:8604
0x7f0cc2b0f2a4 ractor_safe_call_cfunc_m1
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:2734
0x7f0cc2b0fecb vm_call_cfunc_with_frame
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:2924
0x7f0cc2b10088 vm_call_cfunc
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:2945
0x7f0cc2b11b3b vm_call_method_each_type
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:3414
0x7f0cc2b11fde vm_call_method
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:3507
0x7f0cc2b121ca vm_call_general
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:3550
0x7f0cc2b144e7 vm_sendish
/var/tmp/ruby.build/ruby-devel-x86_64/vm_insnhelper.c:4525
0x7f0cc2b1b196 vm_exec_core
/var/tmp/ruby.build/ruby-devel-x86_64/insns.def:789
0x7f0cc2b308f5 rb_vm_exec
/var/tmp/ruby.build/ruby-devel-x86_64/vm.c:2162
0x7f0cc2b316e8 rb_iseq_eval_main
/var/tmp/ruby.build/ruby-devel-x86_64/vm.c:2419
0x7f0cc292778d rb_ec_exec_node
/var/tmp/ruby.build/ruby-devel-x86_64/eval.c:317
0x7f0cc29278d3 ruby_run_node
/var/tmp/ruby.build/ruby-devel-x86_64/eval.c:375
0x55ad53234234 main
./main.c:47
0x7f0cc2468e59 ???
???:0
0x55ad532340f9 ???
???:0
0xffffffffffffffff ???
???:0
</code></pre>
<p>The source code of libbacktrace is available from: <a href="https://github.com/ianlancetaylor/libbacktrace" class="external">https://github.com/ianlancetaylor/libbacktrace</a></p> Ruby master - Feature #17593 (Assigned): load_iseq_eval should override the ISeq pathhttps://bugs.ruby-lang.org/issues/175932021-01-29T18:05:42Zbyroot (Jean Boussier)byroot@ruby-lang.org
<p>Full context in <a href="https://github.com/Shopify/bootsnap/pull/343" class="external">https://github.com/Shopify/bootsnap/pull/343</a></p>
<p>Consider the following script</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">system</span><span class="p">(</span><span class="s1">'mkdir'</span><span class="p">,</span> <span class="s1">'-p'</span><span class="p">,</span> <span class="s1">'/tmp/build'</span><span class="p">,</span> <span class="s1">'/tmp/app'</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s1">'/tmp/app/a.rb'</span><span class="p">,</span> <span class="s1">'p ["app/a", __FILE__, __dir__]'</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s1">'/tmp/app/b.rb'</span><span class="p">,</span> <span class="s1">'p ["app/b", __FILE__, __dir__]'</span><span class="p">)</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s1">'/tmp/build/a.rb'</span><span class="p">,</span> <span class="s1">'p ["build/a", __FILE__, __dir__]; require_relative "b"'</span><span class="p">)</span>
<span class="vg">$iseq</span> <span class="o">=</span> <span class="no">RubyVM</span><span class="o">::</span><span class="no">InstructionSequence</span><span class="p">.</span><span class="nf">compile_file</span><span class="p">(</span><span class="s1">'/tmp/build/a.rb'</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">RubyVM::InstructionSequence</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">load_iseq</span><span class="p">(</span><span class="n">feature</span><span class="p">)</span>
<span class="k">if</span> <span class="n">feature</span> <span class="o">==</span> <span class="s2">"/tmp/app/a.rb"</span>
<span class="vg">$iseq</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">require</span> <span class="s1">'/tmp/app/a.rb'</span>
</code></pre>
<p>Current behavior:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="s2">"build/a"</span><span class="p">,</span> <span class="s2">"/tmp/build/a.rb"</span><span class="p">,</span> <span class="s2">"/private/tmp/build"</span><span class="p">]</span>
<span class="sr">/tmp/</span><span class="n">build</span><span class="o">/</span><span class="n">a</span><span class="p">.</span><span class="nf">rb</span><span class="p">:</span><span class="mi">1</span><span class="ss">:in</span> <span class="sb">`require_relative': cannot load such file -- /private/tmp/build/b (LoadError)
from /tmp/build/a.rb:1:in `</span><span class="o"><</span><span class="n">main</span><span class="o">></span><span class="s1">'
from <internal:/opt/rubies/3.0.0-pshopify2/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'</span>
<span class="n">from</span> <span class="o"><</span><span class="n">internal</span><span class="ss">:/</span><span class="n">opt</span><span class="o">/</span><span class="n">rubies</span><span class="o">/</span><span class="mf">3.0</span><span class="o">.</span><span class="mi">0</span><span class="o">-</span><span class="n">pshopify2</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">ruby</span><span class="o">/</span><span class="mf">3.0</span><span class="o">.</span><span class="mi">0</span><span class="o">/</span><span class="n">rubygems</span><span class="o">/</span><span class="n">core_ext</span><span class="o">/</span><span class="n">kernel_require</span><span class="p">.</span><span class="nf">rb</span><span class="o">></span><span class="p">:</span><span class="mi">85</span><span class="ss">:in</span> <span class="sb">`require'
from /tmp/iseq_debug.rb:16:in `</span><span class="o"><</span><span class="n">main</span><span class="o">></span><span class="err">'</span>
</code></pre>
<p>Expected behavior</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="s2">"build/a"</span><span class="p">,</span> <span class="s2">"/private/tmp/app/a.rb"</span><span class="p">,</span> <span class="s2">"/private/tmp/app"</span><span class="p">]</span>
<span class="p">[</span><span class="s2">"app/b"</span><span class="p">,</span> <span class="s2">"/private/tmp/app/b.rb"</span><span class="p">,</span> <span class="s2">"/private/tmp/app"</span><span class="p">]</span>
</code></pre>
<a name="Whats-going-on"></a>
<h3 >What's going on?<a href="#Whats-going-on" class="wiki-anchor">¶</a></h3>
<p><code>RubyVM::InstructionSequence</code> instances have a <code>pathobj</code> property that is recorded when the source is parsed, and when the ISeq is later evaled, the VM use that <code>path</code> as if you were loading a <code>.rb</code> file located at that path.</p>
<p>So if that source use constructs such as <code>require_relative</code>, <code>__FILE__</code>, <code>__dir__</code>, etc, they will all happen relative to where the source was located upon compilation, not relative to the source was upon evaluation.</p>
<a name="Why-is-it-a-problem"></a>
<h3 >Why is it a problem?<a href="#Why-is-it-a-problem" class="wiki-anchor">¶</a></h3>
<p>Some deployment strategies first build the application in one location, and then later move it elsewhere.</p>
<p>That's for instance the case on the Heroku platform. e.g. the deploy looks like</p>
<pre><code class="bash syntaxhl" data-language="bash">git clone <repo> /tmp/build_xxxx
<span class="nb">cd</span> /tmp/build_xxxx
rake assets:precompile ...
<span class="nb">mv</span> /tmp/build_xxxx /app
</code></pre>
<p>Because of this, all the ISeq cached by bootsnap when the code was in <code>/tmp/build_xxx</code> have to be invalidated as soon as the source is moved to <code>/app</code>, rendering ISeq caching ineffective, and even detrimental as it causes extra writes to disk without bringing any benefits.</p>
<a name="Solution"></a>
<h3 >Solution<a href="#Solution" class="wiki-anchor">¶</a></h3>
<p>I believe there are two changes that would be needed.</p>
<p>First I think that <code>load_iseq_eval</code> should set the <code>fname</code> as the top stack location. Either by copying the ISeq instance and change its <code>pathobj</code>, or by having a way to pass an optional path to <code>vm_set_top_stack</code> that would take precedence.</p>
<p>I experimented with <a href="https://github.com/Shopify/ruby/commit/192f5b477f924243e3f6621383e7a6ad02fbd63d" class="external">a quick hack that changes the ISeq <code>pathobj</code> in place</a>, and it does solve most of the problem.</p>
<p>However even with that quick hack another problem remain, the <code>__FILE__</code> still evaluate to the original source location. However <code>__dir__</code> works as expected, because it is a method that returns the top_stack location. I think <code>__FILE__</code> could be changed to be a method as well.</p> 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 - Feature #17363 (Assigned): Timeoutshttps://bugs.ruby-lang.org/issues/173632020-12-03T14:58:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Builtin methods like <code>Queue.pop</code> and <code>Ractor.receive</code> have no timeout parameter.</p>
<p>We should either:</p>
<ul>
<li>provide such a parameter</li>
<li>and/or provide a <code>Timeout::wake</code> that raises an timeout error only if the block is currently sleeping.</li>
</ul>
<p>Details:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">q</span> <span class="o">=</span> <span class="no">Queue</span><span class="p">.</span><span class="nf">new</span>
<span class="c1"># ...</span>
<span class="n">elem</span> <span class="o">=</span> <span class="no">Timeout</span><span class="o">::</span><span class="n">timeout</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="p">{</span> <span class="n">q</span><span class="p">.</span><span class="nf">pop</span> <span class="p">}</span> <span class="c1"># => It is possible that an element is retreived from the queue but never stored in `elem`</span>
<span class="n">elem</span> <span class="o">=</span> <span class="no">Timeout</span><span class="o">::</span><span class="n">wake</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="p">{</span> <span class="n">q</span><span class="p">.</span><span class="nf">pop</span> <span class="p">}</span> <span class="c1"># => Guaranteed that either element is retrieved from the queue or an exception is raised, never both</span>
<span class="no">Timeout</span><span class="o">::</span><span class="n">wake</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="p">{</span> <span class="kp">loop</span> <span class="p">{}</span> <span class="p">}</span> <span class="c1"># => infinite loop</span>
<span class="c1"># and/or</span>
<span class="n">elem</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="nf">pop</span><span class="p">(</span><span class="ss">timeout: </span><span class="mi">42</span><span class="p">)</span>
</code></pre>
<p>Currently, the only reliable way to have a Queue that accepts a timeout is to re-implement it from scratch. This post describe how involved that can be: <a href="https://spin.atomicobject.com/2017/06/28/queue-pop-with-timeout-fixed/" class="external">https://spin.atomicobject.com/2017/06/28/queue-pop-with-timeout-fixed/</a></p> Ruby master - Feature #17355 (Assigned): Using same set of names in or-patterns (pattern matching...https://bugs.ruby-lang.org/issues/173552020-11-29T19:41:28Zdecuplet (Nikita Shilnikov)fg@flashgordon.ru
<p>Given pattern matching is officially supported in Ruby 3, I have an idea about making it more flexible.</p>
<p>Currently, this piece of code produces a syntax error</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>
<span class="k">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">a</span><span class="p">]</span> <span class="o">|</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="o">=></span> <span class="n">a</span> <span class="k">then</span> <span class="n">a</span>
<span class="k">end</span> <span class="c1"># duplicated variable name</span>
</code></pre>
<p>Duplications don't seem to be a problem here, semantically-wise. We just need to check if all patterns have the same set of names. It's supported in OCaml (also here's an RFC in Rust <a href="https://github.com/rust-lang/rust/issues/54883" class="external">https://github.com/rust-lang/rust/issues/54883</a>) so I think it can work in Ruby too.</p>
<p>I've been using pattern matching in Ruby since day 1 and it worked great so far. Since I use OCaml daily too I miss this feature every once in a while :)<br>
A more practical example: imagine you have code like this</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">user_email</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="k">case</span> <span class="n">user</span>
<span class="k">in</span> <span class="no">User</span><span class="p">(</span><span class="n">email</span><span class="p">:)</span> <span class="k">then</span> <span class="n">email</span>
<span class="k">in</span> <span class="no">Admin</span><span class="p">(</span><span class="n">email</span><span class="p">:)</span> <span class="k">then</span> <span class="n">email</span>
<span class="k">in</span> <span class="no">Moderator</span><span class="p">(</span><span class="n">email</span><span class="p">:)</span> <span class="k">then</span> <span class="n">email</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Clearly, it could be simplified if or-patterns were supported:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">user_email</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="k">case</span> <span class="n">user</span>
<span class="k">in</span> <span class="no">User</span><span class="p">(</span><span class="n">email</span><span class="p">:)</span> <span class="o">|</span> <span class="no">Admin</span><span class="p">(</span><span class="n">email</span><span class="p">:)</span> <span class="o">|</span> <span class="no">Moderator</span><span class="p">(</span><span class="n">email</span><span class="p">:)</span> <span class="k">then</span> <span class="n">email</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I'd like to know @ktsj's thoughts on this.</p> Ruby master - Feature #17339 (Assigned): Semantic grouping with BigDecimal#to_shttps://bugs.ruby-lang.org/issues/173392020-11-21T07:05:31Zchumaltd (Takahiro Chuma)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>Thousands, millions, ... should be expressible with <code>BigDecimal#to_s</code>.</p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p><code>BigDecimal('1234567').to_s('3F')</code> returns "123 456 7.0".</p>
<a name="Proposal"></a>
<h1 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h1>
<ul>
<li>Have an option with which <code>BigDecimal('1234567').to_s('3F')</code> returns "<em>1 234 567</em>.0".</li>
<li>With decimal, <code>BigDecimal('1234567.8901234').to_s('3F')</code> should return "1 234 567.890 123 4".</li>
<li>Default behavior should be the above in long term.</li>
<li>And/Or, it would be nice to have a pretty method name. I think #to_s('3F') has universal use cases like money calculation.</li>
</ul>
<a name="Discussion"></a>
<h1 >Discussion<a href="#Discussion" class="wiki-anchor">¶</a></h1>
<ul>
<li>International System of Units aka SI defines 3-digit-grouping on long numeric sequence.<br>
<a href="https://www1.bipm.org/jsp/en/ViewCGPMResolution.jsp?CGPM=22&RES=10" class="external">https://www1.bipm.org/jsp/en/ViewCGPMResolution.jsp?CGPM=22&RES=10</a>
</li>
<li>Original discussion in 1948 shows some example of 3-digit-grouping.<br>
<a href="https://www1.bipm.org/utils/common/pdf/CGPM/CGPM9.pdf#page=117" class="external">https://www1.bipm.org/utils/common/pdf/CGPM/CGPM9.pdf#page=117</a>
</li>
</ul>
<a name="Summary"></a>
<h1 >Summary<a href="#Summary" class="wiki-anchor">¶</a></h1>
<p>We want to have a natural format.</p> Ruby master - Feature #17297 (Assigned): Feature: Introduce Pathname.mktmpdirhttps://bugs.ruby-lang.org/issues/172972020-10-30T15:09:41Zschneems (Richard Schneeman)
<p>When I want to create a tmpdir I often want to manipulate it as a pathname. By introducing Pathname.mktmpdir I can get this behavior.</p>
<p>Currently I must:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Dir</span><span class="p">.</span><span class="nf">mktmpdir</span> <span class="k">do</span> <span class="o">|</span><span class="n">dir</span><span class="o">|</span>
<span class="n">dir</span> <span class="o">=</span> <span class="no">Pathname</span><span class="p">(</span><span class="n">dir</span><span class="p">)</span>
<span class="c1"># ... code</span>
<span class="k">end</span>
</code></pre>
<p>I would like to be able to instead:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Pathname</span><span class="p">.</span><span class="nf">mktmpdir</span> <span class="k">do</span> <span class="o">|</span><span class="n">dir</span><span class="o">|</span>
<span class="c1"># ... code</span>
<span class="k">end</span>
</code></pre>
<p>Diff:</p>
<pre><code>$ git diff master
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
index e6fb90277d..ec32e7d611 100644
--- a/ext/pathname/lib/pathname.rb
+++ b/ext/pathname/lib/pathname.rb
@@ -597,3 +597,20 @@ def rmtree
end
end
+class Pathname # * tmpdir *
+ # Creates a tmp directory and wraps the returned path in a Pathname object.
+ #
+ # See Dir.mktmpdir
+ def self.mktmpdir
+ require 'tmpdir' unless defined?(Dir.mktmpdir)
+ if block_given?
+ Dir.mktmpdir do |dir|
+ dir = self.new(dir)
+ yield dir
+ end
+ else
+ self.new(Dir.mktmpdir)
+ end
+ end
+end
+
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 43cef4849f..8edcccf666 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -1272,6 +1272,14 @@ def test_s_glob_3args
}
end
+ def test_mktmpdir
+ Pathname.mktmpdir do |dir|
+ assert_equal Pathname(dir), dir
+ assert dir.directory?
+ assert dir.exist?
+ end
+ end
+
def test_s_getwd
wd = Pathname.getwd
assert_kind_of(Pathname, wd)
</code></pre>
<p>Github link: <a href="https://github.com/ruby/ruby/pull/3709" class="external">https://github.com/ruby/ruby/pull/3709</a></p> Ruby master - Feature #17296 (Assigned): Feature: Pathname#chmod use FileUtils.chmod instead of Filehttps://bugs.ruby-lang.org/issues/172962020-10-30T15:08:09Zschneems (Richard Schneeman)
<p>The <code>FileUtils.chmod</code> provides the same numerical interface as <code>File.chmod</code> and it also includes a "symbolic mode" interface. With this patch you'll be able to run this code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Pathname</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"bin/compile"</span><span class="p">).</span><span class="nf">chmod</span><span class="p">(</span><span class="s2">"+x"</span><span class="p">)</span>
</code></pre>
<p>I believe that this is backwards compatible with the existing implementation and all changes are an extension. The only difference between File.chmod and FileUtils.chmod I could find is they have different return values and the previous implementation of <code>Pathname#chmod</code> returned the result of the <code>File.chmod</code> call. From the docs <code>File.chmod</code> returns the number of files modified, since we're only ever able to pass in a maximum of one file through this interface, the return value will always be a <code>1</code> or an exception if the file does not exist.</p>
<p>I checked and the exceptions when the file does not exist match:</p>
<pre><code>irb(main):004:0> File.chmod(0444, "doesnotexist.txt")
Traceback (most recent call last):
6: from /Users/rschneeman/.rubies/ruby-2.7.2/bin/irb:23:in `<main>'
5: from /Users/rschneeman/.rubies/ruby-2.7.2/bin/irb:23:in `load'
4: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
3: from (irb):3
2: from (irb):4:in `rescue in irb_binding'
1: from (irb):4:in `chmod'
Errno::ENOENT (No such file or directory @ apply2files - doesnotexist.txt)
irb(main):005:0> FileUtils.chmod(0444, "doesnotexist.txt")
Traceback (most recent call last):
10: from /Users/rschneeman/.rubies/ruby-2.7.2/bin/irb:23:in `<main>'
9: from /Users/rschneeman/.rubies/ruby-2.7.2/bin/irb:23:in `load'
8: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
7: from (irb):4
6: from (irb):5:in `rescue in irb_binding'
5: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/2.7.0/fileutils.rb:1016:in `chmod'
4: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/2.7.0/fileutils.rb:1016:in `each'
3: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/2.7.0/fileutils.rb:1017:in `block in chmod'
2: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/2.7.0/fileutils.rb:1346:in `chmod'
1: from /Users/rschneeman/.rubies/ruby-2.7.2/lib/ruby/2.7.0/fileutils.rb:1346:in `chmod'
Errno::ENOENT (No such file or directory @ apply2files - doesnotexist.txt)
</code></pre>
<p>If you're open to changing the interface of the return value my preference would be to return <code>self</code> from this method so that it can be chained. Otherwise this current patch is a smaller change.</p>
<p>Diff:</p>
<pre><code>$ git diff master
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
index e6fb90277d..cb6e32d9ac 100644
--- a/ext/pathname/lib/pathname.rb
+++ b/ext/pathname/lib/pathname.rb
@@ -585,6 +585,15 @@ def mkpath
nil
end
+ # Changes file permissions.
+ #
+ # See FileUtils.chmod
+ def chmod(mode)
+ require 'fileutils'
+ FileUtils.chmod(mode, self)
+ return 1
+ end
+
# Recursively deletes a directory, including all directories beneath it.
#
# See FileUtils.rm_r
diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c
index f71cec1b25..6778d4f102 100644
--- a/ext/pathname/pathname.c
+++ b/ext/pathname/pathname.c
@@ -12,7 +12,6 @@ static ID id_binwrite;
static ID id_birthtime;
static ID id_blockdev_p;
static ID id_chardev_p;
-static ID id_chmod;
static ID id_chown;
static ID id_ctime;
static ID id_directory_p;
@@ -552,20 +551,6 @@ path_mtime(VALUE self)
return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
}
-/*
- * call-seq:
- * pathname.chmod(mode_int) -> integer
- *
- * Changes file permissions.
- *
- * See File.chmod.
- */
-static VALUE
-path_chmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
-}
-
/*
* call-seq:
* pathname.lchmod(mode_int) -> integer
@@ -1448,7 +1433,6 @@ path_f_pathname(VALUE self, VALUE str)
* - #birthtime
* - #ctime
* - #mtime
- * - #chmod(mode)
* - #lchmod(mode)
* - #chown(owner, group)
* - #lchown(owner, group)
@@ -1495,6 +1479,7 @@ path_f_pathname(VALUE self, VALUE str)
* === Utilities
*
* These methods are a mixture of Find, FileUtils, and others:
+ * - #chmod(mode)
* - #find(&block)
* - #mkpath
* - #rmtree
@@ -1542,7 +1527,6 @@ Init_pathname(void)
rb_define_method(rb_cPathname, "birthtime", path_birthtime, 0);
rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
- rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
rb_define_method(rb_cPathname, "chown", path_chown, 2);
rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
@@ -1618,7 +1602,6 @@ InitVM_pathname(void)
id_birthtime = rb_intern("birthtime");
id_blockdev_p = rb_intern("blockdev?");
id_chardev_p = rb_intern("chardev?");
- id_chmod = rb_intern("chmod");
id_chown = rb_intern("chown");
id_ctime = rb_intern("ctime");
id_directory_p = rb_intern("directory?");
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 43cef4849f..5673691231 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -823,6 +823,11 @@ def test_chmod
path.chmod(0444)
assert_equal(0444, path.stat.mode & 0777)
path.chmod(old)
+
+ skip "Windows has different symbolic mode" if /mswin|mingw/ =~ RUBY_PLATFORM
+ path.chmod("u=wrx,g=rx,o=x")
+ assert_equal(0751, path.stat.mode & 0777)
+ path.chmod(old)
}
end
</code></pre>
<p>Github link: <a href="https://github.com/ruby/ruby/pull/3708" class="external">https://github.com/ruby/ruby/pull/3708</a></p> Ruby master - Feature #17295 (Assigned): Feature: Create a directory and file with Pathname#touchhttps://bugs.ruby-lang.org/issues/172952020-10-30T15:06:39Zschneems (Richard Schneeman)
<p>Right now if a developer wants to create a file and is not sure if the path exists yet or not they must:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Pathname</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"/a/b/c/d.txt"</span><span class="p">).</span><span class="nf">tap</span> <span class="p">{</span><span class="o">|</span><span class="nb">p</span><span class="o">|</span> <span class="nb">p</span><span class="p">.</span><span class="nf">dirname</span><span class="p">.</span><span class="nf">mkpath</span><span class="p">;</span> <span class="no">FileUtils</span><span class="p">.</span><span class="nf">touch</span><span class="p">(</span><span class="nb">p</span><span class="p">)}</span>
</code></pre>
<p>After this patch a developer can instead call:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Pathname</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"/a/b/c/d.txt"</span><span class="p">).</span><span class="nf">touch</span>
</code></pre>
<p>An alternative name for this behavior could be <code>mkfile</code> but I think it is confusing to have a <code>mkfile</code> and a <code>mkpath</code> where one creates a directory and one creates a file.</p>
<p>Diff:</p>
<pre><code>$ git diff master
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
index e6fb90277d..2ed02a6633 100644
--- a/ext/pathname/lib/pathname.rb
+++ b/ext/pathname/lib/pathname.rb
@@ -585,6 +585,27 @@ def mkpath
nil
end
+ # Creates a file and the full path to the file including any intermediate directories that don't yet
+ # exist.
+ #
+ # Example:
+ #
+ # Dir.exist?("/a/b/c") # => false
+ #
+ # p = Pathname.new("/a/b/c/d.txt")
+ # p.file? => false
+ # p.touch
+ # p.file? => true
+ #
+ # Dir.exist?("/a/b/c") # => true
+ def touch
+ require 'fileutils'
+ dirname.mkpath
+
+ FileUtils.touch(self)
+ self
+ end
+
# Recursively deletes a directory, including all directories beneath it.
#
# See FileUtils.rm_r
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 43cef4849f..3c518cc3da 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -1394,6 +1394,14 @@ def test_mkpath
}
end
+ def test_touch
+ with_tmpchdir('rubytest-pathname') {|dir|
+ Pathname("a/b/c/d.txt").touch
+ assert_file.directory?("a/b/c")
+ assert_file.file?("a/b/c/d.txt")
+ }
+ end
+
def test_rmtree
with_tmpchdir('rubytest-pathname') {|dir|
Pathname("a/b/c/d").mkpath
</code></pre>
<p>Github link: <a href="https://github.com/ruby/ruby/pull/3706" class="external">https://github.com/ruby/ruby/pull/3706</a></p> Ruby master - Feature #17294 (Assigned): Feature: Allow method chaining with Pathname#mkpath Path...https://bugs.ruby-lang.org/issues/172942020-10-30T15:04:06Zschneems (Richard Schneeman)
<p>Currently in my code when I want to create a pathname object and create a path at the same time I must use tap</p>
<pre><code>path = Pathname.new("/tmp/new").tap(&:mkpath)
</code></pre>
<p>I think it would be cleaner to be able to chain on the results of these methods instead:</p>
<pre><code>path = Pathname.new("/tmp/new").mkpath
</code></pre>
<p>This is a change in return value but after research on github I do not believe many (if any) are relying on the current behavior to return nil <a href="https://github.com/search?l=&p=1&q=.mkpath+language%3ARuby&ref=advsearch&type=Code" class="external">https://github.com/search?l=&p=1&q=.mkpath+language%3ARuby&ref=advsearch&type=Code</a>.</p>
<p>Here is my diff:</p>
<pre><code>$ git diff master schneems/return-self-pathname
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
index e6fb90277d..f1eb1e00ae 100644
--- a/ext/pathname/lib/pathname.rb
+++ b/ext/pathname/lib/pathname.rb
@@ -582,7 +582,7 @@ class Pathname # * FileUtils *
def mkpath
require 'fileutils'
FileUtils.mkpath(@path)
- nil
+ self
end
# Recursively deletes a directory, including all directories beneath it.
@@ -593,7 +593,7 @@ def rmtree
# File::Path provides "mkpath" and "rmtree".
require 'fileutils'
FileUtils.rm_r(@path)
- nil
+ self
end
end
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 43cef4849f..149fe15c3a 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -1389,7 +1389,8 @@ def test_find
def test_mkpath
with_tmpchdir('rubytest-pathname') {|dir|
- Pathname("a/b/c/d").mkpath
+ path = Pathname("a/b/c/d")
+ assert_equal(path, path.mkpath)
assert_file.directory?("a/b/c/d")
}
end
@@ -1398,7 +1399,8 @@ def test_rmtree
with_tmpchdir('rubytest-pathname') {|dir|
Pathname("a/b/c/d").mkpath
assert_file.exist?("a/b/c/d")
- Pathname("a").rmtree
+ path = Pathname("a")
+ assert_equal(path, path.rmtree)
assert_file.not_exist?("a")
}
end
</code></pre>
<p>Github PR: <a href="https://github.com/ruby/ruby/pull/3705" class="external">https://github.com/ruby/ruby/pull/3705</a>. If accepted I will make a pr to update the tests here as well <a href="https://github.com/ruby/rbs/blob/b0dee64fdd00cc41c0729fa2c239fc2dcb9c3b18/test/stdlib/Pathname_test.rb#L456-L463" class="external">https://github.com/ruby/rbs/blob/b0dee64fdd00cc41c0729fa2c239fc2dcb9c3b18/test/stdlib/Pathname_test.rb#L456-L463</a>.</p> Ruby master - Feature #17291 (Assigned): Optimize __send__ callhttps://bugs.ruby-lang.org/issues/172912020-10-29T03:05:45Zmrkn (Kenta Murata)muraken@gmail.com
<p>I made a patch to optimize a <code>__send__</code> call. This optimization replaces a <code>__send__</code> method call with a call of the method whose name is the first argument of <code>__send__</code> method. The patch is available in <a href="https://github.com/ruby/ruby/pull/3720" class="external">this pull-request</a>.</p>
<p>By this change, the redefined <code>__send__</code> method is no longer called when it is called by a symbol method name. I guess it is no problem because the following warning message is displayed for a long time.</p>
<pre><code>$ ruby -e 'def __send__; end'
-e:1: warning: redefining `__send__' may cause serious problems
</code></pre>
<p>This proposal introduces two new instructions: <code>sendsym</code> and <code>opt_sendsym_without_block</code>. These instructions handle the cases that the first argument of <code>__send__</code> method is not a symbol literal. I think I can combine these two instructions into one if prefered.</p>
<p>This proposal includes the change proposed in <a class="issue tracker-2 status-1 priority-4 priority-default" title="Feature: Optimize __send__ call with a literal method name (Open)" href="https://bugs.ruby-lang.org/issues/17288">#17288</a>. I'll mark it as a duplicate of this proposal.</p>
<p>I don't handle <code>send</code> method in this proposal. The reason is that we need to examine the redefinition of <code>send</code> method in the instruction execution time. I want to discuss only <code>__send__</code> method in this ticket.</p>
<p>The benchmark result is below:</p>
<pre><code># Iteration per second (i/s)
| |compare-ruby|built-ruby|
|:----------------|-----------:|---------:|
|vm_send_sym | 18.001M| 112.208M|
| | -| 6.23x|
|vm_send_var | 17.779M| 30.922M|
| | -| 1.74x|
|vm_send_var_alt | 3.817M| 6.817M|
| | -| 1.79x|
</code></pre> Ruby master - Misc #17137 (Assigned): Cooperation on maintaining official docker ruby imageshttps://bugs.ruby-lang.org/issues/171372020-08-31T19:52:31Zdeivid (David Rodríguez)
<p>It was pointed out to me at <a href="https://github.com/docker-library/ruby/issues/323" class="external">https://github.com/docker-library/ruby/issues/323</a> that the ruby-core team has started maintaining their own docker images at <a href="https://github.com/ruby/ruby-docker-images" class="external">https://github.com/ruby/ruby-docker-images</a>, and that the base Dockerfiles were initially started from the official docker images.</p>
<p>The maintainers of the official images would be interesting in collaborating on maintaining these images. Maybe merging the projects would be a nice idea from an end user point of view. I'm guessing there's a reason why <a href="https://github.com/ruby/ruby-docker-images" class="external">https://github.com/ruby/ruby-docker-images</a> was started as a separate project, but maybe any improvements over the official project could be merged back. The obvious new feature that I see in the README is the ability to build development images of specific revisions.</p>
<p>Anyways, I mentioned the approach of the docker folks to hsbt and he told me to open a ticket here. So here it is!</p>
<p>Regards!</p> Ruby master - Feature #17111 (Assigned): Improve performance of Net::HTTPHeader#set_form by 40%https://bugs.ruby-lang.org/issues/171112020-08-10T04:09:30Ztonytonyjan (Weihang Jian)tonytonyjan@gmail.com
<a name="diff"></a>
<h2 >diff<a href="#diff" class="wiki-anchor">¶</a></h2>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gh">diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index a8901e7..3f1a008 100644
</span><span class="gd">--- a/lib/net/http/header.rb
</span><span class="gi">+++ b/lib/net/http/header.rb
</span><span class="p">@@ -475,9 +475,8 @@</span> def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
@body = nil
@body_stream = nil
@form_option = formopt
<span class="gd">- case enctype
- when /\Aapplication\/x-www-form-urlencoded\z/i,
- /\Amultipart\/form-data\z/i
</span><span class="gi">+ case enctype.downcase
+ when 'application/x-www-form-urlencoded', 'multipart/form-data'
</span> self.content_type = enctype
else
raise ArgumentError, "invalid enctype: #{enctype}"
</code></pre>
<a name="benchmark"></a>
<h2 >benchmark<a href="#benchmark" class="wiki-anchor">¶</a></h2>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'benchmark'</span>
<span class="nb">require</span> <span class="s1">'net/http'</span>
<span class="k">module</span> <span class="nn">Net::HTTPHeader</span>
<span class="k">def</span> <span class="nf">set_form2</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">enctype</span> <span class="o">=</span> <span class="s1">'application/x-www-form-urlencoded'</span><span class="p">,</span> <span class="n">formopt</span> <span class="o">=</span> <span class="p">{})</span>
<span class="vi">@body_data</span> <span class="o">=</span> <span class="n">params</span>
<span class="vi">@body</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="vi">@body_stream</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="vi">@form_option</span> <span class="o">=</span> <span class="n">formopt</span>
<span class="k">case</span> <span class="n">enctype</span><span class="p">.</span><span class="nf">downcase</span>
<span class="k">when</span> <span class="s1">'application/x-www-form-urlencoded'</span><span class="p">,</span> <span class="s1">'multipart/form-data'</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">content_type</span> <span class="o">=</span> <span class="n">enctype</span>
<span class="k">else</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">,</span> <span class="s2">"invalid enctype: </span><span class="si">#{</span><span class="n">enctype</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">500_000</span>
<span class="n">request</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Post</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">bm</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="no">GC</span><span class="p">.</span><span class="nf">disable</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">times</span> <span class="p">{</span> <span class="n">request</span><span class="p">.</span><span class="nf">set_form</span> <span class="p">[]</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">times</span> <span class="p">{</span> <span class="n">request</span><span class="p">.</span><span class="nf">set_form2</span> <span class="p">[]</span> <span class="p">}</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre>
<pre><code> user system total real
0.777054 0.101768 0.878822 ( 0.880472)
0.539860 0.088957 0.628817 ( 0.630178)
</code></pre>
<p>I don't see any test for <code>#set_form</code> in <code>test/net/http/test_httpheader.rb</code>, let me know if I need to add more tests, thanks!</p> Ruby master - Feature #16937 (Assigned): Add DNS over HTTP to Resolvhttps://bugs.ruby-lang.org/issues/169372020-06-07T23:46:44Zdrbrain (Eric Hodel)drbrain@segment7.net
<p>This adds a DNS over HTTP resolver at Resolv::DoH</p>
<p>It obeys RFC8484 with respect to Cache-Control and Age behavior, but does not use HTTP2 as ruby does not have an HTTP2 client.</p>
<p>It does not allow configuration of the Net::HTTP instance beyond timeouts, but I am willing to add more configuration if this is desired.</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 #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 - Feature #16657 (Assigned): Don't ship bundled gems as .gem files as well as in expa...https://bugs.ruby-lang.org/issues/166572020-02-27T06:50:02Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<p>Working at <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Extensions Do Not Compile on Mingw64 with mingw32-make (Closed)" href="https://bugs.ruby-lang.org/issues/16651">#16651</a>, I wonder why the release tarball ships with the bundled gem in form of .gem packages as well as the expanded sources. It would be nice, if one option is chosen. Ideally just the .gem packages, because these are vanilla upstream packages installable via RubyGems without rbinstall magic.</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 #16512 (Assigned): Improving `www.ruby-lang.org` reference by merging with `ru...https://bugs.ruby-lang.org/issues/165122020-01-16T08:38:13Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/710">@zverok (Victor Shepelev)</a> prepared better-looking reference pages at <code>rubyreferences.github.io</code>. I think there's room for improvement of reference pages on <code>www.ruby-lang.org</code>. <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/572">@hsbt (Hiroshi SHIBATA)</a> Is there a chance to work with?</p>
<p>Matz.</p> Ruby master - Feature #16461 (Assigned): Proc#usinghttps://bugs.ruby-lang.org/issues/164612019-12-28T03:32:34Zshugo (Shugo Maeda)
<a name="Overview"></a>
<h2 >Overview<a href="#Overview" class="wiki-anchor">¶</a></h2>
<p>I propose Proc#using to support block-level refinements.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">IntegerDivExt</span>
<span class="n">refine</span> <span class="no">Integer</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">/</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="n">quo</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">instance_eval_with_integer_div_ext</span><span class="p">(</span><span class="n">obj</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">using</span><span class="p">(</span><span class="no">IntegerDivExt</span><span class="p">)</span> <span class="c1"># using IntegerDivExt in the block represented by the Proc object</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">instance_eval</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># necessary where blocks are defined (not where Proc#using is called)</span>
<span class="n">using</span> <span class="no">Proc</span><span class="o">::</span><span class="no">Refinements</span>
<span class="nb">p</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">2</span> <span class="c1">#=> 0</span>
<span class="n">instance_eval_with_integer_div_ext</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">p</span> <span class="nb">self</span> <span class="o">/</span> <span class="mi">2</span> <span class="c1">#=> (1/2)</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">2</span> <span class="c1">#=> 0</span>
</code></pre>
<a name="PoC-implementation"></a>
<h2 >PoC implementation<a href="#PoC-implementation" class="wiki-anchor">¶</a></h2>
<p>For CRuby: <a href="https://github.com/shugo/ruby/pull/2" class="external">https://github.com/shugo/ruby/pull/2</a><br>
For JRuby: <a href="https://github.com/shugo/jruby/pull/1" class="external">https://github.com/shugo/jruby/pull/1</a></p>
<a name="Background"></a>
<h2 >Background<a href="#Background" class="wiki-anchor">¶</a></h2>
<p>I proposed <a href="https://bugs.ruby-lang.org/issues/12086" class="external">Feature #12086: using: option for instance_eval etc.</a> before, but it has problems:</p>
<ul>
<li>Thread safety: The same block can be invoked with different refinements in multiple threads, so it's hard to implement method caching.</li>
<li>_exec family support: {instance,class,module}_exec cannot be supported.</li>
<li>Implicit use of refinements: every blocks can be used with refinements, so there was implementation difficulty in JRuby and it has usability issue in headius's opinion.</li>
</ul>
<a name="Solutions-in-this-proposal"></a>
<h2 >Solutions in this proposal<a href="#Solutions-in-this-proposal" class="wiki-anchor">¶</a></h2>
<a name="Thread-safety"></a>
<h3 >Thread safety<a href="#Thread-safety" class="wiki-anchor">¶</a></h3>
<p>Proc#using affects the block represented by the Proc object, neither the specific Proc object nor the specific block invocation.<br>
Method calls in a block are resolved with refinements which are used by Proc#using in the block at the time.<br>
Once all possible refinements are used in the block, there is no need to invalidate method cache anymore.</p>
<p>See <a href="https://github.com/shugo/ruby/pull/2/commits/1c922614ad7d1fb43b73e195348c81da7a4546ef" class="external">these tests</a> to understand how it works.<br>
Which refinements are used is depending on the order of Proc#using invocations until all Proc#using calls are finished, but eventually method calls in a block are resolved with the same refinements.</p>
<a name="-_exec-family-support"></a>
<h3 >* _exec family support<a href="#-_exec-family-support" class="wiki-anchor">¶</a></h3>
<p><a href="https://bugs.ruby-lang.org/issues/12086" class="external">Feature #12086</a> was an extension of _eval family, so it cannot be used with _exec family, but Proc#using is independent from _eval family, and can be used with _exec family:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">instance_exec_with_integer_div_ext</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</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">using</span><span class="p">(</span><span class="no">IntegerDivExt</span><span class="p">)</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">instance_exec</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">Proc</span><span class="o">::</span><span class="no">Refinements</span>
<span class="nb">p</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">2</span> <span class="c1">#=> 0</span>
<span class="n">instance_exec_with_integer_div_ext</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">do</span> <span class="o">|</span><span class="n">other</span><span class="o">|</span>
<span class="nb">p</span> <span class="nb">self</span> <span class="o">/</span> <span class="n">other</span> <span class="c1">#=> (1/2)</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">2</span> <span class="c1">#=> 0</span>
</code></pre>
<a name="Implicit-use-of-refinements"></a>
<h3 >Implicit use of refinements<a href="#Implicit-use-of-refinements" class="wiki-anchor">¶</a></h3>
<p>Proc#using can be used only if <code>using Proc::Refinements</code> is called in the scope of the block represented by the Proc object.<br>
Otherwise, a RuntimeError is raised.</p>
<p>There are two reasons:</p>
<ul>
<li>JRuby creates a special CallSite for refinements at compile-time only when <code>using</code> is called at the scope.</li>
<li>When reading programs, it may help understanding behavior. IMHO, it may be unnecessary if libraries which uses Proc#using are well documented.</li>
</ul>
<p><code>Proc::Refinements</code> is a dummy module, and has no actual refinements.</p> Ruby master - Feature #16350 (Assigned): ArithmeticSequence#member? can result in infinite loophttps://bugs.ruby-lang.org/issues/163502019-11-16T17:20:32Zparker (Parker Finch)
<p>I'm not sure if this is a bug or a feature, it feels somewhere in between.</p>
<p>This is my first time contributing to the Ruby code, let me know what I can improve in this report!</p>
<p>ArithmeticSequence#member? enumerates through the sequence in order to determine if an element is included. (It just uses Enumerable#member?.) This leads to an infinite loop if the sequence is infinite and the element is not included, such as <code>1.step.member?(0)</code>.</p>
<p>I expected <code>1.step.member?(0)</code> to return <code>false</code>.</p>
<p>Since ArithmeticSequences are much more constrained than regular Enumerables, the #member? method can be overridden to efficiently determine if an element is included in the sequence.</p>
<p>I started implementing this change (patch attached) but got a little confused when trying to handle floats. Before digging in too deeply, I wanted to check if this is a change that will be accepted.</p>
<p>Let me know if I should keep looking into this!</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 - Feature #16027 (Assigned): Update Ruby's dtrace / USDT API to match what is exposed...https://bugs.ruby-lang.org/issues/160272019-07-27T17:22:38Zdalehamel (Dale Hamel)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>I propose that Ruby's "dtrace" support be extended to match what is available in the TracePoint API, as was the case until feature [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Accept "target" keyword on `TracePoint#enable` (Closed)" href="https://bugs.ruby-lang.org/issues/15289">#15289</a>] landed.</p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>I will refer to Ruby's "dtrace" bindings as USDT bindings for simplicity, as this is the typo of dtrace probe that they support.</p>
<p>Prior to [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Accept "target" keyword on `TracePoint#enable` (Closed)" href="https://bugs.ruby-lang.org/issues/15289">#15289</a>] being merged, Ruby's tracepoint API was able to trace only 'all' instances of a type of event.</p>
<p>Ruby added support for tracing ruby with dtrace, and so Ruby's USDT Ruby TracePoint API were "in sync".</p>
<p>Once the Ruby TracePoint API recently added the ability to do filtered tracing in [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Accept "target" keyword on `TracePoint#enable` (Closed)" href="https://bugs.ruby-lang.org/issues/15289">#15289</a>], it added new functionality but brought the TracePoint and USDT API out of sync.</p>
<p>Currently the TracePoint API is ahead of the USDT API, which presents the problem. There is valuable debug information available, but we do not have<br>
a way to access it with dtrace instrumentation.</p>
<p>Additionally, the recent release of bpftrace adds support for USDT tracing on linux, which makes this a valuable opportunity to be able to use Ruby's TracePoint API in an efficient and targeted way for production tracing. To achieve this, we must synchronize the features of the USDT and TracePoint API.</p>
<p>What is currently lacking is the ability to do filtered, selective tracing as the <code>TracePoint#enable</code> call now supports as per <a href="https://github.com/ruby/ruby/blob/master/prelude.rb#L141" class="external">prelude.rb#L141</a></p>
<a name="Proposal"></a>
<h1 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h1>
<p>When enabling a TracePoint, users can specify a flag: <code>usdt: [LIST_OF_SIMPLE_TYPES]</code>, which will trigger Ruby to also enable the USDT API for when it enables TracePoints.</p>
<p>Within the TracePoint block, users can call <code>tp.fire</code> to send USDT data. So the new default API is:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">trace</span><span class="p">.</span><span class="nf">enable</span><span class="p">(</span><span class="ss">target: </span><span class="kp">nil</span><span class="p">,</span> <span class="ss">target_line: </span><span class="kp">nil</span><span class="p">,</span> <span class="ss">target_thread: nil: usdt: </span><span class="kp">nil</span><span class="p">)</span>
</code></pre>
<p>And the usage might look like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">trace</span><span class="p">.</span><span class="nf">enable</span><span class="p">(</span><span class="ss">target: </span><span class="nb">method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">),</span> <span class="ss">target_line: </span><span class="mi">5</span><span class="p">,</span> <span class="ss">usdt: </span><span class="p">[</span><span class="no">Integer</span><span class="p">,</span> <span class="no">String</span><span class="p">])</span> <span class="k">do</span> <span class="o">|</span><span class="n">tp</span><span class="o">|</span>
<span class="n">tp</span><span class="p">.</span><span class="nf">fire</span><span class="p">(</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span><span class="p">,</span> <span class="s2">"Any String I want to send"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>The types specified must be simple types such as <code>Integer</code> or <code>String</code>, given by their names as constants. When data to the tracepoint, the types must match. If they don't, the tracer won't be able to interpret them properly, but nothing should crash.</p>
<a name="Details"></a>
<h1 >Details<a href="#Details" class="wiki-anchor">¶</a></h1>
<p>I propose that Ruby optionally generate ELF (Linux) or DOF (Darwin) annotations for TracePoint targets when they are enabled.</p>
<p>As ruby is a dynamic language, it cannot do this natively (yet) though Ruby JIT may make this easier, but for now it is not suitable for production use.</p>
<p>To get around this, Ruby can either generate the DOF or ELF stub shared library itself, for example it may do one per class, treating the class as the "provider" for the USDT API, and the methods as tracepoints. This is the approach used by <a href="https://github.com/chrisa/libusdt" class="external">libusdt</a>, which generates DOF usable on Darwin, BSD, and other platforms, and <a href="https://github.com/sthima/libstapsdt" class="external">libstapsdt</a>, which generates ELF stubs for use on linux.</p>
<p>When a tracepoint is triggered, the user may be able to call a new API <code>TracePoint#fire</code>, to send data to the Kernel via the USDT API, using the generated ELF stub as a bridge, giving the kernel an address to target in order to receive this data.</p>
<p>Upon enabling a tracepoint, we can either generate these stubs internally, or by linking to an external library that must be enabled at configure time (without this, USDT tracing wouldn't be enabled at all).</p>
<p>It may be possible to use the existing bridge that is used by ruby jit, or have an experimental flag such as <code>--usdt</code> that enables support for generating these stubs.</p>
<p>It may be more consistent with the future Ruby JIT to do this, or else Ruby can generate these stubs by its own native code, but this will require a sort of merging of libusdt and libstapsdt. This would add a dependency to the libelf development header, but that is probably not a problem on Linux platforms.</p>
<p>I would suggest the first approach, if this feature is accepted, would be to try and implement the ELF / DOF generation directly in Ruby. What libstapsdt and libusdt do isn't that complex and could be done in its own C file that probably wouldn't be too large.</p>
<p>Failing that approach, it may be worth investigating the Ruby JIT code to see if a compiler can generate these stubs for us easily. This approach would be to have ruby generate C code that results in the necessary DOF/ELF annotations, and have the compiler pipeline used by ruby JIT to generate the file. This couples the feature to ruby jit though.</p>
<a name="Usecase"></a>
<h1 >Usecase<a href="#Usecase" class="wiki-anchor">¶</a></h1>
<p>This feature would be used by dtrace / bpftrace users to debug ruby applications. It may be possible for other platforms to benefit from this too, but I think the main use case is for Linux system administrators and developers to use external debuggers (dtrace/bpftrace) to introspect Ruby's behavior.</p>
<a name="Discussion"></a>
<h1 >Discussion<a href="#Discussion" class="wiki-anchor">¶</a></h1>
<a name="Pros"></a>
<h2 >Pros:<a href="#Pros" class="wiki-anchor">¶</a></h2>
<ul>
<li>Syncs the Ruby TracePoint and USDT API</li>
<li>Allows for much more dynamic and targeted USDT tracing</li>
<li>Can help to find problems in both development and production</li>
<li>Can be used for performance and error analysis</li>
<li>Is better than printing, as emitting/collecting data is only done while a "debugger is attached"</li>
</ul>
<a name="Cons"></a>
<h2 >Cons:<a href="#Cons" class="wiki-anchor">¶</a></h2>
<ul>
<li>Complexity introduced, in order to generate the ELF/DOF stub files</li>
<li>Not easily ported to other platforms</li>
<li>Isn't fully consistent with the current dtrace functionality of Ruby, which is built-in to the VM</li>
</ul>
<a name="Limitation"></a>
<h1 >Limitation<a href="#Limitation" class="wiki-anchor">¶</a></h1>
<p>This will only work on *Nix platforms, and probably just on Linux to start, as that is where most of the benefits are.</p>
<p>If the Ruby JIT approach is preferred or much simpler, then that functionality will be tied to the Ruby JIT functionality.</p>
<a name="See-also"></a>
<h1 >See also<a href="#See-also" class="wiki-anchor">¶</a></h1>
<ul>
<li>
<a href="https://bpf.sh/usdt-report-doc/index.html" class="external">https://bpf.sh/usdt-report-doc/index.html</a> a document describing my experimental gem ruby-static-tracing, which prototypes this functionality outside of the RubyVM</li>
<li>
<a href="https://bpf.sh/production-breakpoints-doc/index.html" class="external">https://bpf.sh/production-breakpoints-doc/index.html</a> a work-in-progress on adding more dynamic method and line based USDT tracing to ruby, built atop ruby-static-tracing now using the ruby tracepoint API.</li>
</ul> 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 - Feature #16012 (Assigned): Add a (small) test-install suite?https://bugs.ruby-lang.org/issues/160122019-07-19T14:27:56ZMSP-Greg (Greg L)
<p>At various times there has been discussion about whether testing should require <code>make install</code>. Although I prefer to do testing using install (vs build), I see it as a choice, and not a requirement.</p>
<p>From time to time various issues have arisen that cannot be found with 'build' testing. Often, these issues cause CI test failure with master/trunk/ruby-head in external repos. Sometimes people blame 'Core', other times Travis, or rvm. Regardless, it doesn't look good.</p>
<p>So, might a small set of tests that check install functionality be added? It may need to be two separate (but equivalent) scripts. One for *nix, one for Windows.</p>
<p>In ruby-loco, I'm using a ps1 script to check that CLI bin files work. As soon as the update is pushed here, I'll add a test for nested bundler commands...</p> Ruby master - Feature #15939 (Assigned): Dump symbols reference to their fstr in ObjectSpace.dump()https://bugs.ruby-lang.org/issues/159392019-06-19T12:52:38Zbyroot (Jean Boussier)byroot@ruby-lang.org
<p>Patch: <a href="https://github.com/ruby/ruby/pull/2240" class="external">https://github.com/ruby/ruby/pull/2240</a></p>
<p>Symbols wether they are dynamic or static do hold a reference onto their respective fstring, so it's important to dump these references so that it's possible to see that a String isn't garbage collected because it has an associated Symbol.</p>
<p>Dumping a static Symbol (before):</p>
<pre><code>>> puts ObjectSpace.dump(:foobar)
{"type":"SYMBOL", "value":"foobar"}
</code></pre>
<p>after:</p>
<pre><code>>> puts ObjectSpace.dump(:foobar)
{"address":"0x7a210c", "type":"SYMBOL", "value":"foobar", "references":["0x7f8dd482c7d8"], "dynamic": false}
</code></pre>
<p>Dumping a dynamic Symbol (before):</p>
<pre><code>>> puts ObjectSpace.dump("foobar".to_sym)
{"address":"0x7fcdf7042eb0", "type":"SYMBOL", "class":"0x7fcdf70c8628", "frozen":true, "bytesize":6, "value":"foobar", "memsize":40, "flags":{"wb_protected":true}}
</code></pre>
<p>After:</p>
<pre><code>>> puts ObjectSpace.dump("foobar".to_sym)
{"address":"0x7fcdf7042eb0", "type":"SYMBOL", "class":"0x7fcdf70c8628", "frozen":true, "bytesize":6, "value":"foobar", "dynamic":true, "references":["0x7fcdf7042ed8"], "memsize":40, "flags":{"wb_protected":true}}
</code></pre>
<p>Limitations:</p>
<p><code>ObjectSpace.dump_all</code> rely on <code>rb_objspace_reachable_objects_from</code> to list an object's references.<br>
Because of this static symbol "references" are not followed, and as such are invisible in <code>ObjectSpace.dump_all</code>.</p>
<p>I'd like to correct it but it's quite more complicated because <code>rb_objspace_reachable_objects_from</code> is used by the GC, so I'd need to duplicate that function for <code>objspace_dump</code> usage.</p>
<p>So I wouldn't mind some opinion on that before attempting it.</p> Ruby master - Feature #15878 (Assigned): Make exit faster by not running GChttps://bugs.ruby-lang.org/issues/158782019-05-26T19:13:02Zgrosser (Michael Grosser)michael@grosser.it
<p>I noticed that exit takes 0.2 ... I'm trying to write a fast cli, so any improvement here would be great or an option to opt-out of certain cleanup tasks<br>
exit! takes a constant low time</p>
<pre><code>ruby -rbenchmark -e 'puts Benchmark.realtime { Process.wait(fork { exit }) }' # 0.03 great!
ruby -rbenchmark -rrubocop -e 'puts Benchmark.realtime { Process.wait(fork { exit }) }' # 0.18 :(
ruby -rbenchmark -rrubocop -e 'GC.disable; puts Benchmark.realtime { Process.wait(fork { exit }) }' # 0.04 :D
ruby -rbenchmark -rrubocop -e 'puts Benchmark.realtime { Process.wait(fork { exit! }) }' # 0.002 ... fast but unsafe
</code></pre> 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 - Feature #15628 (Assigned): init_inetsock_internal should fallback to IPv4 if IPv6 i...https://bugs.ruby-lang.org/issues/156282019-02-28T11:51:17Zsonalkr132 (Aditya Prakash)
<p>Hi,</p>
<p>This is not really bug but more of a missing feature. Let me layout steps to reproduce what I am trying to achieve:</p>
<ul>
<li>Add local entries for <code>example.com</code>
</li>
</ul>
<pre><code>$ echo "::1 example.com www.example.com
127.0.0.1 example.com www.example.com" | sudo tee --append /etc/hosts
</code></pre>
<ul>
<li>Add rule to <code>DROP</code> ipv6 packets: <code>sudo ip6tables -P INPUT DROP</code>
</li>
<li>Start a server: <code>ruby -rwebrick -e 'WEBrick::HTTPServer.new(Port: 8000).start'</code>
</li>
<li>Making request using Net:HTTP with timeout (<code>Net::OpenTimeout</code>) after after 60 seconds: <code>ruby -rnet/http -e "Net::HTTP.get(URI('http://example.com:8000'))"</code>
</li>
</ul>
<p>As far as I understand, <a href="https://github.com/ruby/ruby/blob/4444025d16ae1a586eee6a0ac9bdd09e33833f3c/ext/socket/ipsocket.c#L42" class="external">init_inetsock_internal</a> needs to fallback to ipv4 for Net::HTTP.get to work. IPv6 route being broke is expected and hence, <a href="https://tools.ietf.org/html/rfc8305" class="external">RFC8305</a> recommends fallback to IPv4.<br>
Support for IPv6 fallback is spotty across languages and http clients, for example, <a href="https://github.com/golang/go/blob/master/src/net/dial.go#L47" class="external">golang supports it</a> but python doesn't, making request with <code>curl</code> works but <code>wget</code> hangs.</p> 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 - Feature #15281 (Assigned): Speed up Set#intersect with size check.https://bugs.ruby-lang.org/issues/152812018-11-03T13:08:32ZRGBD (Oleg Zubchenko)
<p>Current implementation computes set intersection s1 & s2 in O(s2.size) time.<br>
It can be reduced to O([s1.size, s2.size].min) time.</p>
<p>Additional speedup comes from using #each instead of #do_with_enum.</p>
<p>See files attached for benchmarks.</p>
<p><a href="https://github.com/ruby/ruby/pull/2003" class="external">Pull Request</a></p>
<p>P.S. using benchmark-ips gem</p> Ruby master - Feature #15239 (Assigned): [patch] test-spec win32olehttps://bugs.ruby-lang.org/issues/152392018-10-20T19:32:07ZMSP-Greg (Greg L)
<p>Some of the current Win32OLE spec tests use the InternetExplorer control. This control is not available on Azure pipelines. Attached patch changes to use the MSXML control, adds a guard for it, and also does some refactoring to lower requires when not run under Windows, etc. Also, since the MSXML object is quite a bit 'smaller' than InternetExplorer, tests run faster.</p>
<p>Passed in my fork at <a href="https://ci.appveyor.com/project/MSP-Greg/ruby/builds/19663145" class="external">https://ci.appveyor.com/project/MSP-Greg/ruby/builds/19663145</a></p>
<p>Note also that since there have been recent commits stabilizing the spec suite, the above build job changed the mswin spec tests to run parallel, and they passed. The change from serial to parallel is not included in the patches. It is a separate commit in the branch on my fork.</p>
<p>GitHub patch is at:<br>
<a href="https://github.com/MSP-Greg/ruby/commit/d1daf9a66f491abfac5e84a50f152505baa1ccac.patch" class="external">https://github.com/MSP-Greg/ruby/commit/d1daf9a66f491abfac5e84a50f152505baa1ccac.patch</a></p> Ruby master - Feature #15166 (Assigned): 2.5 times faster implementation than current gcd implmen...https://bugs.ruby-lang.org/issues/151662018-09-26T18:30:29Zjzakiya (Jabari Zakiya)
<p>This is to be more explicit (and accurate) than <a href="https://bugs.ruby-lang.org/issues/15161" class="external">https://bugs.ruby-lang.org/issues/15161</a></p>
<p>This is my modified gcd benchmarks code, originally presented by Daniel Lemire (see 15161).</p>
<p><a href="https://gist.github.com/jzakiya/44eae4feeda8f6b048e19ff41a0c6566" class="external">https://gist.github.com/jzakiya/44eae4feeda8f6b048e19ff41a0c6566</a></p>
<p>Ruby's current implementation of Stein's gcd algorithm is only slightly faster than the<br>
code posted on the wikepedia page, and over 2.5 times slower than the fastest implementation<br>
in the benchmarks.</p>
<pre><code>[jzakiya@localhost ~]$ ./gcdbenchmarks
gcd between numbers in [1 and 2000]
gcdwikipedia7fast32 : time = 99
gcdwikipedia4fast : time = 121
gcdFranke : time = 126
gcdwikipedia3fast : time = 134
gcdwikipedia2fastswap : time = 136
gcdwikipedia5fast : time = 139
gcdwikipedia7fast : time = 138
gcdwikipedia2fast : time = 136
gcdwikipedia6fastxchg : time = 144
gcdwikipedia2fastxchg : time = 156
gcd_iterative_mod : time = 210
gcd_recursive : time = 215
basicgcd : time = 211
rubygcd : time = 267
gcdwikipedia2 : time = 321
gcd between numbers in [1000000001 and 1000002000]
gcdwikipedia7fast32 : time = 100
gcdwikipedia4fast : time = 121
gcdFranke : time = 126
gcdwikipedia3fast : time = 134
gcdwikipedia2fastswap : time = 136
gcdwikipedia5fast : time = 138
gcdwikipedia7fast : time = 138
gcdwikipedia2fast : time = 136
gcdwikipedia6fastxchg : time = 144
gcdwikipedia2fastxchg : time = 156
gcd_iterative_mod : time = 210
gcd_recursive : time = 215
basicgcd : time = 211
rubygcd : time = 269
gcdwikipedia2 : time = 323
</code></pre>
<p>This is Ruby's code per: <a href="https://github.com/ruby/ruby/blob/3abbaab1a7a97d18f481164c7dc48749b86d7f39/rational.c#L285-L307" class="external">https://github.com/ruby/ruby/blob/3abbaab1a7a97d18f481164c7dc48749b86d7f39/rational.c#L285-L307</a><br>
which is basically the wikepedia implementation.</p>
<pre><code>inline static long
i_gcd(long x, long y)
{
unsigned long u, v, t;
int shift;
if (x < 0)
x = -x;
if (y < 0)
y = -y;
if (x == 0)
return y;
if (y == 0)
return x;
u = (unsigned long)x;
v = (unsigned long)y;
for (shift = 0; ((u | v) & 1) == 0; ++shift) {
u >>= 1;
v >>= 1;
}
while ((u & 1) == 0)
u >>= 1;
do {
while ((v & 1) == 0)
v >>= 1;
if (u > v) {
t = v;
v = u;
u = t;
}
v = v - u;
} while (v != 0);
return (long)(u << shift);
}
</code></pre>
<p>This is the fastest implementation from the benchmarks. (I originally, wrongly, cited<br>
the implementation in the article, which is 4|5th fastest in benchmarks, but<br>
still almost 2x faster than the Ruby implementation.)</p>
<pre><code>// based on wikipedia's article,
// fixed by D. Lemire, K. Willets
unsigned int gcdwikipedia7fast32(unsigned int u, unsigned int v)
{
int shift, uz, vz;
if ( u == 0) return v;
if ( v == 0) return u;
uz = __builtin_ctz(u);
vz = __builtin_ctz(v);
shift = uz > vz ? vz : uz;
u >>= uz;
do {
v >>= vz;
int diff = v;
diff -= u;
if ( diff == 0 ) break;
vz = __builtin_ctz(diff);
if ( v < u ) u = v;
v = abs(diff);
} while( 1 );
return u << shift;
}
</code></pre>
<p>The key to speeding up all the algorithms is using the <code>__builtin_ctz(x)</code> directive<br>
to determine the number of trailing binary '0's.</p> 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 - Feature #14901 (Assigned): [PATCH] do not block SIGCHLD in normal Ruby Threadshttps://bugs.ruby-lang.org/issues/149012018-07-08T02:53:23Znormalperson (Eric Wong)normalperson@yhbt.net
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/10073">@k0kubun (Takashi Kokubun)</a>: any opinions on this? Thanks.</p>
<pre><code>I blocked SIGCHLD in normal Ruby Threads for [Bug #14867]
because I noticed at least two places which could not deal
with spurious wakeups in our test suite.
I also want to get rid of timer-thread due to resource
limitations <a href="https://blade.ruby-lang.org/ruby-core/87773">[ruby-core:87773]</a>. MJIT causes many SIGCHLD signals
so I found the following problems with cppflags=-DMJIT_FORCE_ENABLE=1
* OpenSSL::PKey::*.new does not resume on handle signals.
rhenium acknowledged the problem and it should be in trunk soon:
https://bugs.ruby-lang.org/issues/14882
* test/-ext-/gvl/test_last_thread.rb does not handle spurious
wakeups. Original report is in Japanese:
https://bugs.ruby-lang.org/issues/11237
I don't think it's a realistic expectation for code to be
unable to deal with spurious wakeups.
One alternative could be to handle signals with MJIT thread
when MJIT is enabled, or to lazy-spawn timer thread to handle
signals when MJIT is enabled (MJIT + gcc requires a lot of
resources, anyways).
</code></pre> Ruby master - Feature #14737 (Assigned): Split default gems into separate directory structurehttps://bugs.ruby-lang.org/issues/147372018-05-04T10:38:57Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<p>On Fedora, we are using operating_system.rb <a href="https://src.fedoraproject.org/rpms/ruby/blob/master/f/operating_system.rb" class="external">1</a>, <a href="https://src.fedoraproject.org/rpms/ruby/blob/f27/f/operating_system.rb" class="external">2</a> to setup various RubyGems paths. Unfortunately, if we change Gem.default_dir (which we want to point into user home directory on Fedora), then this also changes location for default gems (!!), which are later not discovered by RubyGems <a href="https://lists.fedoraproject.org/archives/list/ruby-sig@lists.fedoraproject.org/message/RZUUKFMNKRB6TGKCQT3FLZYANP5WLEKN/" class="external">3</a>. It was not been a big deal for use, since we used to unbundle the gems shipped in Ruby, but with the gemification of StdLib, unbundlig becomes unsustainable (it is more work, but mainly it is incompatible change).</p>
<p>To fix this issue, I modified the operating_system.rb to behave similarly to what Arch does <a href="https://wiki.archlinux.org/index.php/ruby" class="external">4</a>, i.e. we started to inject "--user-install" option <a href="https://src.fedoraproject.org/rpms/ruby/blob/master/f/operating_system.rb" class="external">1</a>. Unfortunately, this revealed the RubyGems are not respecting their own interfaces and I had to fix at least one of them along the way to make it work <a href="https://github.com/rubygems/rubygems/pull/2116" class="external">6</a>. Apparently, using the "--user-install" option itself has some drawbacks and what is worse, it is not respected by Bundler, which was recently pointed out <a href="https://bugzilla.redhat.com/show_bug.cgi?id=1574594" class="external">5</a>.</p>
<p>When I was fixing RubyGems <a href="https://github.com/rubygems/rubygems/pull/2116" class="external">6</a>, I just realized how the default gems are hacked up and how much is the original RubyGems configurability broken by this. This leads me to the proposal: <strong>Could we please install default gems into different directory then the other, user installed, gems?</strong> Since RubyGems were always designed to support various gem directory structures, the directory structure for default gems would become just other directory directory structure and would not collide with overrides in operating_system.rb, letting the distributions to override what was always designed to be overridable.</p>
<p>BTW I believe that one nice side effect of this change would be simplification of RubyGems code base. The default gems would live in "default_gems" directory, their .gemspec files could be in standard "default_gems/specifications" directory and we could forget about "default_gems/specifications/defaults", etc.</p>
<p>BTW2 I could fill this against RubyGems, but the default gems are Ruby stuff IMO, so I think this is appropriate tracker.</p> Ruby master - Feature #14476 (Assigned): Adding same_all? for checking whether all items in an Ar...https://bugs.ruby-lang.org/issues/144762018-02-14T15:41:30Zmrkn (Kenta Murata)muraken@gmail.com
<p>In this issue, I propose to introduce <code>same_all?</code> instance method of <code>Array</code> class. This new method checks whether all items in the receiver are the same.</p>
<p>Today, I needed to write a code to judge whether all items in an <code>Array</code> are the same. I wanted to make the following expression, which I've written first, more efficient.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">ary</span><span class="p">.</span><span class="nf">all?</span> <span class="p">{</span><span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="n">e</span><span class="p">.</span><span class="nf">foo</span> <span class="o">==</span> <span class="n">ary</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">foo</span> <span class="p">}</span>
</code></pre>
<p>I considered about the following simpler case, too.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">ary</span><span class="p">.</span><span class="nf">all?</span> <span class="p">{</span><span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="n">e</span> <span class="o">==</span> <span class="n">ary</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">}</span>
</code></pre>
<p>As I discussed with some CRuby committers and my colleagues at Speee, Inc., I found that both cases can be written more efficiently as follows:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># for the 1st case</span>
<span class="n">ary</span><span class="p">.</span><span class="nf">empty?</span> <span class="o">||</span> <span class="n">ary</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">foo</span><span class="p">.</span><span class="nf">yield_self</span> <span class="p">{</span><span class="o">|</span><span class="n">e0</span><span class="o">|</span> <span class="n">ary</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="nf">all?</span> <span class="p">{</span><span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="n">e</span><span class="p">.</span><span class="nf">foo</span> <span class="o">==</span> <span class="n">e0</span> <span class="p">}</span> <span class="p">}</span><span class="err"> </span>
<span class="c1"># for the 2nd case</span>
<span class="n">ary</span><span class="p">.</span><span class="nf">empty?</span> <span class="o">||</span> <span class="n">ary</span><span class="p">[</span><span class="mi">0</span><span class="o">..-</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="n">ary</span><span class="p">[</span><span class="mi">1</span><span class="o">..-</span><span class="mi">1</span><span class="p">]</span>
</code></pre>
<p>However, it is not easy to understand the intent of either expression, which is to check whether all items are the same.</p>
<p>I want to give this feature a clear name to make code readable. And I think it should be provided as a core feature because it can be made more efficient by being implemented in C language.</p>
<p>The benchmark script is: <a href="https://gist.github.com/mrkn/26a0fcfc431a45fe809fbbef95aceaf5" class="external">https://gist.github.com/mrkn/26a0fcfc431a45fe809fbbef95aceaf5</a><br>
I used it to find the efficient expressions. The example result of this benchmark on my MacBook Pro is here.</p>
<pre><code>$ ruby -v bench.rb
ruby 2.6.0dev (2018-02-14 trunk 62402) [x86_64-darwin16]
----------------------------------------
Benchmark case: shuffle
user system total real
all?-method-1 0.001525 0.000088 0.001613 ( 0.001632)
all?-method-2 0.000489 0.000031 0.000520 ( 0.000565)
all?-method-3 0.000444 0.000039 0.000483 ( 0.000482)
all?-item 0.000325 0.000078 0.000403 ( 0.000402)
opt-method 0.655959 0.033814 0.689773 ( 0.708515)
opt-item 0.000316 0.000001 0.000317 ( 0.000317)
----------------------------------------
Benchmark case: tail0
user system total real
all?-method-1 9.412810 0.231126 9.643936 ( 9.681118)
all?-method-2 5.375075 0.137908 5.512983 ( 5.754550)
all?-method-3 5.226132 0.167640 5.393772 ( 5.507031)
all?-item 0.873700 0.007545 0.881245 ( 0.917210)
opt-method 5.319648 0.172547 5.492195 ( 5.633140)
opt-item 0.174349 0.001974 0.176323 ( 0.183002)
----------------------------------------
Benchmark case: head0
user system total real
all?-method-1 0.002421 0.000068 0.002489 ( 0.002489)
all?-method-2 0.002169 0.000213 0.002382 ( 0.002382)
all?-method-3 0.001624 0.000026 0.001650 ( 0.001651)
all?-item 0.000623 0.000001 0.000624 ( 0.000624)
opt-method 4.779120 0.146312 4.925432 ( 4.951167)
opt-item 0.000629 0.000001 0.000630 ( 0.000629)
----------------------------------------
Benchmark case: all1
user system total real
all?-method-1 9.379650 0.255865 9.635515 ( 9.683078)
all?-method-2 4.950280 0.150659 5.100939 ( 5.140174)
all?-method-3 4.857898 0.129125 4.987023 ( 5.003142)
all?-item 0.694113 0.001295 0.695408 ( 0.702370)
opt-method 5.032373 0.121708 5.154081 ( 5.189599)
opt-item 0.170540 0.002069 0.172609 ( 0.180343)
</code></pre> Ruby master - Feature #14412 (Assigned): DRb UNIX on local machine: add support for getpeereid()https://bugs.ruby-lang.org/issues/144122018-01-27T17:26:32ZAnonymous
<p>Hi,</p>
<p><code>UNIXSocket</code> has this method <code>#getpeereid()</code> which returns effective user ID and effective group ID.</p>
<p>DRb using <code>drbunix://</code> on local machine doesn't support that method. In my use case, I need to verify clients via that method. So it would be great if you add support to DRb.</p>
<p>Actually that method <code>#getpeereid()</code> is from <code>BaseSocket</code>, but documentation states that it only supports UNIX sockets. I mean, it's a general method from parent class. So you can do the same with DRb: add some similar method, but only works via <code>drbunix://</code> on local machine. Otherwise you can raise error...</p>
<p>Thank you,</p> Ruby master - Feature #14397 (Assigned): public, protected and private should return their argume...https://bugs.ruby-lang.org/issues/143972018-01-24T21:27:26Zusa (Usaku NAKAMURA)usa@garbagecollect.jp
<p>Matsuda-san suggested me that <code>public</code>, <code>protected</code> and <code>private</code> should return their arguments instead of <code>self</code>,<br>
to write such code:`</p>
<pre><code class="Ruby syntaxhl" data-language="Ruby"><span class="nb">require</span> <span class="s2">"finalist"</span>
<span class="c1"># see https://github.com/joker1007/finalist</span>
<span class="k">class</span> <span class="nc">Foo</span>
<span class="kp">extend</span> <span class="no">Finalist</span>
<span class="n">final</span> <span class="kp">private</span> <span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I believe that it's reasonable request, and also believe that there is no product code which uses the return values of <code>public</code>, <code>protected</code> and <code>private</code>.<br>
Matz, how do you think about this change?<br>
The patch is attached.</p> Ruby master - Feature #13847 (Assigned): Gem activated problem for default gemshttps://bugs.ruby-lang.org/issues/138472017-08-29T08:53:45Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>If you try to use some default gems with a fixed version using Bundler, there are cases where the current RubyGems/Bundler/Ruby specification can not be used with the version specified by the user.</p>
<p>For example</p>
<pre><code>$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin17]
$ gem list | grep openssl
openssl (2.0.5, 2.0.4, default: 2.0.3)
</code></pre>
<p>In the environment such as <code>require 'openssl'</code>, the version that is activated when openssl is searched with openssl is the version found first, ie 2.0.5.</p>
<pre><code>$ ruby -ropenssl -e 'p OpenSSL::VERSION'
"2.0.5"
</code></pre>
<p>At this time, for example, suppose the user really wants to use openssl 2.0.4 and wrote the following Gemfile.</p>
<pre><code>> cat Gemfile
# frozen_string_literal: true
source "https://rubygems.org"
gem 'openssl', '2.0.4'
</code></pre>
<p>Unfortunately, since rubygems has required openssl before the bundler runs it will result in an activated error like this:</p>
<pre><code>> bundle exec ruby -ropenssl -e 'p OpenSSL::VERSION'
/path/to/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.15.4/lib/bundler/runtime.rb:317:in `check_for_activated_spec!': You have already activated openssl 2.0.5, but your Gemfile requires openssl 2.0.4. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)
</code></pre>
<p>This problem can be avoided by bundling it as a vendoring library under bundler's repository if it is a default gem implemented with pure ruby.</p>
<p><a href="Https://github.com/bundler/bundler/blob/master/lib/bundler/vendor/fileutils/lib/fileutils.rb" class="external">Https://github.com/bundler/bundler/blob/master/lib/bundler/vendor/fileutils/lib/fileutils.rb</a></p>
<p>In the case of bundler, by separating the namespace as <code>Bundler::FileUtils</code>, even the version specified by the user is made available without conflict at the time of activate. However, this method can not be used with C extension library.</p>
<p>Since we want to use json/psych from the bundler team with rubygems/bundler to serialize data, we need about whether we can implement a way to avoid some kind of C extension on Ruby itself.</p>
<p>I discussed with <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/7068">@indirect (André Arko)</a> who is maintainer of RubyGems/Bundler. We can resolve this problem like following feature of ruby.</p>
<pre><code>require_for_bundler 'json', '2.0.2'
</code></pre>
<p>When we declared above <code>require_for_bundler</code>, We put a json-2.0.2 to placed in a namespace like <code>Bundler::JSON</code>. There were similar issues in the past as well.</p>
<p><a href="https://bugs.ruby-lang.org/issues/10320" class="external">https://bugs.ruby-lang.org/issues/10320</a></p>
<p>I think that the way of writing <code>require 'json', version: '2.0.2', into: :Bundler</code> which extended the method like this issue seems like that. Also, in this use case, it seems to be enough to use <code>require 'json', version: :default, into: :Bundler</code> which forces the use of default gem.</p>
<p>Matz, How do you think about this feature?</p> Ruby master - Feature #13821 (Assigned): Allow fibers to be resumed across threadshttps://bugs.ruby-lang.org/issues/138212017-08-16T17:19:49Zcremes (Chuck Remes)
<p>Given a Fiber created in ThreadA, Ruby 2.4.1 (and earlier releases) raise a FiberError if the fiber is resumed in ThreadB or any other thread other than the one that created the original Fiber.</p>
<p>Sample code attached to demonstrate problem.</p>
<p>If Fibers are truly encapsulating all of the data for the continuation, we should be allowed to move them between Threads and resume their operation.</p>
<p>Why?</p>
<p>One use-case is to support the async-await asynchronous programming model. In that model, a method marked async runs <em>synchronously</em> until the #await method is encountered. At that point the method is suspended and control is returned to the caller. When the #await method completes (asynchronously) then it may resume the suspended method and continue. The only way to capture this program state, suspend and resume, is via a Fiber.</p>
<p>example:</p>
<pre><code>class Wait
include AsyncAwait
def dofirst
async do
puts 'Synchronously print dofirst.'
result = await { dosecond }
puts 'dosecond is complete'
result
end
end
def dosecond
async do
puts 'Synchronously print dosecond from async task.'
slept = await { sleep 3 }
puts 'Sleep complete'
slept
end
end
def run
task = dofirst
puts 'Received task'
p AsyncAwait::Task.await(task)
end
end
Wait.new.run
</code></pre>
<pre><code># Expected output:
# Synchronous print dofirst.
# Received task
# Synchronously print dosecond from async task.
# Sleep complete
# dosecond is complete
# 3
</code></pre>
<p>Right now the best way to accomplish suspension of the #dofirst and #dosecond commands and allow them to run asynchronously is by passing those blocks to <em>another thread</em> (other than the callers thread) so they can be encapsulated in a new Fiber and then yielded. When it's time to resume after #await completes, that other thread must lookup the fiber and resume it. This is lots of extra code and logic to make sure that fibers are only resumed on the threads that created them. Allowing Fibers to migrate between threads would eliminate this problem.</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 - Feature #13610 (Assigned): IPAddr doesn't provide helpful methods to get the subnet...https://bugs.ruby-lang.org/issues/136102017-05-29T09:57:09Zx89 (David John)ruby-lang@vaunt.eu
<p>I've implemented it myself using some "wild" code around the .inspect or default return from an IPAddr object from ipadr.rb</p>
<p>It would be nice to, once having loaded an IP range, to then be able to get its subnet, its IP and its CIDR.</p>
<p>I've created a PR: <a href="https://github.com/ruby/ruby/pull/1636" class="external">https://github.com/ruby/ruby/pull/1636</a> (although it's failing, not entirely sure why as Travis works fine on localhost!).</p>
<p>David</p> Ruby master - Feature #13604 (Assigned): Exposing alternative interface of readlinehttps://bugs.ruby-lang.org/issues/136042017-05-27T10:01:41Zgraywolf (Gray Wolf)
<p>GNU Readline has multiple modes of operation. At the moment, the readline extension only supports typical, <code>Readline.readline</code> mode. However, there is also alternative callback-based interface which is also useful.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require_relative</span> <span class="s1">'readline'</span>
<span class="no">PROMPT</span> <span class="o">=</span> <span class="s2">"rltest$ "</span>
<span class="vg">$running</span> <span class="o">=</span> <span class="kp">true</span>
<span class="vg">$sigwinch_received</span> <span class="o">=</span> <span class="kp">false</span>
<span class="no">Readline</span><span class="p">.</span><span class="nf">handler_install</span><span class="p">(</span><span class="no">PROMPT</span><span class="p">,</span> <span class="ss">add_hist: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
<span class="c1"># Can use ^D (stty eof) or `exit' to exit.</span>
<span class="k">if</span> <span class="o">!</span><span class="n">line</span> <span class="o">||</span> <span class="n">line</span> <span class="o">==</span> <span class="s2">"exit"</span>
<span class="nb">puts</span> <span class="k">unless</span> <span class="n">line</span>
<span class="nb">puts</span> <span class="s2">"exit"</span>
<span class="no">Readline</span><span class="p">.</span><span class="nf">handler_remove</span>
<span class="vg">$running</span> <span class="o">=</span> <span class="kp">false</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"input line: </span><span class="si">#{</span><span class="n">line</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Signal</span><span class="p">.</span><span class="nf">trap</span><span class="p">(</span><span class="s1">'SIGWINCH'</span><span class="p">)</span> <span class="p">{</span> <span class="vg">$sigwinch_received</span> <span class="o">=</span> <span class="kp">true</span> <span class="p">}</span>
<span class="k">while</span> <span class="vg">$running</span> <span class="k">do</span>
<span class="n">rs</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">select</span><span class="p">([</span><span class="vg">$stdin</span><span class="p">])</span>
<span class="k">if</span> <span class="vg">$sigwinch_received</span>
<span class="no">Readline</span><span class="p">.</span><span class="nf">resize_terminal</span>
<span class="vg">$sigwinch_received</span> <span class="o">=</span> <span class="kp">false</span>
<span class="k">end</span>
<span class="no">Readline</span><span class="p">.</span><span class="nf">read_char</span> <span class="k">if</span> <span class="n">r</span> <span class="o">=</span> <span class="n">rs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"rltest: Event loop has exited"</span>
</code></pre>
<p>Patch adding support for this is attached. This is my first try at contributing to ruby, so please tell me what I did wrong (I'm sure something, C is not my strong language).</p> Ruby master - Feature #13577 (Assigned): Digest.file accidentally receives File object but uses f...https://bugs.ruby-lang.org/issues/135772017-05-19T09:03:19Znaruse (Yui NARUSE)naruse@airemix.jp
<p>Digest::SHA256.file()'s first argument is file path name but it accidentally accepts file object.<br>
But for file objects created with O_TMPFILE to_path returns the directory of the temporary file and this File.open will fail.</p>
<pre><code> class ::Digest::Class
# Creates a digest object and reads a given file, _name_.
# Optional arguments are passed to the constructor of the digest
# class.
#
# p Digest::SHA256.file("X11R6.8.2-src.tar.bz2").hexdigest
# # => "f02e3c85572dc9ad7cb77c2a638e3be24cc1b5bea9fdbb0b0299c9668475c534"
def self.file(name, *args)
new(*args).file(name)
end
end
module Instance
# Updates the digest with the contents of a given file _name_ and
# returns self.
def file(name)
File.open(name, "rb") {|f|
buf = ""
while f.read(16384, buf)
update buf
end
}
self
end
</code></pre> Ruby master - Feature #13516 (Assigned): Improve the text of the circular require warninghttps://bugs.ruby-lang.org/issues/135162017-04-27T22:41:20Zjaredbeck (Jared Beck)jared@jaredbeck.com
<p>The warning currently reads:</p>
<p><code>loading in progress, circular require considered harmful - /my/file.rb</code></p>
<p>I think it would be more helpful like:</p>
<p><code>Circular require: Loading of /my/file.rb is already in progress, but require was called again</code></p>
<p>I think this is more helpful because it clarifies that /my/file.rb is the problem.</p>
<p>What do you think? Thanks!</p> Ruby master - Feature #13508 (Assigned): How remove/refactor code related mathn library.https://bugs.ruby-lang.org/issues/135082017-04-25T07:23:26Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>I removed mathn library at r58413 and r58432.</p>
<p>I have some concerns related mathn library. This issue is reminder for this concern.</p>
<ol>
<li>Still remains conditions for mathn loaded. ex. <a href="https://github.com/ruby/ruby/blob/trunk/array.c#L5755" class="external">https://github.com/ruby/ruby/blob/trunk/array.c#L5755</a>
</li>
<li>{complex,rational}.c have {nucomp,nurat}_canonicalization methods for mathn.</li>
<li>lib/cmath.rb have workaround code for mathn see. <a href="https://github.com/ruby/ruby/blob/trunk/lib/cmath.rb#L27" class="external">https://github.com/ruby/ruby/blob/trunk/lib/cmath.rb#L27</a>
</li>
</ol>
<p>I continue to discuss concerns to <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/482">@mrkn (Kenta Murata)</a></p> Ruby master - Feature #13388 (Assigned): gc.c: Add GC.get_parameters and .set_parametershttps://bugs.ruby-lang.org/issues/133882017-03-29T10:03:24Zmakimoto (Shimpei Makimoto)s@makimoto.org
<p>These methods are for inspecting and modifying MRI's GC parameters. It may be<br>
useful for realtime parameter tuning with GC.stat, user requests and so on.</p>
<p>This work is done by Tomohiro Moro (@slightair) and me (<a class="user active user-mention" href="https://bugs.ruby-lang.org/users/6929">@makimoto (Shimpei Makimoto)</a>).</p>
<p>GH issue: <a href="https://github.com/ruby/ruby/pull/1572" class="external">https://github.com/ruby/ruby/pull/1572</a></p>
<p>We're trying this patch with our environments and report here.</p> Ruby master - Feature #13252 (Assigned): C API for creating strings without copyinghttps://bugs.ruby-lang.org/issues/132522017-02-25T00:19:15Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<p>Hi,</p>
<p>I'd like to have a C API that allows me to create String objects without copying the underlying <code>char *</code>. Basically a C API similar to the <code>rb_str_new_static</code>, but have the GC free the underlying <code>char *</code> when the object dies. The use case is that at work we have C libraries that allocate <code>char *</code> and we want to pass those to Ruby land without copying the buffer. Here is an example of what we're doing now:</p>
<p><a href="https://github.com/arthurnn/memcached/commit/1886546944b420dc6953096ba1f5eae772001e31#diff-f508f9b8263ea397534b2b3f8efed987R147" class="external">https://github.com/arthurnn/memcached/commit/1886546944b420dc6953096ba1f5eae772001e31#diff-f508f9b8263ea397534b2b3f8efed987R147</a></p>
<p>I'd like it if there was a public API for doing something like this.</p>
<p>Thank you!</p>
<p>P.S. I am sure I can't be the first to ask for this, but I couldn't find a similar issue in RedMine, so if this has been answered I apologize.<br>
P.P.S. I've added a patch for kind of what I want.</p> Ruby master - Feature #13129 (Assigned): Refinements cannot refine method_missing and respond_to_...https://bugs.ruby-lang.org/issues/131292017-01-14T17:21:59Zmatsuda (Akira Matsuda)ronnie@dio.jp
<p>Refinements with method_missing and respond_to_missing? behaves very strangely.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">C</span><span class="p">;</span> <span class="k">end</span>
<span class="n">using</span> <span class="no">Module</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="n">refine</span> <span class="no">C</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">x</span><span class="p">()</span> <span class="nb">p</span><span class="ss">:x</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="n">m</span> <span class="o">==</span> <span class="ss">:foo</span> <span class="p">?</span> <span class="nb">p</span><span class="p">(</span><span class="ss">:fooo!</span><span class="p">)</span> <span class="p">:</span> <span class="k">super</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">respond_to_missing?</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">include_private</span> <span class="o">=</span> <span class="kp">false</span><span class="p">)</span>
<span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="ss">:foo</span><span class="p">)</span> <span class="o">||</span> <span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="p">}</span>
<span class="no">C</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">x</span>
<span class="nb">p</span> <span class="no">C</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">respond_to?</span> <span class="ss">:foo</span>
<span class="no">C</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">foo</span>
</code></pre>
<p>The script above doesn't respond_to :foo nor run :foo as expected.<br>
Actually, the result differs between ruby versions.</p>
<pre><code>% ruby -v t.rb
ruby 2.5.0dev (2017-01-14 trunk 57328) [x86_64-darwin15]
:x
false
t.rb:19:in `<main>': undefined method `foo' for #<C:0x007f90ca0fb240> (NoMethodError)
% ruby -v t.rb
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]
:x
false
t.rb:19:in `<main>': undefined method `foo' for #<C:0x007f80ae097780> (NoMethodError)
% ruby -v t.rb
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin15]
:x
false
t.rb:19:in `<main>': undefined method `foo' for #<C:0x007fd89c83b518> (NoMethodError)
% ruby -v t.rb
ruby 2.2.6p396 (2016-11-15 revision 56800) [x86_64-darwin15]
:x
false
:fooo!
% ruby -v t.rb
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-darwin15.0]
:x
false
:fooo!
% ruby -v t.rb
ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-darwin15.6.0]
t.rb:4: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!
:x
false
:fooo!
</code></pre>
<p>What I can tell is that method_missing was broken at somewhere in between 2.2 and 2.3, and respond_to_missing? has never worked correctly.</p> Ruby master - Feature #13047 (Assigned): Use String literal instead of `String#+` for multiline p...https://bugs.ruby-lang.org/issues/130472016-12-17T14:21:49Zmtsmfm (Fumiaki Matsushima)mtsmfm@gmail.com
<p>Multiline pretty-printing of multiline strings is introduced. (<a href="https://bugs.ruby-lang.org/issues/12664" class="external">https://bugs.ruby-lang.org/issues/12664</a>)</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">></span> <span class="n">pp</span> <span class="s2">"bundler.rb"</span><span class="o">=></span> <span class="s2">"module Bundler</span><span class="se">\n</span><span class="s2"> BundlerError = Class.new(Exception)</span><span class="se">\n</span><span class="s2"> def self.setup</span><span class="se">\n</span><span class="s2"> end</span><span class="se">\n</span><span class="s2">end</span><span class="se">\n</span><span class="s2">"</span>
<span class="p">{</span><span class="s2">"bundler.rb"</span><span class="o">=></span>
<span class="s2">"module Bundler</span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span>
<span class="s2">" BundlerError = Class.new(Exception)</span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span>
<span class="s2">" def self.setup</span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span>
<span class="s2">" end</span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span>
<span class="s2">"end</span><span class="se">\n</span><span class="s2">"</span><span class="p">}</span>
</code></pre>
<p>It is awesome but we can use String literal instead of <code>String#+</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">></span> <span class="n">pp</span> <span class="s2">"bundler.rb"</span><span class="o">=></span> <span class="s2">"module Bundler</span><span class="se">\n</span><span class="s2"> BundlerError = Class.new(Exception)</span><span class="se">\n</span><span class="s2"> def self.setup</span><span class="se">\n</span><span class="s2"> end</span><span class="se">\n</span><span class="s2">end</span><span class="se">\n</span><span class="s2">"</span>
<span class="p">{</span><span class="s2">"bundler.rb"</span><span class="o">=></span>
<span class="s2">"module Bundler</span><span class="se">\n</span><span class="s2">"</span> <span class="p">\</span>
<span class="s2">" BundlerError = Class.new(Exception)</span><span class="se">\n</span><span class="s2">"</span> <span class="p">\</span>
<span class="s2">" def self.setup</span><span class="se">\n</span><span class="s2">"</span> <span class="p">\</span>
<span class="s2">" end</span><span class="se">\n</span><span class="s2">"</span> <span class="p">\</span>
<span class="s2">"end</span><span class="se">\n</span><span class="s2">"</span><span class="p">}</span>
</code></pre>
<p>It seems that <code>pp</code> want to output evaluable snippet but we can override <code>String#+</code> so it may not work well.</p>
<p>Non-broken String will be:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">></span> <span class="n">pp</span> <span class="s2">"bundler.rb"</span><span class="o">=></span> <span class="s2">"module Bundler</span><span class="se">\n</span><span class="s2">end</span><span class="se">\n</span><span class="s2">"</span>
<span class="p">{</span><span class="s2">"bundler.rb"</span><span class="o">=></span> <span class="s2">"module Bundler</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"end</span><span class="se">\n</span><span class="s2">"</span><span class="p">}</span>
</code></pre>
<p>How do you think?</p>
<hr>
<p>I tried to write patch but I can't find a way to append "" to broken line only by current PP's API.</p> Ruby master - Feature #12676 (Assigned): Significant performance increase, and code conciseness, ...https://bugs.ruby-lang.org/issues/126762016-08-15T01:48:12Zjzakiya (Jabari Zakiya)
<p>I earlier posted code to simplify the prime_division method in prime.rb.<br>
This made the code much more concise and readable/understandable, while<br>
also providing a small speed increase.</p>
<p>The code presented here for prime_division2 maintains the conciseness and<br>
readability, but uses a different/simpler algorithm to provide a significant<br>
speed increase over the current implementation of prime_division in prime.rb.</p>
<p>Timings for selected large primes are provided, run on CRuby 2.3.1.<br>
System: System76 3.5GHz I7 cpu laptop, Linux 64-bit OS in Virtual Box.</p>
<pre><code>n1 = 100_000_000_000_000_003
n2 = 200_000_000_000_000_003
n3 = 1_000_000_000_000_000_003
n1 n2 n3
prime_division 23.7 33.5 74.6
prime_division1 22.9 32.2 72.8
prime_division2 14.8 20.5 45.8
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">tm</span><span class="p">;</span> <span class="n">s</span> <span class="o">=</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">;</span> <span class="k">yield</span><span class="p">;</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span> <span class="o">-</span> <span class="n">s</span> <span class="k">end</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">015</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">100_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">23.730239721</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">016</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">100_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division1</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">22.877657172</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">017</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">100_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division2</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">14.758561827</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">01</span><span class="mi">8</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">200_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">33.502851342</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">01</span><span class="mi">9</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">200_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division1</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">32.23911595</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">020</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">200_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division2</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">20.476660683</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">021</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1_000_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">74.630244055</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">022</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1_000_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division1</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">72.778948947</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">023</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1_000_000_000_000_000_003</span><span class="p">;</span> <span class="n">tm</span><span class="p">{</span> <span class="n">n</span><span class="p">.</span><span class="nf">prime_division2</span> <span class="p">}</span>
<span class="o">=></span> <span class="mf">45.802756121</span>
</code></pre>
<ol>
<li>
<p>Current code for prime_division in prime.rb.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">prime_division</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">generator</span> <span class="o">=</span> <span class="no">Prime</span><span class="o">::</span><span class="no">Generator23</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ZeroDivisionError</span> <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">value</span> <span class="o"><</span> <span class="mi">0</span>
<span class="n">value</span> <span class="o">=</span> <span class="o">-</span><span class="n">value</span>
<span class="n">pv</span> <span class="o">=</span> <span class="p">[[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]]</span>
<span class="k">else</span>
<span class="n">pv</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">end</span>
<span class="n">generator</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">prime</span><span class="o">|</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="p">(</span><span class="n">value1</span><span class="p">,</span> <span class="n">mod</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="nf">divmod</span><span class="p">(</span><span class="n">prime</span><span class="p">)</span>
<span class="n">mod</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">value1</span>
<span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="k">if</span> <span class="n">count</span> <span class="o">!=</span> <span class="mi">0</span>
<span class="n">pv</span><span class="p">.</span><span class="nf">push</span> <span class="p">[</span><span class="n">prime</span><span class="p">,</span> <span class="n">count</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">break</span> <span class="k">if</span> <span class="n">value1</span> <span class="o"><=</span> <span class="n">prime</span>
<span class="k">end</span>
<span class="k">if</span> <span class="n">value</span> <span class="o">></span> <span class="mi">1</span>
<span class="n">pv</span><span class="p">.</span><span class="nf">push</span> <span class="p">[</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>
<span class="k">end</span>
<span class="n">pv</span>
<span class="k">end</span>
</code></pre>
</li>
<li>
<p>Code simplification for current algorithm, increases conciseness/readability, with slight speedup.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">prime_division1</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">generator</span> <span class="o">=</span> <span class="no">Prime</span><span class="o">::</span><span class="no">Generator23</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ZeroDivisionError</span> <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">pv</span> <span class="o">=</span> <span class="n">value</span> <span class="o"><</span> <span class="mi">0</span> <span class="p">?</span> <span class="p">[[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]]</span> <span class="p">:</span> <span class="p">[]</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="nf">abs</span>
<span class="n">generator</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">prime</span><span class="o">|</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="p">(</span><span class="n">value1</span><span class="p">,</span> <span class="n">mod</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="nf">divmod</span><span class="p">(</span><span class="n">prime</span><span class="p">);</span> <span class="n">mod</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">value1</span>
<span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="n">pv</span><span class="p">.</span><span class="nf">push</span> <span class="p">[</span><span class="n">prime</span><span class="p">,</span> <span class="n">count</span><span class="p">]</span> <span class="k">unless</span> <span class="n">count</span> <span class="o">==</span> <span class="mi">0</span>
<span class="k">break</span> <span class="k">if</span> <span class="n">prime</span> <span class="o">></span> <span class="n">value1</span>
<span class="k">end</span>
<span class="n">pv</span><span class="p">.</span><span class="nf">push</span> <span class="p">[</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">value</span> <span class="o">></span> <span class="mi">1</span>
<span class="n">pv</span>
<span class="k">end</span>
</code></pre>
</li>
<li>
<p>Change of algorithm, maintains conciseness/readability with significant speed increase.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">prime_division2</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">generator</span> <span class="o">=</span> <span class="no">Prime</span><span class="o">::</span><span class="no">Generator23</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span>
<span class="k">raise</span> <span class="no">ZeroDivisionError</span> <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">pv</span> <span class="o">=</span> <span class="n">value</span> <span class="o"><</span> <span class="mi">0</span> <span class="p">?</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="p">:</span> <span class="p">[]</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="nf">abs</span>
<span class="n">sqrt_value</span> <span class="o">=</span> <span class="no">Math</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">value</span><span class="p">).</span><span class="nf">to_i</span>
<span class="n">generator</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">prime</span><span class="o">|</span>
<span class="k">break</span> <span class="k">if</span> <span class="n">prime</span> <span class="o">></span> <span class="n">sqrt_value</span>
<span class="k">while</span> <span class="n">value</span> <span class="o">%</span> <span class="n">prime</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">pv</span> <span class="o"><<</span> <span class="n">prime</span>
<span class="n">value</span> <span class="o">/=</span> <span class="n">prime</span>
<span class="n">sqrt_value</span> <span class="o">=</span> <span class="no">Math</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">value</span><span class="p">).</span><span class="nf">to_i</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">pv</span> <span class="o"><<</span> <span class="n">value</span> <span class="k">if</span> <span class="n">value</span> <span class="o">></span> <span class="mi">1</span>
<span class="n">pv</span><span class="p">.</span><span class="nf">group_by</span> <span class="p">{</span><span class="o">|</span><span class="n">prm</span><span class="o">|</span> <span class="n">prm</span> <span class="p">}.</span><span class="nf">map</span><span class="p">{</span><span class="o">|</span><span class="n">prm</span><span class="p">,</span> <span class="n">exp</span><span class="o">|</span> <span class="p">[</span><span class="n">prm</span><span class="p">,</span> <span class="n">exp</span><span class="p">.</span><span class="nf">size</span><span class="p">]</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre>
</li>
</ol> Ruby master - Feature #12656 (Assigned): Expand short paths with File.expand_pathhttps://bugs.ruby-lang.org/issues/126562016-08-04T20:06:47Zdavispuh (Dāvis Mosāns)
<p>Currently File.expand_path expands short path only if it's last part.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">puts</span> <span class="no">File</span><span class="p">.</span><span class="nf">expand_path</span><span class="p">(</span><span class="s1">'C:/VERYLO~1'</span><span class="p">)</span>
<span class="nb">puts</span> <span class="no">File</span><span class="p">.</span><span class="nf">expand_path</span><span class="p">(</span><span class="s1">'C:/VERYLO~1/OTHERL~1'</span><span class="p">)</span>
</code></pre>
<p>Produces</p>
<pre><code>C:/VeryLongName12345
C:/VERYLO~1/OtherLongName54321
</code></pre>
<p>With attached patch it will always be long path</p>
<pre><code>C:/VeryLongName12345
C:/VeryLongName12345/OtherLongName54321
</code></pre>
<p>This also fixes TestDir#test_glob test because it was failing due short path.</p> Ruby master - Feature #12653 (Assigned): Use wide WinAPI for rb_w32_getcwdhttps://bugs.ruby-lang.org/issues/126532016-08-03T18:33:23Zdavispuh (Dāvis Mosāns)
<p>Use wide WinAPI for rb_w32_getcwd.<br>
This will be needed so that Dir.pwd can support Unicode current directory on Windows.</p>
<p>I've attached a patch.</p> Ruby master - Feature #12639 (Assigned): Speed up require in RubyGems by 5xhttps://bugs.ruby-lang.org/issues/126392016-07-31T01:05:41Zsegiddins (Samuel Giddins)segiddins@segiddins.me
<p>This patch makes requiring an already-loaded file approximated 5x faster when the RubyGems mixin for require is present.<br>
Benchmarked via the following script:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"rubygems"</span>
<span class="nb">require</span> <span class="s2">"benchmark/ips"</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"ruby"</span><span class="p">)</span> <span class="p">{</span> <span class="n">gem_original_require</span> <span class="s2">"rubygems"</span> <span class="p">}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"rubygems"</span><span class="p">)</span> <span class="p">{</span> <span class="nb">require</span> <span class="s2">"rubygems"</span> <span class="p">}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">compare!</span>
<span class="k">end</span>
</code></pre>
<p>I understand that it's not ideal to add new global functions, and I'd appreciate guidance on where else I could expose this functionality to ruby code.</p>
<p>Thanks :)</p> Ruby master - Feature #12543 (Assigned): explicit tail call syntax: foo() then returnhttps://bugs.ruby-lang.org/issues/125432016-07-02T17:24:19Zmame (Yusuke Endoh)mame@ruby-lang.org
<p>How about introducing a new syntax for tail call?</p>
<pre><code>def foo()
foo()
end
foo() #=> stack level too deep
</code></pre>
<pre><code>def bar()
bar() then return
end
bar() #=> infinite loop
</code></pre>
<ul>
<li>no new keyword (cf. <code>goto foo()</code>)</li>
<li>no conflict with any existing syntax</li>
<li>an experimental patch is available (attached)</li>
<li>no shift/reduce nor reduce/reduce conflict in parse.y</li>
</ul>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@ruby-lang.org" class="email">mame@ruby-lang.org</a></p> Ruby master - Feature #12497 (Assigned): GMP version of divmod may be slowerhttps://bugs.ruby-lang.org/issues/124972016-06-16T17:04:12Zmame (Yusuke Endoh)mame@ruby-lang.org
<p><a href="https://benchmarksgame.alioth.debian.org/u64q/program.php?test=pidigits&lang=yarv&id=3" class="external">The benchmark program <code>pidigits.rb</code></a> runs faster if USE_GMP is disabled for divmod.</p>
<pre><code>$ time ./miniruby.orig pidigits.rb 10000 > /dev/null
real 0m5.932s
user 0m5.740s
sys 0m0.188s
</code></pre>
<pre><code>$ time ./miniruby.patched pidigits.rb 10000 > /dev/null
real 0m3.212s
user 0m3.056s
sys 0m0.152s
</code></pre>
<pre><code>diff --git a/bignum.c b/bignum.c
index 767659d..33a172e 100644
--- a/bignum.c
+++ b/bignum.c
@@ -2813,12 +2813,6 @@ rb_big_divrem_gmp(VALUE x, VALUE y)
static void
bary_divmod_branch(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT *xds, size_t xn, const BDIGIT *yds, size_t yn)
{
-#ifdef USE_GMP
- if (GMP_DIV_DIGITS < xn) {
- bary_divmod_gmp(qds, qn, rds, rn, xds, xn, yds, yn);
- return;
- }
-#endif
bary_divmod_normal(qds, qn, rds, rn, xds, xn, yds, yn);
}
</code></pre>
<p>We can possibly tune performance.</p> Ruby master - Feature #12281 (Assigned): Allow lexically scoped use of refinements with `using {}...https://bugs.ruby-lang.org/issues/122812016-04-14T03:48:01Zdanielpclark (Daniel P. Clark)6ftdan@gmail.com
<p>In Ruby 2.2.3 a refinement could be used in a begin/end block.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Moo</span>
<span class="n">refine</span> <span class="no">Fixnum</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="s2">"moo"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">begin</span> <span class="c1"># valid Ruby 2.2.3 and NOT Ruby 2.3</span>
<span class="n">using</span> <span class="no">Moo</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">to_s</span>
<span class="k">end</span>
<span class="c1"># => "moo"</span>
</code></pre>
<p>Since this use case has been removed I would like to propose an alternative.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">using</span> <span class="no">Moo</span> <span class="k">do</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">to_s</span>
<span class="k">end</span>
<span class="c1"># => "moo"</span>
</code></pre>
<p>I would like to propose allowing refinements to take a block and perform the refinement within the block and work just as if it were in it's own lexically scoped class.</p>
<p>I've been writing a lot of Rust lately and have found that their way of implementing Traits is just like Ruby's refinements except for that you can use Rust's version of refinements anywhere. Since Ruby's implementation is strictly lexically scoped I merely suggest a block syntax for <code>using</code> to allow greater expansion of refinements.</p>
<pre><code class="rust syntaxhl" data-language="rust"><span class="c1">// Rust</span>
<span class="k">impl</span> <span class="n">MyCapitalize</span> <span class="k">for</span> <span class="nb">String</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">my_capitalize</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="k">Self</span> <span class="p">{</span>
<span class="c1">// code here</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">use</span> <span class="n">MyCapitalize</span><span class="p">;</span>
<span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span><span class="nf">.my_capitalize</span><span class="p">()</span>
</code></pre>
<p>Rust lets you use the "refinement" of the trait implementation anywhere you use <code>use</code> just like Ruby's <code>using</code>. But currently Ruby restricts where <code>using</code> can be used. I would like that restriction to be lifted by allowing <code>using</code> to take a block.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Ruby</span>
<span class="k">module</span> <span class="nn">MyCapitalize</span>
<span class="n">refine</span> <span class="no">String</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">my_capitalize</span>
<span class="c1"># code here</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">MyCapitalize</span> <span class="k">do</span>
<span class="s2">"hello"</span><span class="p">.</span><span class="nf">my_capitalize</span>
<span class="k">end</span>
<span class="c1"># => "Hello"</span>
</code></pre>
<p>This way we keep Ruby's strict lexical scope behavior and at the same time allow refinement usage anywhere we need it.</p> Ruby master - Feature #12020 (Assigned): Documenting Ruby memory modelhttps://bugs.ruby-lang.org/issues/120202016-01-25T19:20:30Zpitr.ch (Petr Chalupa)
<p>Defining a memory model for a language is necessary to be able to reason about a program behavior in a concurrent or parallel environment.</p>
<p>There was a document created describing a Ruby memory model for concurrent-ruby gem, which fits several Ruby language implementations. It was necessary to be able to build lower-level unifying layer that enables creation of concurrency abstractions. They can be implemented only once against the layer, which ensures that it runs on all Ruby implementations.</p>
<p>The Ruby MRI implementation has stronger undocumented guaranties because of GIL semantics than the memory model, but the few relaxations from MRIs behavior allow other implementations to fit the model as well and to improve performance.</p>
<p>This issue proposes to document the Ruby memory model. The above mentioned memory model document which was created for concurrent-ruby can be used as a starting point: <a href="https://docs.google.com/document/d/1pVzU8w_QF44YzUCCab990Q_WZOdhpKolCIHaiXG-sPw/edit#" class="external">https://docs.google.com/document/d/1pVzU8w_QF44YzUCCab990Q_WZOdhpKolCIHaiXG-sPw/edit#</a>. Please comment in the document or here.</p>
<p>The aggregating issue of this effort can be found <a href="https://bugs.ruby-lang.org/issues/12019" class="external">here</a>.</p> Ruby master - Feature #11955 (Assigned): Expose Object that Receives logs in Loggerhttps://bugs.ruby-lang.org/issues/119552016-01-05T21:59:29Zschneems (Richard Schneeman)
<p>I need to be able to perform logic based on the destination of a current logger, this is currently not possible without <code>instance_variable_get</code>. Why would you need to see what destination a logger is going to? There is a common pattern in long lived programs like webservers. You want logs on disk for later reference, but you also want them in STDOUT to make development and debugging easier. Rails does this in development mode. Since there is no way to see if a logger is already going to STDOUT, it gets extended to log to STDOUT so logs show up twice.</p>
<p>While that example was complicated the logic I want is very simple: if you have a logger that is logging to STDOUT, do nothing, otherwise log to STDOUT and current logger. You cannot do this today without exposing the destination of the logger. This patch exposes the logger destination and allows us to write code like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">make_sure_logging_to_stdout</span><span class="p">(</span><span class="n">logger</span><span class="p">)</span>
<span class="k">unless</span> <span class="n">logger</span><span class="p">.</span><span class="nf">destination</span> <span class="o">==</span> <span class="no">STDOUT</span> <span class="c1"># <==== Cannot do this today</span>
<span class="n">stdout_logger</span> <span class="o">=</span> <span class="o">::</span><span class="no">Logger</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">STDOUT</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">extend</span><span class="p">(</span><span class="no">Module</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">add</span><span class="p">((</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="n">stdout_logger</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">logger</span> <span class="o">=</span> <span class="no">Logger</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">STDOUT</span><span class="p">)</span>
<span class="n">make_sure_logging_to_stdout</span><span class="p">(</span><span class="n">logger</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">fatal</span><span class="p">(</span><span class="s2">"An error has occured"</span><span class="p">)</span>
</code></pre>
<p>We should be able to inspect the destination of a logger, this patch enables this functionality.</p> Ruby master - Feature #11816 (Assigned): Partial safe navigation operatorhttps://bugs.ruby-lang.org/issues/118162015-12-14T18:19:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'm extremely surprised (and disappointed) that, currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">x</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="n">x</span><span class="o">&</span><span class="p">.</span><span class="nf">foo</span><span class="p">.</span><span class="nf">bar</span> <span class="c1"># => NoMethodError: undefined method `bar' for nil:NilClass</span>
</code></pre>
<p>To make it safe, you have to write <code>x&.foo&.bar</code>. But if <code>foo</code> is never supposed to return <code>nil</code>, then that code isn't "fail early" in case it actually does. <code>nil&.foo.bar</code> is more expressive, simpler and is perfect if you want to an error if <code>foo</code> returned <code>nil</code>. To actually get what you want, you have to resort using the old form <code>x && x.foo.bar</code>...</p>
<p>In CoffeeScript, you can write <code>x()?.foo.bar</code> and it will work well, since it gets compiled to</p>
<pre><code class="js syntaxhl" data-language="js"><span class="k">if </span><span class="p">((</span><span class="nx">_ref</span> <span class="o">=</span> <span class="nf">x</span><span class="p">())</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">_ref</span><span class="p">.</span><span class="nx">foo</span><span class="p">.</span><span class="nx">bar</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
<p>All the discussion in <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Introduce "Safe navigation operator" (Closed)" href="https://bugs.ruby-lang.org/issues/11537">#11537</a> focuses on <code>x&.foo&.bar</code>, so I have to ask:</p>
<p>Matz, what is your understanding of <code>x&.foo.bar</code>?</p>
<p>I feel the current implementation is not useful and should be changed to what I had in mind. I can't see any legitimate use of <code>x&.foo.bar</code> currently.</p> Ruby master - Feature #11625 (Assigned): Unlock GVL for SHA1 calculationshttps://bugs.ruby-lang.org/issues/116252015-10-27T19:34:06Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<p>I'm trying to calculate many sha1 checksums, but the current sha1 implementation doesn't unlock the GVL, so I can't do it in parallel. I've attached a patch that unlocks the GVL when calculating sha1sums so that I can do them in parallel.</p>
<p>The good point about this patch is that I can calculate sha1's in parallel. Here is the test code I'm using:</p>
<pre><code>require 'digest/sha1'
require 'thread'
Thread.abort_on_exception = true
THREADS = (ENV['THREADS'] || 1).to_i
store = 'x' * (ENV['SIZE'] || 1024).to_i
queue = Queue.new
600000.times do
queue << store
end
THREADS.times { queue << nil }
ts = THREADS.times.map {
Thread.new {
while work = queue.pop
Digest::SHA1.hexdigest(work)
end
}
}
ts.each(&:join)
</code></pre>
<p>Here is what the output looks like after I've applied the patch:</p>
<pre><code>[aaron@TC ruby (trunk)]$ THREADS=1 SIZE=4096 time ./ruby test.rb
22.62 real 21.78 user 0.66 sys
[aaron@TC ruby (trunk)]$ THREADS=4 SIZE=4096 time ./ruby test.rb
15.87 real 34.53 user 8.27 sys
[aaron@TC ruby (trunk)]$
</code></pre>
<p>The digests that I'm calculating are for fairly large strings, so this patch works well for me. The downsides are that it seems slightly slower (though I'm not sure that it's significant) with a single thread:</p>
<p>Test code:</p>
<pre><code>require 'benchmark/ips'
require 'digest/sha1'
Benchmark.ips do |x|
x.report('sha1') { Digest::SHA1.hexdigest('x' * 4096) }
end
</code></pre>
<p>Before my patch (higher numbers are better):</p>
<pre><code>[aaron@TC ruby (trunk)]$ ./ruby shaips.rb
Calculating -------------------------------------
sha1 2.604k i/100ms
-------------------------------------------------
sha1 27.441k (± 3.9%) i/s - 138.012k
</code></pre>
<p>After my patch:</p>
<pre><code>[aaron@TC ruby (trunk)]$ ./ruby shaips.rb
Calculating -------------------------------------
sha1 2.419k i/100ms
-------------------------------------------------
sha1 25.848k (± 2.8%) i/s - 130.626k
</code></pre>
<p>Other downside is that I changed the <code>update</code> method to dup strings so that the GVL can be safely released.</p>
<p>This patch pays off for me because of the size of the strings I'm working with, but I'm not sure if it's fine for the general case.</p> Ruby master - Feature #11527 (Assigned): IPAddr#mask_addr isn't a methodhttps://bugs.ruby-lang.org/issues/115272015-09-15T17:46:37Zfoca (Nicolás Sanguinetti)contacto@nicolassanguinetti.info
<p>Right now there's no way to get the current value of an IP address's mask from an IPAddr instance. While there's an instance variable (<code>@mask_addr</code>), there's no attribute reader to get it's value, and relying on reading the instance variable isn't pretty nice for a stdlib (stable as it might be).</p>
<p>Is there any particular reason why this is not public, or would a patch/pull request adding the corresponding <code>attr_reader</code> be accepted?</p> Ruby master - Feature #11028 (Assigned): standalone running single file ( zipped archives of ruby...https://bugs.ruby-lang.org/issues/110282015-04-03T03:44:09Zzaxebo1 (zaxebo zaxebo)zaxebo1@gmail.com
<p>standalone running single file ( zipped archives of ruby code) running <strong>without installation</strong> using "gem install ..."<br>
prior examples in other languages:</p>
<pre><code>python myprg.pyz
java -jar myprg.jar
</code></pre>
<a name="Detailed-Description"></a>
<h2 >Detailed Description:<a href="#Detailed-Description" class="wiki-anchor">¶</a></h2>
<p>In python, if i have multiple program files: "<code>a1.py</code>, <code>a2.py</code>, <code>__main__.py</code>,<br>
<code>dir1/b1.py</code>, <code>dir1/b2.py</code>" and then i zip it as myprogram1.pyz<br>
then i can run it as "python myprogram.pyz" (<code>__main__.py</code> inside the zip<br>
file will be executed first). It is easy to distribute a single file<br>
myprogram1.pyz</p>
<p>see: <a href="http://blogs.gnome.org/jamesh/2012/05/21/python-zip-files/" class="external">http://blogs.gnome.org/jamesh/2012/05/21/python-zip-files/</a></p>
<hr>
<p>in java also we can bundle all the .class files into a single .jar file<br>
and run it</p>
<pre><code>java -jar myprogram1.jar
</code></pre>
<hr>
<p>Currently in ruby the ".gem" file requires installation using "gem install ...". Then it gives some program file for running.<br>
What i am asking is that some gem file should have manifest with which they can run directly without installing</p>
<p>That is, i request you to kind provide a feature in ruby that if i have lots of files like: <code>a1.rb</code>, <code>a2.rb</code>, <code>__main__.rb</code>, <code>dir1/a4.rb</code> etc.<br>
(say, which uses Ruby-GTK for a Desktop application). Then i should be able to bundle them as zip file, say myprog1.zip or myprog1.pz ( rbz=ruby's zipped executable archive).<br>
And then i can distribute this "single file" and execute it as:</p>
<pre><code>ruby myprog1.rbz
</code></pre>
<p>This will execute the <code>__main__.rb</code> file among all the other .rb files,<br>
inside this .zip archive myprog1.rbz .<br>
Note: this .rbz file extension can be .gemz or whatever, but this functionality of "standalone running zipped archives of ruby code running without installation" is essential</p> Ruby master - Feature #10782 (Assigned): Patch: Add constants for BigDecimal for ZERO, ONE, TENhttps://bugs.ruby-lang.org/issues/107822015-01-25T16:24:59Zgarysweaver (Gary Weaver)garysweaver@gmail.com
<p>We found with use of BigDecimal that we were often needing to compare BigDecimal with zero or initialize BigDecimal as 0 for a default value. This introduces a bit move overhead than is typically needed, since a simple BigDecimal.new('0') will suffice without any additional arguments. This BigDecimal instance does not change, so it makes sense to make it a constant.</p>
<p>In Java, they found that constants for zero, one, and ten were useful (see <a href="http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#ZERO" class="external">http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#ZERO</a>), so I thought it would be good to submit a patch for Ruby 2.3.0, just to see whether others would find this useful. I understand that we don't want to have constants for every possible value, and that it might be helpful if these had the same object id across ruby implementations similar to lower integer values having the same object id, however I don't think it is necessary or useful to compare object_id's for BigDecimal value comparison- the point is only not to have to retain and create new instances of BigDecimal for ZERO, ONE, or TEN.</p> Ruby master - Feature #10637 (Assigned): Puppet orchestration on vagrant fails with Error: Non-HT...https://bugs.ruby-lang.org/issues/106372014-12-23T18:59:56Zeshenayo (Eshe Pickett)eshe.pickett@gmail.com
<p>I encountered this issue while bringing up a VM using vagrant with virtualbox. I am using puppet to do some provisioning</p>
<p>==> default: Notice: Downloading from <a href="https://forge.puppetlabs.com" class="external">https://forge.puppetlabs.com</a> ...<br>
==> default: Error: Non-HTTP proxy URI: https://[proxy]:[port]/ class is: URI::HTTPS<br>
==> default: Error: Try 'puppet help module install' for usage<br>
==> default: Notice: Preparing to install into /etc/puppet/modules ...<br>
==> default: Notice: Downloading from <a href="https://forge.puppetlabs.com" class="external">https://forge.puppetlabs.com</a> ...<br>
==> default: Error: Non-HTTP proxy URI: https://[proxy]:[port]/ class is: URI::HTTPS<br>
==> default: Error: Try 'puppet help module install' for usage</p>
<p>I put in the print out to see what class in the above output</p>
<p>Puppet is using https to download modules, and it hits the open_http function</p>
<p>def OpenURI.open_http(buf, target, proxy, options) # :nodoc:<br>
if proxy<br>
proxy_uri, proxy_user, proxy_pass = proxy<br>
raise "Non-HTTP proxy URI: #{proxy_uri} class is: #{proxy_uri.class}" if proxy_uri.class != URI::HTTP<br>
end</p>
<p>I am new to ruby, so am unsure if this is the expected behavior. I have a work around, I set https_proxy to use the http_proxy, however, this is not by any means a permanent solution. Alternatively, I could change the ruby code to allow both HTTP and HTTPS URIs, please advise.</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 - Feature #10481 (Assigned): Add "if" and "unless" clauses to rescue statementshttps://bugs.ruby-lang.org/issues/104812014-11-05T19:20:10Zjavawizard (Alex Boyd)alex@opengroove.org
<p>I'd like to propose a syntax change: allow boolean "if" and "unless" clauses to follow a rescue statement.</p>
<p>Consider the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="o">...</span>
<span class="k">rescue</span> <span class="no">SomeError</span> <span class="o">=></span> <span class="n">e</span>
<span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="nf">error_code</span> <span class="o">==</span> <span class="mi">1</span>
<span class="o">...</span><span class="n">handle</span> <span class="n">error</span><span class="o">...</span>
<span class="k">else</span>
<span class="k">raise</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>This is a fairly common way of dealing with exceptions where some condition above and beyond the exception's type determines whether the exception should be rescued. It's verbose, though, and it's not obvious at first glance exactly what conditions are being rescued, especially if "...handle error..." is more than a few lines long. I propose that the following be allowed:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="o">...</span>
<span class="k">rescue</span> <span class="no">SomeError</span> <span class="o">=></span> <span class="n">e</span> <span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="nf">error_code</span> <span class="o">==</span> <span class="mi">1</span>
<span class="o">...</span><span class="n">handle</span> <span class="n">error</span><span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>"unless" would, of course, be allowed as well:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="o">...</span>
<span class="k">rescue</span> <span class="no">SomeError</span> <span class="o">=></span> <span class="n">e</span> <span class="k">unless</span> <span class="n">e</span><span class="p">.</span><span class="nf">error_code</span> <span class="o">==</span> <span class="mi">2</span>
<span class="o">...</span><span class="n">handle</span> <span class="n">error</span><span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>A rescue statement whose boolean condition failed would be treated the same as if the exception being raised didn't match the exception being rescued, and move on to the next rescue statement:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="o">...</span>
<span class="k">rescue</span> <span class="no">SomeError</span> <span class="o">=></span> <span class="n">e</span> <span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="nf">error_code</span> <span class="o">==</span> <span class="mi">1</span>
<span class="o">...</span><span class="n">handle</span> <span class="n">error</span> <span class="n">code</span> <span class="mi">1</span><span class="o">...</span>
<span class="k">rescue</span> <span class="no">SomeError</span> <span class="o">=></span> <span class="n">e</span> <span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="nf">error_code</span> <span class="o">==</span> <span class="mi">2</span>
<span class="o">...</span><span class="n">handle</span> <span class="n">error</span> <span class="n">code</span> <span class="mi">2</span><span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>And finally, catch-all rescue statements would be allowed as well:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">begin</span>
<span class="o">...</span>
<span class="k">rescue</span> <span class="o">=></span> <span class="n">e</span> <span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="nf">message</span> <span class="o">==</span> <span class="s2">"some error"</span>
<span class="o">...</span><span class="n">handle</span> <span class="n">error</span><span class="o">...</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #10459 (Assigned): [PATCH] rfc3339 method for Timehttps://bugs.ruby-lang.org/issues/104592014-10-30T11:12:16ZAntiarchitect (Andrey Voronkov)voronkovaa@gmail.com
<p>Alias for iso8601 method for compatibility with DateTime (Ruby on Rails).</p> Ruby master - Feature #10129 (Assigned): More descriptive error message for failed net/http requestshttps://bugs.ruby-lang.org/issues/101292014-08-13T22:34:43Zxshay (Xavier Shay)contact@xaviershay.com
<p>Hello,<br>
I would like to propose the following patch:</p>
<p>Before</p>
<pre><code>2.1.2 :003 > Net::HTTP.get(URI.parse("https://arsrtrtrstsrt.com/arstr"))
SocketError: getaddrinfo: nodename nor servname provided, or not known
</code></pre>
<p>After</p>
<pre><code>2.1.2 :003 > Net::HTTP.get(URI.parse("https://arsrtrtrstsrt.com/arstr"))
SocketError: Failed to open TCP connection to arsrtrtrstsrt.com:443 (getaddrinfo: nodename nor servname provided, or not known)
</code></pre>
<p>I have an implementation with test at <a href="https://github.com/ruby/ruby/pull/700" class="external">https://github.com/ruby/ruby/pull/700</a></p>
<p>Thank you for your consideration,<br>
Xavier</p> Ruby master - Feature #10038 (Assigned): Extend ObjectSpace.dump to expose buffer addresses for S...https://bugs.ruby-lang.org/issues/100382014-07-15T07:15:45Zko1 (Koichi Sasada)
<p>ObjectSpace.dump() expose internal information in JSON.<br>
How about to expose buffer addresses for String and Array?</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gh">Index: ext/objspace/objspace_dump.c
===================================================================
</span><span class="gd">--- ext/objspace/objspace_dump.c (revision 46821)
</span><span class="gi">+++ ext/objspace/objspace_dump.c (working copy)
</span><span class="p">@@ -178,12 +178,16 @@</span> dump_object(VALUE obj, struct dump_confi
dump_append(dc, ", \"broken\":true");
if (FL_TEST(obj, RSTRING_FSTR))
dump_append(dc, ", \"fstring\":true");
<span class="gd">- if (STR_SHARED_P(obj))
</span><span class="gi">+
+ if (STR_SHARED_P(obj)) {
</span> dump_append(dc, ", \"shared\":true");
<span class="gi">+ }
</span> else {
dump_append(dc, ", \"bytesize\":%ld", RSTRING_LEN(obj));
<span class="gd">- if (!STR_EMBED_P(obj) && !STR_SHARED_P(obj) && (long)rb_str_capacity(obj) != RSTRING_LEN(obj))
</span><span class="gi">+ if (!STR_EMBED_P(obj) && !STR_SHARED_P(obj) && (long)rb_str_capacity(obj) != RSTRING_LEN(obj)) {
</span> dump_append(dc, ", \"capacity\":%ld", rb_str_capacity(obj));
<span class="gi">+ dump_append(dc, ", \"ptr\":\"%p\"", RSTRING_PTR(obj));
+ }
</span>
if (is_ascii_string(obj)) {
dump_append(dc, ", \"value\":");
<span class="p">@@ -205,8 +209,14 @@</span> dump_object(VALUE obj, struct dump_confi
dump_append(dc, ", \"length\":%ld", RARRAY_LEN(obj));
if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, ELTS_SHARED))
dump_append(dc, ", \"shared\":true");
<span class="gd">- if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, RARRAY_EMBED_FLAG))
</span><span class="gi">+ if (RARRAY_LEN(obj) > 0) {
+ if (FL_TEST(obj, RARRAY_EMBED_FLAG)) {
</span> dump_append(dc, ", \"embedded\":true");
<span class="gi">+ }
+ else {
+ dump_append(dc, ", \"ptr\":\"%p\"", RARRAY_PTR(obj));
+ }
+ }
</span> break;
case T_CLASS:
</code></pre>
<p>With this hack, we can know the real memory address of them and cooperate with other native tools.</p>
<p>BTW, ObjectSpace.dump() should support T_SYMBOL.</p> Ruby master - Feature #9830 (Assigned): Support for GOST private/public keyshttps://bugs.ruby-lang.org/issues/98302014-05-11T20:34:05ZEnvek (Andrey Novikov)envek@envek.name
<p>Hello everyone.</p>
<p>We're required to use GOST encryption algorithms for signing requests, interacting with HTTPS services with client certificate authentication and so on.</p>
<p>OpenSSL 1.0.0 is bundled with GOST engine, and, if correctly configured, can handle all of these tasks from command line. Also see <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Ruby doesn't respect system OpenSSL configuration (Closed)" href="https://bugs.ruby-lang.org/issues/9822">#9822</a>.</p>
<p><strong>Issue</strong></p>
<p>Ruby can't read GOST private and public keys:</p>
<pre><code>ruby> privkey = OpenSSL::PKey.read(File.read('gost_r_34_10_2001_private_key.pem'))
OpenSSL::PKey::PKeyError: unsupported key type
ruby> # Same for public keys
ruby> crt = OpenSSL::X509::Certificate.new(File.read('gost_r_34_10_2001_certificate.pem'))
ruby> crt.public_key
OpenSSL::PKey::PKeyError: unsupported key type
</code></pre>
<p>The problem is there is no "Generic PKey" class in Ruby's OpenSSL.</p>
<p>In source in <code>ext/openssl/openssl_pkey.c</code> at line 76 in method <code>ossl_pkey_new</code> there is examination of key type and creating appropriate Ruby classes. But GOST R 34.10-2001 key type have type <code>NID_id_GostR3410_2001</code> (811), and Ruby fails.</p>
<p><strong>Possible solution</strong></p>
<p>GOST keys are EC keys in fact (at least for GOST R 34.10-2001). And, if I add <code>case NID_id_GostR3410_2001:</code> right before <code>case EVP_PKEY_EC:</code> and remove checks about key type in <code>ext/openssl/openssl_pkey_ec.c</code> – everything will work.</p>
<p>To illustrate this, I've attached required patches (one from issue <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Ruby doesn't respect system OpenSSL configuration (Closed)" href="https://bugs.ruby-lang.org/issues/9822">#9822</a>), self-signed GOST R 34.10-2001 certificate with private key and two test scripts.</p>
<p><strong>NOTE</strong>: You will need OpenSSL version 1.0.0 or newer with correct configuration, see links below!</p>
<p><strong>Question</strong></p>
<p>How should GOST keys support implemented in Ruby? Should it even use <code>OpenSSL::PKey::EC</code>, or, may be, subclass from it?</p>
<p>I'm not experienced neither in C programming nor in cryptography, but I would be glad to help with the implementation of this.</p>
<p><strong>Further information</strong></p>
<ul>
<li>
<strong>README.gost</strong>: Instructions for setting up OpenSSL and usage: <a href="https://github.com/openssl/openssl/blob/master/engines/ccgost/README.gost" class="external">https://github.com/openssl/openssl/blob/master/engines/ccgost/README.gost</a>
</li>
<li>
<strong>OpenSSL GOST engine source</strong>: <a href="https://github.com/openssl/openssl/tree/master/engines/ccgost" class="external">https://github.com/openssl/openssl/tree/master/engines/ccgost</a>
</li>
<li>
<strong>RFC 5830</strong>: GOST 28147-89: Encryption, Decryption, and Message Authentication Code (MAC) Algorithms:<br>
<a href="http://tools.ietf.org/html/rfc5830" class="external">http://tools.ietf.org/html/rfc5830</a>
</li>
<li>
<strong>RFC 5831</strong>: GOST R 34.11-94: Hash Function Algorithm:<br>
<a href="http://tools.ietf.org/html/rfc5831" class="external">http://tools.ietf.org/html/rfc5831</a>
</li>
<li>
<strong>RFC 5832</strong>: GOST R 34.10-2001: Digital Signature Algorithm:<br>
<a href="http://tools.ietf.org/html/rfc5832" class="external">http://tools.ietf.org/html/rfc5832</a>
</li>
<li>
<strong>RFC 4491</strong>: Using the GOST Algorithms with the Internet X.509 Public Key Infrastructure:<br>
<a href="http://tools.ietf.org/html/rfc4491" class="external">http://tools.ietf.org/html/rfc4491</a>
</li>
<li>
<strong>RFC 4490</strong>: Using the GOST Algorithms with Cryptographic Message Syntax (CMS):<br>
<a href="http://tools.ietf.org/html/rfc4490" class="external">http://tools.ietf.org/html/rfc4490</a>
</li>
<li>
<strong>RFC 4357</strong>: Additional Cryptographic Algorithms for Use with GOST Algorithms</li>
<li>Some stackoverflow.com related questions: <a href="http://stackoverflow.com/questions/12868384/openssl-gost-parameter-set" class="external">http://stackoverflow.com/questions/12868384/openssl-gost-parameter-set</a> and <a href="http://stackoverflow.com/questions/14580340/generate-gost-34-10-2001-keypair-and-save-it-to-some-keystore" class="external">http://stackoverflow.com/questions/14580340/generate-gost-34-10-2001-keypair-and-save-it-to-some-keystore</a>
</li>
</ul> Ruby master - Feature #9816 (Assigned): 文字列内の数字を数値として比較するメソッドhttps://bugs.ruby-lang.org/issues/98162014-05-08T09:37:26Znaruse (Yui NARUSE)naruse@airemix.jp
<p>文字列内の数字を数値として比較するメソッドを追加しませんか</p>
<p>そのような比較は一般的な用途としてはGUIシェルのファイラーが比較に用いており、<br>
Windows では StrCmpLogicalW が、OS X では NSString:compare:options:へのNSNumericSearch定数が提供されています。<br>
<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb759947(v=vs.85).aspx" class="external">http://msdn.microsoft.com/en-us/library/windows/desktop/bb759947(v=vs.85).aspx</a><br>
<a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/c/econst/NSNumericSearch" class="external">https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/c/econst/NSNumericSearch</a></p>
<p>上記のような処理自体はさほど難しいものではありませんが、Rubyレベルで実装すると大量のオブジェクトを作ってしまいます。<br>
例えば <code>Gem::Version.new("2.1.10".freeze)<=>Gem::Version.new("2.1.9".freeze)</code> は47個、<br>
<code>"2.1.10".freeze.split('.').map(&:to_i)<=>"2.1.9".freeze.split('.').map(&:to_i)</code> だと16個のオブジェクトを作ります。<br>
<code>"2.1.10".freeze.numericcmp"2.1.9".freeze</code> ならば、もちろんオブジェクトは一つも作りません。</p>
<p>なお、上記の例でも示唆していますが、本メソッドは Ruby のバージョン表記の TEENY が2桁になった場合の比較に用いることができます。</p>
<p>パッチは以下の通りです。<br>
なお、メソッド名は String#numericcmp としています。<br>
(String#casecmpを念頭に置いた)</p>
<pre><code>diff --git a/string.c b/string.c
index c589c80..66f667f 100644
--- a/string.c
+++ b/string.c
@@ -2569,6 +2569,131 @@ rb_str_casecmp(VALUE str1, VALUE str2)
return INT2FIX(-1);
}
+VALUE
+numerical_compare(const char **pp1, const char *p1end, const char **pp2, const char *p2end)
+{
+ const char *s1 = *pp1, *p1, *s2 = *pp2, *p2;
+ ptrdiff_t len1, len2;
+ int r;
+
+ while (s1 < p1end && *s1 == '0') s1++;
+ p1 = s1;
+ while (p1 < p1end && ISDIGIT(*p1)) p1++;
+ len1 = p1 - s1;
+
+ while (s2 < p2end && *s2 == '0') s2++;
+ p2 = s2;
+ while (p2 < p2end && ISDIGIT(*p2)) p2++;
+ len2 = p2 - s2;
+
+ if (len1 != len2) {
+ return INT2FIX(len1 < len2 ? -1 : 1);
+ }
+
+ r = memcmp(s1, s2, len1);
+ if (r) return r < 0 ? INT2FIX(-1) : INT2FIX(1);
+
+ len1 = s1 - *pp1;
+ len2 = s2 - *pp2;
+ if (len1 != len2) {
+ return INT2FIX(len1 < len2 ? -1 : 1);
+ }
+
+ *pp1 = p1;
+ *pp2 = p2;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * str.numericcmp(other_str) -> -1, 0, +1 or nil
+ *
+ * Variant of <code>String#<=></code>, which considers digits in strings
+ * are numeric value..
+ *
+ * "a1".numericcmp("a1") #=> 0
+ * "aa".numericcmp("a1") #=> 1
+ * "a1".numericcmp("aa") #=> -1
+ * "a1".numericcmp("a01") #=> -1
+ * "2.1.2".numericcmp("2.1.10") #=> 1
+ */
+
+static VALUE
+rb_str_numericcmp(VALUE str1, VALUE str2)
+{
+ long len;
+ rb_encoding *enc;
+ const char *p1, *p1end, *p2, *p2end;
+
+ StringValue(str2);
+ enc = rb_enc_compatible(str1, str2);
+ if (!enc) {
+ return Qnil;
+ }
+
+ p1 = RSTRING_PTR(str1); p1end = RSTRING_END(str1);
+ p2 = RSTRING_PTR(str2); p2end = RSTRING_END(str2);
+ if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
+ while (p1 < p1end && p2 < p2end) {
+ if (ISDIGIT(*p1)) {
+ if (ISDIGIT(*p2)) {
+ VALUE r = numerical_compare(&p1, p1end, &p2, p2end);
+ if (!NIL_P(r)) return r;
+ }
+ else {
+ return INT2FIX(-1);
+ }
+ }
+ else if (ISDIGIT(*p2)) {
+ return INT2FIX(1);
+ }
+ if (*p1 != *p2) return INT2FIX(*p1 < *p2 ? -1 : 1);
+ p1++;
+ p2++;
+ }
+ }
+ else {
+ while (p1 < p1end && p2 < p2end) {
+ int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
+ int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
+
+ if (0 <= c1 && 0 <= c2) {
+ if (ISDIGIT(*p1)) {
+ if (ISDIGIT(*p2)) {
+ VALUE r = numerical_compare(&p1, p1end, &p2, p2end);
+ if (!NIL_P(r)) return r;
+ }
+ else {
+ return INT2FIX(-1);
+ }
+ }
+ else if (ISDIGIT(*p2)) {
+ return INT2FIX(1);
+ }
+ if (*p1 != *p2) return INT2FIX(*p1 < *p2 ? -1 : 1);
+ p1++;
+ p2++;
+ }
+ else {
+ int r;
+ l1 = rb_enc_mbclen(p1, p1end, enc);
+ l2 = rb_enc_mbclen(p2, p2end, enc);
+ len = l1 < l2 ? l1 : l2;
+ r = memcmp(p1, p2, len);
+ if (r != 0)
+ return INT2FIX(r < 0 ? -1 : 1);
+ if (l1 != l2)
+ return INT2FIX(l1 < l2 ? -1 : 1);
+ }
+ p1 += l1;
+ p2 += l2;
+ }
+ }
+ if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) return INT2FIX(0);
+ if (RSTRING_LEN(str1) > RSTRING_LEN(str2)) return INT2FIX(1);
+ return INT2FIX(-1);
+}
+
static long
rb_str_index(VALUE str, VALUE sub, long offset)
{
@@ -8721,6 +8846,7 @@ Init_String(void)
rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
+ rb_define_method(rb_cString, "numericcmp", rb_str_numericcmp, 1);
rb_define_method(rb_cString, "+", rb_str_plus, 1);
rb_define_method(rb_cString, "*", rb_str_times, 1);
rb_define_method(rb_cString, "%", rb_str_format_m, 1);
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 8366424..f9c788b 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -2104,6 +2104,29 @@ class TestString < Test::Unit::TestCase
assert_equal(1, "\u3042B".casecmp("\u3042a"))
end
+ def test_numericcmp
+ assert_equal(-1, "2.1.0".numericcmp("2.1.1"))
+ assert_equal(-1, "2.1.9".numericcmp("2.1.10"))
+ assert_equal( 0, "a1".numericcmp("a1"))
+ assert_equal( 1, "aa".numericcmp("a1"))
+ assert_equal(-1, "a1".numericcmp("aa"))
+ assert_equal(-1, "a1".numericcmp("a01"))
+ assert_equal(-1, "a0001".numericcmp("a00001"))
+ assert_equal( 0, "a1a".numericcmp("a1a"))
+ assert_equal( 1, "a1b".numericcmp("a1a"))
+ assert_equal(-1, "a9a".numericcmp("a10a"))
+ assert_equal( 1, "b".numericcmp("a"))
+ assert_equal( 0, "\u30421".numericcmp("\u30421"))
+ assert_equal( 1, "\u3042\u3042".numericcmp("\u30421"))
+ assert_equal(-1, "\u30421".numericcmp("\u3042\u3042"))
+ assert_equal(-1, "\u30421".numericcmp("\u304201"))
+ assert_equal(-1, "\u30420001".numericcmp("\u304200001"))
+ assert_equal( 0, "\u30421\u3042".numericcmp("\u30421\u3042"))
+ assert_equal( 1, "\u30421\u3044".numericcmp("\u30421\u3042"))
+ assert_equal(-1, "\u30429\u3042".numericcmp("\u304210\u3042"))
+ assert_equal( 1, "\u3044".numericcmp("\u3042"))
+ end
+
def test_upcase2
assert_equal("\u3042AB", "\u3042aB".upcase)
end
</code></pre> Ruby master - Feature #9768 (Assigned): Method that is visible only within a certain module/classhttps://bugs.ruby-lang.org/issues/97682014-04-22T09:57:35Zsawa (Tsuyoshi Sawada)
<p>Some frameworks/libraries monkeypatch their own methods on Ruby core classes like <code>String</code>, <code>Hash</code>, <code>Array</code>, etc., and that is often causing problems/concerns of name conflict.</p>
<p>Seeing that these custom methods are used only in the context of a certain module/class, I request for a way to define a method (<code>foo</code>) on a module/class (<code>A</code>) so that it will be visible only from within a specified module/class (<code>B</code>) or its descendants. The following illustrates this situation:</p>
<pre><code>A.new.foo # => undefined
class B
A.new.foo # => defined
def bar
A.new.foo # => defined
end
def self.baz
A.new.foo # => defined
end
end
class C < B
A.new.foo # => defined
def bar
A.new.foo # => defined
end
def self.baz
A.new.foo # => defined
end
end
</code></pre>
<p>I do not have a certain syntax for this in mind, but I think it can be made much simpler, compared to the complicated syntax of refinement.</p>
<p>This is reminiscent of refinement, but they are pretty much different.</p>
<p>Refinement's purpose is to let certain methods be accessible from only a certain file. A typical use case would be a library developer defining their methods to be used from within the library and making such methods inaccessible from the end user.</p>
<p>On the other hand, the idea I am proposing here is for making method accessible from any file, but only within a certain module/class. A typical use case would be defining a method to be used by an end user, but only from within a context of certain module/class.</p> Ruby master - Feature #9755 (Assigned): Thread::Backtrace::Location#defined_classhttps://bugs.ruby-lang.org/issues/97552014-04-18T09:22:23Zshugo (Shugo Maeda)
<p>I'd like Thread::Backtrace::Location#defined_class.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">X</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="nb">p</span> <span class="n">caller_locations</span><span class="p">.</span><span class="nf">first</span><span class="p">.</span><span class="nf">defined_class</span> <span class="c1">#=> Y</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Y</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="no">X</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Y</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">bar</span>
</code></pre>
<p>nobu created a patch:</p>
<p><a href="https://github.com/nobu/ruby/compare/backtrace-self%2Bclass" class="external">https://github.com/nobu/ruby/compare/backtrace-self%2Bclass</a></p>
<p>But this patch has two problems:</p>
<ol>
<li>The patch adds Thread::Backtrace::Location#self, but it's weird that a location has self.</li>
<li>Thread::Backtrace::Location#class conflicts with Kernel#class.<br>
So I proposed defined_class as the method name.</li>
</ol> Ruby master - Feature #9235 (Assigned): Documentation for commercial supporthttps://bugs.ruby-lang.org/issues/92352013-12-10T05:36:24Zzzak (zzak _)
<p>We should document the following:</p>
<ul>
<li>What happens when a Ruby version goes EOL?</li>
<li>What can (my) company do to help maintain an EOL ruby?</li>
<li>How do we backport security patches?</li>
<li>How do we run tests?</li>
<li>How do we release our own version of ruby?</li>
</ul> 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> Ruby master - Feature #9023 (Assigned): Array#tailhttps://bugs.ruby-lang.org/issues/90232013-10-15T13:28:25Zfuadksd (Fuad Saud)fuadksd@gmail.com
<p>I propose the addition of a <code>tail</code> method to the Array class that returns all elements but the first. It is a pretty common pattern in functional programming, but not limited to - I use it extensively in all kinds of apps/gems. The implementation would be pretty trivial, I won't risk a patch to MRI because I'm uninitiated on ruby core matters, but powerpack gem (<a href="http://github.com/bbatsov/powerpack" class="external">http://github.com/bbatsov/powerpack</a>) implements it in ruby in terms of slices.</p> Ruby master - Feature #9020 (Assigned): Net::HTTPResponse predicate/query methodshttps://bugs.ruby-lang.org/issues/90202013-10-14T20:43:15Ztimcraft (Tim Craft)
<a name="SUMMARY"></a>
<h1 >SUMMARY<a href="#SUMMARY" class="wiki-anchor">¶</a></h1>
<p>I would like to propose adding predicate/query methods to Net::HTTPResponse for testing the status/type of response. For example:</p>
<pre><code>response.ok?
response.not_found?
response.client_error?
response.server_error?
</code></pre>
<a name="BACKGROUND"></a>
<h1 >BACKGROUND<a href="#BACKGROUND" class="wiki-anchor">¶</a></h1>
<p>The approach I've most commonly used/encountered for testing the status of a response is to compare with an integer, for example:</p>
<pre><code>response.code.to_i == 200
</code></pre>
<p>Subjectively I could say this kind of code is awkward/tedious to type, and not very "intention revealing". More practically/objectively it's a potential source of error. By mistyping the "magic number" it's possible for this expression to "silently fail" and test the wrong status. That would be an easy thing to spot in these examples, but much more difficult to track down within a typical codebase.</p>
<p>Another approach would be to test the type/class of the response object, for example:</p>
<pre><code>Net::HTTPOK === response
</code></pre>
<p>Subjectively I would say this doesn't feel very Ruby-ish. More practically/objectively it tightly couples the caller to the implementation details of Net::HTTP, making it difficult to stub or swap in a different library.</p>
<a name="PROPOSAL"></a>
<h1 >PROPOSAL<a href="#PROPOSAL" class="wiki-anchor">¶</a></h1>
<p>I would like to propose adding predicate/query methods to Net::HTTPResponse in order to encapsulate the implementation details of testing for different statuses and to provide a more abstract interface to the caller. For example:</p>
<pre><code>response.ok?
response.not_found?
</code></pre>
<p>This is more concise/readable. In most cases it would be easier and "less fiddly" to type out than the existing approaches presented above.</p>
<p>Compared to testing with integers it is one method call instead of three (I'm considering that as better from a readability perspective, not a performance perspective), and it eliminates the "failing silently" issue.</p>
<p>Compared to testing the type/class of the response object it doesn't couple the caller to implementation details of Net::HTTP, so it would be easier to stub or swap-in another library that provides the same interface.</p>
<p>Overall it feels much simpler and much more Ruby-ish.</p>
<p>In addition I would propose adding a few extra methods to test for ranges of statuses, for example:</p>
<pre><code>response.client_error?
response.server_error?
</code></pre>
<p>Similar benefits/rationale.</p>
<a name="IMPLEMENTATION"></a>
<h1 >IMPLEMENTATION<a href="#IMPLEMENTATION" class="wiki-anchor">¶</a></h1>
<p>I have already been using methods like this in some gems, and I have created a "proof of concept" implementation which monkey-patches Net::HTTP to test the idea out. Available here:</p>
<pre><code>http://rubygems.org/gems/net-http-predicates
https://github.com/timcraft/net-http-predicates
</code></pre>
<p>I can think of various different ways to implement a patch, so if this feature would be accepted into ruby-trunk I would welcome suggestions/guidance on a preferred implementation.</p>
<p>These changes would be backwards compatible and straightforward to provide as a backport, either in the backports library/gem or as a standalone gem.</p>
<a name="DISCUSSION"></a>
<h1 >DISCUSSION<a href="#DISCUSSION" class="wiki-anchor">¶</a></h1>
<p>Before discussing how to implement this patch I would like to get people's thoughts on the idea/proposal, and some indication of whether this could be accepted into ruby-trunk (or not). If it would be accepted I'm happy to write/submit the patch itself.</p>