ruby

Ruby programming patterns including blocks, metaprogramming, and idiomatic Ruby code.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ruby" with this command: npx skills add miles990/claude-software-skills/miles990-claude-software-skills-ruby

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 end

Blocks, 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 &#x3C;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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-quality

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

devops-cicd

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

flame-game-dev

No summary provided by upstream source.

Repository SourceNeeds Review