如何在Ruby中将一个YAML文件包含到另一个YAML文件中

21

在YAML中,是否有自定义标签可以用于将一个YAML文件包含在另一个YAML文件中?

#E.g.:  
--- !include
filename: another.yml

之前有人提出了一个相似的问题,但没有相关答案。

我想知道是否有类似于Python中this的自定义标签适用于Ruby。


可能是重复问题:如何在另一个 YAML 文件中包含一个 YAML 文件? - George Hilliard
7个回答

19

如果你在Rails中,YAML可以包含ERB。

将它们结合起来,以下是如何使用<%= %>从一个文件中引用另一个文件:

database.yml

<% if File.exists?('/tmp/mysql.sock') %>
<%= IO.read('config/database.mysql.yml') %>
<% else %>
<%= IO.read('config/database.sqlite.yml') %>
<% end %>

数据库.sqlite.yml

sqlite: &defaults
  adapter: sqlite3
  pool: 5
  timeout: 5000

development:
  <<: *defaults
  database: db/development.sqlite3

test:
  <<: *defaults
  database: db/test.sqlite3

production:
  <<: *defaults
  database: db/production.sqlite3

数据库.mysql.yml

development:
  adapter: mysql2
  # ... the rest of your mysql configuration ...

15

我找到了使用ERB解决我的情况的方法。

我对YAML模块进行了猴子补丁,以添加两个新方法。

module YAML
    def YAML.include file_name
      require 'erb'
      ERB.new(IO.read(file_name)).result
    end

    def YAML.load_erb file_name
      YAML::load(YAML::include(file_name))
    end  
end

我有三个YAML文件。

mod1_config.yml

mod1:
    age: 30
    city: San Francisco

mod2_config.yml

mod2:
    menu: menu1
    window: window1

all_config.yml

<%= YAML::include("mod1_config.yml") %>
<%= YAML::include("mod2_config.yml") %>

使用方法YAML::load_erb而不是YAML::load来解析yaml文件。

  config = YAML::load_erb('all_config.yml') 
  config['mod1']['age'] # 30
  config['mod2']['menu'] # menu1

注意事项:

  1. 不支持文档合并
  2. 最后一个引用将覆盖相同名称的键

我遇到了错误 private method 'include' called for Psych:Module (NoMethodError),你有什么猜测如何解决吗? 我已经在 initializers/yaml.rb 中添加了 YAML 模块。 - swapab
太棒了@Harish,它甚至可以与<<:* foo一起很好地工作 - jprio

9
如果您的目标是在YAML文件中避免重复,而不一定要包含外部文件,我建议这样做:

如果你的目标是在 YAML 文件中避免重复,而不必要包含外部文件,那么我建议你这样做:

development: &default
  adapter: mysql
  encoding: utf8
  reconnect: false
  database: db_dev
  pool: 5
  username: usr
  password: psw
  host: localhost
  port: 3306

dev_cache:
  <<: *default

new:
  <<: *default
  database: db_new

test:
  <<: *default
  database: db_test

2
你可能需要 YAML::ENGINE.yamler = 'syck' 才能使其正常工作 https://dev59.com/pVfUa4cB1Zd3GeqPJpsi#6140900 - evanrmurphy

4
如果你只想从另一个YAML文件继承,有一个gem提供了这个功能,它通过扩展Ruby的YAML库来实现你所要求的功能。

https://github.com/entwanderer/yaml_extend

https://rubygems.org/gems/yaml_extend

使用方法

yaml_extend 为 YAML 添加了 YAML#ext_load_file 方法。

该方法类似于原始的 YAML#load_file,通过文件继承进行扩展。

示例

# start.yml
extends: 'super.yml'
data:
    name: 'Mr. Superman'
    age: 134    
    favorites:
        - 'Raspberrys'

-

# super.yml
data:
    name: 'Unknown'
    power: 2000
    favorites:
        - 'Bananas'
        - 'Apples'

基本继承

YAML.ext_load_file('start.yml')

导致

data:
    name: 'Mr. Superman'
    age: 134
    power: 2000
    favorites:
        - 'Bananas'
        - 'Apples'
        - 'Raspberrys'

2

I'm using this:

load_config.rb (initializer)

cf_1 = YAML::load(File.read("/etc/my_app/config.yml"))
cf_2 = YAML::load(File.read(File.join(Rails.root, "config", "config.yml")))
CONFIG = cf_1.merge(cf_2)

稍后,您可以通过以下方式访问配置值:
CONFIG['value']

1
  1. !include 不是指令而是标签。
  2. 这不是Python(或PyYAML)的特性,而是“poze”库的特性:

    poze.configuration 公开了一个名为include的默认指令。

  3. YAML规范没有定义这样的标准标签。


1
YAML规范中没有!include标签。我希望有人已经编写了类似“poze”库中自定义标签的自定义标签。我猜这是时候自己编写自定义标签了 :-) - Harish Shetty

0

这取决于你需要做什么。如果你需要传输文件,可以对内部的yaml文件进行base64编码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接