开发者

How to include a YAML file inside a YAML file in Ruby

Is there a custom tag in YAML for ruby to include a YAML file inside a YAML file?

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

A simil开发者_StackOverflowar question was asked some time ago and there was no relevant answer.

I am wondering if there is some custom tag for Ruby similar to this one for Python.


If you are in Rails, YAML can include ERB.

Combine that together, and here is how you can use <%= %> to include one file from another:

database.yml

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

database.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

database.mysql.yml

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


I found a way to address my scenario using ERB.

I monkey patched YAML module to add two new methods

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

I have three YAML files.

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") %>

Parse the yaml file using the method YAML::load_erb instead of the method YAML::load.

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

Caveats:

  1. Does not support document merge
  2. Last include overwrites same named keys


If your aim is avoiding duplication in your YAML file, not necessarily including external file, I recommend doing something like this:

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


If you just want to inherit from another YAML file, there is a gem providing this functionality you are asking for by extending the ruby YAML library:

https://github.com/entwanderer/yaml_extend

https://rubygems.org/gems/yaml_extend

Usage

yaml_extend adds the method YAML#ext_load_file to YAML.

This method works like the original YAML#load_file, by extending it with file inheritance.

Examples

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

-

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

Basic Inheritance

YAML.ext_load_file('start.yml')

results in

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


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)

Later, you can access config values by doing:

CONFIG['value']


  1. !include is not a directive but a tag.
  2. it is not a feature of Python (or PyYAML) but a feature of the "poze" library:

    poze.configuration exposes a default directive named include.

  3. YAML specification does not define such a standard tag.


Depends what you need it for. If you need to transport file, you can base64 encode internal yaml file.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜