From f55a810608cd12bc14df077fa77b18c25f2c5bea Mon Sep 17 00:00:00 2001 From: Patrick Stevens <3138005+Smaug123@users.noreply.github.com> Date: Wed, 14 Feb 2024 23:17:20 +0000 Subject: [PATCH] Allow cancellation token arg to have another name (#96) --- ConsumePlugin/GeneratedRestClient.fs | 4 +- ConsumePlugin/RestApiExample.fs | 2 +- README.md | 5 +- .../HttpClientGenerator.fs | 49 +++++++++++-------- WoofWare.Myriad.Plugins/SynExpr.fs | 4 +- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/ConsumePlugin/GeneratedRestClient.fs b/ConsumePlugin/GeneratedRestClient.fs index 3c29f51..1033e74 100644 --- a/ConsumePlugin/GeneratedRestClient.fs +++ b/ConsumePlugin/GeneratedRestClient.fs @@ -1034,7 +1034,7 @@ module ApiWithBasePath = /// Create a REST client. let make (client : System.Net.Http.HttpClient) : IApiWithBasePath = { new IApiWithBasePath with - member _.GetPathParam (parameter : string, ct : CancellationToken option) = + member _.GetPathParam (parameter : string, cancellationToken : CancellationToken option) = async { let! ct = Async.CancellationToken @@ -1067,7 +1067,7 @@ module ApiWithBasePath = let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask return responseString } - |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = cancellationToken)) } namespace PureGym diff --git a/ConsumePlugin/RestApiExample.fs b/ConsumePlugin/RestApiExample.fs index aa6f933..f373d2d 100644 --- a/ConsumePlugin/RestApiExample.fs +++ b/ConsumePlugin/RestApiExample.fs @@ -121,7 +121,7 @@ type internal IApiWithoutBaseAddress = [] type IApiWithBasePath = [] - abstract GetPathParam : [] parameter : string * ?ct : CancellationToken -> Task + abstract GetPathParam : [] parameter : string * ?cancellationToken : CancellationToken -> Task [] [] diff --git a/README.md b/README.md index 9430be2..636fcb1 100644 --- a/README.md +++ b/README.md @@ -322,10 +322,9 @@ The [Grug-brained developer](https://grugbrain.dev/) would prefer to do this wit But since F# does not let you partially update an interface definition, we instead stamp out a record, thereby allowing the programmer to use F#'s record-update syntax. -### Limitations +### Features -* We make the resulting record type at most internal (never public), since this is intended only to be used in tests. - You will therefore need an `AssemblyInfo.fs` file [like the one in WoofWare.Myriad's own tests](./ConsumePlugin/AssemblyInfo.fs). +* You may supply an `isInternal : bool` argument to the attribute. By default, we make the resulting record type at most internal (never public), since this is intended only to be used in tests; but you can instead make it public with `[]`. # Detailed examples diff --git a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs index bebaaa8..c6a8434 100644 --- a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs @@ -183,27 +183,34 @@ module internal HttpClientGenerator = None ) + let args = + info.Args + |> List.map (fun arg -> + let argName = + match arg.Id with + | None -> failwith "TODO: create an arg name" + | Some id -> id + + let argType = + if arg.IsOptional then + SynType.CreateApp ( + SynType.CreateLongIdent (SynLongIdent.CreateString "option"), + [ arg.Type ], + isPostfix = true + ) + else + arg.Type + + argName, SynPat.CreateTyped (SynPat.CreateNamed argName, argType) + ) + + let cancellationTokenArg = + match List.tryLast args with + | None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}" + | Some (arg, _) -> arg + let argPats = - let args = - info.Args - |> List.map (fun arg -> - let argName = - match arg.Id with - | None -> failwith "TODO: create an arg name" - | Some id -> id - - let argType = - if arg.IsOptional then - SynType.CreateApp ( - SynType.CreateLongIdent (SynLongIdent.CreateString "option"), - [ arg.Type ], - isPostfix = true - ) - else - arg.Type - - SynPat.CreateTyped (SynPat.CreateNamed argName, argType) - ) + let args = args |> List.map snd SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0) |> SynPat.CreateParen @@ -677,7 +684,7 @@ module internal HttpClientGenerator = yield jsonNode ] |> SynExpr.createCompExpr "async" returnExpr - |> SynExpr.startAsTask + |> SynExpr.startAsTask (SynLongIdent.CreateFromLongIdent [ cancellationTokenArg ]) SynMemberDefn.Member ( SynBinding.SynBinding ( diff --git a/WoofWare.Myriad.Plugins/SynExpr.fs b/WoofWare.Myriad.Plugins/SynExpr.fs index d93a545..95805b5 100644 --- a/WoofWare.Myriad.Plugins/SynExpr.fs +++ b/WoofWare.Myriad.Plugins/SynExpr.fs @@ -180,7 +180,7 @@ module internal SynExpr = SynExpr.CreateApp (SynExpr.CreateIdent (Ident.Create "reraise"), SynExpr.CreateConst SynConst.Unit) /// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct) - let startAsTask (body : SynExpr) = + let startAsTask (ct : SynLongIdent) (body : SynExpr) = let lambda = SynExpr.CreateApp ( SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "StartAsTask" ]), @@ -189,7 +189,7 @@ module internal SynExpr = SynExpr.CreateLongIdent (SynLongIdent.CreateString "a") equals (SynExpr.LongIdent (true, SynLongIdent.CreateString "cancellationToken", None, range0)) - (SynExpr.CreateLongIdent (SynLongIdent.CreateString "ct")) + (SynExpr.CreateLongIdent ct) ] ) |> createLambda "a"