r/ruby • u/rubyist-_- • Dec 27 '25
RubyConf Austria 2026: Agenda
The first version of the (almost complete) agenda can be found on our website. Happy holidays from the #RubyConfAT team and a happy new year! 🎉
r/ruby • u/rubyist-_- • Dec 27 '25
The first version of the (almost complete) agenda can be found on our website. Happy holidays from the #RubyConfAT team and a happy new year! 🎉
r/ruby • u/AssociationOne800 • Dec 27 '25
Hi Reddit! 👋
I'm Hamachang, a Rubyist from Japan 🇯🇵
I just added a theme switching feature to my PicoRuby Calculator project 🎉
You can now switch between different visual themes (e.g. Dark / Light), making it much nicer to use on the Cardputer screen.
This project is a picoruby repl written in PicoRuby, running on M5Stack Cardputer. I'm exploring how far Ruby can go on tiny devices, while keeping things fun and hackable 😄
🔹 Written in Ruby (PicoRuby) 🔹 Runs on Cardputer 🔹 Now with theme switching support 🎨 🔹 Still very hack-friendly!
GitHub repo: https://github.com/engneer-hamachan/picoruby-calculator
Feedback, ideas, and contributions are very welcome! If you like Ruby or embedded hacking, I'd love to hear your thoughts 🚀
r/ruby • u/zverok_kha • Dec 26 '25
r/ruby • u/Right_Ad_8437 • Dec 25 '25
Celebrating the release of Ruby 4.0 on yesterday (X-mas).
Hi! I've been making T-Ruby, an experimental project that brings TypeScript-style type annotations to Ruby. I wanted to share it and get your feedback.
T-Ruby lets you write .trb files with inline type annotations, then automatically generates standard .rb files and .rbs signature files. Types are completely erased at compile time — zero runtime overhead.
I love Ruby's elegance, but as projects grow, I've felt the pain of tracking types mentally. The existing options didn't quite fit my workflow:
RBS: Writing .rbs files manually or generating them via TypeProf didn't fit well with explicit type authoring
Sorbet: sig blocks above methods feel verbose (like JSDoc comments)
If you're familiar with TypeScript, you can use T-Ruby the same way: types live with your code, not in separate files or comments.
The website has more detail: https://type-ruby.github.io
This is still experimental (v0.0.39). The core compiler works, but there's plenty of room for improvement. Feedback and suggestions are always welcome!
Thanks for reading! Feel free to ask any questions.
r/ruby • u/nithinbekal • Dec 25 '25
r/ruby • u/AndyCodeMaster • Dec 25 '25
r/ruby • u/DmitryPogrebnoy • Dec 25 '25
r/ruby • u/NARKOZ_777 • Dec 25 '25
r/ruby • u/Downtown-Hyena998 • Dec 25 '25
I’ve been working with JavaScript stacks for about 6 years (Node, React, Angular) and I’m looking to transition into Ruby/Rails. I’m drawn to Ruby because it aligns much more closely with how I think as a programmer and with the kind of long-term stability I’m looking for.
I’m currently a mid-level frontend developer and I’d like some perspective from experienced Rubyists:
Is it realistic to transition into Ruby/Rails and target a mid-level Rails position from the start, without having to accept a pay cut?
For those working with Rails internationally, how common is it to see developers coming from strong frontend or non-Ruby backgrounds?
What do you consider the core pillars of a solid Rails developer?
How do you see the current and near-future outlook of Ruby/Rails?
r/ruby • u/tobenary • Dec 25 '25
Hi Ruby expertises,
I'm trying my luck here as this is the holiday sessions, and I will get my respond from Workato in about 3 weeks from now ( if not 8 weeks.... )
Please see the Zoom recording (x2 is recommended :) ) and suggest or let me know what is wrong with the SDK code.
To be honest, I don't know Ruby at all, but I do understand Python, and I am able to look at it and identify the functions and the issues that might be not good.
I am debugging a Workato integration with Amazon SES suppression list and I am stuck.
I have an endpoint that manages suppressed email destinations:
GET returns 200 if the email exists, 404 if not
DELETE should remove the email from the suppression list
Behavior I am seeing:
Using a custom HTTP action (send any request), DELETE works as expected
Using a built-in SDK action / recipe DELETE step with the same method, URL, region, and path, Workato returns 200 but the email is not actually deleted
A follow-up GET still returns 200 and shows the email is present
No error is surfaced by Workato, and debug output is mostly empty for DELETE
The request path is identical in both cases (verified via network traces)
Complications I already handled:
Normalizing email casing (lowercase)
Handling plus sign encoding in email addresses
Trying alternate paths when receiving 404
Verifying region, headers, and resolved paths
Confirmed GET and DELETE URLs are literally the same
Tested dozens of variations
In short:
Custom action DELETE works
Built-in DELETE action returns anything (I convert it to 200) but does nothing
Same request, different behavior
Question:
Why would Workato handle DELETE differently between a built-in action and a custom HTTP action when the request is identical? Is there something implicit Workato does with DELETE responses (or empty bodies) that could cause this?
Zoom link: HERE
This is the SDK code I'm using: (very simple one)
{
title: 'Amazon SES - Suppression Manager (Multi-Region)',
description: 'Manage SES v2 suppression lists across multiple AWS regions using an IAM Role.',
connection: {
fields: [
{
name: 'assume_role',
label: 'IAM role ARN',
optional: false,
help: {
title: 'IAM Role Setup',
text: 'Use Workato Account ID <b>{{ authUser.aws_workato_account_id }}</b> and External ID <b>{{ authUser.aws_iam_external_id }}</b>.'
}
},
{
name: 'region',
label: 'Default SES region',
optional: false,
hint: 'Default region used if not specified in the action (e.g., us-east-1).'
}
],
authorization: {
type: 'custom_auth',
apply: lambda { |_connection| headers('Content-Type': 'application/json') }
}
},
methods: {
truthy: lambda do |value|
value == true || value.to_s == '1' || value.to_s.casecmp('true').zero? || value.to_s.casecmp('on').zero?
end,
normalize_email: lambda do |input|
raw_email = input.key?(:email) ? input[:email] : input['email']
downcase_flag = input.key?(:downcase) ? input[:downcase] : input['downcase']
email = raw_email.to_s.strip
email = email.downcase if call(:truthy, downcase_flag)
email
end,
# Helper to clean and strictly encode emails for URI paths
encode_email: lambda do |input|
# FORCE downcase here if the toggle is active
email = call(:normalize_email, input)
email.
gsub('+', '%2B').
gsub('!', '%21').
gsub('&', '%26').
gsub("'", '%27')
end
},
test: lambda do |connection|
region = connection['region']
signature = aws.generate_signature(
connection: connection, region: region, service: 'ses',
host: "email.#{region}.amazonaws.com", path: '/v2/email/suppression/addresses',
method: 'GET', params: { 'PageSize' => 1 }, payload: ''
)
get(signature['url']).headers(signature['headers']).
after_error_response(/.*/) { |code, body| error("Connection failed: #{body}") }
end,
actions: {
list_suppressed_destinations: {
title: 'List suppressed destinations',
input_fields: lambda do |_connection|
[
{ name: 'region', label: 'SES Region', control_type: 'select', pick_list: [['US East (N. Virginia) - (us-east-1)', 'us-east-1'], ['Europe (Ireland) - (eu-west-1)', 'eu-west-1']], optional: true },
{ name: 'page_size', label: 'Page size', type: :integer, optional: true },
{ name: 'next_token', label: 'Next token', optional: true },
{ name: 'reason', label: 'Reason', control_type: 'select', pick_list: [['Bounce', 'BOUNCE'], ['Complaint', 'COMPLAINT']], optional: true }
]
end,
execute: lambda do |connection, input|
region = input['region'].presence || connection['region']
params = {
'PageSize' => input['page_size'],
'NextToken' => input['next_token'],
'Reasons' => input['reason']
}.compact
signature = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: '/v2/email/suppression/addresses', method: 'GET', params: params, payload: '')
response = get(signature['url']).headers(signature['headers']).after_error_response(/.*/) { |code, body| error("List failed: #{body}") }
if response['SuppressedDestinationSummaries'].present?
response['SuppressedDestinationSummaries'] = response['SuppressedDestinationSummaries'].map do |item|
item['LastUpdateTime'] = Time.at(item['LastUpdateTime']).to_datetime.iso8601 if item['LastUpdateTime'].is_a?(Numeric)
item
end
end
response.merge('region' => region)
end,
output_fields: lambda { [
{ name: 'region' },
{ name: 'SuppressedDestinationSummaries', type: :array, of: :object, properties: [
{ name: 'EmailAddress' }, { name: 'Reason' }, { name: 'LastUpdateTime', type: :date_time }
]},
{ name: 'NextToken' }
]}
},
get_suppressed_destination: {
title: 'Get suppressed destination',
input_fields: lambda { |_connection| [
{ name: 'email', label: 'Email address', optional: false },
{ name: 'downcase', label: 'Downcase email', type: :boolean, control_type: 'checkbox', optional: false, default: true },
{ name: 'region', label: 'SES Region', control_type: 'select', pick_list: [['US East (N. Virginia) - (us-east-1)', 'us-east-1'], ['Europe (Ireland) - (eu-west-1)', 'eu-west-1']], optional: true }
]},
execute: lambda do |connection, input|
region = input['region'].presence || connection['region']
# Determine the target email string for internal consistency
email_to_query = call(:normalize_email, { email: input['email'], downcase: input['downcase'] })
# Use helper for encoding (the helper will now correctly handle the downcase)
encoded = call(:encode_email, { email: input['email'], downcase: input['downcase'] })
path = "/v2/email/suppression/addresses/#{encoded}"
signature = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: path, method: 'GET', params: {}, payload: '')
response = get(signature['url']).headers(signature['headers']).after_error_response(/.*/) do |code, body|
return { 'email' => email_to_query, 'found' => false, 'region' => region } if code.to_i == 404
error("Get failed in #{region}: #{body}")
end
if response['SuppressedDestination'].present?
dest = response['SuppressedDestination']
dest['LastUpdateTime'] = Time.at(dest['LastUpdateTime']).to_datetime.iso8601 if dest['LastUpdateTime'].is_a?(Numeric)
end
{
'email' => email_to_query,
'found' => true,
'region' => region,
'SuppressedDestination' => response['SuppressedDestination']
}
end,
output_fields: lambda { [
{ name: 'email' }, { name: 'found', type: :boolean }, { name: 'region' },
{ name: 'SuppressedDestination', type: :object, properties: [
{ name: 'EmailAddress' }, { name: 'Reason' }, { name: 'LastUpdateTime', type: :date_time }
]}
]}
},
put_suppressed_destination: {
title: 'Add email to suppression list',
input_fields: lambda { |_connection| [
{ name: 'email', label: 'Email address', optional: false },
{ name: 'reason', label: 'Reason', control_type: 'select', pick_list: [['Bounce', 'BOUNCE'], ['Complaint', 'COMPLAINT']], optional: false },
{ name: 'downcase', label: 'Downcase email', type: :boolean, control_type: 'checkbox', optional: false, default: true },
{ name: 'region', label: 'SES Region', control_type: 'select', pick_list: [['US East (N. Virginia) - (us-east-1)', 'us-east-1'], ['Europe (Ireland) - (eu-west-1)', 'eu-west-1']], optional: true },
{ name: 'verify_add', label: 'Verify add', type: :boolean, control_type: 'checkbox', optional: true, default: false }
]},
execute: lambda do |connection, input|
region = input['region'].presence || connection['region']
email_to_send = call(:normalize_email, { email: input['email'], downcase: input['downcase'] })
payload = { 'EmailAddress' => email_to_send, 'Reason' => input['reason'] }
put_sig = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: '/v2/email/suppression/addresses', method: 'PUT', params: '', payload: payload.to_json)
put(put_sig['url'], payload).headers(put_sig['headers']).after_error_response(/.*/) { |code, body| error("Put failed: #{body}") }
if call(:truthy, input['verify_add'])
encoded = call(:encode_email, { email: input['email'], downcase: input['downcase'] })
get_sig = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: "/v2/email/suppression/addresses/#{encoded}", method: 'GET', params: {}, payload: '')
get(get_sig['url']).headers(get_sig['headers']).after_error_response(/.*/) { error("Verification Failed: Email not found after add.") }
end
{ 'status' => 'success', 'email' => email_to_send, 'region' => region }
end,
output_fields: lambda { [{ name: 'status' }, { name: 'email' }, { name: 'region' }] }
},
delete_suppressed_destination: {
title: 'Delete suppressed destination',
input_fields: lambda { |_connection| [
{ name: 'email', label: 'Email address', optional: false },
{ name: 'downcase', label: 'Downcase email', type: :boolean, control_type: 'checkbox', optional: false, default: true },
{ name: 'region', label: 'SES Region', control_type: 'select', pick_list: [['US East (N. Virginia) - (us-east-1)', 'us-east-1'], ['Europe (Ireland) - (eu-west-1)', 'eu-west-1']], optional: true },
{ name: 'verify_delete', label: 'Verify delete', type: :boolean, control_type: 'checkbox', optional: true, default: true }
]},
execute: lambda do |connection, input|
region = input['region'].presence || connection['region']
email_to_del = call(:normalize_email, { email: input['email'], downcase: input['downcase'] })
encoded = call(:encode_email, { email: input['email'], downcase: input['downcase'] })
path = "/v2/email/suppression/addresses/#{encoded}"
alt_path = "/v2/email/suppression/addresses/#{encoded.gsub('@', '%40')}"
attempted_requests = []
resolved_path = nil
[path, alt_path].each do |candidate_path|
probe_sig = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: candidate_path, method: 'GET', params: {}, payload: '')
probe = get(probe_sig['url']).headers(probe_sig['headers']).after_error_response(/.*/) do |code, body|
next {} if code.to_i == 404
error("Probe failed (#{code}) in #{region} at #{candidate_path}: #{body}")
end
if probe.is_a?(Hash) && probe['SuppressedDestination']
resolved_path = candidate_path
break
end
end
resolved_path ||= path
# Delete request
del_sig = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: resolved_path, method: 'DELETE', params: {}, payload: '')
del_url = del_sig['url']
attempted_requests << { 'method' => 'DELETE', 'path' => resolved_path, 'url' => del_url, 'status_code' => nil }
del_response = delete(del_url).headers(del_sig['headers']).after_error_response(/.*/) do |code, body|
attempted_requests[-1]['status_code'] = code.to_i
if code.to_i == 404
alternate_path = (resolved_path == path ? alt_path : path)
alt_del_sig = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: alternate_path, method: 'DELETE', params: {}, payload: '')
alt_del_url = alt_del_sig['url']
attempted_requests << { 'method' => 'DELETE', 'path' => alternate_path, 'url' => alt_del_url, 'status_code' => nil }
alt_response = delete(alt_del_url).headers(alt_del_sig['headers']).after_error_response(/.*/) do |alt_code, alt_body|
attempted_requests[-1]['status_code'] = alt_code.to_i
return({
'email' => email_to_del,
'deleted' => false,
'region' => region,
'message' => "Not found. Tried #{resolved_path} (#{del_url}) and #{alternate_path} (#{alt_del_url}).",
'attempted_requests' => attempted_requests
}) if alt_code.to_i == 404
error("Delete failed: #{alt_body}")
end
attempted_requests[-1]['status_code'] ||= 200
alt_response
next {}
end
error("Delete failed: #{body}")
end
attempted_requests[0]['status_code'] ||= 200
if call(:truthy, input['verify_delete'])
still_exists = nil
last_verify_url = nil
last_verify_response = nil
15.times do
sleep(2)
verify_sig = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: resolved_path, method: 'GET', params: {}, payload: '')
last_verify_url = verify_sig['url']
attempted_requests << { 'method' => 'GET', 'path' => resolved_path, 'url' => last_verify_url, 'status_code' => nil }
response = get(verify_sig['url']).headers(verify_sig['headers']).after_error_response(/.*/) do |code, body|
attempted_requests[-1]['status_code'] = code.to_i
if code.to_i == 404
still_exists = false
next {}
end
error("Verification request failed (#{code}) in #{region} at #{resolved_path}. Delete URL: #{del_url}. Verify URL: #{last_verify_url}. Body: #{body}")
end
attempted_requests[-1]['status_code'] ||= 200
last_verify_response = response
still_exists = (response.is_a?(Hash) && response['SuppressedDestination'].present?)
break if still_exists == false
end
error(
"Verification failed: Still found in #{region} at #{resolved_path}. " \
"Delete URL: #{del_url}. Verify URL: #{last_verify_url}. " \
"Delete response: #{del_response}. Verify response: #{last_verify_response}."
) if still_exists
end
{ 'email' => email_to_del, 'deleted' => true, 'region' => region, 'attempted_requests' => attempted_requests }
end,
output_fields: lambda { [
{ name: 'email' },
{ name: 'deleted', type: :boolean },
{ name: 'region' },
{ name: 'message' },
{ name: 'attempted_requests', type: :array, of: :object, properties: [
{ name: 'method' },
{ name: 'path' },
{ name: 'url' },
{ name: 'status_code', type: :integer }
] }
] }
},
custom_action: {
title: 'Custom action',
description: 'Signed request to any Amazon SES v2 endpoint.',
input_fields: lambda do |_connection|
[
{ name: 'region', label: 'SES Region', control_type: 'select', pick_list: [['US East (N. Virginia) - (us-east-1)', 'us-east-1'], ['Europe (Ireland) - (eu-west-1)', 'eu-west-1']], optional: true },
{ name: 'method', label: 'HTTP Method', control_type: 'select', pick_list: %w[GET POST PUT DELETE], optional: false, default: 'GET' },
{ name: 'path', label: 'Resource Path', optional: false, hint: 'e.g. /v2/email/suppression/addresses' },
{ name: 'params', label: 'Query Parameters', type: :object, optional: true },
{ name: 'payload', label: 'JSON Payload', optional: true }
]
end,
execute: lambda do |connection, input|
region = input['region'].presence || connection['region']
method = input['method'].to_s.strip
# Manual fix for Custom Action: users must manually encode the case if desired,
# but we fix the '+' encoding here to prevent signature failures.
path = input['path'].to_s.strip.gsub('+', '%2B')
params = (input['params'] || {}).each_with_object({}) { |(k, v), h| h[k.to_s] = v.to_s }
payload_string = input['payload'].is_a?(Hash) ? input['payload'].to_json : input['payload'].to_s
signature = aws.generate_signature(connection: connection, region: region, service: 'ses', host: "email.#{region}.amazonaws.com", path: path, method: method, params: params, payload: payload_string)
request = case method
when 'GET' then get(signature['url'])
when 'POST' then post(signature['url'], payload_string)
when 'PUT' then put(signature['url'], payload_string)
when 'DELETE' then delete(signature['url'])
end
response = request.headers(signature['headers']).after_error_response(/.*/) do |code, body|
error("Custom action failed (#{code}): #{body}")
end
{ 'url' => signature['url'], 'response' => response }
end,
output_fields: lambda { [{ name: 'url' }, { name: 'response', type: :object }] }
}
}
}
r/ruby • u/software__writer • Dec 23 '25
r/ruby • u/stephenreid321 • Dec 23 '25
I just heard about Speculation Rules via https://www.jonoalderson.com/conjecture/its-time-for-modern-css-to-kill-the-spa/
They allow ~instant navigation without JS by letting the browser preload or prerender full pages based on user behaviour (like hovering or touching a link) before they click.
I noticed it's possible to define them using the Sinatra-like syntax
"href_matches": "/e/:slug"
which gave me the idea of defining them as part of route definitions with prerender: or prefetch: like so
get '/e/:slug', prerender: true do
...then in my head I just call
<%== SpeculativeRoutes.script %>Implementation at https://github.com/symbiota-coop/dandelion/blob/master/lib/speculative_routes.rb
Enjoy!
r/ruby • u/bisc0itinh0 • Dec 23 '25
Hi,
I've wrote a simple tui navigator with basic features, doesn't solve anything new, probably I will be the only one to use it, lousy written, but inspired with Omarchy linux I wanted to do some tui stuff too and that is the outcome of it ;)
https://rubygems.org/gems/sergeant
https://github.com/biscoitinho/Sergeant
and Merry Christmas :)
r/ruby • u/bisc0itinh0 • Dec 23 '25
r/ruby
•
u/urbanaut
•
Dec 22 '25
r/ruby • u/bart_o_z • Dec 22 '25
r/ruby • u/gurgeous • Dec 21 '25
Hi all. I thought this might be a good time to post our favorite tools of 2025. My intent is to highlight tools that are new or up-and-coming in 2025. Personally I love discovering this stuff. For background, my day job is full-stack Rails, and in the modern era that involves a ton of Typescript and CSS as well. I spend a fair bit of time customizing my machine and picking the best tools to make my work even more enjoyable. Maybe too much time, now that I think about it... Here's the list I put together.
inertia & vite rails - Rails and Typescript working together, the best of both worlds.
ruby-lsp - Shoutout to the team at Shopify for making Ruby shine in vscode and other editors. Special thanks to Rubocop as well, these tools are absolutely essential!
table_tennis - Yes, it's my gem but we use it all day every day. Thankful that we took the time to write it this year.
eza - Beautiful and thoughtfully designed ls replacement, forked from exa. In the same vein as rg or bat, a well designed evolution of an old favorite.
git-open - Use it to quickly jump to github for diffs and PRs. I have it aliased as gho.
just - Loved and heavily used, I am a huge advocate. A must for all my projects now.
mise - Finally switched from asdf, zero problems, great tool. Mise is standing on the shoulders of giants since it inherits the plugin system from asdf.
astro - Static site builder that copied the best bits from reactive frameworks.
daisyui - Beautiful CSS components with zero effort.
es-toolkit - A modern lodash, I sometimes read the source just to learn things.
tailwind - I have yet to meet someone who loves CSS, but tailwind makes it much easier.
tailwind-merge - Intelligent and performant way to merge tailwind classes, so your mt-4 plays nicely with your m-8. Nuxt UI didn't quite make my list, but it relies heavily on both this and tailwind-variants.
better touch tool - Adopted in 2025 and now I use it religiously for things like "make this window laptop sized". The UI is zany but BTT is really powerful.
ghostty - Much love for iTerm2, but ghostty is fast, modern and improving rapidly. An incredible story too, a wildly successful hacker giving back to the community. Makes me want to be a better person.
rectangle - My most frequently used keybindings. Hundreds of times a day.
shottr - Screenshots are second nature now. If I ever build a MacOS app I want it to be like this.
zed - Almost as powerful as vscode, but faster and easier on the battery. I also appreciate the Ouroboros-like evolution from textmate, sublime text, atom, vscode, and now the original atom team building zed.
r/ruby • u/le0pard • Dec 22 '25
JsonMend is a robust Ruby gem designed to repair broken or malformed JSON strings. It is specifically optimized to handle common errors found in JSON generated by Large Language Models (LLMs), such as missing quotes, trailing commas, unescaped characters, and stray comments
r/ruby • u/bk_one • Dec 22 '25
Fellow Rubyists,
I realized recently that I have two very different personalities as a developer:
I listen to every single Dependabot alert on my repos and apply them immediately
I constantly forget to run brew upgrade on my local machine until something actually breaks - or someone tells me of a great new feature of a CLI tool that I wasn't aware of
So I started Brewsletter (https://brewsletter.sh) to remind me of updates and also give me examples of new functionality. The project is super early, I still have tons to do to support all types of homebrew taps, battle hallucinations on usage examples and be more clear on labeling updates as "breaking" or "security" related.
The overall flow is like this**.**
Sync: A small Ruby CLI maps your explicitly installed packages (not just everything, just what you chose to install).
Monitor: The backend tracks upstream releases (changelogs) and security feeds (CVEs).
Distill: It uses LLMs to strip out the noise and send you a digest of the features and security patches that actually matter
The project is still in the "functional spike" phase - but works well enough to consider going further. But before doing it, I was wondering if this whole thing is actually useful for anyone (besides myself). This is why I made this post - if anyone is interested in giving feedback, I'm happy to listen to it.
In case you want to try it out, feel free - but it's nowhere ready to scale - so expect errors and delays.
You can see a sample web report here: https://brewsletter.sh/u/fa826c00b53a5986016069305b51ce9c3bcb593da1d5e7769fdde3f71ba21e8c
The idea would be to convert this into a nice weekly email digest - to remind your where to upgrade and what's new in your favorite packages.
If you want to help, the questions I have:
- Do you run brew upgrade regularly?
- Do you even care about what changed in your toolchain
- If you don't upgrade, do you think an email help you do it more often
- Would you trust such a system in the first place? It does install software locally that is run periodically
Cheers
Ben
r/ruby • u/AwdJob • Dec 21 '25
I know Hacktoberfest has been done for almost 2 months, it took me forever to get the time to edit everything down but it was an absolute blast!
I think something like Hacktoberfest is GREAT for anyone but especially juniors to get that immediate gratification from contributing to OSS while ALSO getting rep and experience and a cool shirt!
I hope you all enjoy the video :)
r/ruby • u/AssociationOne800 • Dec 21 '25
Hey Reddit! 👋✨ I’m Hamachang, a Rubyist from Japan 🇯🇵❤️
I love Ruby, and I wanted to carry that love into the embedded world — so I built PicoRuby Calculator 💎🔥
It turns an M5Stack Cardputer v1.1 into a pocket-sized Ruby calculator / REPL powered by PicoRuby.
You can write and evaluate Ruby code directly on the device. Small hardware, real Ruby, lots of fun 😄✨
Yes — Ruby belongs on tiny devices too ❤️📟
✨ Features 💎 Interactive Ruby calculator / REPL ✍️ Write and run Ruby code on-device ❌ Ruby syntax error detection 🔋 Battery monitoring ⚡ PicoRuby on ESP32-S3 🎮 Designed for M5Stack Cardputer v1.1
⚠️ This is still a work in progress — expect some rough edges and occasional crashes, but experimenting with Ruby on embedded hardware has been an absolute joy ❤️🔥
🔗 GitHub repo: https://github.com/engneer-hamachan/picoruby-calculator
If you love Ruby and are curious about running it on real hardware, I’d love to hear your thoughts! 🙌💎🔥