Claude
Skills
Sign in
Back

ruby-pattern-detector

Included with Lifetime
$97 forever

# Ruby Pattern Detector Skill

Generalscripts

What this skill does

# Ruby Pattern Detector Skill

Automatically detect and suggest common Ruby patterns when working with Ruby code.

## When to Activate

This skill activates when:
- Reading or editing Ruby files
- User asks about Ruby patterns or best practices
- Refactoring Ruby code
- Reviewing Ruby code

## Patterns to Detect

### 1. Data Object Pattern

**Detect:**
- Classes with many attr_reader/attr_accessor declarations
- Classes that primarily hold data
- Classes with `to_h` or `to_json` methods

**Suggest:**
```ruby
class DataObject
  # Add .build class method for construction
  def self.build(attributes)
    new(
      name: attributes[:name],
      email: attributes[:email]
    )
  end
  
  # Add serialization
  def to_h
    {
      name: name,
      email: email
    }
  end
  
  # Add factory methods
  def self.from_json(json)
    build(JSON.parse(json, symbolize_names: true))
  end
  
  def self.from_h(hash)
    build(hash)
  end
end
```

### 2. Loggable Module Pattern

**Detect:**
- Classes with logging statements
- Multiple classes that need logging
- Direct Logger instantiation in classes

**Suggest:**
```ruby
# Create shared Loggable module
module Loggable
  def logger
    @logger ||= Logger.new(STDOUT).tap do |log|
      log.progname = self.class.name
      log.level = ENV.fetch('LOG_LEVEL', 'INFO')
    end
  end
end

# Include in classes
class MyClass
  include Loggable
  
  def process
    logger.info "Processing started"
    # ...
    logger.debug "Details: #{details}"
  end
end
```

### 3. Custom Exception Pattern

**Detect:**
- Raising generic exceptions (RuntimeError, StandardError)
- Classes with domain-specific errors
- Rescue blocks catching broad exceptions

**Suggest:**
```ruby
# Define custom exceptions
module MyApp
  class Error < StandardError; end
  class NotFoundError < Error; end
  class ValidationError < Error; end
  class AuthenticationError < Error; end
end

# Use specific exceptions
class UserService
  def find(id)
    user = repository.find(id)
    raise MyApp::NotFoundError, "User #{id} not found" unless user
    user
  end
  
  def authenticate(credentials)
    raise MyApp::ValidationError, "Invalid credentials" if invalid?(credentials)
    # ...
  rescue SomeExternalError => e
    raise MyApp::AuthenticationError, "Auth failed: #{e.message}"
  end
end
```

### 4. Dependency Injection Pattern

**Detect:**
- Classes instantiating other classes directly
- Hard-coded dependencies
- Difficult to test classes
- Use of global state or singletons

**Suggest:**
```ruby
# Before - hard-coded dependency
class OrderProcessor
  def process(order)
    mailer = EmailMailer.new
    mailer.send_confirmation(order)
  end
end

# After - injected dependency
class OrderProcessor
  def initialize(mailer: EmailMailer.new)
    @mailer = mailer
  end
  
  def process(order)
    @mailer.send_confirmation(order)
  end
end

# Easy to test with mock
processor = OrderProcessor.new(mailer: MockMailer.new)
```

### 5. Null Object Pattern

**Detect:**
- Frequent nil checks
- Conditional logic checking for nil
- `try` or `&.` operators used extensively

**Suggest:**
```ruby
# Create Null Object
class NullUser
  def name
    "Guest"
  end
  
  def email
    nil
  end
  
  def admin?
    false
  end
  
  def null?
    true
  end
end

# Use in code
class Session
  def current_user
    @current_user || NullUser.new
  end
end

# No more nil checks needed
session.current_user.name  # Returns "Guest" instead of raising error
```

### 6. Value Object Pattern

**Detect:**
- Primitive obsession (lots of strings/integers used as domain concepts)
- Data validation scattered throughout code
- Lack of encapsulation for related data

**Suggest:**
```ruby
# Before - primitive obsession
def send_email(email_string)
  raise "Invalid email" unless email_string =~ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  # ...
end

# After - Value Object
class Email
  attr_reader :value
  
  def initialize(value)
    @value = value.to_s.downcase.strip
    validate!
  end
  
  def ==(other)
    value == other.value
  end
  
  def to_s
    value
  end
  
  private
  
  def validate!
    raise ArgumentError, "Invalid email: #{value}" unless valid?
  end
  
  def valid?
    value =~ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  end
end

def send_email(email)
  # Email already validated
  mailer.send(to: email.to_s)
end
```

### 7. Query Object Pattern

**Detect:**
- Complex ActiveRecord scopes
- Long chains of where clauses
- Business logic in controllers or models

**Suggest:**
```ruby
# Extract to Query Object
class ActiveUsersQuery
  def initialize(relation = User.all)
    @relation = relation
  end
  
  def call
    @relation
      .where(active: true)
      .where('last_login_at > ?', 30.days.ago)
      .order(created_at: :desc)
  end
end

# Usage
active_users = ActiveUsersQuery.new.call
recent_active_users = ActiveUsersQuery.new(User.where('created_at > ?', 1.week.ago)).call
```

### 8. Service Object Pattern

**Detect:**
- Fat controllers or models
- Complex multi-step operations
- Methods that orchestrate multiple objects

**Suggest:**
```ruby
class CreateOrderService
  def initialize(user:, items:, payment_method:)
    @user = user
    @items = items
    @payment_method = payment_method
  end
  
  def call
    ActiveRecord::Base.transaction do
      order = create_order
      process_payment(order)
      send_confirmation(order)
      order
    end
  rescue PaymentError => e
    handle_payment_failure(e)
  end
  
  private
  
  attr_reader :user, :items, :payment_method
  
  def create_order
    # ...
  end
  
  def process_payment(order)
    # ...
  end
  
  def send_confirmation(order)
    # ...
  end
end

# Usage
result = CreateOrderService.new(
  user: current_user,
  items: cart.items,
  payment_method: params[:payment_method]
).call
```

## Activation Response

When a pattern is detected, respond with:

**Pattern Detected: [Pattern Name]**

I noticed [specific code smell or opportunity].

This is a good opportunity to use the **[Pattern Name]** pattern, which:
- [Benefit 1]
- [Benefit 2]
- [Benefit 3]

Would you like me to refactor this code to use this pattern?

[Show brief before/after example]

## Guidelines

- Only suggest patterns when clearly beneficial
- Don't over-engineer simple code
- Explain the "why" behind each pattern suggestion
- Provide concrete code examples
- Consider the context and project size
- Balance between pattern purity and pragmatism

Related in General