Sử dụng YAML với các biến


82

Các biến trong tệp YAML có khả thi không? Ví dụ:

theme:
  name: default
  css_path: compiled/themes/$theme.name
  layout_path: themes/$theme.name

Trong ví dụ này, làm thế nào có thể theme: name: defaultđược sử dụng trong các cài đặt khác? Cú pháp là gì?


Bạn đang sử dụng ngôn ngữ / thư viện nào để phân tích cú pháp YAML này? Không có cách chuẩn nào để thực hiện việc này trong YAML, nhưng có thể thư viện của bạn có một số thủ thuật.
Jesse Beder


@CiroSantilli 巴拿馬 文件 六四 事件 法轮功 ;; có liên quan chặt chẽ, nhưng không trùng lặp. Các biến tùy ý không được hỗ trợ trong YAML tiêu chuẩn, tuy nhiên có sẵn các tham chiếu chéo đến toàn bộ phần tử từ cây phân tích cú pháp YAML. Do đó các câu hỏi hơi khác nhau.
dreftymac


Câu trả lời:


106

Tôi cũng có câu hỏi này, và sau rất nhiều nghiên cứu, có vẻ như không thể .

Câu trả lời từ cgat đang đi đúng hướng, nhưng bạn không thể thực sự nối các tham chiếu như vậy.

Dưới đây là những điều bạn có thể làm với "biến" trong YAML (được gọi chính thức là "neo nút" khi bạn đặt chúng và "tham chiếu" khi bạn sử dụng chúng sau này):

Xác định một giá trị và sử dụng một bản sao chính xác của nó sau này:

default: &default_title This Post Has No Title
title: *default_title

{ hoặc là }

example_post: &example
  title: My mom likes roosters
  body: Seriously, she does. And I don't know when it started.
  date: 8/18/2012
first_post: *example
second_post:
  title: whatever, etc.

Để biết thêm thông tin, hãy xem phần này của trang wiki về YAML: http://en.wikipedia.org/wiki/YAML#Reference

Xác định một đối tượng và sử dụng nó với các sửa đổi sau:

default: &DEFAULT
  URL:          stooges.com
  throw_pies?:  true  
  stooges:  &stooge_list
    larry:  first_stooge
    moe:    second_stooge
    curly:  third_stooge

development:
  <<: *DEFAULT
  URL:      stooges.local
  stooges: 
    shemp: fourth_stooge

test:
  <<: *DEFAULT
  URL:    test.stooges.qa
  stooges: 
    <<: *stooge_list
    shemp: fourth_stooge

Điều này được lấy trực tiếp từ một bản demo tuyệt vời tại đây: https://gist.github.com/bowsersenior/979804


1
Ngoài ra, câu hỏi này về cơ bản là một bản sao: stackoverflow.com/questions/2063616/...
benrugg

1
Làm gì <<? Tôi dường như không thể tìm thấy nó trong tài liệu .
Hi-Angel

1
@ Hi-Angel YAML Merge Key Specification trả lời câu hỏi <<làm gì?
dreftymac

46

Sau một số tìm kiếm, tôi đã tìm thấy một giải pháp sạch hơn sử dụng %toán tử.

Trong tệp YAML của bạn:

key : 'This is the foobar var : %{foobar}'

Trong mã ruby ​​của bạn:

require 'yaml'

file = YAML.load_file('your_file.yml')

foobar = 'Hello World !'
content = file['key']
modified_content = content % { :foobar => foobar }

puts modified_content

Và đầu ra là:

This is the foobar var : Hello World !

Như @jschorr đã nói trong nhận xét, bạn cũng có thể thêm nhiều biến vào giá trị trong tệp Yaml:

Yaml:

key : 'The foo var is %{foo} and the bar var is %{bar} !'

Ruby:

# ...
foo = 'FOO'
bar = 'BAR'
# ...
modified_content = content % { :foo => foo, :bar => bar }

Đầu ra:

The foo var is FOO and the bar var is BAR !

1
Tìm thấy tuyệt vời; điều thú vị là bạn cũng có thể thực hiện nhiều biến:% {var1: 'anything', var2: 'anotherone'}.
jschorr

2
Tìm hiểu thêm về %điều hành của Ruby chuỗi: ruby-doc.org/core-2.2.3/String.html#method-i-25
Trantor Liu

Một cách khác là tải yaml, nó sẽ cung cấp cho bạn một hàm băm trong ruby. Các thay đổi có thể được thực hiện đối với hàm băm và sau đó được ghi lại vào tệp.
leoOrion

Công cụ tuyệt vời. Cũng hoạt động với ReactJS + Webpack + messageformat-loader + react-message-context + giải pháp YAML. Nó thực sự hoạt động tốt khi sử dụng biến làm prop: <Message id = {'textId'} foo = {'some text'} />
Arkadiusz Lendzian

3

Đây là một bài viết cũ, nhưng tôi cũng có nhu cầu tương tự và đây là giải pháp mà tôi nghĩ ra. Nó là một chút hack, nhưng nó hoạt động và có thể được tinh chỉnh.

require 'erb'
require 'yaml'

doc = <<-EOF
  theme:
  name: default
  css_path: compiled/themes/<%= data['theme']['name'] %>
  layout_path: themes/<%= data['theme']['name'] %>
  image_path: <%= data['theme']['css_path'] %>/images
  recursive_path: <%= data['theme']['image_path'] %>/plus/one/more
EOF

data = YAML::load("---" + doc)

template = ERB.new(data.to_yaml);
str = template.result(binding)
while /<%=.*%>/.match(str) != nil
  str = ERB.new(str).result(binding)
end

puts str

Một nhược điểm lớn là nó tích hợp vào tài liệu yaml một tên biến (trong trường hợp này là "dữ liệu") có thể tồn tại hoặc không. Có lẽ giải pháp tốt hơn sẽ là sử dụng $ và sau đó thay thế nó bằng tên biến trong Ruby trước ERB. Ngoài ra, vừa thử nghiệm bằng cách sử dụng hashes2ostruct cho phép ký hiệu kiểu data.theme.name dễ nhìn hơn nhiều. Tất cả những gì được yêu cầu là quấn YAML :: tải bằng cái này

data = hashes2ostruct(YAML::load("---" + doc))

Sau đó, tài liệu YAML của bạn có thể trông như thế này

doc = <<-EOF
  theme:
  name: default
  css_path: compiled/themes/<%= data.theme.name %>
  layout_path: themes/<%= data.theme.name %>
  image_path: <%= data.theme.css_path %>/images
  recursive_path: <%= data.theme.image_path %>/plus/one/more
EOF

0

Các khung công tác Rails / ruby ​​có thể thực hiện một số khuôn mẫu ... nó thường được sử dụng để tải các biến env ...

# fooz.yml
  foo:
    bar: <%= $ENV[:some_var] %>

Không có ý tưởng nếu điều này hoạt động cho các khung javascript vì tôi nghĩ rằng định dạng YML là tập hợp lớn hơn của json và nó phụ thuộc vào những gì đọc tệp yml cho bạn.

Nếu bạn có thể sử dụng mẫu như vậy hoặc << >>hoặc các {{ }}kiểu tùy thuộc vào người đọc của bạn, sau đó bạn chỉ cần ...

Trong một tệp yml khác ...

# boo.yml

development:
  fooz: foo

Điều này cho phép bạn về cơ bản chèn một biến làm tham chiếu đến tệp gốc của bạn mỗi lần được đặt động. Khi đọc, tôi cũng thấy bạn có thể tạo hoặc mở tệp YML dưới dạng đối tượng cho một số ngôn ngữ cho phép bạn tạo tệp và ghi chuỗi một loạt tệp YML hoặc chỉ cần đặt tất cả chúng một cách tĩnh trỏ đến tệp được tạo động.


0

nếu yêu cầu của bạn giống như phân tích cú pháp một biến thay thế nhiều biến và sau đó sử dụng nó như một hàm băm / hoặc bất cứ thứ gì thì bạn có thể làm như thế này

require 'yaml'
require 'json'
yaml = YAML.load_file("xxxx.yaml")
blueprint = yaml.to_json % { var_a: "xxxx", var_b: "xxxx"}
hash = JSON.parse(blueprint)

bên trong yaml chỉ cần đặt các biến như thế này

"%{var_a}"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.