|
| 1 | +# Refactor with scalafix |
| 2 | + |
| 3 | +We are happy to announce the release of [scalafix v0.3][scalafix]. |
| 4 | +This release introduces a new `Rewrite` and `Patch` API powered by the [scala.meta semantic API][meta-1.6]. |
| 5 | +We are excited about this release because we believe it enables a number promising tooling applications. |
| 6 | + |
| 7 | +This first release of the scala.meta semantic API enables rewrites to query for the "symbol" of a name that appears in a Scala source file. |
| 8 | +A symbol is a unique identifier of a definition such as a class, val, def or trait. |
| 9 | +This ability to query for symbols opens possibilities for a great number of refactorings including imports management and identifier renaming. |
| 10 | +To demonstrate what rewrites can be implemented with scalafix v0.3, let's take one example. |
| 11 | + |
| 12 | +## Example: Xor to Either |
| 13 | + |
| 14 | +The functional programming library [cats][cats] migrated recently from its `Xor` data type to `Either` from the standard library. |
| 15 | +It requires a few mechanical steps to migrate code to use `Either` instead of `Xor`. |
| 16 | +For example, below is a diff that's taken from [circe][xor-cire]'s migration to `Either`. |
| 17 | + |
| 18 | +```diff |
| 19 | +- final def either: Xor[HCursor, HCursor] = if (succeeded) Xor.right(any) else Xor.left(any) |
| 20 | ++ final def either: Either[HCursor, HCursor] = if (succeeded) Right(any) else Left(any) |
| 21 | +``` |
| 22 | + |
| 23 | +Scalafix rewrites are composed of so-called "patches". |
| 24 | +A patch describes a single refactoring operation. |
| 25 | +`Replace` is one patch that can be used to rename identifiers |
| 26 | + |
| 27 | +```scala |
| 28 | +Replace(Symbol("_root_.cats.data.Xor."), q"Either") |
| 29 | +Replace(Symbol("_root_.cats.data.Xor.Left."), q"Left") |
| 30 | +Replace(Symbol("_root_.cats.data.Xor.Right."), q"Right") |
| 31 | +``` |
| 32 | + |
| 33 | +To introduce new imports on renmae, it's possible to pass in `additionalImports` |
| 34 | +```scala |
| 35 | +Replace(Symbol("_root_.cats.data.XorT."), q"EitherT", |
| 36 | + additionalImports = List(importer"cats.data.EitherT")), |
| 37 | +``` |
| 38 | + |
| 39 | +Imports can be removed with the `RemoveGlobalImport` patch |
| 40 | + |
| 41 | +```scala |
| 42 | +RemoveGlobalImport(importer"cats.data.Xor") |
| 43 | +``` |
| 44 | +Nothing happens if the import does not appear in the source file. |
| 45 | +Likewise, it's OK to add the same import twice, scalafix will de-duplicate it. |
| 46 | + |
| 47 | +The full `Xor` to `Either` scalafix rewrite can be found [here][xor2either] and its accompanying test |
| 48 | +suite [here][xor2either-test]. |
| 49 | + |
| 50 | +To learn more about how to start with scalafix, visit the [installation docs][install]! |
| 51 | + |
| 52 | +## Cross-building |
| 53 | + |
| 54 | +TODO: Shane |
| 55 | + |
| 56 | +## Custom rewrites |
| 57 | +You can write your own custom rewrites. |
| 58 | + |
| 59 | +[xor2either-test]: https://github.com/scalacenter/scalafix/blob/f61136fad79afcdbb03528ce78c7928afc6eafd6/scalafix-nsc/src/test/resources/syntactic/Xor2Either.source |
| 60 | +[xor2either]: https://github.com/scalacenter/scalafix/blob/f61136fad79afcdbb03528ce78c7928afc6eafd6/core/src/main/scala/scalafix/rewrite/Xor2Either.scala |
| 61 | +[xor-circe]: https://github.com/circe/circe/pull/343/files |
| 62 | +[cats]: http://github.com/typelevel/cats |
| 63 | +[ghpages]: http://github.com/scalacenter/scalafix |
| 64 | +[prevpost]: http://scala-lang.org/blog/2016/10/24/scalafix.html |
| 65 | +[scalafix]: https://scalacenter.github.io/scalafix/#0.3.0 |
| 66 | +[install]: https://scalacenter.github.io/scalafix/#Installation |
| 67 | +[meta-1.6]: https://github.com/scalameta/scalameta/blob/master/changelog/1.6.0.md#semantic-api |
0 commit comments