{"id":19422536,"url":"https://github.com/scalalandio/catnip","last_synced_at":"2025-04-24T15:32:20.890Z","repository":{"id":57736150,"uuid":"144788053","full_name":"scalalandio/catnip","owner":"scalalandio","description":"Static annotations for Kittens for people who don't like to write semiautomatic derivations into companion objects themselves.","archived":false,"fork":false,"pushed_at":"2020-11-30T22:31:21.000Z","size":275,"stargazers_count":42,"open_issues_count":4,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-03T07:12:55.984Z","etag":null,"topics":["annotations","cats","kittens","scala"],"latest_commit_sha":null,"homepage":"https://scalalandio.github.io/catnip/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scalalandio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-15T01:03:44.000Z","updated_at":"2024-03-17T22:30:59.000Z","dependencies_parsed_at":"2022-08-24T01:20:27.855Z","dependency_job_id":null,"html_url":"https://github.com/scalalandio/catnip","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scalalandio%2Fcatnip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scalalandio%2Fcatnip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scalalandio%2Fcatnip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scalalandio%2Fcatnip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scalalandio","download_url":"https://codeload.github.com/scalalandio/catnip/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250654470,"owners_count":21465887,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotations","cats","kittens","scala"],"created_at":"2024-11-10T13:34:06.388Z","updated_at":"2025-04-24T15:32:20.547Z","avatar_url":"https://github.com/scalalandio.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# catnip\n\n[![Build Status](https://travis-ci.org/scalalandio/catnip.svg?branch=master)](https://travis-ci.org/scalalandio/catnip)\n[![Maven Central](https://img.shields.io/maven-central/v/io.scalaland/catnip_2.13.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccatnip)\n[![Scala.js](https://www.scala-js.org/assets/badges/scalajs-1.0.0.svg)](https://www.scala-js.org)\n[![License](http://img.shields.io/:license-Apache%202-green.svg)](http://www.apache.org/licenses/LICENSE-2.0.txt)\n\nStatic annotations for Kittens for people who don't like to write\nsemiautomatic derivations into companion objects themselves.\n\n## Usage\n\nAdd to your sbt (2.11, 2.12, 2.13):\n\n```scala\nlibraryDependencies += \"io.scalaland\" %% \"catnip\" % catnipVersion // see Maven badge\n// If you use Scala \u003e= 2.13:\nscalacOptions += \"-Ymacro-annotations\"\n// If you use Scala 2.12 or 2.11:\naddCompilerPlugin(\"org.scalamacros\" % \"paradise\" % \"2.1.1\" cross sbt.CrossVersion.patch)\n```\n\nor, if you use Scala.js:\n\n```scala\nlibraryDependencies += \"io.scalaland\" %%% \"catnip\" % catnipVersion // see Maven badge\n// If you use Scala \u003e= 2.13:\nscalacOptions += \"-Ymacro-annotations\"\n// If you use Scala 2.12 or 2.11:\naddCompilerPlugin(\"org.scalamacros\" % \"paradise\" % \"2.1.1\" cross sbt.CrossVersion.patch)\n```\n\nFrom now on you can add implicit Kittens-generated type classes for your case classes\nwith a simple macro-annotation:\n\n```scala\nimport io.scalaland.catnip._\nimport cats._\nimport cats.implicits._ // don't forget to import the right implicits!\nimport alleycats.std.all._ // might also come handy\n\n@Semi(Eq, Monoid, Show) final case class Test(a: String)\n\nTest(\"a\") === Test(\"b\") // false\nTest(\"a\") |+| Test(\"b\") // Test(\"ab\")\nTest(\"a\").show          // \"Test(a = a)\"\n```\n\nYou can also test it with ammonite like:\n\n```scala\ninterp.preConfigureCompiler(_.processArguments(List(\"-Ymacro-annotations\"), true))\n\n@\n\nimport $ivy.`io.scalaland::catnip:1.0.0`, io.scalaland.catnip._, cats._, cats.implicits._\n\n@Semi(Eq, Monoid, Functor) final case class Test[A](a: A)\n\nTest(\"a\") === Test(\"b\") // false\nTest(\"a\") |+| Test(\"b\") // Test(\"ab\")\nTest(\"1\").map(_.toInt)  // Test(1)\n```\n\n## Implemented\n\n`cats.Eq`, `cats.PartialOrder`, `cats.Order`,\n`cats.Functor`, `cats.Foldable`, `cats.Traverse`, `cats.Show`, `cats.derived.ShowPretty`,\n`cats.Monoid`, `cats.MonoidK`, `cats.Semigroup`, `cats.SemigroupK`,\n`alleycats.Empty`, `alleycats.Pure`.\n\n## Internals\n\nMacro turns\n\n```scala\n@Semi(cats.Semigroup) final case class TestSemi(a: String)\n\n@Semi(cats.SemigroupK, cats.Eq) final case class TestSemiK[A](a: List[A])\n```\ninto\n```scala\nfinal case class TestSemi(a: String)\nobject TestSemi {\n  implicit val _derived_cats_kernel_Semigroup = cats.derived.semi.semigroup[TestSemi]\n}\n\nfinal case class TestSemiK[A](a: List[A])\nobject TestSemiK {\n  implicit val _derived_cats_SemigroupK = cats.derived.semi.semigroupK[TestSemiK];\n  implicit def _derived_cats_kernel_Eq[A](implicit cats_kernel_Eq_a: cats.kernel.Eq[List[A]]) = cats.derived.semi.eq[TestSemiK[A]]\n}\n```\n\nIn order to do so it:\n\n * takes the companion object from the argument\n * turns it into a class name an dealias it (so CO should match the class!)\n * then reads [`derive.semi.conf`](modules/catnip/src/main/resources/derive.semi.conf)\n   - this class contains type class to kittens generator mappings\n * for plain types is just paste the body\n * for parametric types `[A]` is reuses `TypeClass` to create an implicit\n   `TypeClass[A]` argument\n * in special cases like `Show` which would require additional type class\n   (`shapeless.Typeable[A]`), they are defined in config after the generator\n   function and separated by commas\n\n## Customizations\n\nYou should be able to extend the abilities of the macro by expanding\nthe content of `derive.semi.conf`. You can create this file and add it to your library\nif you want Catnip to support it as all files with that name are looked through during\ncompilation. When it comes to sbt it doesn't always export resources to `Compile` scope,\nso your configs might not be visible in your modules while they would be available\nin created JARs. (Creating somewhat inconsistent experience).\nPersonally, I fixed this by adding something like\n\n```\nval myProject = project.in(file(\"my-project\"))\n  // other settings\n  .settings(Compile / unmanagedResourceDirectories += baseDirectory.value / \"../src/main/resources\")\n```\n\nto sbt. This will make your customizations immediately available to your modules.\n\nTake a look at an [example](modules/catnip-custom-example) project to see how customization works\nin practice.\n\n## Debugging\n\nTo debug you can use `catnip.debug` flag:\n\n```\n\u003e sbt -Dcatnip.debug=debug # show info about derivation\n\u003e sbt -Dcatnip.debug=trace # show even more infor about derivation\n```\n\n## Limitations\n\nType checker complains if you use type aliases from the same compilation unit\n\n```scala\ntype X = cats.Eq; val X = cats.Eq\n@Semi(X) final case class Test(a: String)\n// scala.reflect.macros.TypecheckException: not found: type X\n```\nsame if you rename type during import\n```scala\nimport cats.{ Eq =\u003e X }\n@Semi(X) final case class Test(a: String)\n// scala.reflect.macros.TypecheckException: not found: type X\n```\n\nHowever, if you simply import definitions or aliases already defined somewhere else,\nyou should have no issues.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscalalandio%2Fcatnip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscalalandio%2Fcatnip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscalalandio%2Fcatnip/lists"}