Getting started
Beid is a Ruby library for Markdown tools that need to change a document while preserving its original formatting. Parse a source snapshot, choose a node, and edit its source range. The result is a new document; the original stays unchanged.
Install
Use Ruby 3.1 or newer:
gem install beid
For a Bundler project, add gem "beid" to your Gemfile and run bundle install.
Beid has no runtime dependencies beyond Ruby’s standard library. It is a library;
there is no command-line editor to launch.
Make your first edit
Save this as example.rb and run ruby example.rb. In a Bundler project, run
bundle exec ruby example.rb instead.
require "beid"
source = "# Title\n\nKeep this *formatting*.\n"
document = Beid::Document.parse(source)
heading = document.root.children.first
updated = Beid::Editing.set_attribute(document, heading, :level, 2)
puts updated.to_s
# ## Title
#
# Keep this *formatting*.
document.to_s == source # => true
Only the heading marker changes. The blank line, emphasis marker, and final
newline remain as written. Document#to_s returns the stored source rather than
generating Markdown from the tree.
Make another edit
Every editing operation reparses the result. Find a node in the returned document before editing again:
require "beid"
document = Beid::Document.parse("# Title\n\nKeep this *formatting*.\n")
heading = document.root.children.first
document = Beid::Editing.set_attribute(document, heading, :level, 2)
heading = document.root.children.first
document = Beid::Editing.replace_text(document, heading, "New title")
document.to_s # => "## New title\n\nKeep this *formatting*.\n"
Passing the old heading to a new document raises ArgumentError. Nodes and
ranges belong to one source snapshot, even if an edit leaves their text unchanged.
Read and save a file
Use binary I/O to preserve line endings across platforms. Mark the input as UTF-8, then check the document before editing it:
require "beid"
source = File.binread("notes.md").force_encoding(Encoding::UTF_8)
document = Beid::Document.parse(source)
raise Beid::Error, document.diagnostics.join("; ") unless document.valid?
heading = document.root.children.find { |node| node.type == :heading }
raise ArgumentError, "notes.md needs a top-level heading" unless heading
updated = Beid::Editing.replace_text(document, heading, "Updated notes")
File.binwrite("notes.updated.md", updated.to_s)
This writes a separate file you can compare with the original. Setting the
encoding does not transcode invalid input. See
Validation and limits for what valid? checks.