Contributing Guidelines
March 3, 2026 · View on GitHub
Pull request, bug reports, and any other forms of contribution are welcomed and highly encouraged.
If you encounter any issues when following along with this file please don't hesitate to reach out and file an issue!
Running Locally
Requirements
- Check: For unit testing.
- Clang 21: The compiler used to build this project.
- Clang Format 21: For formatting the project.
- Clang Tidy 21: For linting the project.
- Prism Ruby Parser v1.9.0: We use Prism for Parsing the Ruby Source Code in the HTML+ERB files.
- Ruby: We need Ruby as a dependency for
bundler. - Bundler: We are using
bundlerto buildprismfrom source so we can buildherbagainst it. - Emscripten 5: For the WebAssembly build of
libherbso it can be used in the browser using the@herb-tools/browserpackage. - Doxygen: For building the C-Reference documentation pages.
For Linux
Before installing the dependencies, you need to add the LLVM repository and GPG key to get Clang 21:
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-21 main"
sudo apt update
Then install the required packages:
xargs sudo apt-get install < Aptfile
or:
sudo apt-get install check clang-21 clang-tidy-21 clang-format-21 emscripten doxygen
For macOS (using Homebrew)
brew bundle
or:
brew install check llvm@21 emscripten doxygen
Building
Clone the Repo
Clone the Git Repository:
git clone https://github.com/marcoroth/herb && cd herb/
Build Herb
We can now compile all source files in src/ and generate the herb executable.
make all
Note
For any consecutive builds you can just run make/make all.
Run
The herb executable exposes a few commands for interacting with .html.erb files:
❯ ./herb
./herb [command] [options]
Herb 🌿 Powerful and seamless HTML-aware ERB toolchain.
./herb lex [file] - Lex a file
./herb parse [file] - Parse a file
./herb ruby [file] - Extract Ruby from a file
./herb html [file] - Extract HTML from a file
./herb prism [file] - Extract Ruby from a file and parse the Ruby source with Prism
Running the executable shows a pretty-printed output for the respective command and the time it took to execute:
❯ ./herb lex examples/simple_erb.html.erb
#<Herb::Token type="TOKEN_ERB_START" value="<%" range=[0, 2] start=(1:0) end=(1:2)>
#<Herb::Token type="TOKEN_ERB_CONTENT" value=" title " range=[2, 9] start=(1:2) end=(1:9)>
#<Herb::Token type="TOKEN_ERB_END" value="%>" range=[9, 11] start=(1:9) end=(1:11)>
#<Herb::Token type="TOKEN_NEWLINE" value="\n" range=[11, 12] start=(1:0) end=(2:1)>
#<Herb::Token type="TOKEN_EOF" value="" range=[12, 12] start=(2:1) end=(2:1)>
Finished lexing in:
12 µs
0.012 ms
0.000012 s
Building the Ruby extension
We use rake and rake-compiler to compile the Ruby extension. Running rake will generate the needed templates, run make, build the needed artifacts, and run the Ruby tests.
bundle exec rake
If rake was successful you can use bundle console to interact with Herb:
bundle console
irb(main):001> Herb.parse("<div></div>")
# => #<Herb::ParseResult:0x0000000 ... >
Test
Builds the test suite from files in test/ and creates the run_herb_tests executable to run the tests:
For the C Tests
make test && ./run_herb_tests
For the Ruby Tests
bundle exec rake test
Clean
Removes the herb, run_herb_tests, prism installation, and all .o files.
make clean
Local Integration Testing
The bin/integration script allows for quick local iteration. On every run it cleans the directory, builds the source from scratch and runs all checks, including the C-Tests, Ruby Tests, Linters, and examples in succession.
bin/integration
The integration was successful if you see:
❯ bin/integration
[...]
Integration successful!