在 Markdown 文件中编辑 YAML Frontmatter

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

Ruby 中是否有某种方法可以编辑 Markdown 文件顶部的 YAML Frontmatter,就像 Jekyll 和 Middleman 中使用的那样?

类似:

def update_yaml
  #magic that changes A: 1 to A: 2 in Frontmatter block
end

然后我的 Markdown 文件将更改为

---
A: 1
---
# Title
Words. More words. This is the words part of the file.

---
A: 2
---
# Title
Words. More words. This is the words part of the file.

似乎唯一的选择是解析整个文件,然后重写整个文件,仅更改所需的部分,但我希望有更好的东西。

ruby yaml jekyll middleman yaml-front-matter
5个回答
3
投票

最近我遇到了同样的问题,作为替代方案,你可以使用

python-frontmatter
。它很容易使用。以下是更改 yaml 变量值的代码:

    import frontmatter
    import io
    with io.open('File.md', 'r') as f:
        post = frontmatter.load(f)
        post['A'] = 2

        # Save the file.
        newfile = io.open(fname, 'w', encoding='utf8')
        frontmatter.dump(post, newfile)
        newfile.close()

欲了解更多示例,您可以访问此页面


1
投票

是的,你可以做得更好,你只需要从源代码中阅读 YAML 文档 并在末尾停止读取 (

---
),然后处理 YAML,将其写入新文件(数据的实际长度可能会改变,因此不太可能就地重写),然后读取输入文件的其余部分,并将其写出。

我看到的最大问题是,您的 ruby YAML 解析器将在往返过程中删除所有注释、标签名称以及可能使 YAML 人类可读的其他内容。


1
投票

我不知道有什么更好的,但实现起来非常简单:

require "yaml"

YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m

def update_data(data)
  data.merge("A" => 2)
end

if $stdin.read =~ YAML_FRONT_MATTER_REGEXP
  data, content = YAML.load($1), Regexp.last_match.post_match
  data = update_data(data)
  YAML.dump(data, $stdout)
  $stdout.puts("---", content)
end

上面从

$stdin
读取并写入
$stdout
(在 Ideone 上查看它的实际操作),但实际上,您可能想要 从文件读取并写入 Tempfile,然后成功用临时文件替换原始文件(例如, FileUtils
)。

如果你想知道,我直接从 Jekyll

偷了

YAML_FRONT_MATTER_REGEXP
并改编了它的 frontmatter 处理代码


0
投票
Middleman 的一位开发人员实际上在 Twitter 上进行了联系,并提供了 Middleman 特定的但仍然非常慷慨和有用的回复。它在实践中与其他答案类似(截至撰写本文时),但它使用了一些中间人功能。他们的回应(经过编辑以在这种情况下有意义)如下。


如果您制作脚本或扩展,您可以需要

middleman-core/util/data

,它提供 
::Middleman::Util::Data.parse


这将采用文件名和 Middleman“源文件”以及分隔符列表(前面使用的

---

)并返回 2 个值:前面内容的数据对象和文件其余部分的字符串内容.

然后您可以修改此 ruby 对象并写入文件。

所以,阅读看起来像:

require "middleman-core/util/data” resource = app.sitemap.resources.find_resource_by_destination_path(“whatever.html”) frontmatter, content = ::Middleman::Util::Data.parse(resource.file_descriptor, app.config[:frontmatter_delims])

并写道:

# change frontmatter ::File.write(resource.source_file, %Q{ --- #{frontmatter.to_yaml} --- #{content} })

抱歉,数据解析的东西有点奇怪(需要特殊的文件描述符和配置值),这些东西通常不在核心之外使用。


0
投票
我发现

front_matter_parser

 与 python frontmatter
 包非常相似。看起来很简单:

使用此文件:

--- title: Hello World category: Greetings --- Some actual content
你可以这样玩:

parsed = FrontMatterParser::Parser.parse_file('example.md') parsed.front_matter #=> {'title' => 'Hello World', 'category' => 'Greetings'} parsed.content #=> 'Some actual content'
所以,你的问题是更改

parsed.front_matter['A'] = 2

,然后保存文件(覆盖旧文件)。

© www.soinside.com 2019 - 2024. All rights reserved.