Search code examples
ruby-on-railsrakesorbet

How to run sorbet typecheck on rake tasks


I notice that by default, srb init etc doesn't put # typed flag on rake tasks. However, on VSCode, it does show error (eg missing constant) on rake task.

I've tried to add # typed: true to rake tasks but it would immediately show errors like "namespace is not available in Root". Have anyone tried to typecheck your rake tasks? What's the set up to do that?


Solution

  • Rake monkeypatches the global main object (i.e., top-level code) to extend their DSL:

    # Extend the main object with the DSL commands. This allows top-level
    # calls to task, etc. to work from a Rakefile without polluting the
    # object inheritance tree.
    self.extend Rake::DSL
    

    lib/rake/dsl_definition.rb

    Sorbet cannot model that a single instance of an object (in this case main) has a different inheritance hierarchy than that instance's class (in this case Object).

    To get around this, we recommend refactoring the Rakefile to make a new class where the inheritance hierarchy is explicit:

    # -- my_rake_tasks.rb --
    
    # (1) Make a proper class inside a file with a *.rb extension
    class MyRakeTasks
      # (2) Explicitly extend Rake::DSL in this class
      extend Rake::DSL
    
      # (3) Define tasks like normal:
      task :test do
        puts 'Testing...'
      end
    
      # ... more tasks ...
    end
    
    # -- Rakefile --
    
    # (4) Require that file from the Rakefile
    require_relative './my_rake_tasks'
    

    Alternatively, we it's possible to write an RBI for Object that makes it appear to extend Rake::DSL. This RBI would be mostly wrong: not all instances of Object have this extend, only one does. We DO NOT suggest this approach because it could make it look like some code type checks even though methods like task and namespace are not defined. If you wanted to do this anyways, you can write this RBI file for Object:

    # -- object.rbi --
    
    # Warning!! Monkeypatches all Object's everywhere!
    class Object
      extend Rake::DSL
    end