For my Middleman-built website I have stored links and other information about all pages in a data file.
data/pages.yaml
:
pageA:
link: /some-long-url-subject-to-change.html
name: PageA name
info: Some other related info
Then, in my HAML template (source/test.haml
), I can print relative path to pageA with = data.pages.pageA.link
.
Now, I want to use markdown syntax to reference that page by its name (pageA).
Example (source/test.html.haml
):
.info
:markdown
This is some text with a [manual link](https://google.com) to somewhere.
This is another text with a [data-referenced link](pageA) to that page.
In the same way as first "manual link" links to Google, I would like second link to use relative path stored in data file to create a link. One solution that I see to solve this problem would be to replace (pageA)
text with evaluation of = data.pages.pageA.link
prior to it being rendered by markdown.
I assume this would be possible by creating custom helper, but I can't quite nail it.
My attempt at solution
I tried to write a custom helper to replace (pageA)
text with evaluation of = data.pages.pageA.link
prior to it being rendered by markdown.
I was able to replace specific text (pageA
) with information from data and I was also able to write more generic case, which replaces all data references with explicit text of typical data reference. But I can't get to replace data.pages.pageA.link
in generic case for evaluation of = data.pages.pageA.link
.
My helper:
# Replace specific text with information from ``data/pages.yaml``
specific = text.gsub("pageA",data.pages.pageA.link)
# Generic case: using explicit text
generic = text.gsub(/\]\((.*?)\)/,'](data.pages.\1.link)')
# Generic case: trying to use variable name, but getting explicit text
generic = text.gsub(/\]\((.*?)\)/,'](#{data.pages.\1.link})')
Usage of helper in my test.html.haml
:
= myhelper("This is another text with a [data-referenced link](pageA) to that page.")
Printing specific
variable gives me what I want (/some-long-url-subject-to-change.html
). But printing generic
variable results in plain text, instead of information from data file.
It is possible that I am lacking some basic Ruby knowledge and solution is indeed very simple.
It looks as if you are trying to write your own templating system, which is probably not the best idea. First, you'll need to write a regex that properly parses Markdown and finds link notation. Then you need to eval the string you pulled to get the value from your data. And finally you'll need to substitute the placeholder with that value. I more or less got that working with this code in config.rb:
helpers do
def myhelper(text)
page=/\]\((.*?)\)/.match(text)[1]
link=eval( "data.pages.#{page}.link" )
text.gsub(page,link)
end
end
But please don't use this code! It's fragile and error-prone. Worse, there's a much simpler way to do what you are trying to do. Replace your test.haml with test.haml.erb:
.info
:markdown
This is some text with a [manual link](https://google.com) to somewhere.
This is another text with a [data-referenced link](<%= data.pages.pageA.link %>) to that page.
= myhelper("This is another text with a [data-referenced link](pageA) to that page.")
The .erb extension tells Middleman to treat the file as an ERB template. In particular, it'll evaluate whatever is between <%=
and %>
as Ruby code. That means you can skip using a messy helper method. As a bonus, you don't need to write more code to get the other bits of data:
<%= data.pages.pageA.name %>
=> 'PageA name'
<%= data.pages.pageA.info %>
=> 'Some other related info'
If you need to do some more complex processing, such as iterating over a list, you can do that right in the template itself. It's easier to read and maintain that way.
I also included a call to the helper method as contrast. It's a lot less clear what's going on than just using the existing templating system. Plus, you are bound to forget to wrap all the relevant strings in the method and end up with broken links down the road.
As Adam suggested, you might be even better off using Markdown directly and skipping Haml.
I'm not sure exactly what you are encountering here. The following works on my end:
Assuming your data file data/pages.yaml
contains
pageA:
link: /some-long-url-subject-to-change.html
name: PageA name
info: Some other related info
and your template test.haml.md.erb
looks like
---
title: Test
---
This is another text with a [<%= data.pages.pageA.name %>](<%= data.pages.pageA.link %>) to that page.
the output should be as follows, with PageA name being the clickable link.
This is another text with a PageA name to that page.
It seems like you are running into issues with the markdown interpretation. Try adjusting the template filename from test.haml
to test.haml.md.erb
.
This construction tells Middleman to first interpret the ERB bits, then the Markdown bits, and finally the HAML (or plain HTML if not using HAML).