1
votes

I have a Jekyll project where two separate pages (A.html and B.html) are displaying different content based on data in YAML files A.yml and B.yml respectively. Each yml file has a bunch of variables that are defined identically. I'd prefer to keep this common list of variables in a third file C.yml and include it into both A.yml and B.yml. How can I do this?

Things I've tried:

  • Using * to reference global data like *site.data.C.vars - this didn't parse.
  • Put C.yml in _includes directory and use front matter treat the page like a liquid template and call {% include C.yml %} - this compiled, but the emitted html page had no content whatsoever.

Edit - example usage

Using a common data file in multiple views isn't quite sufficient for me because there would also need to be name-resolution logic in liquid to accompany it. Here's an example of what my data might look like:

A.yml

ingredients:
  - avacado: &avacado
      name: Avacado
      color: Green
      foods:
        - *octopus_ceviche

B.yml

chefs:
  - anthony_bourdain: &anthony_bourdain
      name: Anthony Bourdain
      hobby: Brazilian Jiu-Jitsu
      foods:
        - *octopus_ceviche

C.yml

foods:
  - octopus_ceviche: &octopus_ceviche
      name: Octopus Ceviche
      taste: Delicious

If there's no way to include C.yml in A and B, then all the foods need to be shared in both places. If food is used in the md/html page entries need to be accessed by direct hash access (e.g. {{ site.data.foods[octopus_ceviche] }}), which a) doesn't seem to work and b) feels like too much logic for a view.

4
*octupus_ceviche is not Liquid name resolution, it's a YAML feature. Therefore, it can only reference entities in the same file. If you do not want to duplicate the values in C.yml, you have to merge all data in one single file with root keys A, B and C.flyx
@flyx merging to the same file is actually what I ended up doing earlier today. I was planning to write it up as an answer, but if you want to take the rep, please do.user12341234

4 Answers

2
votes

New answer based on the edited question:

*octupus_ceviche is a YAML alias and has nothing to do with Liquid. As I said, YAML files are not processed with Liquid. YAML, however, defines that aliases must point to achors in the same document. One YAML document must reside in one stream which for most YAML processors means that it cannot be split into multiple files.

That being said, a valid option would be to place all data into a single YAML file:

C:
  foods:
    - octopus_ceviche: &octopus_ceviche
        name: Octopus Ceviche
        taste: Delicious
A:
  ingredients:
    - avacado: &avacado
        name: Avacado
        color: Green
        foods:
          - *octopus_ceviche
B:
  chefs:
    - anthony_bourdain: &anthony_bourdain
        name: Anthony Bourdain
        hobby: Brazilian Jiu-Jitsu
        foods:
          - *octopus_ceviche

You may leave out A, B and C if their child keys are disjoint as they are in this example. Note however that the anchor must always be located in front of the alias (textually), even though YAML defines that mapping keys have no order. That's why I moved C in front.

Nota Bene: Anchors and aliases in YAML have been designed to serialize cyclic structures. Using them as named, reusable values is generally fine. But actually, you do not need a list with all defined “variables”, you can also just define them on first occurrence. Example:

A:
  ingredients:
    - avocado: &avocado
        name: Avocado
        color: Green
        foods:
          - &octopus_ceviche
            name: Octopus Ceviche
            taste: Delicious
B:
  chefs:
    - anthony_bourdain: &anthony_bourdain
        name: Anthony Bourdain
        hobby: Brazilian Jiu-Jitsu
        foods:
          - *octopus_ceviche

But this can be less readable of course. ymmv.

3
votes

To have a common list of key-value variables define a third data file _data/common.yml.

Then in A.html and B.html you can access all the common.yml variables with:

 {{ site.data.common.myvar }}
1
votes

Since Jekyll does not process data files with Liquid when it loads them, it is not possible to include one YAML file in another with {% include %}. YAML itself does not have the ability to include other files (because it is stream-based, not file-based).

However, it should not be necessary. If you move all common variables to C.yml, you can just access them via {{ site.data.C.myvar }} in both your HTML files and do not need to include anything in A.yml or B.yml.

0
votes

As the question above is worded, @flyx’s is the most appropriate answer, however given external constraints (see my other question) I ended writing my own plugin to let data files textually include one another through liquid.

The goals of this plugin are to let the data be:

  1. DRY - (don’t repeat yourself) each model should be defined only once.
  2. Grouped - all similar data should be defined in the same format next to each other.
  3. Separated - different data should be defined in different places.

@flyx’s solutions here fail goals #2 and #3, requiring all different types of data to be defined in the same place, and in the case of the second suggestion intermixing the definitions of foods and ingredients.

My proposed solution allows textual inclusion of one data file into another. This allows different models to be defined in different files, yet referenced from other files as if they were defined in the same place, in an arbitrary order. Applied to this problem, my solution would like this:

A.yml

{% include_relative_once C.yml %}

 ingredients:
  - avacado: &avacado
      name: Avacado
      color: Green
      foods:
        - *octopus_ceviche

B.yml

{% include_relative_once C.yml %}

chefs:
  - anthony_bourdain: &anthony_bourdain
      name: Anthony Bourdain
      hobby: Brazilian Jiu-Jitsu
      foods:
        - *octopus_ceviche

C.yml

foods:
  - octopus_ceviche: &octopus_ceviche
      name: Octopus Ceviche
      taste: Delicious

For the plugin itself, see this gist