我总是认为自己是一个Powershell纯粹主义者。用PowerShell编写的DSL(特定于域的语言)滥用我所养成的所有规则。我最近发现自己构建一个由作为DSL实现的模块,我真的很喜欢它是如何结果的。不仅如此,而且我也很开心写它。

这是一个系列中的第一篇文章,涵盖了DSL是什么以及如何编写一个。

指数

什么是DSL?

“特定于域的语言(DSL)是一种专门用于特定应用程序域的计算机语言。这与通用语言(GPL)相反,这在域中广泛适用,并且缺乏特定域的专业功能。“ - 维基百科

再说一次?

应用程序域可以专门用于它具有描述事物的自己的语言。有时,这对我们正在使用的工具并不好。我们有很多方法可以接近这些问题并使用DSL是其中之一。

任何好的例子?

HTML. ,CSS,XML和SQL都是DSL。这是一些基本片段。

HTML.

    <html>
        <body>
        <h1>My heading</h1>
            A basic page of html
        </body>
    </html>

CSS.

p {
  color: red;
  text-align: center;
}

XML.

<persons>
    <person first="Kevin" last="Marquette" />
<persons>

SQL.

Select Name From tablePerson Where ID = 1

在每种情况下,他们都有自己的术语和模式领域。我们现在也有几个良好的榜样。 DSC, 纠缠 , Psake. Psgraph.. 全部实施为DSL。

DSC.

Configuration myConfig {
    Node 'localhost' {
        File 'tools' {
            Destination = 'c:\tools'
        }
    }
}

纠缠

Describe "Unit Test" {
    It "Does something" {
        "Something" | Should -Be "Something"
    }
}

Psake.

Task default -Depends Test

Task Test -Depends Compile {
    "This is a test"
}

Task Compile {
    "Compile"
}

invokebuild.

Task Default Test

Task Test Compile,{
    "This is a test"
}

Task Compile {
    "Compile"
}

Psgraph..

Graph {
    Node @{shape='rectangle'}
    Edge start -To end
}

PowerShell中的一个DSL

创建DSL有两种方法。第一个使用数据部分来限制可用的命令。另一个滥用参数的机制。值得学习,因为它们可以混合在一起。

数据部分

电源外壳 中有一点已知关键字,可让您定义一个 数据部分 。这是一个脚本块,其唯一包含数据,除非您否则指定。

    Data {'Hellow Wolrd'}

It can handle some basic logic but most cmdlets are not allowed to be executed in a data section. If you have some special commands that you want to include, then you need specify them as -SupportedCommands.

    DATA -SupportedCommand Format-XML {
        Format-XML -strings string1, string2, string3
    }

在实践中

I went looking for examples in Github. The common use case I saw for this was when importing a text file that contained their specific DSL. The -SuppportedCommand was used to limit the text file to only data and their DSL commands.

这是它是如何使用的例子:

    $Content = Get-Conent -Path $Path
    Invoke-Expression -Command "DATA -SupportedCommand Import-DscConfigurationData,Import-PSEncryptedCredential,Import-PSEncryptedData {$($Content)}"

The pattern was to import the contents of a file into a string like the one above and either Invoke-Expression on it or create a [scriptblock] 和 run invoke().

原始DSL功能

在跟踪一些早期谈论PowerShell可以用于创建一个DSL之后,我觉得这是他们正在谈论的功能。我认为使用CDMLETS为DSL的方式我在下一节中描述的方式是出乎意料的,当他们第一次到达现场时出乎意料。

基于CMDLET的DSL示例

我们在PowerShell实现的自定义DSL中最常见的方式是使用cmdlet。它们往往不要使用名词 - 动词结构,并且它们大量使用位置参数。让我们看看纠缠纠纷的一个例子。

    Describe "Unit Test" {
        It "Does something" {
            "Something" | Should Be "Something"
        }
    }

乍一看,看起来与PowerShell一样。让我翻译成传统的力量。

    Describe -Name "Unit Test" -Fixture {
        It -Name "Does Something" -Fixture {
            Should -ActualValue "Something" -Be -ExpectedContent "Something"
        }
    }

This looks a little more like the Powershell we know, but it still takes advantage of the [scriptblock] in a less common way. Here is one more translation that don’t nest the [scriptblock].

    $TestScript = {
        Should -ActualValue "Something" -Be -ExpectedContent "Something"
    }
    $DescribeScript = {
        It -Name "Does Something" -Fixture $TestScript
    }
    Describe -Name "Unit Test" -Fixture $DescribeScript

如果您不得不编写所有测试,就像用正常的PowerShell写下你的测试就会更容易。希望有助于显示写入良好的DSL的价值。

下一步是什么?

下周我们将构建基于DSL的cmdlet,为Microsoft的远程桌面连接管理器生成RDG文件。我不能说我们需要一个DSL,但这将是一个简单的示例,介绍了一些不同的技术。

继续第2部分: 为RDC Manager写一个DSL

测试