簡體   English   中英

在Ruby項目的YAML文件中訪問環境變量(使用$ {ENVVAR}語法)

[英]Accessing environment variables in a YAML file for Ruby project (using ${ENVVAR} syntax)

我正在構建一個使用Ruby來測試HTTP服務的開源項目: https//github.com/Comcast/http-blackbox-test-tool

我希望能夠在test-plan.yaml文件中引用環境變量。 我可以使用ERB,但是我不想支持嵌入任何隨機Ruby代碼,並且ERB語法對於非rubyists來說很奇怪,我只想使用常用的Unix樣式${ENV_VAR}語法來訪問環境變量。

例如

order-lunch-app-health:
  request:
    url: ${ORDER_APP_URL}
    headers: 
      content-type: 'application/text'
    method: get
  expectedResponse:
    statusCode: 200
    maxRetryCount: 5

我發現Ruby的所有例子都使用了ERB。 有沒有人有關於處理這個問題的最佳方法的建議? 我願意使用另一個工具來預處理YAML,然后將其發送到Ruby應用程序。

我相信這樣的事情在大多數情況下應該有效:

require 'yaml'

def load_yaml(file)
  content = File.read file
  content.gsub! /\${([^}]+)}/ do
    ENV[$1]
  end

  YAML.load content
end

p load_yaml 'sample.yml'

與我原來的答案相反,這既簡單又處理未定義的ENV變量。

試試這個YAML:

# sample.yml
path: ${PATH}
home: ${HOME}
error: ${NO_SUCH_VAR}

原始答案(留待參考)

有幾種方法可以做到這一點。 如果您希望允許用戶使用${VAR}語法,那么可能有一種方法是首先將這些變量轉換為Ruby字符串替換格式%{VAR} ,然后一起評估所有環境變量。

這是概念的粗略證明:

require 'yaml'

# Transform environments to a hash of { symbol: value }
env_hash = ENV.to_h.transform_keys(&:to_sym)

# Load the file and convert ${ANYTHING} to %{ANYTHING}
content = File.read 'sample.yml'
content.gsub! /\${([^}]+)}/, "%{\\1}"

# Use Ruby string substitution to replace %{VARS}
content %= env_hash

# Done
yaml = YAML.load content
p yaml

與此sample.yml使用例如:

# sample.yml
path: ${PATH}
home: ${HOME}

當然,有很多方法可以改進。

預處理很簡單,我建議您使用基於YAML loaderd / dumper的解決方案,因為替換可能需要替換標量周圍的引號。 (例如,您將字符串替換為true ,如果未引用該字符串,則生成的YAML將被讀取為布爾值)。

假設你的“來源”在input.yaml和你的環境中。 變量ORDER_APP_URL設置為https://some.site/and/url 以及expand.py的以下腳本:

import sys
import os
from pathlib import Path
import ruamel.yaml

def substenv(d, env):
    if isinstance(d, dict):
        for k, v in d.items():
            if isinstance(v, str) and '${' in v:
                d[k] = v.replace('${', '{').format(**env)
            else:
                substenv(v, env)
    elif isinstance(d, list):
        for idx, item in enumerate(d):
            if isinstance(v, str) and '${' in v:
                d[idx] = item.replace('${', '{').format(**env)
            else:
                substenv(item, env)


yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load(Path(sys.argv[1]))

substenv(data, os.environ)
yaml.dump(data, Path(sys.argv[2]))

然后你可以這樣做:

python expand.py input.yaml output.yaml

寫出output.yaml

order-lunch-app-health:
  request:
    url: https://some.site/and/url
    headers:
      content-type: 'application/text'
    method: get
  expectedResponse:
    statusCode: 200
    maxRetryCount: 5

請注意,'application / text'周圍的虛假引號會被保留,原始文件中的任何注釋都會被保留。

替換URL周圍的引號不是必需的,但是如果它們已經添加了。

substenv例程遞歸地遍歷加載的數據,並且即使替換是在標量中,並且如果在一個標量中存在多個替換,則替換。 你可以“收緊”測試:

        if isinstance(v, str) and '${' in v:

如果那將匹配從YAML加載的太多字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM