简体   繁体   English

从文件到函数内部全局范围的点源函​​数

[英]Dot-sourcing functions from file to global scope inside of function

I want to import external function from file, not converting it to a module (we have hundreds of file-per-function, so treat all them as modules is overkill).我想从文件中导入外部函数,而不是将其转换为模块(我们每个函数有数百个文件,因此将它们全部视为模块是多余的)。

Here is code explanation.这里是代码解释。 Please notice that I have some additional logic in Import-Function like adding scripts root folder and to check file existence and throw special error, to avoid this code duplication in each script which requires that kind of import.请注意,我在 Import-Function 中有一些额外的逻辑,例如添加脚本根文件夹并检查文件是否存在并抛出特殊错误,以避免在需要这种导入的每个脚本中出现此代码重复。

C:\\Repository\\Foo.ps1: C:\\Repository\\Foo.ps1:

Function Foo {
    Write-Host 'Hello world!'
}

C:\\InvocationTest.ps1: C:\\InvocationTest.ps1:

# Wrapper func
Function Import-Function ($Name) {
    # Checks and exception throwing are omitted
    . "C:\Repository\$name.ps1"

    # Foo function can be invoked in this scope
}

# Wrapped import
Import-Function -Name 'Foo'
Foo          # Exception: The term 'Foo' is not recognized

# Direct import
. "C:\Repository\Foo.ps1"
Foo          # 'Hello world!'

Is there any trick, to dot source to global scope?有什么技巧可以将源点到全局范围吗?

You can't make the script run in a parent scope, but you can create a function in the global scope by explicitly scoping it. 您不能使脚本在父作用域中运行,但是可以通过显式作用域在全局作用域中创建一个函数。

Would something like this work for you? 这样的事情对您有用吗?

# Wrapper func
Function Import-Function ($Path) {
    # Checks and exception throwing are omitted
    $script = Get-Content $Path
    $Script -replace '^function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)', 'function Global:$1'
    .([scriptblock]::Create($script))

}

The above regex only targets root functions (functions left justified; no white space to left of the word function ). 上面的正则表达式仅针对根函数(左对齐的函数;单词function左侧没有空格)。 In order to target all functions, regardless of spacing (including sub-functions), change the $Script -replace line to: 为了以所有功能为目标,而与空格(包括子功能)无关,请将$Script -replace行更改为:

$Script -replace '^\s*function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)','function Global:$1'

You can change the functions that are defined in the dot-sourced files so that they are defined in the global scope: 您可以更改基于点的文件中定义的功能,以便在全局范围内定义它们:

function Global:Get-SomeThing {
    # ...
}

When you dot source that from within a function, the function defined in the dot sourced file will be global. 当您在函数中对源进行点运算时,在点源文件中定义的函数将是全局的。 Not saying this is best idea, just another possibility. 不说这是最好的主意,只是另一种可能性。

I can't remember a way to run a function in global scope right now. 我不记得现在在全局范围内运行函数的方法。 You could do something like this: 您可以执行以下操作:

$name = "myscript"

$myimportcode= {
    # Checks and exception throwing are omitted
    . .\$name.ps1
    # Foo function can be invoked in this scope
}

Invoke-Expression -Command $myimportcode.ToString()

When you convert the scriptblock to a string .ToString() , the variable will expand. 当您将脚本块转换为字符串.ToString() ,变量将扩展。

Just dot-source the function as well:也只需点源函数:

. Import-Function -Name 'Foo'
Foo # Hello world!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM