How to reverse (revert) some Thor actions by jgn on Wednesday, December 4, 2024 in programming and ruby

It's pretty cool that in many cases Rails migrations can reverse their action when you use the destroy command. For example:

% rails generate model user name:string
      invoke  active_record
      create    db/migrate/20241204143118_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
% rails destroy model user
      invoke  active_record
      remove    db/migrate/20241204143118_create_users.rb
      remove    app/models/user.rb
      invoke    test_unit
      remove      test/models/user_test.rb
      remove      test/fixtures/users.yml

So that's pretty fun. Rails migrations are built on Thor, but there's not a lot of documentation on how to reverse a Thor action.

I had to study the code and its specs to figure this out, and even then it took some noodling around.

Here's how to do it. In your Thor file, you create actions like so. Note the setting of self.behavior.

  desc "prepend-before", "prepend to a file before a match"
  def prepend_before
    # behavior: Does not inject if the content exists *anywhere* in the file
    inject_into_file "doc/README", "more content\n", before: "__end__"
  end

  desc "revoke-prepend", "revoke prepend"
  def revoke_prepend
    self.behavior = :revoke
    inject_into_file "doc/README", "more content\n", :before => "__end__"
  end

Here's what run the looks like.

% thor ex:prepend-before
      insert  doc/README
% thor ex:revoke-prepend
    subtract  doc/README

You're welcome. Note that not all Thor actions allow for revocation: At some point I'll add a list of such actions here.

comments powered by Disqus