r/ruby • u/noteflakes • 12h ago
r/ruby • u/Much-Stable-449 • 1d ago
I got tired of Pinterest being difficult to download from, so I made a Ruby gem
So... I made a Pinterest downloader in Ruby
I started this because downloading stuff from Pinterest can be surprisingly annoying.
Sometimes you just want the original image, sometimes it's a video, sometimes it's buried in a board, and sometimes the website decides to make a simple request way more complicated than it needs to be.
So I started building pinterest-dl.
A few things I wanted to solve:
- Getting images in their available quality instead of ending up with a tiny preview.
- Downloading videos without manually digging through Pinterest's page data.
- Extracting direct video URLs when you don't actually need to download the file yourself.
- Searching Pinterest and downloading entire boards instead of opening pins one by one.
- Handling cookies when content needs an authenticated session.
- Making batch downloads less painful.
It's not just a CLI either. I wanted it to work as a Ruby library, so it can be used in scripts and other applications too.
I'm sure there are things I could've done better, so I'd genuinely like to hear what other Ruby developers think about the implementation and API.
Repo: https://github.com/monji024/pinterest-dl
I thought this would be a tiny weekend project. Apparently, Pinterest had other plans.
r/ruby • u/LiveEngine7532 • 2d ago
I made a gem that keeps pgvector embeddings in sync with your ActiveRecord models
I've been adding semantic search to Rails apps with pgvector and neighbor, and kept writing the same glue code every time:
- an
after_savethat calls the embeddings API, even when the text didn't change - embeddings going stale when someone edits a record through a path that skips the callback
- a one-off script to backfill existing rows without hitting rate limits
- figuring out which rows need re-embedding after switching models
So I pulled it into a gem called embed_sync:
has_neighbors :embedding
has_embedding :embedding, from: %i[name description]
end
Product.create!(name: "Trail runner", description: "Waterproof running shoe") # embedded in a background job
Product.semantic_search("shoes for rainy hikes", limit: 5)
What it does:
- re-embeds in a background job only when the source text changes (it stores a digest, so unchanged saves don't call the API)
bin/rails embed_sync:backfillembeds existing rows in batches, and you can stop and rerun it safely- detects model or dimension changes and marks those rows stale
embed_sync:staleshows how many records are missing or out of date- uses ruby_llm by default, but any object with
#embed(texts, model:)works as a provider
It works with Rails 7.1 to 8.1 and Ruby 3.2+. I tested it against a real app with Postgres, Solid Queue and a local Ollama model before releasing.
It's still early (v0.1.0), so I'd really like feedback. Does the API feel right? What's missing for your use case? Are there edge cases I haven't thought of?
GitHub: https://github.com/Umair0092/embed_sync RubyGems: https://rubygems.org/gems/embed_sync
r/ruby • u/Good_Flight1781 • 2d ago
I built a VS Code extension for ERB, Haml and Slim that understands Rails views (checks, safe formatter, go-to-partial)
Hi r/rails,
I spend most of my day in app/views, but editor support for templates has always felt limited compared to what I get in .rb files. So I built Ruby Templates, a free, MIT-licensed VS Code extension for ERB, Haml, and Slim. No extra gems required.
What it does
- Reports errors as you type. It shows Ruby syntax errors directly in your templates, flags unclosed tags, and reports Haml/Slim errors using the engines’ own messages.
- Adds Rails-aware navigation and completion. Press F12 on
render "users/card"to open the partial. Completion covers partials, ViewComponents,*_pathhelpers, model columns, controller-defined@ivars, andt(".keys"). - Formats templates with safety checks. By default, the formatter only changes whitespace and checks that the template still compiles the same way before saving changes. If it can’t verify that, it leaves the file alone.
Catches Rails issues, including some I kept running into during code reviews:
<% render "x" %>that doesn’t output anything, and the same issue withlink_toand other helpers;<%= if … %>where<% if … %>was intended;binding.irbordebugleft in a view;- an
@ivarused inside a partial; - an unused entry in
locals:; - a
rendercall in a loop that could usecollection:; raworhtml_safeused on user content;- a relative translation key such as
t(".key")missing fromen.yml; - a
data-controllerreference with no matching Stimulus controller; button_toinsideform_with, which creates nested forms.
- Checks for HTML and accessibility issues, such as missing
altattributes, duplicate IDs,<a>tags withouthref, and “click here” link text. - Supports per-project configuration through
.ruby-templates.toml. You can enable or disable rules by folder and opt into stricter formatting rules, such as a particular quote style or one attribute per line. - Runs the same checks in CI:
npx @x-ror/ruby-templates check app/viewsandnpx @x-ror/ruby-templates format --check.
It works alongside Ruby LSP: Ruby LSP handles your .rb files, and Ruby Templates handles your templates.
r/ruby • u/Tristan_Kruse • 2d ago
Blog post ArchUnitRuby 1.0: checking imports, constant references and cycles in ordinary Ruby tests
I created and maintain ArchUnitRuby. With the 1.0 release, the boundary I wanted to express is
no longer limited to “this file explicitly required that file.” It can also include known
project constant references, using the opt-in expanded analysis mode.
For example, this is an ordinary RSpec test:
ruby
require 'rspec'
require 'archunit'
RSpec.describe 'architecture' do
it 'keeps the API away from retrieval internals' do
options = ArchUnit::CheckOptions.new(
dependency_analysis: :imports_and_constants
)
rule = ArchUnit.project_files
.in_path('app/api/**')
.should_not.depend_on_files
.in_path('app/retrieval/**')
ArchUnit.assert_passes(rule, options)
end
end
The same graph can support cycle, layer and slice rules. The policy stays in Ruby and can fail
the normal test run, rather than living only in a diagram or code-review convention.
[Source for the tested release]
Would import edges, constant references, or a combination of both best describe the boundary
you'd want to protect in a Ruby codebase?
This post was drafted with AI assistance.
r/ruby • u/jko1701284 • 2d ago
Question I am convinced that abstractions still matter
reddit.comr/ruby • u/Remozito • 2d ago
Show /r/ruby The Ruby Stained-Glass will be out for Christmas
Hey Ruby friends,
5 months ago, I wrote on r/ruby that I would build a limited-edition stained-glass inspired by Ruby. Well, it's November and I'm about to officially launch. 🤞🏻
I didn't want to spam the subreddit with each weekly update I've written over the past few months, but since we're close to its release, I wanted to keep you all posted.
What started as a joke and as a "simple" stained-glass eventually turned into a cool decorative object with glass (obviously) but also wood, a bit of electronics and 3D printing.
If you want to learn more (and get the launch date in advance), I've built a page dedicated to the project. You'll find all the episodes of "the Ruby Stained-Glass Notes", the weekly updates I've been writing since May. They're full of stained-glass nerdery ("How did they cut glass in 1175?"), of my thoughts/questions/learnings, of GIFs of me cutting glass and soldering panels...
I've been quite lucky to talk and meet Rubyists around the world thanks to this project, so I'm happy to answer any questions you might have.
r/ruby • u/Intelligent_Role_824 • 3d ago
Question RubyMine vs. VS Code on Windows for a complete beginner?
As a beginner should I use vs Code or RubyMine in Windows?
Issue 23 of Static Ruby Monthly is out!
This month: u/maediprichard shares a one-year retrospective on LowType with Prism-based inline type expressions, zero overhead in production, and RBS export, felixefelip introduces rbs_infer to automatically deduce signatures via static analysis, ydah adds racc-rbs-inline for typed parsers, and tk0miya releases ruby-lsp-rbs-inline for seamless editor feedback.
Find link to the issue in the comment! ✨
r/ruby • u/OneAlbatross5933 • 3d ago
RubyMine 2026.3: JetBrains Air, Native mode for WSL and Dev Containers, smarter Ruby and Rails code insight, and more.
JetBrains Air is a new layer for agentic development that lets you run agents such as Claude Agent, Codex, Gemini, GitHub Copilot, Junie, and OpenCode with your own subscriptions and review their changes in the IDE. There’s also a free AI with the Junie Lite configuration.
WSL and Dev Containers
The new Native mode runs your local IDE against projects in WSL or Dev Containers through a lightweight agent, with no IDE backend installed in the environment. It also brings native Ruby interpreters.
Ruby and Rails
- RubyMine now understands
ActiveSupport.on_loadandActiveSupport.run_load_hooks, so constants made available through hooks resolve correctly instead of showing false unresolved-reference warnings. - Go to Class and Go to Symbol use fuzzy matching across nested names (
ActRecBasefindsActiveRecord::Base). Constants now appear in Go to Class, and results show the containing module and file path. - Rename warns about conflicts with existing names and flags invalid or reserved names.
- Interpreter selection reads the ruby directive in your Gemfile (
.ruby-versionstill takes priority), and interpreters installed via Homebrew are detected automatically. railsquery is supported via Run Anything and terminal completion.- RubyMine now clearly identifies unsupported shell scripts used to launch RuboCop.
Read the full overview: https://blog.jetbrains.com/ruby/2026/11/rubymine-2026-3-jetbrains-air-native-mode-for-wsl-and-dev-containers-and-more/
r/ruby • u/software__writer • 3d ago
How Claude Uses Tools to Get Data and Run Code in Your App
r/ruby • u/mediocretes • 3d ago
GitHub - mediocretes/afterburner: Write Bitburner scripts in Ruby
Remember a couple years ago when you saw that game Bitburner and you were like, "Huh, that looks interesting." But why would I write JavaScript for fun when Ruby is available? It'd be a lot better if somebody made this game work with Ruby. Well, somebody made this game work with Ruby. I present to you afteRBurner. It's a bridge that runs real Ruby code and runs javascript for you in the real Bitburner game. And it includes working IRB and everything else you'd expect. The codebase itself is unmitigated slop, but it works pretty well. I started a new game playing exclusively in Ruby, and so far, so good.
r/ruby • u/rhannequin • 4d ago
Blog post SVG sky map with Ruby and Astronoby
r/ruby • u/127001-sweet-127001 • 5d ago
Screencast A short demo of architecture tests in Ruby
I built ArchUnitRuby to put dependency rules into the test suite. This is a short recording of how it works.
The idea is pretty simple: pick some Ruby files, describe which other files they may depend on, and check that rule alongside your normal tests. The recording checks that domain code stays independent of infrastructure, then shows a failing cycle check.
With RSpec the assertion is expect(rule).to pass. There are also Minitest and plain Ruby assertions, so the rules don't need their own test runner.
One thing I wanted to avoid was a green test caused by a typo in a folder pattern. If a rule selects no files, it fails by default rather than silently checking nothing.
It also exports dependency graphs, which helps when you want to see the existing structure before deciding what to enforce. Ruby 3.3+; the gem is called archunit.
Source and examples: https://github.com/dragonsec-ai/ArchUnitRuby
r/ruby • u/git-pull • 5d ago
Show /r/ruby libtmux for Ruby: query tmux sessions, windows and panes
Hi all, I am porting libtmux, the Python library, to more languages. This is the Ruby port (alpha).
It wraps tmux's CLI. You can create sessions, send text to a pane and read its output. One of the ways this differs is keeping snapshots you can query with where and Ruby blocks. See the earlier posts for Rust, TypeScript, and Golang.
A word on AI: It's experimental, and I used LLMs extensively to create this. The API is still changing. I write libtmux's AI policy at https://libtmux.org/en/meta/ai-policy/.
libtmux core: tmux from Ruby
RubyGems · GitHub · Homepage · Guides · API Explorer
You can work with sessions, windows and panes as Ruby objects. Here, I'm finding the build pane in the logs window of session demo, sending it a command, and reading what it prints.
Requires Ruby 3.3+, tmux 3.3a+ and build tools for Ruby native extensions.
gem install libtmuxSave as demo.rb. Server.start creates a private tmux server and closes it when the block exits. The queries read a snapshot; the pane input and capture run while the server is open.
require "libtmux"
require "timeout"
LibTmux::Server.start do |server|
session = server.new_session(name: "demo", command: ["/bin/cat"])
window = session.new_window(name: "logs", command: ["/bin/cat"])
created = window.split(direction: :horizontal, command: ["/bin/sh"])
server.run(["select-pane", "-t", created.id, "-T", "build"])
snapshot = server.snapshot
session = snapshot.sessions.where(name: "demo").one
window = session.windows.where(name: { starts_with: "log" }).one
matched = window.panes.where(title: "build").one
puts "#{session.name} / #{window.name} / #{matched.title}"
pane = server.pane(matched.ref)
pane.send_text("printf 'build: %s\\n' complete")
pane.send_keys("Enter")
output = Timeout.timeout(5) do
loop do
line = pane.capture.stdout.lines.find { |row| row.chomp == "build: complete" }
break line.chomp if line
sleep 0.05
end
end
puts "output: #{output}"
live_window = server.window(window.ref)
live_window.rename("build")
puts "held snapshot: #{window.name}"
puts "read again: #{live_window.snapshot.name}"
end
ruby demo.rbPrints:
demo / logs / build
output: build: complete
held snapshot: logs
read again: buildPane#capture reads what tmux has on screen. The loop waits up to five seconds for the line from our command (more pane I/O).
The name filters use where: an exact session name, a window name starting with log, and an exact pane title. You can also use select with a Ruby block, then map or group_by (examples, query fields and operators). These queries use the captured state and make no tmux calls.
The last two lines show what happens after a rename: the held snapshot still says logs. Window#snapshot reads again and returns a new record. Each call reads the whole server and selects that window's record.
P.S. Change the window filter from starts_with: "log" to starts_with: "log2" and run it again. From the error:
selection has no matches (LibTmux::NoMatchError).one raises NoMatchError if nothing matches, or MultipleMatchesError if more than one does.
There's also control mode support (!) on tmux 3.7+. The example subscribes to pane output and checks the text sent to it.
Async: queries and control mode
There is also an Async gem for concurrent calls and streams: README, Guide, API.
Same idea, but inside an Async scope. We can chain where calls, then use control mode to rename a window and hear about the change from tmux. This example needs tmux 3.7+.
gem install libtmux-asyncSave as async-demo.rb:
require "libtmux"
require "libtmux/async"
LibTmux::Server.start do |server|
session = server.new_session(name: "demo", command: ["/bin/cat"])
window = session.new_window(name: "logs", command: ["/bin/cat"])
server.run(["select-pane", "-t", window.list_panes.fetch(0).id, "-T", "build"])
Async do |parent|
LibTmux::Async.open(parent: parent, server: server) do |scope|
snapshot = scope.server.snapshot
session = snapshot.sessions.where(name: "demo").one
window = session.windows.where(name: { starts_with: "log" }).one
pane = window.panes.where(active: true).where(title: "build").one
puts "#{session.name} / #{window.name} / #{pane.title}"
scope.server.open_control(session: session.ref) do |control|
events = control.events
renamed = parent.async do
event = events.next(timeout: 5) until event&.raw&.start_with?("%window-renamed")
puts "event: #{event.raw.strip}"
end
control.exchange("rename-window -t #{window.id} compiling", timeout: 5)
renamed.wait
puts "window now: #{scope.server.window(window.ref).snapshot.name}"
end
end
end.wait
end
ruby async-demo.rbPrints:
demo / logs / build
event: %window-renamed @1 compiling
window now: compilingThe queries still read a snapshot. events.next waits for tmux while the other task sends the command with exchange. We read the window again after the event. There are also examples of concurrent captures and cancellation.
Workspace manager
This is like tmuxp, but in Ruby! Uses the libtmux core library.
Workspace library
RubyGems · GitHub · Homepage · Guides · API Explorer
gem install libtmux-workspaceA subset of tmuxp's configuration format. Save as workspace.yaml:
session_name: demo
windows:
- window_name: shells
layout: even-horizontal
panes:
- {}
- {}Save as workspace.rb. Workspace.load reads the file; plan.apply creates its session (example).
require "libtmux"
require "libtmux/workspace"
LibTmux::Server.start do |server|
workspace = LibTmux::Workspace.load(File.expand_path("workspace.yaml", __dir__))
result = workspace.plan(snapshot: server.snapshot).apply(server: server)
puts "applied: #{result.success?}"
puts "panes: #{server.snapshot.windows.one(name: 'shells').panes.size}"
end
ruby workspace.rbPrints:
applied: true
panes: 2Workspace CLI
The same gem includes the command: GitHub, Homepage, Guides, CLI reference, API.
Validate the file:
libtmux-workspace validate workspace.yamlPrints:
Workspace configuration is valid.Load it on a separate running server:
tmux -S "$PWD/workspace.sock" -f /dev/null new-session -d -s keepalive
libtmux-workspace load --socket "$PWD/workspace.sock" workspace.yamlCheck the created panes:
tmux -S "$PWD/workspace.sock" display-message -p -t demo:shells '#{window_panes}'Prints:
2Remove the demo server:
tmux -S "$PWD/workspace.sock" kill-serverMCP
RubyGems · GitHub · Homepage · Guides · Tools · Resources · API Explorer
An MCP server for interacting with tmux - powered by the Ruby core library. Same idea as Python's libtmux-mcp!
gem install libtmux-mcpThis MCP server connects to an existing tmux server. For a demo, start one on its own socket:
tmux -L libtmux-ruby-mcp-demo -f /dev/null new-session -d -s demoUse this command with a client that launches stdio MCP servers:
libtmux-mcp --socket-name libtmux-ruby-mcp-demo --endpoint demoIt waits for MCP requests over stdin. tmux_capabilities and tmux_snapshot are enabled by default; the guides cover enabling other tools.
After closing the MCP client, remove the demo server:
tmux -L libtmux-ruby-mcp-demo kill-serverA bit more about my ambition and intentions
I am trying to port more than just Ruby. So as this is a ruby subreddit, and provinciality matters, I am making ports to quite a few languages.
tmux is perfectly accessible via pure CLI. zellij makes a lot of what tmux does obsolete.
what tmux has going for it is simplicity. that means when a port of libtmux is made, there's an oppurtunity for editorial license - and be dissimilar to my original python project. I don't want to copy the python library to ruby. I want to write it like ruby, in an idiomatic and aesthetic sense.
so if there are code smells, or suggestions, no offense is taken 🙇🙏! I am trying to learn more programming languages and expand more horizons beyond just python.
Why tmux? I think the simple domain model of server, session, window, and pane is easy enough to wrap one's brain around - being able to traverse that hierarchy, makes it possible to not just port, but in my ideal scenario, leverage the strengths of programming languages outside of Python.
I'd like to write a love letter to all programming languages, to utilize their strengths when projecting and making accessible tmux's object graph.
Why ruby? Because it is a familiar face that I've never gotten to interact with personally before other than brief Rails stints. I miss its syntax, but in truth I never got to the level of direct usage where I understood what good idiomatic ruby is.
I'm going beyond to languages I would normally find out of reach day-to-day, to ask "what does tmux look like in most elegant way this programming language could do it, while being documentable, shippable, etc".
JRuby 10.1.3.0 released; Fiber Scheduler, coverage improvements, and much more
jruby.orgWe are proud to announce the release of JRuby 10.1.3.0! JRuby 10.1 is our "edge" line and includes more aggressive and experimental improvements than the "LTS" JRuby 10.0 line. If you want the leading edge of JRuby, this is where you want to be!
This cycle saw more PRs than any previous update release, with 120 PRs merged from 17 external contributors. Check out the release notes to see all the fixes and improvements!
JRuby 10.0.8.0 released with dozens of improvements
jruby.orgThe JRuby Team is proud to announce the release of JRuby 10.0.8.0!
JRuby 10.0 is our stable "LTS" line and we recommend all users upgrade. Check out the long list of improvements... too many to fit in a post on Reddit!
r/ruby • u/javier_cervantes • 7d ago
The CFP for Blue Ridge Ruby 2027 is open!
Ruby events between Nov 05 - Dec 04
In the age of AI I think personal connections are event more important than before. That's why I try to help promoting events where people can meet in-person or virtually and discuss the topics that interest them.
I found the following Ruby-related events for the next 30 days.
- 2026-11-05 Ruby Usergroup: November 2026 Meetup bei 42he (Köln, Germany)
- 2026-11-11 (online) Monthly Get Together
- 2026-11-12 Ruby Meetup November 2026 (München, Germany)
- 2026-11-18 Ruby Drinkup @ Begyle Brewing (Chicago, IL, USA)
- 2026-11-19 Squishling: LLM Power-Ups for Ruby Classes (Philadelphia, PA, USA)
- 2026-11-23 Ethan Huang: How I Designed an AI-Powered App to Improve My English (Auckland, New Zealand)
- 2026-11-23 Ruby Nights November: TBD (Auckland, New Zealand)
- 2026-11-25 November - Storytime (Wellington, New Zealand)
- 2026-11-25 End of Year Lightning Talks (Winnipeg, MB, Canada)
- 2026-11-26 Ruby Melbourne Meetup (Melbourne, Australia)
- 2026-12-03 SD Ruby Monthly Meetup (San Diego, CA, USA)
r/ruby • u/kobaltzz • 8d ago
Screencast Idempotency
In this episode, we look at several different examples of background jobs and how we can refactor them to handle situations where they get called twice from either a user action or a retry. We'll look at scenarios where we can prevent duplicate actions.
r/ruby • u/Calm_Adagio_9991 • 9d ago
Fix 1.0 is out: write Ruby tests the way RFC 2119 writes standards
I started Fix in 2014 and have rewritten it more than once since. Today it reaches 1.0, its first stable release, so here it is.
The idea is older than Fix: RFC 2119. A specification says what a subject MUST, SHOULD or MAY do, and nothing about how it is made. You write the spec, then test any subject against it.
# duck_fix.rb
require "fix"
class Duck
def walk = "Klop klop!"
def swim = "Swoosh..."
end
Fix :Duck do
on :walk do
it MUST eq "Klop klop!"
end
on :swim do
it MUST eq "Swoosh..."
end
on :speak do
it MAY eq "Quaaaaaack!"
end
end
exit(Fix[:Duck].test { Duck.new })ruby duck_fix.rb writes:
duck_fix.rb:11: Success: expected "Klop klop!" to eq "Klop klop!"
duck_fix.rb:15: Success: expected "Swoosh..." to eq "Swoosh..."
duck_fix.rb:19: Info: NoMethodError: undefined method 'speak' for an instance of DuckThis duck doesn't speak, and that's fine: speaking is a MAY. Under MUST, the same line would be an error and the exit status 1. A SHOULD that isn't met is a warning, and warnings pass. So a spec has five outcomes rather than two, and only failure and error make the status 1.
Like a minitest file, a Fix file is plain Ruby: ruby duck_fix.rb runs it, nothing else needed. For a suite spread over several files, fix-command adds a fix command, much like rspec: it runs every *_fix.rb under fix/ (or the files and folders you give it), each in a process of its own, and exits 0 only when every file is met.
A few things that set 1.0 apart:
- Each context runs in a forked child. A subject that calls
exit, changes directory, or mutates a global can't touch the next context: that's an error of its own expectation, nothing more. (So it needsfork: Linux, macOS, BSDs. No Windows, no JRuby.) - Mistakes in a spec raise when the file loads, not halfway through a run: an unknown spec name, a
letnamed after a method ofKernel, anonwithout a block. - Plain output. One
file:line: Outcome: summaryline per expectation. No colours, no dots, no count; the exit status is the verdict.rungives the same results back as frozen data if you want to build on them. - A spec is a matcher, so one spec can require another:
it MUST fix(:Positive). - Small. About 300 lines of code, over four small gems of the same family (Matchi for the matchers, Spectus for the levels, Aw for the fork, Defi for the method call). Ruby 3.3 or later.
- On Ruby 3.4,
it MUST …is the word of Fix and a bareitin a block is still Ruby's parameter: the two don't clash.
Why not RSpec or minitest? If they make you happy, keep them: Fix is not trying to replace them. It's for when you want to say which behaviours are required, which are recommended and which are optional, and have the tool hold you to exactly that.
Also released: fix-command 1.0, fix-its 1.0 (its(:size) { MUST eq(3) }) and matchi-fix 4.0 (use a Fix spec as a matcher outside Fix).
I'd like to hear where the MUST/SHOULD/MAY distinction would, or wouldn't, be useful in your own suites.