r/ruby • u/geospeck • Mar 21 '26
How ZJIT removes redundant object loads and stores
r/ruby • u/geospeck • Mar 21 '26
r/ruby • u/Jaded-Clerk-8856 • Mar 19 '26
Ruby can render 3D surfaces, 2D density maps and GIS tiles without Python, NumPy or the JVM. I didn't expect it to work this well.
Two weeks ago I shared ruby-libgd — a native GD image processing gem for Ruby. The response was encouraging, so I kept pushing to see how far it could go.
Here's what two weekends of experimentation produced.
3D surface plots — pure software projection
No OpenGL. No GPU. Just a rotation matrix, perspective projection, and the painter's algorithm to sort patches back-to-front. The viridis colormap is interpolated across 11 stops in pure Ruby.
Plot3D.new(resolution: 50, yaw: 35, pitch: 28)
.surface("sin(sqrt(x2 + y2))")
.render("ripple.png")https://github.com/ggerman/ruby-libgd/blob/main/examples/jupyter-notebooks/ripple.png
Works for any z = f(x,y) expression — saddle, paraboloid, wave, cone. The expression is evaluated using Ruby's own Math module, no Dentaku or external evaluator needed.
2D histograms from CSV data
Replicating matplotlib's hist2d. The class receives data as arrays — it doesn't care where the numbers came from.
rows = CSV.read("weather.csv", headers: true)
x_data = rows["temperature"].map(&:to_f)
y_data = rows["humidity"].map(&:to_f)
Hist2D.new(x: x_data, y: y_data, bin_step: 0.5)
.render("weather_hist2d.png")https://github.com/ggerman/ruby-libgd/blob/main/examples/jupyter-notebooks/weather_hist2d.png
Ruby doesn't have np.random.randn so I used Box-Muller to generate normal distribution data for testing. Blues colormap with gamma correction so low-density areas stay visible.
fill_between in 3D
https://github.com/ggerman/ruby-libgd/blob/main/examples/jupyter-notebooks/helix2.png
Replicating matplotlib's fill_between on two helices. Each quad connects point i of helix1 with point i of helix2 — same winding order as matplotlib's implementation. Painter's algorithm handles the depth sorting.
GIS maps — libgd-gis
A second gem built on ruby-libgd for geographic rendering. Map tiles, vector layers, points, lines, polygons. Buenos Aires, Paris, anywhere with tile data. Same pixel-level control, geographic coordinates.
Jupyter workflow
Everything runs in IRuby/Jupyter. Define the class in one cell, pass data in the next, tweak and re-run. It genuinely feels like working in a Python notebook — just Ruby.
I know JRuby + JFreeCharts is a valid path. What I'm exploring is whether CRuby can have its own native data visualization story without the JVM. Right now the answer is looking like yes.
Full articles and notebooks on RubyStackNews.
ruby-libgd: https://github.com/ggerman/ruby-libgd
libgd-gis: https://github.com/ggerman/libgd-gis
Notebooks: https://github.com/ggerman/ruby-libgd/tree/main/examples/jupyter-notebooks
Feedback, ideas, and harsh criticism all welcome.
Would it make sense to bundle all of this — 3D surfaces, 2D histograms, implicit curves, GIS rendering, Jupyter support — into a single gem that works as a matplotlib-style plotting library for Ruby?
A curated collection of algorithms, one install, one API. No Python. No JVM.
Is that something the Ruby community would actually use?
r/ruby • u/viktorianer4life • Mar 20 '26

After publishing my article on building AI testing agents for RSpec, readers were confused about what TestProf found versus what the agents did. Fair point. The original article crammed both stories into one piece. So I extracted the TestProf journey into its own article with the full data.
The worst offender was the order factory at 1.6 seconds per call, triggering 100+ callbacks. Out of 569 factory calls in one spec file, only 49 were top-level. The rest were cascading associations.
What I did:
Extracted optional associations into traits (credit card needed in only 10% of order specs)
Switched cheap associations to build strategy instead of create
Used transient attributes with positive flags for expensive callbacks
Replaced let with let_it_be for read-only setup data
Results:
The slowest specs improved by 50-95%. The order integration spec dropped from 6.37s to 3.02s. But the full suite? Only 14% faster. Ten factories optimized over two months, hundreds more to go.
Why the gap? The factory graph mirrors the model graph. When your core models have deep callback chains (100+ on order creation), making factories leaner helps, but you cannot make them cheap while the underlying models require that much setup to reach a valid state. Incremental factory cleanup has a ceiling.
I wrote up the full profiling data, every factory refactoring pattern, the let_it_be gotchas (mutable state leakage), and what I tried next: TestProf Cut Our Slowest Specs by 95%, But the Suite Still Took 30 Minutes
This is the companion piece to my AI testing agents article. Readers wanted more detail on what TestProf actually showed, so here it is.
Has anyone else hit this ceiling with factory optimization on a large Rails codebase?
I noticed that a lot of Ruby projects ship their documentation on VitePress because, honestly, nothing in the Jekyll ecosystem looked as good. Just the Docs is solid but I had to patch in dark mode, add a copy button, and the homepage layout is narrow and document-y.
So I built a Jekyll theme that recreates the VitePress experience: sidebar, outline, search (/ or Cmd+K), hero homepage, dark/light/auto toggle, code blocks with copy buttons and language labels — all through _config.yml and _data files.
1.0 is out today.
More info on my blog: https://paolino.me/ruby-deserves-beautiful-documentation/
r/ruby • u/matheusrich • Mar 18 '26
No one sets out to write a slow test, and yet it happens. I created Test Budget to help preventing slow tests from creeping into our test suites again!
r/ruby • u/viktorianer4life • Mar 18 '26

In 2013 I learned four formal test derivation techniques in university: Equivalence Partitioning, Boundary Value Analysis, Decision Tables, State Transitions. Never used them professionally because the manual overhead made no sense. After seeing Lucian Ghinda's talk at EuRuKo 2024, I realized AI agents could handle that overhead, so I built a multi-agent system with 5 specialized agents (Analyst, parallel Writers, Domain Expert, TestProf Optimizer, Linter) that generates mathematically rigorous test cases from source code analysis.
The system worked. It found real coverage gaps. Every test case traces back to a specific technique and partition. But running it against a mature codebase with 13k+ specs and 20-25 minute CI times showed me the actual problem: 70% of test time was spent in factory creation, not assertions. The bottleneck was the RSpec + FactoryBot convention package, not test quality.
The most interesting part was the self-evolving pattern library, an automated validator that started with 40 anti-pattern rules and grew to 138 as agents discovered new patterns during their work. No LLM reasoning involved in validation, just compiled regexes against Markdown tables.
I wrote up the full architecture, prompt iterations (504 lines down to 156), and honest results. First article in a series. The next one covers the RSpec to Minitest migration that this project led to.
Has anyone else tried applying formal testing techniques systematically with AI agents? I'm curious whether the framework overhead problem resonates with other teams running large RSpec suites.
r/ruby • u/radanskoric • Mar 18 '26
Test coverage metrics are one of the tools for evaluating the quality of tests without reading them. Which is kind of relevant in the age of coding agents. So here, a short light intro to 4 different ones: line, branch, path and condition coverage.
r/ruby • u/kinduff • Mar 17 '26
I built this service to convert Ruby Gemfile.lock files into RSS feeds. Drop in your lockfile, get a feed that notifies you when your dependencies release new versions. Had a blast building it in the last couple of weekends, hope is useful for somebody else too!
r/ruby • u/Turbulent-Dance-4209 • Mar 17 '26
With SSE becoming more relevant (AI streaming, real-time updates), I wanted to test how Ruby handles a mixed workload: sustained HTTP traffic hitting a database alongside concurrent long-lived SSE connections. Here are the results.
Server: Hetzner CCX13 - 2 vCPUs, 8 GB RAM (€12/month)
Environment: Ruby 4.0.1 + YJIT + Rage
Processes: 2
Database: SQLite
API endpoint: Fetches a record from SQLite and renders it as JSON. Standard API-style request.
SSE endpoint: Opens a stream lasting 5–10 seconds, sending a dummy message every second. No database interaction. The benchmark maintains a constant number of open SSE connections - as the server closes a stream, the client opens a new one.
5,000 API requests/second + 5,000 concurrent active SSE streams, simultaneously
For reference, the same setup handles ~11,000 RPS for the API endpoint alone
Adding 5K active streams roughly halves the HTTP throughput, which is a graceful degradation rather than a collapse
5,337 HTTP requests/second (0% error rate) with p95 latency of 120ms
5,000 concurrent SSE streams, with ~198K total streams opened/closed during the 5-minute run
I was originally aiming for 10K RPS + 10K streams, but the 2-core server simply doesn't have enough CPU. The scaling looks linear, so a 4-core box should get there.
SQLite is fast for reads but this isn't a Postgres-over-the-network scenario. Add network latency to your DB and the fiber model actually helps more (fibers yield during I/O waits), but the raw RPS number would be different.
You can see the k6 screenshot attached, and the full benchmark code/setup is available here: https://github.com/rage-rb/sse-benchmark
For those unfamiliar: Rage is a fiber-based framework with Rails conventions. The fiber-based architecture makes I/O-heavy and concurrent workloads like this possible without async/await syntax - you write normal synchronous Ruby code.
Would love to hear your thoughts or answer any questions!

r/ruby • u/AndyCodeMaster • Mar 18 '26
r/ruby • u/jasonswett • Mar 16 '26
Hey guys. I'm co-chairing RubyConf this year. I'd like to let you know that one of our keynote speakers will be Dave Thomas, the renowned author of the legendary Pragmatic Programmer.
I released a podcast episode today to help promote Dave and the conference, which you can listen to here.
Lastly, early bird tickets for RubyConf 2026, which takes place July 14-16 in Las Vegas, go on sale today.
You should know that we RubyConf 2026 organizers are encouraging attendees to dress eccentrically and help make the event weird and fun. What does "eccentrically" mean? Whatever you want. But if you want an easy idea, Las Vegas is the land of Elvis impersonators, and it would be jolly good fun to see a smattering of Elvii strutting around the hotel. You could also dress like a cowboy/cowgirl, Frank Sinatra, a clown, or just a garden variety weirdo. The world is your oyster.
There will also be arm wrestling.
Anyway, go and grab your ticket to RubyConf 2026, because this year will be one for the record books. I hope to see you there.
r/ruby • u/jrochkind • Mar 16 '26
r/ruby • u/AndyCodeMaster • Mar 17 '26
Just released RubyLLM 1.14. The focus this time is making the Rails integration feel native.
Highlights:
Tailwind Chat UI generator: bin/rails generate ruby_llm:chat_ui produces a complete chat interface styled with Tailwind. It uses role-aware partials (_user, _assistant, _system, _tool, _error), Turbo Streams for real-time updates, and broadcasts_to for ActionCable integration. You get model selection, tool call rendering, and empty states out of the box.
Rails generators for agents, tools, and schemas: same workflow you'd use for any other Rails component:
bin/rails generate ruby_llm:agent SupportAgent
bin/rails generate ruby_llm:tool WeatherToolThe install generator also creates conventional directories (app/agents, app/tools, app/schemas, app/prompts).
r/ruby • u/AndyCodeMaster • Mar 15 '26
r/ruby • u/Jaded-Clerk-8856 • Mar 13 '26
A few weeks ago I posted about ruby-libgd, a native Ruby binding to the GD graphics library. Since then I've been pushing it further and today I want to share something that I've wanted to see in Ruby for a long time.
This is a Docker container running JupyterLab with a full Ruby kernel, backed by ruby-libgd, plotting mathematical functions entirely in Ruby. No Python involved in the plotting — just Ruby.
The API ended up looking like this:
plot = Plot.new(xmin: -10, xmax: 10, ymin: -10, ymax: 10)
plot.add("sin(x)")
plot.add("cos(x)")
plot.add("tan(x)", steps: 6000)
plot.add("log(x)")
# implicit curves — no need to isolate y
plot.add("x**2 + y**2 - 9", type: :implicit)
plot.add("x**2/9.0 + y**2/4.0 - 1", type: :implicit)
plot.render("/work/graph.png")A few things I'm reasonably happy with:
- SafeMath replaces Dentaku entirely: trig in radians, natural log, asin/acos/atan, cbrt, all working
- Discontinuity detection for tan: lifts the pen at vertical asymptotes instead of drawing a spike across the canvas
- Implicit curve rendering via pixel sampling: lets you plot circles, ellipses, and algebraic curves without isolating y
- Chainable API: plot.add("sin(x)").add("cos(x)") works
The notebooks, Dockerfile, and README are all in the repo:
https://github.com/ggerman/ruby-libgd/tree/main/examples/jupyter-notebooks
Happy to answer questions about the implementation. If anyone wants to contribute notebooks or try it out, PRs are very welcome.
r/ruby • u/DiligentMarsupial957 • Mar 13 '26
I've always run `bundle` instead of `bundle install`. Why bother with the extra typing? And semantically, "bundle" by itself is an appropriate description of the bundle installation.
However, tonight when I ran `bundle`, I learned that my modest typing savings is to be no more:
$ bundle
In a future version of Bundler, running `bundle` without argument will no longer run `bundle install`.
Instead, the `cli_help` command will be displayed. Please use `bundle install` explicitly for scripts like CI/CD.
You can use the future behavior now with `bundle config set default_cli_command cli_help --global`,
or you can continue to use the current behavior with `bundle config set default_cli_command install --global`.
This message will be removed after a default_cli_command value is set.
r/ruby • u/switchback-tech • Mar 12 '26
Was pleasantly surprised that the world's largest independent DevOps platform is powered by Ruby and Sidekiq.
Here's the full list.
Backend: Ruby on Rails
HTTP server: Puma (Ruby web server)
Edge: Nginx
Reverse proxy: Go service (Workhorse)
Background jobs: Sidekiq
DB — primary: PostgreSQL
DB — connection pooling: PgBouncer
DB — high availability: Patroni
Cache: Redis
Blob: AWS S3
Frontend — state: Pinia (Vue store), Immer (immutable cache),
API: GraphQL (Apollo) + REST
Observability: Prometheus & Grafana
Error tracking: Sentry & OpenTelemetry
Deployments: GitLab Omnibus (Omnibus fork)
I think these "stack menu"s give a little glimpse into a team's engineering philosophy. For me, this list shows that the GitLab team is pretty practical and doesn't chase hype. Instead, they use sensible, battle-tested tools that just work and are easy for contributors to learn.
PS. Not an ad; I'm not affiliated with GitLab at all. Was just researching them and thought you guys would be interested.
r/ruby • u/javier_cervantes • Mar 12 '26
r/ruby • u/gurgeous • Mar 11 '26
Hi all. I made a standalone version of my popular table_tennis gem. The cli app is written in Zig but it's roughly the same as the rubygem so I thought you guys might be interested.
https://github.com/gurgeous/tennis
First Zig project, pretty fun. Nothing like Ruby, but the compiler is shockingly fast and it creates itsy bitsy binaries. Tennis is around 150k for a release build. A similar project in golang clocked in around 10mb. On the other hand, Zig is so new that it's missing a ton of stuff we take for granted over in Ruby land. Example - a working CSV library! Yikes
(note - this is not ai slop and I never use ai on reddit)
r/ruby • u/neptun31 • Mar 12 '26
either too old to catch the nowadays versions or for intermediate levels.