
Ruby
- 38 installs
- 19 repo stars
- Updated January 20, 2026
- miles990/claude-software-skills
Helps with ai & agent building tasks.
About
ruby is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- ruby
- AI & Agent Building
- AI-coding skill
Ruby by the numbers
- 38 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #8,404 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/miles990/claude-software-skills --skill rubyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 38 |
|---|---|
| repo stars | ★ 19 |
| Last updated | January 20, 2026 |
| Repository | miles990/claude-software-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Ruby
Overview
Ruby programming patterns including blocks, metaprogramming, and idiomatic Ruby code.
---
Core Ruby Patterns
Classes and Modules
# Class definition
class User
attr_accessor :name, :email
attr_reader :id
attr_writer :password
# Class variable
@@count = 0
# Class method
def self.count
@@count
end
# Initialize
def initialize(name, email)
@id = SecureRandom.uuid
@name = name
@email = email
@@count += 1
end
# Instance method
def display_name
"#{name} <#{email}>"
end
# Private methods
private
def validate_email
email.include?('@')
end
end
# Inheritance
class Admin < User
attr_accessor :permissions
def initialize(name, email, permissions = [])
super(name, email)
@permissions = permissions
end
def has_permission?(perm)
permissions.include?(perm)
end
end
# Modules for mixins
module Timestampable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def timestamped_attrs
[:created_at, :updated_at]
end
end
def touch
@updated_at = Time.now
end
def created_at
@created_at ||= Time.now
end
end
# Including module
class Document
include Timestampable
include Comparable
attr_accessor :title, :content
def <=>(other)
title <=> other.title
end
end
# Module for namespacing
module MyApp
module Services
class UserService
def create(params)
# ...
end
end
end
endBlocks, Procs, and Lambdas
# Block usage
[1, 2, 3].each { |n| puts n }
[1, 2, 3].map do |n|
n * 2
end
# Yield to block
def with_timing
start = Time.now
result = yield
elapsed = Time.now - start
puts "Elapsed: #{elapsed}s"
result
end
with_timing { sleep(0.1) }
# Block with arguments
def transform_items(items)
items.map { |item| yield(item) }
end
transform_items([1, 2, 3]) { |n| n * 2 }
# Check if block given
def optional_block
if block_given?
yield
else
"No block provided"
end
end
# Convert block to proc
def with_block(&block)
block.call(42)
end
# Proc
my_proc = Proc.new { |x| x * 2 }
my_proc.call(21) # => 42
# Lambda
my_lambda = ->(x) { x * 2 }
my_lambda.call(21) # => 42
# Proc vs Lambda differences
proc_example = Proc.new { |x, y| x }
proc_example.call(1) # Works, y is nil
lambda_example = ->(x, y) { x }
# lambda_example.call(1) # ArgumentError
# Symbol to proc
['a', 'b', 'c'].map(&:upcase)
# Equivalent to: ['a', 'b', 'c'].map { |s| s.upcase }Enumerable and Iterators
# Array operations
numbers = [1, 2, 3, 4, 5]
# Map/collect
doubled = numbers.map { |n| n * 2 }
# Select/filter
evens = numbers.select(&:even?)
# Reject
odds = numbers.reject(&:even?)
# Reduce/inject
sum = numbers.reduce(0) { |acc, n| acc + n }
sum = numbers.reduce(:+)
# Each with index
numbers.each_with_index do |n, i|
puts "#{i}: #{n}"
end
# Find
found = numbers.find { |n| n > 3 }
# Any/all/none
numbers.any?(&:even?) # true
numbers.all? { |n| n > 0 } # true
numbers.none? { |n| n > 10 } # true
# Group by
users = [
{ name: 'Alice', role: 'admin' },
{ name: 'Bob', role: 'user' },
{ name: 'Charlie', role: 'admin' }
]
grouped = users.group_by { |u| u[:role] }
# => { 'admin' => [...], 'user' => [...] }
# Partition
passed, failed = scores.partition { |s| s >= 60 }
# Flat map
nested = [[1, 2], [3, 4]]
flat = nested.flat_map { |arr| arr.map { |n| n * 2 } }
# Lazy evaluation
(1..Float::INFINITY).lazy
.select(&:even?)
.map { |n| n * 2 }
.take(10)
.to_a
# Custom iterator
class Countdown
include Enumerable
def initialize(start)
@start = start
end
def each
@start.downto(0) { |n| yield n }
end
end
Countdown.new(5).to_a # => [5, 4, 3, 2, 1, 0]---
Metaprogramming
# Method missing
class DynamicProxy
def initialize(target)
@target = target
end
def method_missing(method, *args, &block)
puts "Calling #{method} with #{args}"
@target.send(method, *args, &block)
end
def respond_to_missing?(method, include_private = false)
@target.respond_to?(method) || super
end
end
# Define method dynamically
class User
ROLES = %w[admin moderator user]
ROLES.each do |role|
define_method("#{role}?") do
@role == role
end
end
end
# Class macro
class MyModel
def self.attribute(name, type)
define_method(name) do
instance_variable_get("@#{name}")
end
define_method("#{name}=") do |value|
instance_variable_set("@#{name}", value)
end
end
attribute :name, :string
attribute :age, :integer
end
# Hook methods
class Base
def self.inherited(subclass)
puts "#{subclass} inherits from #{self}"
end
def self.method_added(method_name)
puts "Method #{method_name} added"
end
end
# Instance eval / class eval
class Config
def self.configure(&block)
instance_eval(&block)
end
def self.setting(name, value)
define_singleton_method(name) { value }
end
end
Config.configure do
setting :api_key, 'abc123'
setting :timeout, 30
end
# Send / public_send
obj.send(:private_method) # Can call private
obj.public_send(:public_method) # Only public
# Refinements (safer monkey patching)
module StringExtensions
refine String do
def to_slug
downcase.gsub(/\s+/, '-')
end
end
end
class MyClass
using StringExtensions
def process(title)
title.to_slug
end
end---
Error Handling
# Basic exception handling
begin
risky_operation
rescue StandardError => e
puts "Error: #{e.message}"
puts e.backtrace.first(5).join("\n")
ensure
cleanup
end
# Multiple rescue clauses
begin
parse_file(path)
rescue Errno::ENOENT
puts "File not found"
rescue JSON::ParserError => e
puts "Invalid JSON: #{e.message}"
rescue => e
puts "Unknown error: #{e.class}"
end
# Retry
attempts = 0
begin
attempts += 1
connect_to_server
rescue ConnectionError
retry if attempts < 3
raise
end
# Custom exceptions
class AppError < StandardError
attr_reader :code
def initialize(message, code: nil)
super(message)
@code = code
end
end
class ValidationError < AppError
attr_reader :errors
def initialize(errors)
super("Validation failed")
@errors = errors
end
end
# Raise with custom exception
raise ValidationError.new({ email: ['is invalid'] })
# Re-raise with context
begin
process_order(order)
rescue => e
raise "Failed to process order #{order.id}: #{e.message}"
end
# Result object pattern
class Result
attr_reader :value, :error
def self.success(value)
new(value: value)
end
def self.failure(error)
new(error: error)
end
def initialize(value: nil, error: nil)
@value = value
@error = error
end
def success?
error.nil?
end
def failure?
!success?
end
def then
return self if failure?
yield(value)
end
end
# Usage
def create_user(params)
return Result.failure('Email required') unless params[:email]
user = User.create(params)
Result.success(user)
rescue ActiveRecord::RecordInvalid => e
Result.failure(e.message)
end---
Testing with RSpec
# spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'validations' do
it { is_expected.to validate_presence_of(:email) }
it { is_expected.to validate_uniqueness_of(:email) }
end
describe 'associations' do
it { is_expected.to have_many(:posts) }
it { is_expected.to belong_to(:organization) }
end
describe '#display_name' do
subject(:user) { build(:user, name: 'John', email: 'john@example.com') }
it 'returns formatted name with email' do
expect(user.display_name).to eq('John <john@example.com>')
end
end
describe '.active' do
let!(:active_user) { create(:user, active: true) }
let!(:inactive_user) { create(:user, active: false) }
it 'returns only active users' do
expect(User.active).to contain_exactly(active_user)
end
end
context 'when user is admin' do
subject(:admin) { build(:user, :admin) }
it 'has admin privileges' do
expect(admin).to be_admin
end
end
end
# spec/services/user_service_spec.rb
RSpec.describe UserService do
describe '#create' do
subject(:service) { described_class.new }
let(:params) { { email: 'test@example.com', name: 'Test' } }
let(:email_service) { instance_double(EmailService) }
before do
allow(EmailService).to receive(:new).and_return(email_service)
allow(email_service).to receive(:send_welcome)
end
it 'creates a user' do
expect { service.create(params) }.to change(User, :count).by(1)
end
it 'sends welcome email' do
service.create(params)
expect(email_service).to have_received(:send_welcome)
end
context 'with invalid params' do
let(:params) { { email: '' } }
it 'raises validation error' do
expect { service.create(params) }.to raise_error(ValidationError)
end
end
end
end---
Concurrency
# Threads
threads = []
results = []
mutex = Mutex.new
5.times do |i|
threads << Thread.new do
result = heavy_computation(i)
mutex.synchronize { results << result }
end
end
threads.each(&:join)
# Thread pool with Concurrent Ruby
require 'concurrent'
pool = Concurrent::FixedThreadPool.new(5)
futures = urls.map do |url|
Concurrent::Future.execute(executor: pool) do
fetch_url(url)
end
end
results = futures.map(&:value)
# Async/await with Async gem
require 'async'
Async do
results = urls.map do |url|
Async do
fetch_url(url)
end
end.map(&:wait)
end
# Fiber (cooperative concurrency)
fiber = Fiber.new do
puts "Start"
Fiber.yield 1
puts "Middle"
Fiber.yield 2
puts "End"
end
fiber.resume # "Start", returns 1
fiber.resume # "Middle", returns 2
fiber.resume # "End", returns nil
# Ractor (Ruby 3.0+ parallel execution)
ractor = Ractor.new do
val = Ractor.receive
val * 2
end
ractor.send(21)
result = ractor.take # => 42---
Related Skills
- [[backend]] - Ruby on Rails
- [[testing]] - RSpec, Minitest
- [[automation-scripts]] - Ruby scripting
# ===========================================
# RuboCop Configuration Template
# Usage: Copy to project root
# ===========================================
require:
- rubocop-rspec
- rubocop-performance
AllCops:
TargetRubyVersion: 3.2
NewCops: enable
Exclude:
- 'vendor/**/*'
- 'node_modules/**/*'
- 'db/schema.rb'
- 'bin/**/*'
- 'tmp/**/*'
# ===========================================
# Layout
# ===========================================
Layout/LineLength:
Max: 120
AllowedPatterns:
- '^\s*#' # Comments
Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented
Layout/FirstArrayElementIndentation:
EnforcedStyle: consistent
Layout/FirstHashElementIndentation:
EnforcedStyle: consistent
Layout/EmptyLinesAroundAttributeAccessor:
Enabled: true
Layout/SpaceAroundMethodCallOperator:
Enabled: true
# ===========================================
# Metrics
# ===========================================
Metrics/MethodLength:
Max: 20
CountAsOne:
- array
- hash
- heredoc
Metrics/ClassLength:
Max: 150
CountAsOne:
- array
- hash
- heredoc
Metrics/BlockLength:
Exclude:
- 'spec/**/*'
- '*.gemspec'
- 'Rakefile'
- 'config/routes.rb'
Metrics/AbcSize:
Max: 20
Metrics/CyclomaticComplexity:
Max: 10
Metrics/PerceivedComplexity:
Max: 10
# ===========================================
# Style
# ===========================================
Style/StringLiterals:
EnforcedStyle: single_quotes
Style/StringLiteralsInInterpolation:
EnforcedStyle: double_quotes
Style/Documentation:
Enabled: false
Style/FrozenStringLiteralComment:
EnforcedStyle: always
Style/TrailingCommaInArrayLiteral:
EnforcedStyleForMultiline: consistent_comma
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: consistent_comma
Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: consistent_comma
Style/HashEachMethods:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
Style/ExponentialNotation:
Enabled: true
Style/SlicingWithRange:
Enabled: true
Style/RedundantRegexpCharacterClass:
Enabled: true
Style/RedundantRegexpEscape:
Enabled: true
# ===========================================
# Naming
# ===========================================
Naming/PredicateName:
ForbiddenPrefixes:
- is_
Naming/MethodParameterName:
MinNameLength: 2
AllowedNames:
- id
- to
- by
- db
- io
# ===========================================
# RSpec
# ===========================================
RSpec/ExampleLength:
Max: 20
RSpec/MultipleExpectations:
Max: 5
RSpec/NestedGroups:
Max: 4
RSpec/ContextWording:
Prefixes:
- when
- with
- without
- if
- unless
- for
RSpec/DescribeClass:
Exclude:
- 'spec/requests/**/*'
- 'spec/features/**/*'
- 'spec/system/**/*'
# ===========================================
# Performance
# ===========================================
Performance/Caller:
Enabled: true
Performance/DeletePrefix:
Enabled: true
Performance/DeleteSuffix:
Enabled: true
Performance/Sum:
Enabled: true
Performance/MapCompact:
Enabled: true
# ===========================================
# Gemfile Template
# Usage: Copy to project root
# ===========================================
source 'https://rubygems.org'
ruby '~> 3.2'
# ===========================================
# Web Framework (uncomment as needed)
# ===========================================
# Rails
# gem 'rails', '~> 7.1'
# gem 'puma', '~> 6.4'
# gem 'bootsnap', require: false
# Sinatra
# gem 'sinatra', '~> 3.1'
# gem 'sinatra-contrib', '~> 3.1'
# ===========================================
# Database
# ===========================================
gem 'pg', '~> 1.5'
gem 'sequel', '~> 5.74'
# gem 'activerecord', '~> 7.1'
# gem 'redis', '~> 5.0'
# ===========================================
# HTTP & API
# ===========================================
gem 'faraday', '~> 2.7'
gem 'faraday-retry', '~> 2.2'
gem 'oj', '~> 3.16' # Fast JSON
# ===========================================
# Authentication & Security
# ===========================================
gem 'bcrypt', '~> 3.1'
gem 'jwt', '~> 2.7'
gem 'rack-attack', '~> 6.7'
# ===========================================
# Background Jobs
# ===========================================
gem 'sidekiq', '~> 7.2'
gem 'sidekiq-scheduler', '~> 5.0'
# ===========================================
# Utilities
# ===========================================
gem 'dotenv', '~> 2.8'
gem 'dry-validation', '~> 1.10'
gem 'dry-types', '~> 1.7'
gem 'zeitwerk', '~> 2.6'
# ===========================================
# Development & Test
# ===========================================
group :development, :test do
gem 'rspec', '~> 3.12'
gem 'factory_bot', '~> 6.4'
gem 'faker', '~> 3.2'
gem 'pry', '~> 0.14'
gem 'pry-byebug', '~> 3.10'
end
group :development do
gem 'rubocop', '~> 1.57', require: false
gem 'rubocop-rspec', '~> 2.25', require: false
gem 'rubocop-performance', '~> 1.19', require: false
gem 'solargraph', '~> 0.49', require: false
end
group :test do
gem 'simplecov', '~> 0.22', require: false
gem 'webmock', '~> 3.19'
gem 'vcr', '~> 6.2'
gem 'database_cleaner-sequel', '~> 2.0'
end
Ruby Templates
Project configuration templates for Ruby applications.
Files
| Template | Purpose |
|---|---|
Gemfile | Dependency management |
.rubocop.yml | Code style/linting |
Usage
Quick Start
# Copy templates
cp templates/Gemfile ./Gemfile
cp templates/.rubocop.yml ./.rubocop.yml
# Install dependencies
bundle install
# Run linter
bundle exec rubocop
# Auto-fix issues
bundle exec rubocop -AGemfile Features
| Category | Gems |
|---|---|
| Database | pg, sequel, redis |
| HTTP | faraday, oj |
| Auth | bcrypt, jwt, rack-attack |
| Jobs | sidekiq |
| Validation | dry-validation, dry-types |
| Testing | rspec, factory_bot, faker |
| Coverage | simplecov |
| Mocking | webmock, vcr |
RuboCop Configuration
| Setting | Value |
|---|---|
| Ruby Version | 3.2 |
| Line Length | 120 |
| Method Length | 20 |
| Class Length | 150 |
Plugins
rubocop-rspec- RSpec best practicesrubocop-performance- Performance optimizations
Project Structure
my-project/
├── Gemfile
├── Gemfile.lock
├── .rubocop.yml
├── .ruby-version
├── lib/
│ └── my_app/
│ └── version.rb
├── spec/
│ ├── spec_helper.rb
│ └── my_app/
└── bin/
└── consoleCommon Commands
# Install gems
bundle install
# Update gems
bundle update
# Run tests
bundle exec rspec
# Run tests with coverage
COVERAGE=true bundle exec rspec
# Lint code
bundle exec rubocop
# Auto-fix lint issues
bundle exec rubocop -A
# Interactive console
bundle exec bin/consoleEnvironment Setup
# .ruby-version
echo "3.2.2" > .ruby-version
# .env
DATABASE_URL=postgres://localhost/myapp_dev
REDIS_URL=redis://localhost:6379RSpec Setup
# spec/spec_helper.rb
require 'simplecov'
SimpleCov.start
require 'factory_bot'
require 'webmock/rspec'
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
FactoryBot.find_definitions
end
endCustomization
Add Rails
Uncomment Rails gems in Gemfile:
gem 'rails', '~> 7.1'
gem 'puma', '~> 6.4'Disable Cops
# .rubocop.yml
Style/SomeCop:
Enabled: falsePer-file Exceptions
# .rubocop.yml
Metrics/MethodLength:
Exclude:
- 'db/migrate/*.rb'Related skills
AI & Agent Buildingagents