有没有办法在 YAML 中别名/锚定数组?

问题描述 投票:0回答:6

我正在使用 Jammit 为 Rails 应用程序打包资源,并且我有一些资源文件,我希望将它们包含在几个组中的每个组中。例如,我希望 Sammy 及其插件同时出现在我的

mobile
screen
JS 包中。

我试过这个:

sammy: &SAMMY
  - public/javascripts/vendor/sammy.js
  - public/javascripts/vendor/sammy*.js

mobile:
  <<: *SAMMY
  - public/javascripts/something_else.js

还有这个:

mobile:
  - *SAMMY

但是两者都将 Sammy JS 文件放入嵌套数组中,这是 Jammit 无法理解的。是否有一种语法可以将一个数组的元素直接包含在另一个数组中?

NB:我意识到在这种情况下,

SAMMY
数组中只有两个元素,因此在每个包中为每个元素提供别名和引用也不会太糟糕。对于这种情况来说这很好,但是当有五个或十个具有特定加载顺序的元素时,很快就会变得难以维护。

yaml assets
6个回答
79
投票

我知道的最接近的解决方案是这个:

sammy:
  - &SAMMY1
    public/javascripts/vendor/sammy.js
  - &SAMMY2
    public/javascripts/vendor/sammy*.js

mobile:
  - *SAMMY1
  - *SAMMY2
  - public/javascripts/something_else.js

或者,正如已经建议的那样,展平代码片段中的嵌套列表。

注意:根据 yaml-online-parser,您的第一个建议不是 << (used to merge keys from two dictionaries. The anchor then has to point to another dictionary I believe.

的有效使用

50
投票

如果你想让

mobile
等于
sammy
,你可以这样做:

mobile: *SAMMY

但是,如果您希望

mobile
除了
sammy
中的元素之外还包含其他元素,据我所知,在 YAML 中无法做到这一点。


37
投票

您的示例是有效的 YAML(一个方便检查的地方是 YPaste),但它没有定义合并的作用。根据 spec,合并键可以有一个值:

  1. 映射,在这种情况下,它会合并到父映射中。
  2. 一系列映射,在这种情况下,每个映射都会被一一合并到父映射中。

无法在 YAML 级别合并序列

但是,您可以在代码中执行此操作。使用第二个想法中的 YAML:

mobile:
  - *SAMMY

你会得到嵌套序列 - 所以将它们展平!假设您有此类嵌套序列的映射:

data = YAML::load(File.open('test.yaml'))
data.each_pair { |key, value| value.flatten! }

(当然,如果你有一个更复杂的 YAML 文件,并且你不希望每个序列都被展平(或者它们不是全部序列),你就必须进行一些过滤。)


1
投票

此解决方案仅适用于 Symfony/PHP (其他语言的注意事项,请参阅下文)

有关 PHP 数组手册页中的数组键的注释

包含有效十进制整数的字符串,除非数字前面有 + 号,否则将被转换为 int 类型。例如。键“8”实际上将存储在 8 下。[...]

这意味着,如果您实际上使用整数键对锚数组进行索引,则可以通过继续初始列表来简单地添加新键。所以你的解决方案将如下所示:

sammy: &SAMMY
  1: public/javascripts/vendor/sammy.js
  2: public/javascripts/vendor/sammy*.js

mobile:
  <<: *SAMMY
  3: public/javascripts/something_else.js

您甚至可以覆盖密钥并仍然添加新密钥:

laptop:
  <<: *SAMMY
  1: public/javascripts/sammy_laptop.js
  3: public/javascripts/something_else.js

在这两种情况下,最终结果都是一个完全有效的索引数组,就像以前一样。


其他编程语言

根据您的 YAML 实现 以及 您如何迭代数组,这也可以在其他编程语言中使用。尽管有一个警告。

例如,在 JS 中,您也可以通过整数值访问数字字符串键:

const sammy = {"1": "public/javascripts/vendor/sammy.js"}

sammy["1"]; // "public/javascripts/vendor/sammy.js"
sammy[1]; // "public/javascripts/vendor/sammy.js"

但是您需要记住,您的初始数组现在是一个对象,并且您需要相应地迭代它,例如:

Object.keys(sammy).forEach(key => console.log(sammy[key]))

0
投票

这是一个仅使用 yaml 的有效示例,其中在列表中包含更复杂的项目(例如具有多个键的对象):

sammy:
  - &A1
    public/javascripts/vendor/sammy.js: asdf
    public/javascripts/vendor/sammyz.js: asdfz
  - &A2
    public/javascripts/vendor/sammy2.js: asdf2
    public/javascripts/vendor/sammy2z.js: asdf2z

mobile: [*A1, *A2, { 
  public/javascripts/something_else.js: else,
  public/javascripts/something_else2.js: else2,

}]

输出的 JSON 表示:

{
  "mobile": [
    {
      "public/javascripts/vendor/sammy.js": "asdf", 
      "public/javascripts/vendor/sammyz.js": "asdfz"
    }, 
    {
      "public/javascripts/vendor/sammy2.js": "asdf2", 
      "public/javascripts/vendor/sammy2z.js": "asdf2z"
    }, 
    {
      "public/javascripts/something_else.js": "else", 
      "public/javascripts/something_else2.js": "else2"
    }
  ], 
  "sammy": [
    ...
  ]
}

您会得到简洁,但需要权衡的是需要使用显式的括号语法。


-4
投票

正如所建议的,当您需要展平列表时,至少在 ruby 中,向 mobile 添加“!展平”类型说明符并实现一个扩展 Array 的类、添加 yaml_tag 并展平编码器 seq 是微不足道的在 init_with 上。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.