Writing a recipe, part 2 ======================== The first tutorial explained how to search for code and how to automatically give suggestions. This second tutorial will focus mainly on improving our existing recipe and making it a bit more generic in order for it to also work for ``System.out.print`` statements. Afterwards, we'll learn how to limit the scope of our recipe. Making the recipe more generic ------------------------------ An important aspect of Sensei is creating recipes that are generic enough as not to miss any unwanted bits of code. This can be done through multiple mechanisms. First we will use the logic operators, and secondly, we will use string matching techniques to produce a similar result. .. role:: raw-html(raw) :format: html Let's open up our recipe again by putting the cursor on the highlighted piece of code and pressing the `Show intention actions and quick-fixes `_ shortcut (by default: :kbd:`Alt+Enter` or :kbd:`⌘↵`). Choose :menuselection:`Edit recipe` and the recipe editor window should open up. As said during the introduction of this tutorial, we'll first use the logical operators. There are 3 operators that we can use: ``anyOf``, ``allOf`` and ``not``. In our example, we'll use ``anyOf``. The goal is to mark the code if the name is equal to ``println`` and to ``print``. The way to configure this is as follows: .. code-block:: yaml search: methodcall: anyOf: - name: "println" - name: "print" on: field: name: "out" in: class: name: "java.lang.System" Another way to make this recipe more generic is by not specifying that the name should be equal to ``println`` or ``print`` but rather configuring that the name should start with ``print``. This is a very common pattern, and something that we've created UI-helper for. If you look at the ``UI View`` you will see that there is a :menuselection:`...` button next to the text box of name. Once you've clicked this, a more advanced configuration of the name target will be shown: .. code-block:: yaml name: is: println We can remove the ``is`` option and click on the :menuselection:`+` to choose ``matches``. Inside this field we have the ability to specify a regular expression. To check if the name starts with ``print`` choose the pattern ``print.*``. This pattern tells Sensei to look for a name that starts with ``print`` and contains 0 or more characters after that (``.*``). .. code-block:: yaml search: methodcall: name: matches: "print.*" on: field: name: "out" in: class: name: "java.lang.System" As seen in the previous example, certain options can be configured as a string but also as another target. These options are indicated by the :menuselection:`...` button inside the UI builder. Take a look at these, since they contain powerful features, especially when matching types. Scoping the recipe ------------------ Of course, not every recipe is valid for the entire project. That's why we've provided an easy and flexible way to limit the scope of the recipe. It is always possible to specify on the root level that a certain recipe should only trigger if the element is ``in`` another element. This option is again a target specification that can be nested and configured the same way as all the others. An example of this would be: .. code-block:: yaml search: methodcall: name: matches: "print.*" on: field: name: "out" in: class: name: "java.lang.System" in: class: name: "Example" What to read next? ------------------ We've come to the end of our quick introductory tutorial. Keep in mind that we've only scratched the surface of the possibilities that Sensei provides. To continue learning how to use Sensei we highly recommend reading starting with the :doc:`/topics` section, where certain high-level concepts are explained to help search for common patterns.