Extend Rails code metrics

Rails ships with an easy way to get some quick code metrics about your application’s code and test coverage.

For instance, running bin/rails stats will provide you with some important bits of information about the status and health of your project:

+----------------------+--------+--------+---------+---------+-----+-------+
| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
+----------------------+--------+--------+---------+---------+-----+-------+
| Controllers | 969 | 744 | 24 | 122 | 5 | 4 |
| Helpers | 95 | 73 | 0 | 8 | 0 | 7 |
| Jobs | 66 | 51 | 4 | 6 | 1 | 6 |
| Models | 609 | 463 | 22 | 57 | 2 | 6 |
| Mailers | 6 | 4 | 1 | 0 | 0 | 0 |
| Channels | 12 | 8 | 2 | 0 | 0 | 0 |
| JavaScripts | 11 | 0 | 0 | 0 | 0 | 0 |
| Libraries | 601 | 454 | 9 | 69 | 7 | 4 |
| Controller tests | 1233 | 972 | 26 | 126 | 4 | 5 |
| Helper tests | 104 | 80 | 4 | 9 | 2 | 6 |
| Model tests | 1425 | 1126 | 20 | 206 | 10 | 3 |
| Mailer tests | 13 | 9 | 1 | 2 | 2 | 2 |
| Job tests | 55 | 41 | 4 | 4 | 1 | 8 |
| Integration tests | 0 | 0 | 0 | 0 | 0 | 0 |
| System tests | 139 | 27 | 9 | 0 | 0 | 0 |
+----------------------+--------+--------+---------+---------+-----+-------+
| Total | 5338 | 4052 | 126 | 609 | 4 | 4 |
+----------------------+--------+--------+---------+---------+-----+-------+
Code LOC: 1797 Test LOC: 2255 Code to Test Ratio: 1:1.3

Most likely, as your projects grows, you will probably add some custom folders for holding code like services, validators or serializers.

However, when you do and run the stats task again, you will notice that Rails does not include them in the code metrics.

Extend the stats task

Luckily, it is not that hard to add your non-Rails directories to the statistics. All you need to do is create a rake task that “extends” the existing stats task.

    task stats: 'statsetup'
    
    task :statsetup do
        require 'rails/code_statistics'

        custom_directories = [
            %w[Serializers app/serializers],
            %w[Services app/services],
            %w[Statistics app/statistics],
            %w[Validators app/validators],
            %w[Serializer\ tests test/serializers],
            %w[Service\ tests test/services],
            %w[Statistic\ tests test/statistics],
            %w[Validator\ tests test/validators]
        ]
        STATS_DIRECTORIES.concat(custom_directories)

        custom_test_types = %w[Serializer\ tests Service\ tests Statistic\ tests Validator\ tests]
        CodeStatistics::TEST_TYPES.concat(custom_test_types)
    end

When you look at the above snippet, you will see a new task called statsetup.

Firstly, add the custom folders to the STATS_DIRECTORIES constant. This constant is defined in the Rails statistics.rake file.

The STATS_DIRECTORIES constant is a nested array, where each element is an array that consists of a label and its appropriate directory inside your project.

Assign the custom directories to a variable and and after that concat it with the STATS_DIRECTORIES constant.

Secondly, extend the CodeStatistics::TEST_TYPES constant. This constant is defined in the CodeStatistics class, used by the stats task. This constant is used to determine which directories contain test code, so Rails can calculate the correct test coverage.

The CodeStatistics::TEST_TYPES constant is a plain array where each element is a string that points to a directory from your test suite.

Most importantly, don’t forget to require the class, otherwise the constant will not be available and you will get an exception.

In conclusion, this custom rake task won’t run automatically when you call the stats task. That is why you need to add task stats: 'statsetup' to your code. This will make sure the custom task statsetip will be called before running the stats task and the constants are properly set.