[英]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.