Parse Ruby's Gemfile.lock in pure Go - no Ruby required!
Ever wanted to parse Ruby's Gemfile.lock from Go? Maybe you're building developer tools, analyzing dependencies, or just curious about what's in that lockfile. This library lets you do it all without having Ruby installed!
Think of it as Bundler's lockfile parser, but speaking Go.
go get github.com/contriboss/gemfile-goWelcome Ruby friend! π Here's a translation guide:
| Ruby Concept | Go Equivalent in This Library |
|---|---|
Bundler.locked_gems |
lockfile.ParseLockfile() |
gem.dependencies |
GemSpec.Dependencies |
Gem::Version |
String (but semver compatible) |
bundle install |
Parse lockfile β download gems |
Gemfile.lock |
Lockfile struct |
package main
import (
"fmt"
"log"
"github.com/contriboss/gemfile-go/lockfile"
)
func main() {
// Parse your Gemfile.lock (hard API: error if missing)
lock, err := lockfile.ParseLockfile("Gemfile.lock")
if err != nil {
log.Fatal(err)
}
// How many gems do you have?
fmt.Printf("π¦ Found %d gems\n", len(lock.GemSpecs))
// What Ruby version was it bundled with?
fmt.Printf("π Bundled with: %s\n", lock.BundledWith)
// List all Rails-related gems (because why not?)
for _, gem := range lock.GemSpecs {
if strings.Contains(gem.Name, "rails") {
fmt.Printf("π %s (%s)\n", gem.Name, gem.Version)
}
}
}// Finding gems is like `bundle show gemname`
gem := lock.FindGem("rails")
if gem != nil {
fmt.Printf("Rails version: %s\n", gem.Version)
fmt.Printf("Dependencies: %v\n", gem.Dependencies)
}Gemfiles and gemspecs can have arbitrary Ruby code in them, which makes support untenable.
// Check if a gem works on your platform
if gem.Platform == "" || gem.Platform == "ruby" {
fmt.Println("β
Pure Ruby gem - works everywhere!")
} else if gem.Platform == "x86_64-linux" {
fmt.Println("π§ Linux native extension detected!")
}// Verify gem integrity (just like Bundler does!)
if gem.Checksum != "" {
fmt.Printf("π Gem %s is checksum-protected\n", gem.Name)
}// Find all gems from git repos (living on the edge!)
for _, gitGem := range lock.GitSpecs {
fmt.Printf("π₯ %s from %s (rev: %s)\n",
gitGem.Name, gitGem.Remote, gitGem.Revision[:7])
}We use Mage for builds (it's like Rake but for Go!):
# Install Mage
go install github.com/magefile/mage@latest
# Run tests
mage test
# Run linter
mage lint
# Run benchmarks
mage bench
# Run everything (CI mode)
mage ci-
No Version Operators: In Ruby you have
~>,>=, etc. In the lockfile, versions are exact, so we just use strings. -
No Gem Installation: This library reads Gemfile.lock but doesn't install gems. Think of it as read-only Bundler. The sibling project ore will install your gems (also without Ruby).
-
Groups as Strings: Ruby uses symbols (
:development), we use strings ("development"). -
Error Handling: Go doesn't have exceptions. We return errors as second values:
// Ruby: lock = Bundler.locked_gems (might raise) // Go: lock, err := lockfile.ParseFile("Gemfile.lock") if err != nil { // Handle error }
- CI/CD Tools: Analyze Ruby dependencies without Ruby
- Security Scanners: Check for vulnerable gems
- Developer Tools: Build IDE support for Ruby projects
- Dependency Analysis: Understand Ruby project dependencies
- Migration Tools: Help migrate from Ruby to other languages
- Fun Projects: Because parsing is fun! π
Full API docs at pkg.go.dev
This library exposes both hard and soft parsing helpers so callers can decide whether a missing lockfile should be an error.
Hard API (missing or invalid lockfile returns an error):
lock, err := lockfile.ParseLockfile("Gemfile.lock")Soft API (missing lockfile returns nil, nil):
lock, err := lockfile.ParseLockfileIfPresent("Gemfile.lock")
if err != nil {
// parse error or read error
}
if lock == nil {
// lockfile is missing
}The shorter ParseFile and ParseFileIfPresent helpers are also available if you prefer those names.
Every parser function has tests! We test with real Gemfile.lock files from popular Ruby projects like Rails, Sinatra, and Jekyll.
# Run tests with coverage
mage test
# Run tests with race detector
mage testrace
# Run benchmarks
mage benchSometimes you need to understand Ruby dependencies from Go:
- You're building polyglot developer tools
- You're analyzing dependencies across languages
- You're migrating from Ruby to Go (we don't judge!)
- You just want fast lockfile parsing
Parsing a typical Rails Gemfile.lock:
- gemfile-go: ~1ms π
- Bundler (Ruby): ~100ms
That's 100x faster! (Your mileage may vary)
MIT - Use it, fork it, enjoy it!
- The Bundler team for the lockfile format
- The Go community for being awesome
- Coffee β for making this possible
Made with π by @contriboss - Bridging Ruby and Go, one parser at a time!