Ruby Issue Tracking System: Issues
https://bugs.ruby-lang.org/
https://bugs.ruby-lang.org/favicon.ico?1711330511
2019-05-16T06:34:55Z
Ruby Issue Tracking System
Redmine
Ruby master - Feature #15854 (Open): Tracing instance variable assignment
https://bugs.ruby-lang.org/issues/15854
2019-05-16T06:34:55Z
igaiga (Kuniaki Igarashi)
igaiga@gmail.com
<p>I suggest a feature "tracing instance variable assignment". It's useful for debugging.</p>
<p>Use case:</p>
<p>In Rails, we use instance variables in views and controllers. When we got a bug caused by instance variable unintentional values, if we traced instance variable assignment timing, it would be good informations.</p>
<p>And in Rails views, there are no source codes of self class. That's built dynamically.</p>
<p>Current behavior (Ruby2.6):</p>
<p>In Ruby 2.6, only if there is a source code file to assign instance variable, we can trace instance variable assignment by following code (check_instance_variable_assignment.rb). But it's difficult if the assignment codes are defined dynamically. For example, in Rails view.</p>
<p>(And in another story, global variables assignment are traced by Kernel#trace_var.)</p>
<p>check_instance_variable_assignment.rb</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">trace_start</span>
<span class="no">TracePoint</span><span class="p">.</span><span class="nf">trace</span><span class="p">(</span><span class="ss">:line</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">target_class_name</span> <span class="o">=</span> <span class="s2">"Foo"</span>
<span class="n">target_instance_variable_name</span> <span class="o">=</span> <span class="s2">"@bar"</span>
<span class="n">line</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">){</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="p">.</span><span class="nf">readlines</span><span class="p">[</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="p">}</span>
<span class="n">node</span> <span class="o">=</span> <span class="no">RubyVM</span><span class="o">::</span><span class="no">AbstractSyntaxTree</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">line</span><span class="p">).</span><span class="nf">children</span><span class="p">.</span><span class="nf">last</span>
<span class="c1"># check instance variable assignment</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">node</span><span class="p">.</span><span class="nf">type</span> <span class="o">==</span> <span class="ss">:IASGN</span>
<span class="c1"># check class name</span>
<span class="n">target_class</span> <span class="o">=</span> <span class="no">Kernel</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="n">target_class_name</span><span class="p">)</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">tp</span><span class="p">.</span><span class="nf">self</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">target_class</span><span class="p">)</span>
<span class="c1"># check variable name</span>
<span class="n">instance_variable_name</span> <span class="o">=</span> <span class="n">node</span><span class="p">.</span><span class="nf">children</span><span class="p">.</span><span class="nf">first</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">instance_variable_name</span> <span class="o">==</span> <span class="n">target_instance_variable_name</span><span class="p">.</span><span class="nf">to_sym</span>
<span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">target_class_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">target_instance_variable_name</span><span class="si">}</span><span class="s2"> is assigned in </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">defined_class</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">method_id</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="vi">@bar</span> <span class="o">=</span> <span class="s2">"text"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">trace_start</span>
<span class="no">Foo</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">bar</span>
<span class="c1">#=> Foo @bar is assigned in check_instance_variable_assignment.rb:25 Foo bar</span>
</code></pre>
<p>Suggesting feature example:</p>
<p>Add new arguments for TracePoint.new method like :line and :call to trace instance variables assignment.</p>
<ul>
<li>:iasgn (IASGN name from RubyVM::AbstractSyntaxTree::Node)</li>
<li>:casgn (CVASGN (or CASGN?) name from RubyVM::AbstractSyntaxTree::Node. I think class variables tracing is useful too.)</li>
</ul>
<p>And get informations</p>
<ul>
<li>class name (It might be get by trace_point.self)</li>
<li>variable name ("@foo", "@@foo")</li>
</ul>
<p>A sample code to use the feature:</p>
<p>tp_iasgn.rb</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">TracePoint</span><span class="p">.</span><span class="nf">trace</span><span class="p">(</span><span class="ss">:iasgn</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">target_class_name</span> <span class="o">=</span> <span class="s2">"Foo"</span>
<span class="n">target_instance_variable_name</span> <span class="o">=</span> <span class="s2">"@bar"</span>
<span class="c1"># check class name</span>
<span class="n">target_class</span> <span class="o">=</span> <span class="no">Kernel</span><span class="p">.</span><span class="nf">const_get</span><span class="p">(</span><span class="n">target_class_name</span><span class="p">)</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">tp</span><span class="p">.</span><span class="nf">self</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">target_class</span><span class="p">)</span>
<span class="c1"># check variable name</span>
<span class="k">next</span> <span class="k">unless</span> <span class="n">target_instance_variable_name</span> <span class="o">==</span> <span class="n">tp</span><span class="p">.</span><span class="nf">variable_name</span>
<span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">target_class_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">target_instance_variable_name</span><span class="si">}</span><span class="s2"> is assigned in </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">method_id</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">tp</span><span class="p">.</span><span class="nf">defined_class</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="nb">caller</span> <span class="c1"># even in dynamic code case, we can get caller informations.</span>
<span class="k">end</span>
</code></pre>
Ruby master - Bug #14845 (Closed): Endless Range with nil
https://bugs.ruby-lang.org/issues/14845
2018-06-13T07:53:21Z
igaiga (Kuniaki Igarashi)
igaiga@gmail.com
<p>endless Rangeで次のケースで困ることがあります。</p>
<ul>
<li>1..nilはendless Rangeになる</li>
<li>endless Rangeはto_aすると返ってこなくなる</li>
<li>1..変数 のケースで意図せずendless Rangeになる可能性があり、そのときto_aすると返ってこなくなる</li>
</ul>
<p>Ruby 2.5.1 では 1..nil はArgumentError (bad value for range) になります。</p>
<p>たとえば、 1..nil がendless Rangeではなくエラーになればこの問題は解決します。</p>
<a name="Info"></a>
<h3 >Info<a href="#Info" class="wiki-anchor">¶</a></h3>
<ul>
<li>An endless range <code>(1..)</code> : <a href="https://bugs.ruby-lang.org/issues/12912" class="external">https://bugs.ruby-lang.org/issues/12912</a>
</li>
<li>twitter での話 : <a href="https://twitter.com/igaiga555/status/1006715631796813824" class="external">https://twitter.com/igaiga555/status/1006715631796813824</a>
</li>
</ul>