Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop setting methodNameStyle = Capitalize when useIdiomaticEndpoints is true #342

Merged
merged 7 commits into from
Oct 9, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
[comment]: <> (Don't edit this file!)
[comment]: <> (It is automatically updated after every release of https://github.com/47degrees/.github)
[comment]: <> (If you want to suggest a change, please open a PR or issue in that repository)

[![codecov.io](http://codecov.io/gh/higherkindness/skeuomorph/branch/master/graph/badge.svg)](http://codecov.io/gh/higherkindness/skeuomorph) [![Maven Central](https://img.shields.io/badge/maven%20central-0.0.22-green.svg)](https://oss.sonatype.org/#nexus-search;gav~io.higherkindness~skeuomorph*) [![Latest version](https://img.shields.io/badge/skeuomorph-0.0.22-green.svg)](https://index.scala-lang.org/higherkindness/skeuomorph) [![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/higherkindness/skeuomorph/master/LICENSE) [![Join the chat at https://gitter.im/higherkindness/skeuomorph](https://badges.gitter.im/higherkindness/skeuomorph.svg)](https://gitter.im/higherkindness/skeuomorph?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GitHub Issues](https://img.shields.io/github/issues/higherkindness/skeuomorph.svg)](https://github.com/higherkindness/skeuomorph/issues)
[![codecov.io](http://codecov.io/gh/higherkindness/skeuomorph/branch/master/graph/badge.svg)](http://codecov.io/gh/higherkindness/skeuomorph)
[![Maven Central](https://img.shields.io/badge/maven%20central-0.0.25-green.svg)](https://oss.sonatype.org/#nexus-search;gav~io.higherkindness~skeuomorph*)
[![Latest version](https://img.shields.io/badge/skeuomorph-0.0.25-green.svg)](https://index.scala-lang.org/higherkindness/skeuomorph)
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/higherkindness/skeuomorph/master/LICENSE)
[![Join the chat at https://gitter.im/higherkindness/skeuomorph](https://badges.gitter.im/higherkindness/skeuomorph.svg)](https://gitter.im/higherkindness/skeuomorph?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![GitHub Issues](https://img.shields.io/github/issues/higherkindness/skeuomorph.svg)](https://github.com/higherkindness/skeuomorph/issues)

# @NAME@

Expand All @@ -18,15 +26,17 @@ More information can be found at the [microsite][].

For installing this library, add the following line to your `build.sbt` file:

```scala
```sbt
libraryDependencies += "io.higherkindness" %% "skeuomorph" % "@VERSION@"
```

The full documentation is available at the [skeuomorph](https://higherkindness.io/skeuomorph/) site.

## NOTICE

The following files `api-with-examples.yaml`, `petstore-expanded.yaml`, `callback-example.yaml`, `petstore.yaml`, `link-example.yaml` and `uspto.yaml` inside the folder (`test/resources/openapi/yaml`) were copied from [**OpenAPI Specification**](https://github.com/OAI/OpenAPI-Specification/) project under the terms of the licence [*Apache License Version 2.0, January 2004*](https://github.com/OAI/OpenAPI-Specification/blob/master/LICENSE).
The following files `api-with-examples.yaml`, `petstore-expanded.yaml`, `callback-example.yaml`, `petstore.yaml`, `link-example.yaml` and `uspto.yaml`
inside the folder (`test/resources/openapi/yaml`) were copied from [**OpenAPI Specification**](https://github.com/OAI/OpenAPI-Specification/)
project under the terms of the licence [*Apache License Version 2.0, January 2004*](https://github.com/OAI/OpenAPI-Specification/blob/master/LICENSE).

## Skeuomorph in the wild

Expand Down
13 changes: 4 additions & 9 deletions microsite/docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ title: Intro
permalink: docs/
---


# Skeuomorph

Skeuomorph is a library for transforming different schemas in Scala.
Expand Down Expand Up @@ -32,7 +31,7 @@ example. Or to a mu service description.

You can install skeuomorph as follows:

```scala
```sbt
libraryDependencies += "io.higherkindness" %% "skeuomorph" % "@VERSION@"
```

Expand Down Expand Up @@ -102,11 +101,9 @@ println("=====")
It would generate the following output:

```scala mdoc:passthrough
println("```scala")
(toMuSchema >>> println)(avroSchema)
println("=====")
(toMuSchema >>> printSchemaAsScala >>> println)(avroSchema)
println("```")
```

## Protobuf
Expand All @@ -117,8 +114,9 @@ Given the proto file below:

_user.proto_

```protobuf
```proto
syntax = "proto3";

package example.proto;

message User {
Expand All @@ -145,7 +143,7 @@ val source = ParseProto.ProtoSource("user.proto", new java.io.File(".").getAbsol
val protobufProtocol: Protocol[Mu[ProtobufF]] = ParseProto.parseProto[IO, Mu[ProtobufF]].parse(source).unsafeRunSync()

val toMuProtocol: Protocol[Mu[ProtobufF]] => mu.Protocol[Mu[MuF]] = { p: Protocol[Mu[ProtobufF]] =>
mu.Protocol.fromProtobufProto(CompressionType.Identity, true)(p)
mu.Protocol.fromProtobufProto(CompressionType.Identity)(p)
}

val printProtocolAsScala: mu.Protocol[Mu[MuF]] => Either[String, String] = { p =>
Expand All @@ -162,13 +160,10 @@ println("=====")

It would generate the following output:


```scala mdoc:passthrough
println("```scala")
(toMuProtocol >>> println)(protobufProtocol)
println("=====")
(toMuProtocol >>> printProtocolAsScala >>> println)(protobufProtocol)
println("```")
```

#### Proto2 Incompatibility
Expand Down
16 changes: 4 additions & 12 deletions microsite/docs/docs/optimizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,33 +49,25 @@ they're inside a product themselves. And we do this with the
def nestedNamedTypesTrans[T](implicit T: Basis[MuF, T]): Trans[MuF, MuF, T] = Trans {
case TProduct(name, fields, np, nc) =>
def nameTypes(f: Field[T]): Field[T] = f.copy(tpe = namedTypes(T)(f.tpe))
TProduct[T](
name,
fields.map(nameTypes),
np,
nc
)
TProduct[T](name, fields.map(nameTypes), np, nc)
case other => other
}

def namedTypesTrans[T]: Trans[MuF, MuF, T] = Trans {
case TProduct(name, _, _, _) => TNamedType[T](Nil, name)
case TSum(name, _) => TNamedType[T](Nil, name)
case other => other
case TSum(name, _) => TNamedType[T](Nil, name)
case other => other
}

def namedTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(namedTypesTrans.algebra)
def nestedNamedTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(nestedNamedTypesTrans.algebra)

```

and then apply the `namedTypes` combinator to the AST:

```scala mdoc:invisible
```scala mdoc
def ast = Mu(TNull[Mu[MuF]]())
```

```scala mdoc
val optimization = Optimize.namedTypes[Mu[MuF]]

optimization(ast)
Expand Down
18 changes: 10 additions & 8 deletions microsite/docs/docs/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ Currently in skeuomorph there are schemas defined for different cases:

Currently, Skeuomorph only supports proto3 compliance, and the recommended approach when using skeuomorph with [mu][]
is to use proto3 for all gRPC communications. While it is still possible to generate valid Scala code from a proto2 spec,
Skeuomorph will _not_ generate case classes for optional fields. For example, given a schema that looks like this:
Skeuomorph will _not_ generate case classes for optional fields. For example, given a `hello.proto` schema that looks like this:

```protobuf mdoc:silent
```proto
syntax = "proto2";

package src.main.hello;
package src.main;

message SayHelloRequest {
optional string name = 1;
Expand All @@ -44,15 +44,17 @@ service HelloWorldService {
}
```

Skeuomorph (with mu) will generate the following Scala code:
Skeuomorph (with mu and default plugin options) will generate the following Scala code:

```scala
object hello {
final case class SayHelloRequest(name: String)
final case class SayHelloResponse(message: String)
@service(Protobuf, Identity, namespace = Some("src.main.hello"), methodNameStyle = Capitalize)

final case class SayHelloRequest(name: _root_.java.lang.String)
final case class SayHelloResponse(message: _root_.java.lang.String)

@service(Protobuf, compressionType = Identity, methodNameStyle = Unchanged, namespace = Some("src.main"))
trait HelloWorldService[F[_]] {
def SayHello(req: src.main.hello.hello.SayHelloRequest): F[src.main.hello.hello.SayHelloResponse]
def SayHello(req: _root_.src.main.hello.SayHelloRequest): F[_root_.src.main.hello.SayHelloResponse]
}
}
```
Expand Down
4 changes: 2 additions & 2 deletions microsite/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
layout: homeFeatures
features:
- first: ["Non-recursive ADTs", "Declare languages as constructors in a simple way"]
- second: ["Transformations & optimizations", "Apply nanopass optimizations to the Abstract Syntax Trees of your program"]
- third: ["Recursion Schemes", "Leverage the power of Recursion Schemes to make performant and easy to write programs on your ADTs"]
- second: ["Transformations & optimizations", "Apply nanopass optimizations to the Abstract Syntax Trees of your program", "schemas"]
- third: ["Recursion Schemes", "Leverage the power of Recursion Schemes to make performant and easy to write programs on your ASTs", "optimizations"]
---
5 changes: 5 additions & 0 deletions src/main/scala/higherkindness/skeuomorph/StringUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package higherkindness.skeuomorph

object StringUtils {
def decapitalize(s: String): String = if (s.isEmpty) s else s"${s.head.toLower}${s.tail}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use s.capitalize?

}
23 changes: 13 additions & 10 deletions src/main/scala/higherkindness/skeuomorph/mu/codegen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import higherkindness.skeuomorph.mu.MuF._
import higherkindness.skeuomorph.mu.Optimize._
import higherkindness.skeuomorph.{protobuf => pb}
import higherkindness.skeuomorph.Printer.toValidIdentifier
import higherkindness.skeuomorph.StringUtils.decapitalize
import scala.reflect.ClassTag
import cats.syntax.either._
import cats.syntax.traverse._
Expand Down Expand Up @@ -231,19 +232,19 @@ object codegen {
def service[T](srv: Service[T], streamCtor: (Type, Type) => Type.Apply)(implicit
T: Basis[MuF, T]
): Either[String, Stat] = {
val deCapitalize = srv.useIdiomaticScala && srv.operations.forall(_.name.head.isUpper)
val serializationType = Term.Name(srv.serializationType.toString)
val compressionType = Term.Name(srv.compressionType.toString)
val methodNameStyle = Term.Name(if (deCapitalize) "Capitalize" else "Unchanged")

val serviceAnnotation = srv.idiomaticEndpoints match {
case IdiomaticEndpoints(Some(pkg), true) =>
mod"@service($serializationType, $compressionType, namespace = Some($pkg), methodNameStyle = Capitalize)"
case IdiomaticEndpoints(None, true) =>
mod"@service($serializationType, $compressionType, methodNameStyle = Capitalize)"
val serviceAnnotation = srv.namespace match {
case Some(namespace) if srv.useIdiomaticGrpc =>
mod"@service($serializationType, compressionType = $compressionType, methodNameStyle = $methodNameStyle, namespace = Some($namespace))"
case _ =>
mod"@service($serializationType, $compressionType)"
mod"@service($serializationType, compressionType = $compressionType, methodNameStyle = $methodNameStyle, namespace = None)"
}

srv.operations.traverse(op => operation(op, streamCtor)).map { ops =>
srv.operations.traverse(op => operation(op, streamCtor, deCapitalize)).map { ops =>
q"""
@$serviceAnnotation trait ${Type.Name(srv.name)}[F[_]] {
..$ops
Expand All @@ -252,13 +253,15 @@ object codegen {
}
}

def operation[T](op: Service.Operation[T], streamCtor: (Type, Type) => Type.Apply)(implicit
def operation[T](op: Service.Operation[T], streamCtor: (Type, Type) => Type.Apply, deCapitalize: Boolean)(implicit
T: Basis[MuF, T]
): Either[String, Decl.Def] =
): Either[String, Decl.Def] = {
val name = if (deCapitalize) decapitalize(op.name) else op.name
for {
reqType <- requestType(op.request, streamCtor)
respType <- responseType(op.response, streamCtor)
} yield q"def ${Term.Name(op.name)}(req: $reqType): $respType"
} yield q"def ${Term.Name(name)}(req: $reqType): $respType"
}

def requestType[T](opType: Service.OperationType[T], streamCtor: (Type, Type) => Type.Apply)(implicit
T: Basis[MuF, T]
Expand Down
48 changes: 27 additions & 21 deletions src/main/scala/higherkindness/skeuomorph/mu/protocol.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@

package higherkindness.skeuomorph.mu

import higherkindness.skeuomorph.protobuf
import higherkindness.skeuomorph.protobuf.ProtobufF
import higherkindness.skeuomorph.avro
import higherkindness.droste._
import higherkindness.skeuomorph.avro.AvroF
import higherkindness.skeuomorph.mu.Service.OperationType
import higherkindness.skeuomorph.mu.Transform.transformAvro
import higherkindness.skeuomorph.mu.Transform.transformProto
import higherkindness.droste._
import higherkindness.skeuomorph.mu.Transform._
import higherkindness.skeuomorph._
import higherkindness.skeuomorph.protobuf.ProtobufF

sealed trait SerializationType extends Product with Serializable
object SerializationType {
private[skeuomorph] sealed trait SerializationType extends Product with Serializable
private[skeuomorph] object SerializationType {
case object Protobuf extends SerializationType
case object Avro extends SerializationType
case object AvroWithSchema extends SerializationType
Expand All @@ -38,8 +36,6 @@ object CompressionType {
case object Identity extends CompressionType
}

final case class IdiomaticEndpoints(pkg: Option[String], value: Boolean)

final case class Protocol[T](
name: Option[String],
pkg: Option[String],
Expand All @@ -53,9 +49,11 @@ object Protocol {
/**
* create a [[higherkindness.skeuomorph.mu.Protocol]] from a [[higherkindness.skeuomorph.avro.Protocol]]
*/
def fromAvroProtocol[T, U](compressionType: CompressionType, useIdiomaticEndpoints: Boolean)(
proto: avro.Protocol[T]
)(implicit T: Basis[AvroF, T], U: Basis[MuF, U]): Protocol[U] = {
def fromAvroProtocol[T, U](
compressionType: CompressionType,
useIdiomaticGrpc: Boolean = true,
useIdiomaticScala: Boolean = false
)(proto: avro.Protocol[T])(implicit T: Basis[AvroF, T], U: Basis[MuF, U]): Protocol[U] = {

val toMu: T => U = scheme.cata(transformAvro[U].algebra)
val toOperation: avro.Protocol.Message[T] => Service.Operation[U] =
Expand All @@ -76,17 +74,21 @@ object Protocol {
proto.name,
SerializationType.Avro,
compressionType,
IdiomaticEndpoints(proto.namespace, useIdiomaticEndpoints),
proto.namespace,
useIdiomaticGrpc,
useIdiomaticScala,
proto.messages.map(toOperation)
)
),
imports = Nil
)
}

def fromProtobufProto[T, U](compressionType: CompressionType, useIdiomaticEndpoints: Boolean)(
protocol: protobuf.Protocol[T]
)(implicit T: Basis[ProtobufF, T], U: Basis[MuF, U]): Protocol[U] = {
def fromProtobufProto[T, U](
compressionType: CompressionType,
useIdiomaticGrpc: Boolean = true,
useIdiomaticScala: Boolean = false
)(protocol: protobuf.Protocol[T])(implicit T: Basis[ProtobufF, T], U: Basis[MuF, U]): Protocol[U] = {
val toMu: T => U = scheme.cata(transformProto[U].algebra)
val toOperation: protobuf.Protocol.Operation[T] => Service.Operation[U] =
msg =>
Expand All @@ -99,18 +101,20 @@ object Protocol {
val toImports: DependentImport[T] => DependentImport[U] =
imp => DependentImport(imp.pkg, imp.protocol, toMu(imp.tpe))

new Protocol[U](
Protocol[U](
name = Some(protocol.name),
pkg = Option(protocol.pkg),
options = protocol.options,
declarations = protocol.declarations.map(toMu),
services = protocol.services
.map(s =>
new Service[U](
Service[U](
s.name,
SerializationType.Protobuf,
compressionType,
IdiomaticEndpoints(Option(protocol.pkg), useIdiomaticEndpoints),
Option(protocol.pkg),
useIdiomaticGrpc,
useIdiomaticScala,
s.operations.map(toOperation)
)
),
Expand All @@ -125,7 +129,9 @@ final case class Service[T](
name: String,
serializationType: SerializationType,
compressionType: CompressionType,
idiomaticEndpoints: IdiomaticEndpoints,
namespace: Option[String],
useIdiomaticGrpc: Boolean,
useIdiomaticScala: Boolean,
operations: List[Service.Operation[T]]
)
object Service {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package higherkindness.skeuomorph.openapi.client

import higherkindness.skeuomorph.Printer
import higherkindness.skeuomorph.Printer.{konst => κ, _}
import higherkindness.skeuomorph.StringUtils.decapitalize
import higherkindness.skeuomorph.catz.contrib.ContravariantMonoidalSyntax._
import higherkindness.skeuomorph.catz.contrib.Decidable._
import higherkindness.skeuomorph.openapi
Expand Down
3 changes: 1 addition & 2 deletions src/main/scala/higherkindness/skeuomorph/openapi/print.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package higherkindness.skeuomorph.openapi

import higherkindness.skeuomorph.Printer
import higherkindness.skeuomorph.Printer.{konst => κ, _}
import higherkindness.skeuomorph.StringUtils.decapitalize
import higherkindness.skeuomorph.catz.contrib.ContravariantMonoidalSyntax._
import higherkindness.skeuomorph.catz.contrib.Decidable._
import higherkindness.skeuomorph.openapi.JsonSchemaF.{string => _, _}
Expand Down Expand Up @@ -282,6 +283,4 @@ object print {
def duplicate[A, B](pair: (A, B)): ((A, A), (B, B)) = (pair._1 -> pair._1, pair._2 -> pair._2)
def second[A, B, C](pair: (A, B))(f: B => C): (A, C) = (pair._1, f(pair._2))
def flip[A, B](pair: (A, B)): (B, A) = (pair._2, pair._1)
def decapitalize(s: String): String = if (s.isEmpty) s else s"${s(0).toLower}${s.substring(1)}"

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import com.google.protobuf.DescriptorProtos.FileDescriptorSet
import com.google.protobuf.DescriptorProtos.UninterpretedOption.NamePart
import com.google.protobuf.DescriptorProtos._
import higherkindness.skeuomorph.FileUtils._
import higherkindness.skeuomorph.{Parser, _}
import higherkindness.skeuomorph._

import higherkindness.droste._
import higherkindness.droste.syntax.embed._
Expand Down
4 changes: 2 additions & 2 deletions src/test/resources/avro/GreeterService.avdl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@namespace("foo.bar")
@namespace("com.acme")
protocol MyGreeterService {

record HelloRequest {
Expand All @@ -13,7 +13,7 @@ protocol MyGreeterService {
array<string> arg3;
}

foo.bar.HelloResponse sayHelloAvro(foo.bar.HelloRequest arg);
com.acme.HelloResponse sayHelloAvro(com.acme.HelloRequest arg);

void sayNothingAvro();
}
Loading