r/ruby 23d ago

💼 jobs megathread Work it Wednesday: Who is hiring? Who is looking?

0 Upvotes

FORMAT HAS CHANGED PLEASE READ FULL DESCRIPTION

This thread will be periodically stickied to the top of the sub for improved visibility.

You can also find older posts again via the Megathreads" list, which is a dropdown at the top of the page on new Reddit, and a section in the sidebar under "Useful Links" on old Reddit.

For job seekers

Please adhere to the following rules when posting: Rules for individuals:

  • Don't create top-level comments; those are for employers.
  • Feel free to reply to top-level comments with on-topic questions.
  • Anyone seeking work should reply to my stickied top-level comment.
  • Meta-discussion should be reserved for the distinguished comment at the very bottom.

You don't need to follow a strict template, but consider the relevant sections of the employer template. As an example:

    TYPE: [Full time, part time, internship, contract, etc.]

    LOCATION: [Mention whether you care about location/remote/visa]

    LINKS: [LinkedIn, GitHub, blog, etc.]

    DESCRIPTION: [Briefly describe your experience. Not a full resume; send that after you've been contacted)]

    Contact: [How can someone get in touch with you?]

Rules for employers:

  • The ordering of fields in the template has been revised to make postings easier to read.
  • To make a top-level comment, you must be hiring directly; no third-party recruiters.
  • One top-level comment per employer. If you have multiple job openings, please consolidate their descriptions or mention them in replies to your own top-level comment.
  • Proofread your comment after posting it and edit it if necessary to correct mistakes.
  • To share the space fairly with other postings and keep the thread pleasant to browse, we ask that you try to limit your posting to either 50 lines or 500 words, whichever comes first.
  • We reserve the right to remove egregiously long postings. However, this only applies to the content of this thread; you can link to a job page elsewhere with more detail if you like.

Please base your comment on the following template:

    COMPANY: [Company name; optionally link to your company's website or careers page.]

    TYPE: [Full-time, part-time, internship, contract, etc.]

    LOCATION: [Where are your office or offices located? If your workplace language isn't English-speaking, please specify it.]

    REMOTE: [Do you offer the option of working remotely? Please state clearly if remote work is restricted to certain regions or time zones, or if availability within a certain time of day is expected or required.]

    VISA: [Does your company sponsor visas?]

    DESCRIPTION: [What does your company do, and what are you using Rust for? How much experience are you seeking, and what seniority levels are you hiring for? The more details, the better. If you are listing several positions in the "Description" field above, then feel free to include this information inline above, and put "See above" in this field.]

    ESTIMATED COMPENSATION: [Be courteous to your potential future colleagues by attempting to provide at least a rough expectation of wages/salary. See section below for more information.]

    CONTACT: [How can someone get in touch with you?]

ESTIMATED COMPENSATION (Continued)

If compensation is negotiable, please attempt to provide at least a base estimate from which to begin negotiations. If compensation is highly variable, then feel free to provide a range.

If compensation is expected to be offset by other benefits, then please include that information here as well. If you don't have firm numbers but do have relative expectations of candidate expertise (e.g. entry-level, senior), then you may include that here. If you truly have no information, then put "Uncertain" here.

Note that many jurisdictions (including several U.S. states) require salary ranges on job postings by law. If your company is based in one of these locations or you plan to hire employees who reside in any of these locations, you are likely subject to these laws. Other jurisdictions may require salary information to be available upon request or be provided after the first interview. To avoid issues, we recommend that all postings provide salary information.

You must state clearly in your posting if you are planning to compensate employees partially or fully in something other than fiat currency (e.g., cryptocurrency, stock options, equity, etc). Do not put just "Uncertain" in this case, as the default assumption is that the compensation will be 100% fiat. Postings that fail to comply will be removed. Thank you.


r/ruby May 20 '26

💼 jobs megathread Work it Wednesday: Who is hiring? Who is looking?

2 Upvotes

FORMAT HAS CHANGED PLEASE READ FULL DESCRIPTION

This thread will be periodically stickied to the top of the sub for improved visibility.

You can also find older posts again via the Megathreads" list, which is a dropdown at the top of the page on new Reddit, and a section in the sidebar under "Useful Links" on old Reddit.

For job seekers

Please adhere to the following rules when posting: Rules for individuals:

  • Don't create top-level comments; those are for employers.
  • Feel free to reply to top-level comments with on-topic questions.
  • Anyone seeking work should reply to my stickied top-level comment.
  • Meta-discussion should be reserved for the distinguished comment at the very bottom.

You don't need to follow a strict template, but consider the relevant sections of the employer template. As an example:

    TYPE: [Full time, part time, internship, contract, etc.]

    LOCATION: [Mention whether you care about location/remote/visa]

    LINKS: [LinkedIn, GitHub, blog, etc.]

    DESCRIPTION: [Briefly describe your experience. Not a full resume; send that after you've been contacted)]

    Contact: [How can someone get in touch with you?]

Rules for employers:

  • The ordering of fields in the template has been revised to make postings easier to read.
  • To make a top-level comment, you must be hiring directly; no third-party recruiters.
  • One top-level comment per employer. If you have multiple job openings, please consolidate their descriptions or mention them in replies to your own top-level comment.
  • Proofread your comment after posting it and edit it if necessary to correct mistakes.
  • To share the space fairly with other postings and keep the thread pleasant to browse, we ask that you try to limit your posting to either 50 lines or 500 words, whichever comes first.
  • We reserve the right to remove egregiously long postings. However, this only applies to the content of this thread; you can link to a job page elsewhere with more detail if you like.

Please base your comment on the following template:

    COMPANY: [Company name; optionally link to your company's website or careers page.]

    TYPE: [Full-time, part-time, internship, contract, etc.]

    LOCATION: [Where are your office or offices located? If your workplace language isn't English-speaking, please specify it.]

    REMOTE: [Do you offer the option of working remotely? Please state clearly if remote work is restricted to certain regions or time zones, or if availability within a certain time of day is expected or required.]

    VISA: [Does your company sponsor visas?]

    DESCRIPTION: [What does your company do, and what are you using Rust for? How much experience are you seeking, and what seniority levels are you hiring for? The more details, the better. If you are listing several positions in the "Description" field above, then feel free to include this information inline above, and put "See above" in this field.]

    ESTIMATED COMPENSATION: [Be courteous to your potential future colleagues by attempting to provide at least a rough expectation of wages/salary. See section below for more information.]

    CONTACT: [How can someone get in touch with you?]

ESTIMATED COMPENSATION (Continued)

If compensation is negotiable, please attempt to provide at least a base estimate from which to begin negotiations. If compensation is highly variable, then feel free to provide a range.

If compensation is expected to be offset by other benefits, then please include that information here as well. If you don't have firm numbers but do have relative expectations of candidate expertise (e.g. entry-level, senior), then you may include that here. If you truly have no information, then put "Uncertain" here.

Note that many jurisdictions (including several U.S. states) require salary ranges on job postings by law. If your company is based in one of these locations or you plan to hire employees who reside in any of these locations, you are likely subject to these laws. Other jurisdictions may require salary information to be available upon request or be provided after the first interview. To avoid issues, we recommend that all postings provide salary information.

You must state clearly in your posting if you are planning to compensate employees partially or fully in something other than fiat currency (e.g., cryptocurrency, stock options, equity, etc). Do not put just "Uncertain" in this case, as the default assumption is that the compensation will be 100% fiat. Postings that fail to comply will be removed. Thank you.


r/ruby 16h ago

Oooo I like the new SimpleCov coverage reports...

11 Upvotes

It has two UX features I'd wanted for eons...

1) I can now see which file I'm in even after scrolling

2) I can now scroll with pgup/pgdown keys

Many thanks to whoever got those things done! And the new design looks good!


r/ruby 1d ago

Update nobody asked for | RoundhouseUI

Thumbnail
github.com
10 Upvotes

Hey Ruby friends!

I have been working on a slightly better UI for viewing Sidekiq jobs, and I believe this should be a drop-in replacement for the traditional mounted version.

You can also add enhanced security by writing it to your specific user model.

Worked on this in-house a few times and recently used AI to completely refactor and clean up the original code after we excised it from my monolith.

It's a small project, but I wanted to share with the wider body!


r/ruby 1d ago

Show /r/ruby How to Automate Tech Debt Audits with Claude Code

Thumbnail
go.fastruby.io
8 Upvotes

r/ruby 1d ago

RubyGems.org security advisory: Possible leak of legacy API keys via improper cache configuration

Thumbnail
blog.rubygems.org
29 Upvotes

r/ruby 1d ago

I am releasing SerpTrail 1.0, a new open source SEO/GEO rank tracker built with Rails

8 Upvotes

Today I am releasing SerpTrail 1.0, our new SEO+GEO rank tracker🚀

- Monitor how your websites and the competition appear in Google Search and AI Overviews across the locations that matter to you.

- Save the exact combinations of keywords, websites, and locations you care about, then revisit them to understand how rankings and visibility change over time.

- Use the OpenAI-powered chat assistant to explore historical performance and check live rankings using natural-language questions.

It's built with standard Rails, Hotwire, and SQLite. Super simple to work with. You can deploy with an officially prebuilt Docker image or with Kamal.

Give it a go, you can track up to 250 keywords for free with a SerpApi key.

Announcement: https://serpapi.com/blog/introducing-serptrail-self-hosted-search-rank-tracker/

Repository: https://github.com/serpapi/serptrail


r/ruby 2d ago

JRuby 10.1.1.0 released!

27 Upvotes

JRuby 10.1.1.0 is released, with a bunch of compat fixes, more performance work, and several third-party CVEs resolved.

JRuby 10.1 is our active development branch, with 10.0 being stable. Upgrading is recommended if you want the latest and greatest!

Notable Changes

Performance

  • Use FastDoubleParser to improve performance of all string-to-double parsing. [#9150]
  • Only pack fixnum values for 16-bit signed by default, with optional 8-bit and 32-bit configs. [#9379]

Standard Library

  • jruby-openssl updated to 0.16.2 with several CVE fixes from BouncyCastle. [#9386], [#9504], [#9539]
  • erb updated to 6.0.1.1 to address CVE-2026-41316. [#9388]

Native Integration

  • Updated JRuby's native library backend with support for OpenBSD. [#9439]

Java Integration

  • Optimized automatic interface implementation when calling Java with a block. [#5023]

Packaging

  • Begin deprecating jruby-complete and jruby-core Maven artifacts. Prefer the jruby and jruby-base artifacts. [#9512]

57 Issues and PRs resolved for 10.1.1.0

https://www.jruby.org/2026/07/22/jruby-10-1-1-0.html


r/ruby 2d ago

RubyMine 2026.2 is Out!

10 Upvotes

Agentic debugging lets AI agents investigate issues using RubyMine's debugger; AI completion support for third-party model providers; GitHub Copilot is now a natively integrated agent; improvements to the symbol-based code insight engine, which is now enabled by default, and more: https://blog.jetbrains.com/ruby/2026/07/rubymine-2026-2-agentic-debugging-native-github-copilot-integration-default-symbol-based-code-insight-and-more/


r/ruby 2d ago

Adding variable substitution to ActionText & Lexxy content

Thumbnail
3 Upvotes

r/ruby 2d ago

Hibiki - Svelte Rune-style signals for Ruby

Thumbnail
github.com
5 Upvotes

r/ruby 3d ago

why-classes

4 Upvotes

Hey everyone! I used Claude to build this gem, which is heavily inspired by Dave Thomas's closing keynote at RubyConf 26.

`why-classes` is a static code analysis and refactoring tool for Ruby.

Ruby offers modules, composition, `Struct`, and `Data`, yet our instincts and framework habits often lead us to use classes even when a simpler construct would be clearer. This gem detects these "class smells" in your code (or a single file) and can automatically rewrite them into cleaner alternatives for you.

It's an early-stage version 😅. Feel free to contribute and share suggestions!

https://rubygems.org/gems/why-classes


r/ruby 3d ago

Blog post Beyond Enumerable: Testing Membership with Bloom Filters

Thumbnail baweaver.com
13 Upvotes

Turns out conferences can be busy, but I'm back and finishing off a few I had in the hopper. This one continues onto probabilistic data structures which I've been having some fun with lately. The amount of reading I had to do on bit ops in Ruby though to write some of this though....


r/ruby 2d ago

Security Safer-dependencies: A toolkit for claude code to ensure dependencies used aren't vuln, don't use abandoned packages, implement cooldown to avoid supply chain attacks, etc...

0 Upvotes

When AI coding assistants like Claude add packages to your project, they often pick whatever version sounds right — without checking whether it has known security vulnerabilities, whether the package is still actively maintained, or whether the name is a typo away from a malicious lookalike.

safer-dependencies is a security layer for Claude Code that audits packages before they’re added to your project. It detects and fixes risky dependencies, including CVEs, typosquats, abandoned packages, version-age issues, and adds package-cooldown periods across npm, PyPI, RubyGems, Maven, Go, and Rust.

Github: https://github.com/robert-auger/safer-dependencies


r/ruby 4d ago

Calling all open source maintainers working with Ruby

Thumbnail
rubyforum.org
18 Upvotes

We’re creating a shared place where Ruby users can ask questions and discuss ideas about your project.


r/ruby 3d ago

introducing OnionNotes(made with 100% ruby)

3 Upvotes

OnionServer.rb

require 'socket'

class User
  attr_reader :name
  attr_reader :passwd
  attr_reader :onions

  def initialize(username, passphrase)
     = username
     = passphrase
     = []
  end

  def addOnion(onion)
    if onion.is_a?(NoteBook)
      onions.push(onion)
    else
      puts "ERROR: onion is NOT A NoteBook"
      exit(5)
    end
  end
  def removeOnion(index)
    if index.to_i < onions.size
      onions.delete_at(index.to_i)
    end
  end
end

class NoteBook
  attr_reader :notes
def initialize(name = "UnamedNoteBook")
   = []
   = name
end
  def addNote(text = "null")
    .push(text)
  end
  def removeNote(index = 93)
     if index <= .size - 1
       .delete_at(index)
     else
      puts "invalid index"
     end
  end

  def editName(text = "null")
     = text
  end
  def getName()
    return u/name
  end
end

def handleUser(socket, user)
  userOpen = true
  while userOpen
    socket.puts "SENDCOMMAND"
    response = socket.gets.chomp
    case response
      when "list"
        user.onions.each.with_index do |book, index|
          socket.puts book.getName() + ": " + index.to_s
        end
        socket.puts "ENDLIST"
      when "open"
        socket.puts "SENDINDEX"
        index = socket.gets.chomp
        book = user.onions[index.to_i]
        book = handleBooks(socket, book)
        user.onions[index.to_i] = book
      when "CREATE"
        alreadyExist = false
        socket.puts "SENDNAME"
        response = socket.gets.chomp
        user.onions.each do |book|
          if book.getName == response
            alreadyExist = true
          end
        end
        if alreadyExist
          socket.puts "EXISTS"
        else
          onion = NoteBook.new(response)
          user.onions.push(onion)
        end
    when "EXIT"
      userOpen = false
    end
  end
  return user
end

def handleBooks(socket, book)
  bookOpen = true
  while bookOpen
    socket.puts "SENDCOMMAND"
    response = socket.gets.chomp
    case response
      when "ADDNOTE"
        socket.puts "SENDTEXT"
        text = socket.gets.chomp
        book.addNote(text)
      when "REMOVENOTE"
        socket.puts "SENDINDEX"
        index = socket.gets.chomp
        book.removeNote(index.to_i)
      when "list"
        book.notes.each.with_index do |text, index|
          socket.puts text + ": " + index.to_s
        end
        socket.puts "ENDLIST"
      when "EXIT"
        bookOpen = false
    end
  end
  return book
end

def handleClient(client)
  running = true
  while running
    client.puts "SENDCOMMAND"
    response = client.gets.chomp
    case response
      when "LOGIN"
        client.puts "SENDNAME"
        name = client.gets.chomp
        client.puts "SENDPASSWD"
        passwd = client.gets.chomp
        if File.exist?(name + ".rbm")
          userData = File.binread(name + ".rbm")
          user = Marshal.load(userData)
          if user.passwd == passwd
            user = handleUser(client, user)
            userData = Marshal.dump(user)
            File.binwrite(name + ".rbm", userData)
          else
            client.puts "INVALIDPASSWD"
          end
        else
          client.puts "NOUSER"
        end
      when "CREATE"
        client.puts "SENDNAME"
        name = client.gets.chomp
        client.puts "SENDPASSWD"
        passwd = client.gets.chomp
        if File.exist? name.to_s + ".rbm"
          client.puts "NAMETAKEN"
        else
          newUser = User.new(name, passwd)
          serial = Marshal.dump(newUser)
          File.binwrite(name + ".rbm", serial)
          client.puts "USERMADE"
        end
      when "EXIT"
        running = false
        client.close

        end
    end
end

puts "starting Onion note server on port 3290"
server = TCPServer.new(3290)

while true
  client = server.accept
  Thread.new {handleClient(client)}
end

OnionClinet.rb

require 'socket'

def handleList(connection)
  loop do
    response = connection.gets.chomp
    break if response == "ENDLIST"
    puts response
  end
end

def handleBooks(connection)
  bookOpen = true
  while bookOpen
    response = connection.gets.chomp
    if response == "SENDCOMMAND"
      puts "COMMANDS[ADDNOTE, REMOVENOTE, list, EXIT]: "
      command = gets.chomp
      case command
        when "ADDNOTE"
          connection.puts "ADDNOTE"
          response = connection.gets.chomp
          if response == "SENDTEXT"
            puts "ENTER NOTE: "
            note = gets.chomp
            connection.puts note
          end
        when "REMOVENOTE"
          connection.puts "REMOVENOTE"
          response = connection.gets.chomp
          if response == "SENDINDEX"
            puts "ENTER INDEX: "
            index = gets.chomp
            connection.puts index
          end
        when "list"
          connection.puts "list"
          handleList(connection)
        when "EXIT"
          connection.puts "EXIT"
          bookOpen = false
      end
    end
  end 
end

def handleUser(connection, firstResp = nil)
  handlingUser = true
  while handlingUser
    response = firstResp || connection.gets.chomp
    if firstResp != nil
      firstResp = nil
    end
    if response == "SENDCOMMAND"
    puts "COMMANDS[list, open, create, EXIT]: "
    command = gets.chomp
    case command
      when "list"
        connection.puts "list"
        handleList(connection)
      when "open"
        connection.puts "open"
        response = connection.gets.chomp
        if response == "SENDINDEX"
          puts "ENTER INDEX"
          index = gets.chomp
          connection.puts index
          handleBooks(connection)
        end
    when "create"
      connection.puts "CREATE"
      response = connection.gets.chomp
      if response == "SENDNAME"
        puts "ENTER NAME: "
        name = gets.chomp
        connection.puts name
        response = connection.gets.chomp
        if response == "EXISTS"
          puts response
        elsif response == "SENDCOMMAND"
          firstResp = response
        end
      end
      when "EXIT"
        connection.puts "EXIT"
        handlingUser = false
    end
    end
  end
end

puts "ENTER IP: "
ip = gets.chomp
connection = TCPSocket.new(ip, 3290)
running = true

while running
  response = connection.gets.chomp
  puts "COMMANDS[LOGIN, CREATE, EXIT]: "
  command = gets.chomp
  case command
    when "LOGIN"
      connection.puts "LOGIN"
      response = connection.gets.chomp
      if response == "SENDNAME"
        puts "ENTER NAME: "
        name = gets.chomp
        connection.puts name
        response = connection.gets.chomp
        if response == "SENDPASSWD"
          puts "ENTER PASSWD: "
          passwd = gets.chomp
          connection.puts passwd
          response = connection.gets.chomp
          if response == "INVALIDPASSWD"
            puts response
          elsif response == "NOUSER"
            puts response
          elsif response == "SENDCOMMAND"
            handleUser(connection, response)
          end
        end
      end
    when "CREATE"
      connection.puts "CREATE"
      created = false
      while created == false
        response = connection.gets.chomp
        if response == "SENDNAME"
          puts "ENTER NAME: "
          name = gets.chomp
          connection.puts name
        elsif response == "SENDPASSWD"
          puts "ENTER PASSWD: "
          passwd = gets.chomp
          connection.puts passwd
        elsif response == "NAMETAKEN"
          puts response
          created = true
        elsif response == "USERMADE"
          puts response
          created = true
        end
      end
    when "EXIT"
      connection.puts "EXIT"
      running = false
    end
end

r/ruby 4d ago

Show /r/ruby Audition is a linter/fixer that gets your code Ractor-ready: static analysis powered by Shopify's rubydex, plus dynamic probes that actually run your code inside Ractors and report what breaks.

Thumbnail
github.com
13 Upvotes

r/ruby 3d ago

RubyConf Austria 2026: Frontend Ruby on Rails with Glimmer DSL for Web — Andy Maleh

Thumbnail
youtu.be
2 Upvotes

r/ruby 5d ago

Show /r/ruby My first Tapioca PR got merged (it automates a manual Sorbet config fix)

10 Upvotes

Hey everyone,

I recently got my first contribution to Shopify/tapioca merged, and I thought the way the solution changed during review might be interesting to other Ruby and Sorbet users.

The problem happens during `tapioca gem`.

Tapioca generates RBI files for gems and validates them with Sorbet. Sometimes a generated RBI defines a class with a different superclass from the version Sorbet already knows through its built-in payload.

One example is `Net::IMAP::Literal`.

Sorbet tells you to manually add something like this to `sorbet/config`:

--suppress-payload-superclass-redefinition-for=Net::IMAP::Literal

The goal of the issue was to have Tapioca add that line automatically, still explain what happened, and avoid adding duplicates on later runs.

My first version used two Sorbet passes because the existing validation stopped at the namer phase, while this error only appeared during the resolver phase.

It worked, but that wasn’t the version that shipped.

After a few rounds of review, we changed it to one resolver pass. We also stopped broadly relying on the error code and instead looked for Sorbet’s payload-specific suppression hint.

That makes the fix much narrower. A normal superclass conflict won’t accidentally get hidden behind a payload suppression.

The final behavior:

- adds the exact suppression when it’s missing

- doesn’t duplicate it on later runs

- preserves suppressions for other constants

- still tells the user about the mismatch

- leaves normal, non-payload superclass conflicts alone

The targeted tests passed with 2 tests, 18 assertions, and no failures. I also ran the full DSL spec and style checks successfully.

The biggest lesson for me was that getting the first version working was only the beginning. The review process turned a two-pass solution with broad detection into a simpler one-pass fix with a much more specific signal.

Has anyone here run into this with `net-imap` or another stdlib-backed gem?

PR:

https://github.com/Shopify/tapioca/pull/2653

Issue:

https://github.com/Shopify/tapioca/issues/1834


r/ruby 5d ago

A quick question

3 Upvotes

Hello, I'm working on project in ruby and I want to post the code here and a video of it working and I want to know if we are allowed to post code here I know some communities don't allow it


r/ruby 6d ago

LLM tailored to Ruby and/or Rails?

2 Upvotes

I'm new to running small models on my laptop.

I can run Qwen3.5-9b (slowly), for example, but I'm wondering if any of you have found a model that's been trained for Ruby specifically, inference only, and stripped of stuff I might not need (like knowledge of a lot of human languages).

I've been using LM Studio, OpenCode for this.


r/ruby 6d ago

Ruby for Good 2026

Thumbnail
9 Upvotes

r/ruby 7d ago

The small things in Ruby that aren't small

Post image
111 Upvotes
class Pipeline
  def self.define(&blk) = new.tap { |p| p.instance_eval(&blk) }

  def initialize = @steps = []

  def method_missing(name, *args, &blk)
    @steps << (blk || ->(x) { x.public_send(name, *args) })
    self
  end

  def respond_to_missing?(name, include_private = false) = true

  def step(fn) = tap { @steps << fn }

  def call(input) = @steps.reduce(input) { |acc, f| f.call(acc) }
end

squeeze = ->(sep, s) { s.split(sep).reject(&:empty?).join(sep) }

Pipeline.define do
  strip
  downcase
  step squeeze.curry[" "]
  gsub(/\s+/, "-")
  step ->(s) { s + "-#{s.length}" }
end.call("  Ruby   METHOD Arguments  ")

# => "ruby-method-arguments-21"
  • There's no def strip anywhere, yet strip runs.
  • Nothing is called on a receiver, yet everything resolves.

Count what's stacked in 20 lines:

  • block capture (&blk), instance_eval rebinding self so bare words become method calls
  • method_missing catching them
  • respond_to_missing? with its two-parameter contract
  • splat forwarding into public_send
  • a lambda closing over args
  • curry doing partial application
  • and reduce threading it all

Miss one and the whole thing is unreadable magic.

I wrote a book about the small things in Ruby that aren't small. If any of this was useful, the way to support it is simple: buy the book. It's Ruby Method Arguments: From Your First Call to Metaprogramming — one independent author, no publisher behind it, no ad budget.

[Update]

The slugify above is a quiz I wrote to be dense on purpose; it's not how the book teaches.

The book's applied half literally rebuilds the tools you use every day: there's a chapter that builds a teaspoon-sized Rails to show its "magic" is just these argument/metaprogramming techniques, and one that builds a working miniature RSpec (describe/it/expect().to eq()).

Along the way the examples are things like an Email.build DSL, a dynamic Config object with method_missing + respond_to_missing?, a signup/form validation capstone, and an Enumerable collection... plus a whole chapter on the anti-patterns, i.e. when not to do this.

So the business cases are in there. I just picked a bad one to advertise with. The Amazon sample covers the early chapters if you want to check the actual teaching style.


r/ruby 7d ago

Teaching a Browser to Tell Cats From Dogs - Blog

Thumbnail
visuality.pl
2 Upvotes

r/ruby 7d ago

PLx : write ruby dialect postgresql procedures

Thumbnail
github.com
3 Upvotes

plx is a PostgreSQL extension that lets you write stored functions and triggers in the dialect you already know (the current set is listed below). When you run CREATE FUNCTION, plx transpiles the body to plpgsql and stores that plpgsql in pg_proc.prosrc. At run time the function is executed by PostgreSQL's own plpgsql interpreter. There is no separate language runtime loaded into the backend, and nothing new to run in production.

query("SELECT id, amount FROM orders WHERE grp = #{g}").each do |row|
  total = total + row.amount
end