Skip to content

Fast walkthrough

This is the main interactive tutorial we have on fast. If you're reading it on the web, please consider also try it in the command line: fast .intro in the terminal to get a rapid pace on reading and testing on your own computer.

The objective here is give you some insights about how to use ffast gem in the command line.

Let's start finding the main fast.rb file for the fast library:

$ gem which fast

And now, let's combine the previous expression that returns the path to the file and take a quick look into the methods match? in the file using a regular grep:

$ grep "def match\?" $(gem which fast)

Boring results, no? The code here is not easy to digest because we just see a fragment of the code block that we want. Let's make it a bit more advanced with grep -rn to file name and line number:

$ grep -rn "def match\?" $(gem which fast)

Still hard to understand the scope of the search.

That's why fast exists! Now, let's take a look on how a method like this looks like from the AST perspective. Let's use ruby-parse for it:

$ ruby-parse -e "def match?(node); end"

Now, let's make the same search with fast node pattern:

fast "(def match?)" $(gem which fast)

Wow! in this case you got all the match? methods, but you'd like to go one level upper and understand the classes that implements the method with a single node as argument. Let's first use ^ to jump into the parent:

fast "^(def match?)" $(gem which fast)

As you can see it still prints some match? methods that are not the ones that we want, so, let's add a filter by the argument node (args (arg node)):

fast "(def match? (args (arg node)))" $(gem which fast)

Now, it looks closer to have some understanding of the scope, filtering only methods that have the name match? and receive node as a parameter.

Now, let's do something different and find all methods that receives a node as an argument:

fast "(def _ (args (arg node)))" $(gem which fast)

Looks like almost all of them are the match? and we can also skip the match? methods negating the expression prefixing with !:

fast "(def !match? (args (arg node)))" $(gem which fast)

Let's move on and learn more about node pattern with the RuboCop project:

$ VISUAL=echo gem open rubocop

RuboCop contains def_node_matcher and def_node_search. Let's make a search for both method names wrapping the query with {} selector:

fast "(send nil {def_node_matcher def_node_search})" $(VISUAL=echo gem open rubocop)

As you can see, node pattern is widely adopted in the cops to target code. Rubocop contains a few projects with dedicated cops that can help you learn more.

How to automate refactor using AST

Moving towards to the code automation, the next step after finding some target code is refactor and change the code behavior.

Let's imagine that we already found some code that we want to edit or remove. If we get the AST we can also cherry-pick any fragment of the expression to be replaced. As you can imagine, RuboCop also benefits from automatic refactoring offering the --autocorrect option.

All the hardcore algorithms are in the parser rewriter, but we can find a lot of great examples on RuboCop project searching for the autocorrect method.

fast "(def autocorrect)" $(VISUAL=echo gem open rubocop)

Look that most part of the methods are just returning a lambda with a corrector. Now, let's use the --ast to get familiar with the tree details for the implementation:

fast --ast "(def autocorrect)" $(VISUAL=echo gem open rubocop)/lib/rubocop/cop/style

As we can see, we have a (send (lvar corrector)) that is the interface that we can get the most interesting calls to overwrite files:

fast "(send (lvar corrector)" $(VISUAL=echo gem open rubocop)

That is all for now!

I hope you enjoyed to learn by example searching with fast. If you like it, please star the project!

You can also build your own tutorials simply using markdown files like I did here, you can find this tutorial here.