dotnet add package Myriad.Sdk --version 0.8.3
NuGet\Install-Package Myriad.Sdk -Version 0.8.3
<PackageReference Include="Myriad.Sdk" Version="0.8.3" />
paket add Myriad.Sdk --version 0.8.3
#r "nuget: Myriad.Sdk, 0.8.3"
// Install Myriad.Sdk as a Cake Addin #addin nuget:?package=Myriad.Sdk&version=0.8.3 // Install Myriad.Sdk as a Cake Tool #tool nuget:?package=Myriad.Sdk&version=0.8.3
Myriad
Myriad是一个代码生成器。它接受任意文件,并提供不同的机制来允许在响应文件时生成F#代码,无论该文件是F#源文件还是简单的文本文件。
可以从MSBuild扩展或从其CLI工具使用Myriad。
Myriad的理念尽可能简化F#中的元编程能力。在这里,我所说的元编程是在F#中使用F#原生类型(如区分联合和记录)生成惯用F#代码,这是使用仅输出基本.NET类的F# Type Providers等不可能做到的。
Myriad是我与F#的类型提供者和其他元编程功能(如引言和AST操作)一起工作时开发的思想的进化。Myriad旨在通过Myriad插件轻松扩展编译器。Myriad提供了一种编译器扩展方法,不需要修改或调整Type Providers或等待其他F#语言改进。您编写一个用于处理AST输入片段的Myriad插件,然后插件提供AST输出,最终形式是构建到项目中的源代码。这可以使编译器优化输出,同时允许工具有效地运行。
如果您想要帮助和贡献代码,那么 đó thực sự rất tốt; 请检查问题并通过创建PR来进行。
如果您喜欢这个仓库并想表达您的感激之情等,那么我有Ko-fi。
通过MSBuild使用
要使用Myriad的MSBuild支持,请添加 Myriad.Core
和 Myriad.Sdk
包引用。
<ItemGroup>
<PackageReference Include="Myriad.Core" Version="0.5.0" />
<PackageReference Include="Myriad.Sdk" Version="0.5.0" />
</ItemGroup>
通过使用通常的Compile
元素指定输入文件。
<Compile Include="Library.fs"/>
<Compile Include="Generated.fs">
<MyriadFile>Library.fs</MyriadFile>
</Compile>
本教程通过配置Myriad,将名为 Generated.fs
的文件包含在构建中,并将 Library.fs
作为Myriad的输入。
还可以将生成的内容追加到输入文件中。
<Compile Include="Library.fs">
<MyriadInlineGeneration>true</MyriadInlineGeneration>
</Compile>
Myriad通过使用插件来生成代码来工作。Myriad附带了一个名为fields的插件,它从同名的OCaml ppx_fields_conv 插件中汲取灵感。
本示例中的输入文件 Library.fs
看起来如下所示
namespace Example
open Myriad.Plugins
[<Generator.Fields "fields">]
type Test1 = { one: int; two: string; three: float; four: float32 }
type Test2 = { one: Test1; two: string }
使用属性是为了让代码生成器知道哪些输入AST的部分将被插件处理。如果您有多个记录并且只想让fields插件处理Test1
,则可以使用示例中的属性来仅将Generator.Fields
应用于Test1
。注意,如果您需要一个只需要整个输入AST的插件,那么没有必要提供输入。Myriad旨在成为一个库,而不是一个完整的框架,该框架绑定到输入和生成代码的机制。传递给"fields"属性的参数指定了在myriad.toml
文件中表示的配置部分。在本例中,使用了fields,而myriad.toml
文件如下所示
[fields]
namespace = "TestFields"
这指定了用于插件的命名空间,在这种情况下是“TestFields”。
在本例中,fields插件将在预构建时生成以下代码并将其编译到您的程序集
//------------------------------------------------------------------------------
// This code was generated by myriad.
// Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace rec TestFields
module Test1 =
open Example
let one (x : Test1) = x.one
let two (x : Test1) = x.two
let three (x : Test1) = x.three
let four (x : Test1) = x.four
let create (one : int) (two : string) (three : float) (four : float32) : Test1 =
{ one = one
two = two
three = three
four = four }
let map (mapone : int -> int) (maptwo : string -> string) (mapthree : float -> float) (mapfour : float32 -> float32) (record': Test1) =
{ record' with
one = mapone record'.one
two = maptwo record'.two
three = mapthree record'.three
four = mapfour record'.four }
fields插件为输入记录中的每个字段生成一个map
,一个接受每个字段的create
函数,以及一个接受输入记录中的每个字段的一个函数的map
函数。
对于每个字段使用的map函数在只需要从记录中使用单个字段的地方非常有用,例如记录的列表
let records = [{one = "a"; two = "aa"; three = 42.0; four = 172.0f}
{one = "b"; two = "bb"; three = 42.0; four = 172.0f}]
records |> List.sortBy Test1.one
Lens插件
Myriad还可以为记录和单案例判别联合生成lenses。Lens是一个pair,包含一个类型的单个属性的getter
和setter
。给定对象Lens
后,您可以获取属性的值或更新它,创建一个新的对象。lenses的优点是能够将它们组合起来读取或更新对象的嵌套字段。
要为您的类型创建lenses,首先使用Generator.Lenses
属性注释您希望生成lenses的类型
[<Generator.Lenses("lens")>]
type Record =
{ one: int
two: string }
Myriad将生成以下代码
module RecordLenses =
let one = (fun (x: Test1) -> x.one), (fun (x: Test1) (value: int) -> { x with one = value })
let two = (fun (x: Test1) -> x.two), (fun (x: Test1) (value: string) -> { x with two = value })
通常,lenses被定义为一个单案例联合,其中包含getter和setter对。Myriad还可以添加调用此类DU构造函数的调用。
为了实现这一点,请使用Lens
属性装饰您的类型,指定DU构造函数的名称:[<Generator.Lenses("Lens")>]
,Myriad将生成以下代码
module RecordLenses =
let one = Lens((fun (x: Test1) -> x.one), (fun (x: Test1) (value: int) -> { x with one = value }))
let two = Lens((fun (x: Test1) -> x.two), (fun (x: Test1) (value: string) -> { x with two = value }))
您可以通过几种方式提供DU构造函数的名称
- 作为字符串:
[<Generator.Lenses("lens", "Lens")>]
; - 或作为类型:
[<Generator.Lenses("lens", typedefof<Lens<_, _>>)>]
或[<Generator.Lenses(typeof<Lens<_, _>>)>]
。
如果Lens类型与带属性装饰的类型在不同的命名空间/模块中,提供Lens构造函数的完整名称:[<Generator.Lenses("Namespace.And.Module.Of.Lens")>]
。
完整的fsproj细节如下所示
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Library.fs" />
<Compile Include="Generated.fs">
<MyriadFile>Library.fs</MyriadFile>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Myriad.Core" Version="0.5.0" />
<PackageReference Include="Myriad.Sdk" Version="0.5.0" />
</ItemGroup>
</Project>
插件
为Myriad提供的插件是通过将nuget包包含在您的项目中。nuget基础设施提供必要的MSBuild props和targets,这样插件就可以自动由Myriad使用。有关fields插件的源可以使用作参考,直到有关创建插件的更多详细信息创建出来。
插件命名
如果您创建了一个插件,非正式的命名约定是使用:{{OwnerNamespace}}.Myriad.Plugin
使用外部插件
为了使用不包含在"Myriad.Plugins"包中的外部插件,您必须在"Myriad"中注册它们。如果您正在使用CLI工具,那么可以通过传递--plugin <dll文件路径>
命令行参数来完成此操作。如果您使用MSBuild,则可以通过将MyriadSdkGenerator
属性添加到您的项目文件中来实现。
<ItemGroup>
<MyriadSdkGenerator Include="<path to plugin dll>" />
</ItemGroup>
例如,如果您有一个如图所示的项目布局
\src
-\GeneratorLib
- Generator.fs
- Generator.fsproj
-\GeneratorTests
- Tests.fs
- GeneratorTests.fsproj
您将需要在Generator.fsproj
中添加以下内容
<ItemGroup>
<Content Include="build\Generator.props">
<Pack>true</Pack>
<PackagePath>%(Identity)</PackagePath>
<Visible>true</Visible>
</Content>
</ItemGroup>
然后在其中添加一个名为build
的新文件夹,并在其中包含Generator.props
文件。
<Project>
<ItemGroup>
<MyriadSdkGenerator Include="$(MSBuildThisFileDirectory)/../lib/netstandard2.1/Generator.dll" />
</ItemGroup>
</Project>
通常还会使用一个额外的props文件(在本示例中,该文件为Generator.InTest.props
)来简化测试。匹配测试.fsproj
的元素可能如下所示
<Project>
<ItemGroup>
<MyriadSdkGenerator Include="$(MSBuildThisFileDirectory)/../bin/$(Configuration)/netstandard2.1/Generator.dll" />
</ItemGroup>
</Project>
请注意,包含路径是指向本地而不是打包的nuget文件夹结构。
在您的测试fsproj
中,您将需要添加以下内容以允许在本地使用插件而不是消耗nuget包
<Import Project="<Path to Generator plugin location>\build\Myriad.Plugins.InTest.props" />
调试
要调试"Myriad",您可以使用以下两个命令行选项
--verbose
— 将诊断日志写入标准输出--wait-for-debugger
— 使"Myriad"等待调试器附加到"Myriad"进程
这些可以通过通过<MyriadSdkVerboseOutput>true</MyriadSdkVerboseOutput>
和<MyriadSdkWaitForDebugger>true</MyriadSdkWaitForDebugger>
属性分别在MSBuild中触发。
Nuget
"Myriad"的nuget包可以在这里找到:Nuget包。
Dotnet模板
Myriad插件/生成器的dotnet模板可在以下位置找到
#install dotnet template
dotnet new -i Myriad.Templates
#create myriad generator from the template
dotnet new myriadgenerator -n myMyriadPlugin
如何构建和测试
- 请确保您已安装.Net Core SDK - 在
global.json
中检查所需版本 - 运行
dotnet tool restore
- 运行
dotnet build -c Release -t:Build
如何发布新版本
- 通过添加新条目(
## [0.X.X]
)并提交来更新CHANGELOG.md。 - 创建版本标签(
git tag v0.X.X
) - 在
Directory.Build.props
中更新VersionPrefix
以与上述标签匹配。 - 运行
dotnet build -t:Pack
以创建nuget包并在本地测试/检查它。 - 将标签推送到仓库(
git push origin v0.X.X
) - 这将启动CI过程,将创建GitHub发布并在此发布中放入生成的NuGet包 - 将生成的包上传到NuGet.org
此外,还可以参考
外部插件
以下是已构建的外部插件列表
此包没有依赖项。
Nuget包 (4)
显示依赖于Myriad.Sdk的前4个Nuget包
包 | 下载 |
---|---|
BinaryDefense.Myriad.Plugins.JsonWrapper
为[Myriad](https://github.com/MoiraeSoftware/myriad)生成的插件,可围绕给定的模式生成关于JToken的静态类型无损耗包装器。 |
|
AndreasDorfer.BehaviorTestGenerator
一个Myriad插件,可从行为生成测试类。 |
|
TheAngryByrd.Myriad.Plugins.TypeSafeInternals
TheAngryByrd.Myriad.Plugins.TypeSafeInternals使用Myriad生成对内部函数/属性/方法的类型安全反射调用。 |
|
Godot.FSharp.SourceGenerators
包描述 |
GitHub 仓库
此包未被任何流行的GitHub仓库使用。
版本 | 下载 | 最后更新 |
---|---|---|
0.8.3 | 6,378 | 9/8/2023 |
0.8.2 | 1,473 | 2/10/2023 |
0.8.1 | 4,718 | 5/13/2022 |
0.8.0 | 568 | 5/4/2022 |
0.7.4 | 1,615 | 10/29/2021 |
0.7.3 | 342 | 10/28/2021 |
0.7.3-alpha | 261 | 10/28/2021 |
0.7.2 | 352 | 10/28/2021 |
0.7.1 | 316 | 10/26/2021 |
0.7.0 | 307 | 10/21/2021 |
0.6.4 | 340 | 10/11/2021 |
0.6.3 | 450 | 9/22/2021 |
0.6.2 | 334 | 9/17/2021 |
0.6.1 | 303 | 9/17/2021 |
0.6.0 | 364 | 9/9/2021 |
0.5.4 | 348 | 9/2/2021 |
0.5.3 | 2,858 | 5/21/2021 |
0.5.1 | 665 | 4/15/2021 |
0.5.0 | 1,096 | 12/22/2020 |
0.4.1 | 765 | 9/23/2020 |
0.4.0 | 785 | 7/21/2020 |
0.2.8 | 1,129 | 6/5/2020 |
0.2.7 | 1,061 | 5/18/2020 |
0.2.6 | 503 | 5/13/2020 |
0.2.4 | 647 | 11/3/2019 |
0.2.3 | 560 | 11/3/2019 |
0.2.2 | 495 | 11/2/2019 |
0.2.1 | 519 | 11/2/2019 |
0.2.0 | 539 | 10/23/2019 |
0.1.0 | 714 | 4/19/2019 |
0.0.5 | 614 | 4/18/2019 |
0.0.4 | 544 | 4/17/2019 |
0.0.3 | 572 | 4/17/2019 |
0.0.2 | 564 | 4/17/2019 |
0.0.1 | 547 | 4/16/2019 |
0.0.1-master-0000006 | 435 | 4/16/2019 |