I like to contribute to opensource projects and learn from them. This post is about what I learned while working on my pull request to Ruby Spec which got merged recently. In Ruby github repository I found that it has a spec folder which has a Readme
file and that's how I & learned about Ruby Spec Suite project. Ruby Spec Suite is a test suite which has specs for Ruby methods. It is used to check if any Ruby version passes the specs or not. While going through the issues in Ruby Spec Suite Github repository I came across an issue of TracePoint Specs i.e. to add specs for TracePoint class which were missing since it was introduced in Ruby 2.0. I decided to work on this issue myself and started learning about TracePoint.
TracePoint class
TracePoint is a Ruby class that lets you listen to events that happen at the Ruby virtual machine level and lets you register callbacks for these events. It provides methods for getting more information about the event. Let's take an example to trace a method call to find the class where the method is defined.
We can provide event names to the new
method as a parameter. After tracepoint object is enabled it starts listening to the events and hence we get the value of the last_class_name as A. The following are some other tracepoint events which you can try -
- class
- end
- call
- return
- raise
TracePoint Examples
Running Ruby Specs using mspec tool
The mspec gem is used as RSpec-like test runner for the Ruby Spec Suite. The mspec gem can be installed using -
If specs are missing for a Ruby class we can contribute by first running a generator to generate spec files for methods of the class in the Ruby Spec folder using the mkspec command -
After adding specs for a Ruby class we can run specs using mspec -
The documentation for mspec is available here.
Bugs in TracePoint class
- For TracePoint#enable & TracePoint#disable I added a spec -
I thought of checking what arguments get passed to the block using *args
.
It contains nil
as the value in the *args
array. I added assertion for that --
I asked myself should args be nil? There is no reason for enable
to yield nil
here. In fact, it should not yield anything. I created an issue for this in the Ruby issue tracker and added a spec for the expected behavior as shown below. Notice how issues are tagged using ruby_bug
:
- For TracePoint#new I initilized an object without a block and it raised a ThreadError -
Why did ThreadError get raised? We are not dealing with threads in this code. This looks like a bug, there is no need for a ThreadError to be raised if block is not provided for TracePoint#new. We can write a spec for this bug --
The bugs have been reported on Ruby issue tracker:
- TracePoint#enable and TracePoint#disable should not yield arguments.
- TracePoint#new without a block should not raise ThreadError.
Adding specs for bugs
We need to add specs for bugs so as to reflect the correct behavior of the method. mspec provides a guard ruby_bug that wraps the spec showing what is considered to be the correct behavior.
The ruby_bug method takes 3 arguments i.e.
- bug id - from Ruby Issue Tracking website
- version - which version of Ruby is affected by this bug.
- block - the spec block
Contributing to Ruby Specs helps to learn and improve our Ruby skills. I hope you find this useful to learn more about Ruby & contributing to the Ruby Spec Suite.