Myriad.Plugins 0.8.3
dotnet add package Myriad.Plugins --version 0.8.3
NuGet\Install-Package Myriad.Plugins -Version 0.8.3
<PackageReference Include="Myriad.Plugins" Version="0.8.3" />
paket add Myriad.Plugins --version 0.8.3
#r "nuget: Myriad.Plugins, 0.8.3"
// Install Myriad.Plugins as a Cake Addin #addin nuget:?package=Myriad.Plugins&version=0.8.3 // Install Myriad.Plugins as a Cake Tool #tool nuget:?package=Myriad.Plugins&version=0.8.3
Myriad
Myriad 是一个代码生成器。它接受任意文件,并提供了不同的机制来允许产生 F# 代码,无论是 F# 源文件还是简单的文本文件。
可以从 MSBuild 扩展或 Myriad 的 CLI 工具使用 Myriad。
Myriad 的理念在于尽可能简化 F# 中进行元编程的能力。在这里,我所说的元编程是指在 F# 中使用原生类型(如区分联合和记录)来生成惯用 F# 代码,这是 F# 类型提供程序等所无法做到的,因为它们只输出基本的 .NET 类。
Myriad 是我在与 F# 的类型提供器和类似引用和 AST 简化等功能一起工作时发展出的想法的演变。Myriad 致力于通过 Myriad 插件轻松扩展编译器。Myriad 提供了一种编译器扩展方法,该方法不修改或调整类型提供器,也不需要等待很长时间的其他 F# 语言改进。您编写一个对 AST 输入片段进行操作的 Myriad 插件,插件提供最终形式的 AST 输出,这是一段编译到您项目中的源代码。这可以让编译器优化生成的输出,并允许工具有效地运行。
如果您想帮助并提供代码,那就太好了,请检查问题并做出拉的请求。
如果您喜欢这个存储库并且希望表达您的感激之情等,那么我确实有 Ko-fi
通过 MSBuild 使用
要通过 MSBuild 支持使用 Myriad,您需要添加 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
进行操作,那么属性就可以像示例中那样使用,只为 Test1
应用 Generator.Fields
。注意,如果您需要一个只需要整个输入 AST 的插件,则不需要提供输入。Myriad 致力于成为一个库,而不是一个完整的框架,该框架将您绑定到用于输入和生成代码的机制。传递给 "fields" 属性的参数指定了用于配置部分的 myriad.toml
文件中的插件。在此实例中,使用了 fields,而 myriad.toml
文件如下
[fields]
namespace = "TestFields"
这指定了插件使用的命名空间,在这个例子中是 "TestFields"。
在这个例子中,field 插件将在预构建时间生成以下代码并将代码编译到您的程序集
//------------------------------------------------------------------------------
// 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 }
Field 插件为输入记录中的每个字段生成一个 map
,一个接受每个字段的 create
函数,以及一个接受输入记录中每个字段的函数的 map
函数。
每个字段的 map 函数在只想使用记录中的单个字段的情况下很有用,例如在记录列表中使用 lambda。
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 是类型中一个属性的 对 ,包含一个 getter
和一个 setter
。给定对象 Lens 允许您获取属性的值或更新它,创建一个新的对象。Lens 优势在于可以组合它们以读取或更新对象的嵌套字段。
要为您的类型创建 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 })
通常,镜头被定义为围绕一对获取器和设置器的一个单例联合。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属性和目标,以便插件能够被Myriad自动使用。按照对字段插件的来源,可以作为编写插件的参考,直到创建更多有关插件的详细信息。
插件的命名
如果您编写了一个插件,则非正式的命名约定是使用:{{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
如何发布新版本
- 更新CHANGELOG.md,并添加新的条目(例如:
## [0.X.X]
)并提交 - 创建版本标签(
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
另请参阅
外部插件
以下是一些已经构建的外部插件列表
产品 | 版本 兼容和额外的计算目标框架版本。 |
---|---|
.NET | net5.0 已计算。 net5.0-windows 已计算。 net6.0 兼容。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。 |
.NET Core | netcoreapp3.0 已计算。 netcoreapp3.1 已计算。 |
.NET Standard | netstandard2.1 兼容。 |
MonoAndroid | monoandroid 已计算。 |
MonoMac | monomac 已计算。 |
MonoTouch | monotouch 已计算。 |
Tizen | tizen60 已计算。 |
Xamarin.iOS | xamarinios 已计算。 |
Xamarin.Mac | xamarinmac 已计算。 |
1. Xamarin.TVOS | xamarintvos 已计算。 |
2. Xamarin.WatchOS | xamarinwatchos 已计算。 |
-
.NETStandard 2.1
- Myriad.Core (>= 0.8.3)
-
net6.0
- Myriad.Core (>= 0.8.3)
NuGet 包
此包未被任何 NuGet 包使用。
GitHub 仓库
此包未被任何流行的 GitHub 仓库使用。
版本 | 下载 | 最后更新 |
---|---|---|
0.8.3 | 1,659 | 9/8/2023 |
0.8.2 | 1,122 | 2/10/2023 |
0.8.1 | 493 | 5/13/2022 |
0.8.0 | 454 | 5/4/2022 |
0.7.4 | 743 | 10/29/2021 |
0.7.3 | 317 | 10/28/2021 |
0.7.3-alpha | 217 | 10/28/2021 |
0.7.2 | 344 | 10/28/2021 |
0.7.1 | 306 | 10/26/2021 |
0.7.0 | 308 | 10/21/2021 |
0.6.4 | 334 | 10/11/2021 |
0.6.3 | 318 | 9/22/2021 |
0.6.2 | 350 | 9/17/2021 |
0.6.1 | 310 | 9/17/2021 |
0.6.0 | 330 | 9/9/2021 |
0.5.4 | 347 | 9/2/2021 |
0.5.3 | 910 | 5/21/2021 |
0.5.1 | 616 | 4/15/2021 |
0.5.0 | 868 | 12/22/2020 |
0.4.1 | 709 | 9/23/2020 |
0.4.0 | 650 | 7/21/2020 |
0.2.8 | 486 | 6/5/2020 |
0.2.7 | 724 | 5/18/2020 |
0.2.6 | 461 | 5/13/2020 |