smithery/miles990

ruby

Ruby programming patterns and idioms

Installation

$ npx skills add smithery/miles990 --skill ruby

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/miles990 · top by installs.

npx skills add smithery/miles990

Browse all from smithery/miles990

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,629 B
  • docs SUMMARY.md 48 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

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: '[email protected]') }

    it 'returns formatted name with email' do
      expect(user.display_name).to eq('John <[email protected]>')
    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: '[email protected]', 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