Ruby Issue Tracking System: Issues
https://bugs.ruby-lang.org/
https://bugs.ruby-lang.org/favicon.ico?1711330511
2019-05-01T13:52:20Z
Ruby Issue Tracking System
Redmine
Ruby master - Feature #15815 (Open): Add option to raise NoMethodError for OpenStruct
https://bugs.ruby-lang.org/issues/15815
2019-05-01T13:52:20Z
mtsmfm (Fumiaki Matsushima)
mtsmfm@gmail.com
<p>GitHub PR: <a href="https://github.com/ruby/ruby/pull/2164" class="external">https://github.com/ruby/ruby/pull/2164</a></p>
<p>Currently, <code>OpenStruct#method_missing</code> returns <code>nil</code> even if the key isn't registered.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'ostruct'</span>
<span class="n">os</span> <span class="o">=</span> <span class="no">OpenStruct</span><span class="p">.</span><span class="nf">new</span><span class="p">({</span><span class="ss">a: </span><span class="mi">1</span><span class="p">})</span>
<span class="n">os</span><span class="p">.</span><span class="nf">a</span> <span class="c1">#=> 1</span>
<span class="n">os</span><span class="p">.</span><span class="nf">b</span> <span class="c1">#=> nil</span>
</code></pre>
<p>I'd like to add <code>exception</code> option to raise <code>NoMethodError</code> in such case.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s1">'ostruct'</span>
<span class="n">os</span> <span class="o">=</span> <span class="no">OpenStruct</span><span class="p">.</span><span class="nf">new</span><span class="p">({</span><span class="ss">a: </span><span class="mi">1</span><span class="p">},</span> <span class="ss">exception: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">os</span><span class="p">.</span><span class="nf">a</span> <span class="c1">#=> 1</span>
<span class="n">os</span><span class="p">.</span><span class="nf">b</span> <span class="c1">#=> NoMethodError</span>
</code></pre>
<a name="Use-case"></a>
<h2 >Use case<a href="#Use-case" class="wiki-anchor">¶</a></h2>
<p>I sometimes use OpenStruct as a JSON API response wrapper.<br>
It's useful to use method call instead of key access (<code>obj[:key]</code>) because we can use <code>Symbol#to_proc</code> if it's a method (for example <code>users.map(&:id)</code>)</p>
<p>But I want to prevent typo for a key name. Currently <code>users.map(&:idd)</code> just returns <code>[nil,...]</code></p>
<p>Even if we have this <code>exception</code> option, we can't enable this option for JSON parser easily though:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="ss">object_class: </span><span class="no">Class</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">OpenStruct</span><span class="p">)</span> <span class="p">{</span> <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="nb">hash</span><span class="p">);</span> <span class="k">super</span><span class="p">(</span><span class="nb">hash</span><span class="p">,</span> <span class="ss">exception: </span><span class="kp">true</span><span class="p">);</span> <span class="k">end</span> <span class="p">})</span>
</code></pre>
<p>What do you think?</p>
<hr>
<p>I've searched with "openstruct nomethoderror" on bugs.ruby-lang.org though, please let me know if it's duplicated.<br>
<a href="https://bugs.ruby-lang.org/search?utf8=%E2%9C%93&scope=&q=nomethoderror+openstruct" class="external">https://bugs.ruby-lang.org/search?utf8=%E2%9C%93&scope=&q=nomethoderror+openstruct</a></p>
Ruby master - Feature #12676 (Assigned): Significant performance increase, and code conciseness, ...
https://bugs.ruby-lang.org/issues/12676
2016-08-15T01:48:12Z
jzakiya (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 #9347 (Open): Accept non callable argument to detect
https://bugs.ruby-lang.org/issues/9347
2014-01-03T07:37:33Z
marcandre (Marc-Andre Lafortune)
marcandre-ruby-core@marc-andre.ca
<p>Currently, the only argument that <code>Enumerable#detect</code> accepts is a callable object.</p>
<p>Shouldn't we accept non callable objects too?</p>
<pre><code>[42].detect(:not_found){} # => NoMethodError: undefined method `call' for :not_found:Symbol
# would return :not_found instead.
</code></pre>
<p>I'd suggest that if the given argument does not <code>respond_to? :call</code>, then it would be returned as is instead of raising an error as currently.<br>
Wouldn't this be more flexible and possibly more performant?</p>
<p>Inspired by <a href="http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda" class="external">http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda</a></p>